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