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 #if ! defined(_OSL_DIAGNOSE_H_) 27 #include "osl/diagnose.h" 28 #endif 29 #if ! defined(_OSL_INTERLOCK_H_) 30 #include "osl/interlck.h" 31 #endif 32 #if ! defined(_OSL_MUTEX_HXX_) 33 #include "osl/mutex.hxx" 34 #endif 35 #if ! defined(INCLUDED_RTL_ALLOCATOR_HXX) 36 #include "rtl/allocator.hxx" 37 #endif 38 #if ! defined(_RTL_INSTANCE_HXX_) 39 #include "rtl/instance.hxx" 40 #endif 41 #include <hash_set> 42 #include <functional> 43 #include <typeinfo> 44 45 namespace osl { 46 /// @internal 47 namespace detail { 48 49 struct ObjectRegistryData; 50 51 } // namespace detail 52 } // namespace osl 53 54 extern "C" { 55 56 /** @internal */ 57 bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses( char const* pName ) 58 SAL_THROW_EXTERN_C(); 59 60 /** @internal */ 61 bool SAL_CALL osl_detail_ObjectRegistry_checkObjectCount( 62 ::osl::detail::ObjectRegistryData const& rData, ::std::size_t nExpected ) 63 SAL_THROW_EXTERN_C(); 64 65 /** @internal */ 66 void SAL_CALL osl_detail_ObjectRegistry_registerObject( 67 ::osl::detail::ObjectRegistryData & rData, void const* pObj ) 68 SAL_THROW_EXTERN_C(); 69 70 /** @internal */ 71 void SAL_CALL osl_detail_ObjectRegistry_revokeObject( 72 ::osl::detail::ObjectRegistryData & rData, void const* pObj ) 73 SAL_THROW_EXTERN_C(); 74 75 /** @internal */ 76 ::osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex() 77 SAL_THROW_EXTERN_C(); 78 79 } // extern "C" 80 81 namespace osl { 82 83 /// @internal 84 namespace detail { 85 86 struct VoidPtrHash : ::std::unary_function<void const*, ::std::size_t> { 87 ::std::size_t operator()( void const* p ) const { 88 ::std::size_t const d = static_cast< ::std::size_t >( 89 reinterpret_cast< ::std::ptrdiff_t >(p) ); 90 return d + (d >> 3); 91 } 92 }; 93 94 typedef ::std::hash_set<void const*, VoidPtrHash, ::std::equal_to<void const*>, 95 ::rtl::Allocator<void const*> > VoidPointerSet; 96 97 struct ObjectRegistryData { 98 ObjectRegistryData( ::std::type_info const& rTypeInfo ) 99 : m_pName(rTypeInfo.name()), m_nCount(0), m_addresses(), 100 m_bStoreAddresses(osl_detail_ObjectRegistry_storeAddresses(m_pName)){} 101 102 char const* const m_pName; 103 oslInterlockedCount m_nCount; 104 VoidPointerSet m_addresses; 105 bool const m_bStoreAddresses; 106 }; 107 108 template <typename T> 109 class ObjectRegistry 110 { 111 public: 112 ObjectRegistry() : m_data( typeid(T) ) {} 113 ~ObjectRegistry() { checkObjectCount(0); } 114 115 bool checkObjectCount( ::std::size_t nExpected ) const { 116 bool const bRet = osl_detail_ObjectRegistry_checkObjectCount( 117 m_data, nExpected ); 118 if (!bRet && m_data.m_bStoreAddresses) { 119 MutexGuard const guard( osl_detail_ObjectRegistry_getMutex() ); 120 // following loop is for debugging purposes, iterating over map: 121 VoidPointerSet::const_iterator iPos(m_data.m_addresses.begin()); 122 VoidPointerSet::const_iterator const iEnd(m_data.m_addresses.end()); 123 for ( ; iPos != iEnd; ++iPos ) { 124 OSL_ASSERT( *iPos != 0 ); 125 } 126 } 127 return bRet; 128 } 129 130 void registerObject( void const* pObj ) { 131 osl_detail_ObjectRegistry_registerObject(m_data, pObj); 132 } 133 134 void revokeObject( void const* pObj ) { 135 osl_detail_ObjectRegistry_revokeObject(m_data, pObj); 136 } 137 138 private: 139 // not impl: 140 ObjectRegistry( ObjectRegistry const& ); 141 ObjectRegistry const& operator=( ObjectRegistry const& ); 142 143 ObjectRegistryData m_data; 144 }; 145 146 } // namespace detail 147 148 /** Helper class which indicates leaking object(s) of a particular class in 149 non-pro builds; use e.g. 150 151 <pre> 152 class MyClass : private osl::DebugBase<MyClass> {...}; 153 </pre> 154 155 Using the environment variable 156 157 OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;... 158 159 you can specify a ';'-separated list of strings matching to class names 160 (or "all" for all classes), for which DebugBase stores addresses to created 161 objects instead of just counting them. This enables you to iterate over 162 leaking objects in your debugger. 163 164 @tpl InheritingClassT binds the template instance to that class 165 @internal Use at own risk. 166 For now this is just public (yet unpublished) API and may change 167 in the future! 168 */ 169 template <typename InheritingClassT> 170 class DebugBase 171 { 172 public: 173 #if OSL_DEBUG_LEVEL <= 0 174 static bool checkObjectCount( ::std::size_t = 0 ) { return true; } 175 #else // OSL_DEBUG_LEVEL > 0 176 /** @return whether the expected number of objects is alive, 177 else this function OSL_ASSERTs 178 */ 179 static bool checkObjectCount( ::std::size_t nExpected = 0 ) { 180 return StaticObjectRegistry::get().checkObjectCount(nExpected); 181 } 182 183 protected: 184 DebugBase() { 185 StaticObjectRegistry::get().registerObject( this ); 186 } 187 ~DebugBase() { 188 StaticObjectRegistry::get().revokeObject( this ); 189 } 190 191 private: 192 struct StaticObjectRegistry 193 : ::rtl::Static<detail::ObjectRegistry<InheritingClassT>, 194 StaticObjectRegistry> {}; 195 #endif 196 }; 197 198 } // namespace osl 199 200 #endif // ! defined(OSL_DIAGNOSE_HXX_INCLUDED) 201 202