Branch libreoffice-5-0-4
[LibreOffice.git] / include / osl / diagnose.hxx
blob577b07c91d839664652c197245a323b4aaab1c90
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
19 #ifndef INCLUDED_OSL_DIAGNOSE_HXX
20 #define INCLUDED_OSL_DIAGNOSE_HXX
22 /// @cond INTERNAL
24 #include <sal/config.h>
26 #include <functional>
27 #include <typeinfo>
29 #include <boost/unordered_set.hpp>
30 #include <osl/diagnose.h>
31 #include <osl/interlck.h>
32 #include <osl/mutex.hxx>
33 #include <rtl/instance.hxx>
34 #include <sal/log.hxx>
35 #include <sal/saldllapi.h>
36 #include <sal/types.h>
38 namespace osl {
39 namespace detail {
41 struct ObjectRegistryData;
43 } // namespace detail
44 } // namespace osl
46 extern "C" {
48 SAL_DLLPUBLIC bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses(
49 char const* pName )
50 SAL_THROW_EXTERN_C();
52 SAL_DLLPUBLIC bool SAL_CALL osl_detail_ObjectRegistry_checkObjectCount(
53 ::osl::detail::ObjectRegistryData const& rData, ::std::size_t nExpected )
54 SAL_THROW_EXTERN_C();
56 SAL_DLLPUBLIC void SAL_CALL osl_detail_ObjectRegistry_registerObject(
57 ::osl::detail::ObjectRegistryData & rData, void const* pObj )
58 SAL_THROW_EXTERN_C();
60 SAL_DLLPUBLIC void SAL_CALL osl_detail_ObjectRegistry_revokeObject(
61 ::osl::detail::ObjectRegistryData & rData, void const* pObj )
62 SAL_THROW_EXTERN_C();
64 // These functions presumably should not be extern "C", but changing
65 // that would break binary compatibility.
66 #ifdef __clang__
67 #pragma clang diagnostic push
68 // Guard against slightly older clang versions that don't have
69 // -Wreturn-type-c-linkage...
70 #pragma clang diagnostic ignored "-Wunknown-pragmas"
71 #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
72 #endif
74 SAL_DLLPUBLIC ::osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex()
75 SAL_THROW_EXTERN_C();
77 #ifdef __clang__
78 #pragma clang diagnostic pop
79 #endif
81 } // extern "C"
83 namespace osl {
85 namespace detail {
87 struct VoidPtrHash : ::std::unary_function<void const*, ::std::size_t> {
88 ::std::size_t operator()( void const* p ) const {
89 ::std::size_t const d = static_cast< ::std::size_t >(
90 reinterpret_cast< ::std::ptrdiff_t >(p) );
91 return d + (d >> 3);
95 typedef ::boost::unordered_set<void const*, VoidPtrHash, ::std::equal_to<void const*> > VoidPointerSet;
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)){}
102 char const* const m_pName;
103 oslInterlockedCount m_nCount;
104 VoidPointerSet m_addresses;
105 bool const m_bStoreAddresses;
108 template <typename T>
109 class ObjectRegistry
111 public:
112 ObjectRegistry() : m_data( typeid(T) ) {}
113 ~ObjectRegistry() { checkObjectCount(0); }
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 SAL_WARN_IF( *iPos == 0, "sal.debug", "null pointer" );
127 return bRet;
130 void registerObject( void const* pObj ) {
131 osl_detail_ObjectRegistry_registerObject(m_data, pObj);
134 void revokeObject( void const* pObj ) {
135 osl_detail_ObjectRegistry_revokeObject(m_data, pObj);
138 private:
139 ObjectRegistry( ObjectRegistry const& ) SAL_DELETED_FUNCTION;
140 ObjectRegistry const& operator=( ObjectRegistry const& ) SAL_DELETED_FUNCTION;
142 ObjectRegistryData m_data;
145 } // namespace detail
147 /** Helper class which indicates leaking object(s) of a particular class in
148 non-pro builds; use e.g.
150 <pre>
151 class MyClass : private osl::DebugBase<MyClass> {...};
152 </pre>
154 Using the environment variable
156 OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;...
158 you can specify a ';'-separated list of strings matching to class names
159 (or "all" for all classes), for which DebugBase stores addresses to created
160 objects instead of just counting them. This enables you to iterate over
161 leaking objects in your debugger.
163 @tparam InheritingClassT binds the template instance to that class
164 @attention Use at own risk.
165 For now this is just public (yet unpublished) API and may change
166 in the future!
168 template <typename InheritingClassT>
169 class DebugBase
171 public:
172 #if OSL_DEBUG_LEVEL <= 0
173 static bool checkObjectCount( ::std::size_t = 0 ) { return true; }
174 #else // OSL_DEBUG_LEVEL > 0
175 /** @return whether the expected number of objects is alive,
176 else this function SAL_WARNs
178 static bool checkObjectCount( ::std::size_t nExpected = 0 ) {
179 return StaticObjectRegistry::get().checkObjectCount(nExpected);
182 protected:
183 DebugBase() {
184 StaticObjectRegistry::get().registerObject( this );
186 ~DebugBase() {
187 StaticObjectRegistry::get().revokeObject( this );
190 private:
191 struct StaticObjectRegistry
192 : ::rtl::Static<detail::ObjectRegistry<InheritingClassT>,
193 StaticObjectRegistry> {};
194 #endif
197 } // namespace osl
199 /// @endcond
201 #endif // ! defined( INCLUDED_OSL_DIAGNOSE_HXX)
203 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */