Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 : #ifndef OSL_DIAGNOSE_HXX_INCLUDED
20 : #define OSL_DIAGNOSE_HXX_INCLUDED
21 :
22 : #include "sal/config.h"
23 :
24 : #include <functional>
25 : #include <typeinfo>
26 :
27 : #ifndef HAVE_CXX0X
28 : #define BOOST_NO_0X_HDR_TYPEINDEX
29 : #endif
30 : #include "boost/unordered_set.hpp"
31 : #include "osl/diagnose.h"
32 : #include "osl/interlck.h"
33 : #include "osl/mutex.hxx"
34 : #include "rtl/allocator.hxx"
35 : #include "rtl/instance.hxx"
36 : #include "sal/log.hxx"
37 : #include "sal/saldllapi.h"
38 : #include "sal/types.h"
39 :
40 : /// @cond INTERNAL
41 :
42 : namespace osl {
43 : namespace detail {
44 :
45 : struct ObjectRegistryData;
46 :
47 : } // namespace detail
48 : } // namespace osl
49 :
50 : extern "C" {
51 :
52 : SAL_DLLPUBLIC bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses(
53 : char const* pName )
54 : SAL_THROW_EXTERN_C();
55 :
56 : SAL_DLLPUBLIC bool SAL_CALL osl_detail_ObjectRegistry_checkObjectCount(
57 : ::osl::detail::ObjectRegistryData const& rData, ::std::size_t nExpected )
58 : SAL_THROW_EXTERN_C();
59 :
60 : SAL_DLLPUBLIC void SAL_CALL osl_detail_ObjectRegistry_registerObject(
61 : ::osl::detail::ObjectRegistryData & rData, void const* pObj )
62 : SAL_THROW_EXTERN_C();
63 :
64 : SAL_DLLPUBLIC void SAL_CALL osl_detail_ObjectRegistry_revokeObject(
65 : ::osl::detail::ObjectRegistryData & rData, void const* pObj )
66 : SAL_THROW_EXTERN_C();
67 :
68 : // These functions presumably should not be extern "C", but changing
69 : // that would break binary compatibility.
70 : #ifdef __clang__
71 : #pragma clang diagnostic push
72 : // Guard against slightly older clang versions that don't have
73 : // -Wreturn-type-c-linkage...
74 : #pragma clang diagnostic ignored "-Wunknown-pragmas"
75 : #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
76 : #endif
77 :
78 : SAL_DLLPUBLIC ::osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex()
79 : SAL_THROW_EXTERN_C();
80 :
81 : #ifdef __clang__
82 : #pragma clang diagnostic pop
83 : #endif
84 :
85 : } // extern "C"
86 :
87 : namespace osl {
88 :
89 : namespace detail {
90 :
91 : struct VoidPtrHash : ::std::unary_function<void const*, ::std::size_t> {
92 0 : ::std::size_t operator()( void const* p ) const {
93 : ::std::size_t const d = static_cast< ::std::size_t >(
94 0 : reinterpret_cast< ::std::ptrdiff_t >(p) );
95 0 : return d + (d >> 3);
96 : }
97 : };
98 :
99 : typedef ::boost::unordered_set<void const*, VoidPtrHash, ::std::equal_to<void const*>,
100 : ::rtl::Allocator<void const*> > VoidPointerSet;
101 :
102 : struct ObjectRegistryData {
103 : ObjectRegistryData( ::std::type_info const& rTypeInfo )
104 : : m_pName(rTypeInfo.name()), m_nCount(0), m_addresses(),
105 : m_bStoreAddresses(osl_detail_ObjectRegistry_storeAddresses(m_pName)){}
106 :
107 : char const* const m_pName;
108 : oslInterlockedCount m_nCount;
109 : VoidPointerSet m_addresses;
110 : bool const m_bStoreAddresses;
111 : };
112 :
113 : template <typename T>
114 : class ObjectRegistry
115 : {
116 : public:
117 : ObjectRegistry() : m_data( typeid(T) ) {}
118 : ~ObjectRegistry() { checkObjectCount(0); }
119 :
120 : bool checkObjectCount( ::std::size_t nExpected ) const {
121 : bool const bRet = osl_detail_ObjectRegistry_checkObjectCount(
122 : m_data, nExpected );
123 : if (!bRet && m_data.m_bStoreAddresses) {
124 : MutexGuard const guard( osl_detail_ObjectRegistry_getMutex() );
125 : // following loop is for debugging purposes, iterating over map:
126 : VoidPointerSet::const_iterator iPos(m_data.m_addresses.begin());
127 : VoidPointerSet::const_iterator const iEnd(m_data.m_addresses.end());
128 : for ( ; iPos != iEnd; ++iPos ) {
129 : SAL_WARN_IF( *iPos == 0, "sal.debug", "null pointer" );
130 : }
131 : }
132 : return bRet;
133 : }
134 :
135 : void registerObject( void const* pObj ) {
136 : osl_detail_ObjectRegistry_registerObject(m_data, pObj);
137 : }
138 :
139 : void revokeObject( void const* pObj ) {
140 : osl_detail_ObjectRegistry_revokeObject(m_data, pObj);
141 : }
142 :
143 : private:
144 : // not impl:
145 : ObjectRegistry( ObjectRegistry const& );
146 : ObjectRegistry const& operator=( ObjectRegistry const& );
147 :
148 : ObjectRegistryData m_data;
149 : };
150 :
151 : } // namespace detail
152 :
153 : /** Helper class which indicates leaking object(s) of a particular class in
154 : non-pro builds; use e.g.
155 :
156 : <pre>
157 : class MyClass : private osl::DebugBase<MyClass> {...};
158 : </pre>
159 :
160 : Using the environment variable
161 :
162 : OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;...
163 :
164 : you can specify a ';'-separated list of strings matching to class names
165 : (or "all" for all classes), for which DebugBase stores addresses to created
166 : objects instead of just counting them. This enables you to iterate over
167 : leaking objects in your debugger.
168 :
169 : @tparam InheritingClassT binds the template instance to that class
170 : @attention Use at own risk.
171 : For now this is just public (yet unpublished) API and may change
172 : in the future!
173 : */
174 : template <typename InheritingClassT>
175 9245 : class DebugBase
176 : {
177 : public:
178 : #if OSL_DEBUG_LEVEL <= 0
179 : static bool checkObjectCount( ::std::size_t = 0 ) { return true; }
180 : #else // OSL_DEBUG_LEVEL > 0
181 : /** @return whether the expected number of objects is alive,
182 : else this function SAL_WARNs
183 : */
184 : static bool checkObjectCount( ::std::size_t nExpected = 0 ) {
185 : return StaticObjectRegistry::get().checkObjectCount(nExpected);
186 : }
187 :
188 : protected:
189 : DebugBase() {
190 : StaticObjectRegistry::get().registerObject( this );
191 : }
192 : ~DebugBase() {
193 : StaticObjectRegistry::get().revokeObject( this );
194 : }
195 :
196 : private:
197 : struct StaticObjectRegistry
198 : : ::rtl::Static<detail::ObjectRegistry<InheritingClassT>,
199 : StaticObjectRegistry> {};
200 : #endif
201 : };
202 :
203 : } // namespace osl
204 :
205 : /// @endcond
206 :
207 : #endif // ! defined(OSL_DIAGNOSE_HXX_INCLUDED)
208 :
209 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|