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