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