xref: /trunk/main/sal/inc/osl/diagnose.hxx (revision 22076bf1)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 #if ! defined(OSL_DIAGNOSE_HXX_INCLUDED)
24 #define OSL_DIAGNOSE_HXX_INCLUDED
25 
26 #include "osl/diagnose.h"
27 #include "osl/interlck.h"
28 #include "osl/mutex.hxx"
29 #include "rtl/instance.hxx"
30 #include <hash_set>
31 #include <functional>
32 #include <typeinfo>
33 
34 namespace osl {
35 /// @internal
36 namespace detail {
37 
38 struct ObjectRegistryData;
39 
40 } // namespace detail
41 } // namespace osl
42 
43 extern "C" {
44 
45 /** @internal */
46 bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses( char const* pName )
47     SAL_THROW_EXTERN_C();
48 
49 /** @internal */
50 bool SAL_CALL osl_detail_ObjectRegistry_checkObjectCount(
51     ::osl::detail::ObjectRegistryData const& rData, ::std::size_t nExpected )
52     SAL_THROW_EXTERN_C();
53 
54 /** @internal */
55 void SAL_CALL osl_detail_ObjectRegistry_registerObject(
56     ::osl::detail::ObjectRegistryData & rData, void const* pObj )
57     SAL_THROW_EXTERN_C();
58 
59 /** @internal */
60 void SAL_CALL osl_detail_ObjectRegistry_revokeObject(
61     ::osl::detail::ObjectRegistryData & rData, void const* pObj )
62     SAL_THROW_EXTERN_C();
63 
64 /** @internal */
65 ::osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex()
66     SAL_THROW_EXTERN_C();
67 
68 } // extern "C"
69 
70 namespace osl {
71 
72 /// @internal
73 namespace detail {
74 
75 struct VoidPtrHash : ::std::unary_function<void const*, ::std::size_t> {
operator ()osl::detail::VoidPtrHash76     ::std::size_t operator()( void const* p ) const {
77         ::std::size_t const d = static_cast< ::std::size_t >(
78             reinterpret_cast< ::std::ptrdiff_t >(p) );
79         return d + (d >> 3);
80     }
81 };
82 
83 typedef ::std::hash_set<void const*, VoidPtrHash, ::std::equal_to<void const*> > VoidPointerSet;
84 
85 struct ObjectRegistryData {
ObjectRegistryDataosl::detail::ObjectRegistryData86     ObjectRegistryData( ::std::type_info const& rTypeInfo )
87         : m_pName(rTypeInfo.name()), m_nCount(0), m_addresses(),
88           m_bStoreAddresses(osl_detail_ObjectRegistry_storeAddresses(m_pName)){}
89 
90     char const* const m_pName;
91     oslInterlockedCount m_nCount;
92     VoidPointerSet m_addresses;
93     bool const m_bStoreAddresses;
94 };
95 
96 template <typename T>
97 class ObjectRegistry
98 {
99 public:
ObjectRegistry()100     ObjectRegistry() : m_data( typeid(T) ) {}
~ObjectRegistry()101     ~ObjectRegistry() { checkObjectCount(0); }
102 
checkObjectCount(::std::size_t nExpected) const103     bool checkObjectCount( ::std::size_t nExpected ) const {
104         bool const bRet = osl_detail_ObjectRegistry_checkObjectCount(
105             m_data, nExpected );
106         if (!bRet && m_data.m_bStoreAddresses) {
107             MutexGuard const guard( osl_detail_ObjectRegistry_getMutex() );
108             // following loop is for debugging purposes, iterating over map:
109             VoidPointerSet::const_iterator iPos(m_data.m_addresses.begin());
110             VoidPointerSet::const_iterator const iEnd(m_data.m_addresses.end());
111             for ( ; iPos != iEnd; ++iPos ) {
112                 OSL_ASSERT( *iPos != 0 );
113             }
114         }
115         return bRet;
116     }
117 
registerObject(void const * pObj)118     void registerObject( void const* pObj ) {
119         osl_detail_ObjectRegistry_registerObject(m_data, pObj);
120     }
121 
revokeObject(void const * pObj)122     void revokeObject( void const* pObj ) {
123         osl_detail_ObjectRegistry_revokeObject(m_data, pObj);
124     }
125 
126 private:
127     // not impl:
128     ObjectRegistry( ObjectRegistry const& );
129     ObjectRegistry const& operator=( ObjectRegistry const& );
130 
131     ObjectRegistryData m_data;
132 };
133 
134 } // namespace detail
135 
136 /** Helper class which indicates leaking object(s) of a particular class in
137     non-pro builds; use e.g.
138 
139     <pre>
140     class MyClass : private osl::DebugBase<MyClass> {...};
141     </pre>
142 
143     Using the environment variable
144 
145     OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;...
146 
147     you can specify a ';'-separated list of strings matching to class names
148     (or "all" for all classes), for which DebugBase stores addresses to created
149     objects instead of just counting them.  This enables you to iterate over
150     leaking objects in your debugger.
151 
152     @tpl InheritingClassT binds the template instance to that class
153     @internal Use at own risk.
154               For now this is just public (yet unpublished) API and may change
155               in the future!
156 */
157 template <typename InheritingClassT>
158 class DebugBase
159 {
160 public:
161 #if OSL_DEBUG_LEVEL <= 0
checkObjectCount(::std::size_t=0)162     static bool checkObjectCount( ::std::size_t = 0 ) { return true; }
163 #else // OSL_DEBUG_LEVEL > 0
164     /** @return whether the expected number of objects is alive,
165                 else this function OSL_ASSERTs
166     */
167     static bool checkObjectCount( ::std::size_t nExpected = 0 ) {
168         return StaticObjectRegistry::get().checkObjectCount(nExpected);
169     }
170 
171 protected:
172     DebugBase() {
173         StaticObjectRegistry::get().registerObject( this );
174     }
175     ~DebugBase() {
176         StaticObjectRegistry::get().revokeObject( this );
177     }
178 
179 private:
180     struct StaticObjectRegistry
181         : ::rtl::Static<detail::ObjectRegistry<InheritingClassT>,
182                         StaticObjectRegistry> {};
183 #endif
184 };
185 
186 } // namespace osl
187 
188 #endif // ! defined(OSL_DIAGNOSE_HXX_INCLUDED)
189 
190