1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
24 #include "sal/config.h"
28 #include <unordered_set>
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"
41 struct ObjectRegistryData
;
48 SAL_DLLPUBLIC
bool SAL_CALL
osl_detail_ObjectRegistry_storeAddresses(
52 SAL_DLLPUBLIC
bool SAL_CALL
osl_detail_ObjectRegistry_checkObjectCount(
53 ::osl::detail::ObjectRegistryData
const& rData
, ::std::size_t nExpected
)
56 SAL_DLLPUBLIC
void SAL_CALL
osl_detail_ObjectRegistry_registerObject(
57 ::osl::detail::ObjectRegistryData
& rData
, void const* pObj
)
60 SAL_DLLPUBLIC
void SAL_CALL
osl_detail_ObjectRegistry_revokeObject(
61 ::osl::detail::ObjectRegistryData
& rData
, void const* pObj
)
64 // These functions presumably should not be extern "C", but changing
65 // that would break binary compatibility.
67 #pragma clang diagnostic push
68 #pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
71 SAL_DLLPUBLIC ::osl::Mutex
& SAL_CALL
osl_detail_ObjectRegistry_getMutex()
75 #pragma clang diagnostic pop
85 ::std::size_t operator()( void const* p
) const {
86 ::std::size_t const d
= static_cast< ::std::size_t >(
87 reinterpret_cast< ::std::ptrdiff_t >(p
) );
92 typedef ::std::unordered_set
<void const*, VoidPtrHash
> VoidPointerSet
;
94 struct ObjectRegistryData
{
95 ObjectRegistryData( ::std::type_info
const& rTypeInfo
)
96 : m_pName(rTypeInfo
.name()), m_nCount(0),
97 m_bStoreAddresses(osl_detail_ObjectRegistry_storeAddresses(m_pName
)) {}
99 char const* const m_pName
;
100 oslInterlockedCount m_nCount
;
101 VoidPointerSet m_addresses
;
102 bool const m_bStoreAddresses
;
105 template <typename T
>
109 ObjectRegistry() : m_data( typeid(T
) ) {}
110 ~ObjectRegistry() { checkObjectCount(0); }
112 bool checkObjectCount( ::std::size_t nExpected
) const {
113 bool const bRet
= osl_detail_ObjectRegistry_checkObjectCount(
115 if (!bRet
&& m_data
.m_bStoreAddresses
) {
116 MutexGuard
const guard( osl_detail_ObjectRegistry_getMutex() );
117 // following loop is for debugging purposes, iterating over map:
118 VoidPointerSet::const_iterator
iPos(m_data
.m_addresses
.begin());
119 VoidPointerSet::const_iterator
const iEnd(m_data
.m_addresses
.end());
120 for ( ; iPos
!= iEnd
; ++iPos
) {
121 SAL_WARN_IF( *iPos
== NULL
, "sal.debug", "null pointer" );
127 void registerObject( void const* pObj
) {
128 osl_detail_ObjectRegistry_registerObject(m_data
, pObj
);
131 void revokeObject( void const* pObj
) {
132 osl_detail_ObjectRegistry_revokeObject(m_data
, pObj
);
136 ObjectRegistry( ObjectRegistry
const& ) SAL_DELETED_FUNCTION
;
137 ObjectRegistry
const& operator=( ObjectRegistry
const& ) SAL_DELETED_FUNCTION
;
139 ObjectRegistryData m_data
;
142 } // namespace detail
144 /** Helper class which indicates leaking object(s) of a particular class in
145 non-pro builds; use e.g.
148 class MyClass : private osl::DebugBase<MyClass> {...};
151 Using the environment variable
153 OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;...
155 you can specify a ';'-separated list of strings matching to class names
156 (or "all" for all classes), for which DebugBase stores addresses to created
157 objects instead of just counting them. This enables you to iterate over
158 leaking objects in your debugger.
160 @tparam InheritingClassT binds the template instance to that class
161 @attention Use at own risk.
162 For now this is just public (yet unpublished) API and may change
165 template <typename InheritingClassT
>
169 #if OSL_DEBUG_LEVEL <= 0
170 static bool checkObjectCount( ::std::size_t = 0 ) { return true; }
171 #else // OSL_DEBUG_LEVEL > 0
172 /** @return whether the expected number of objects is alive,
173 else this function SAL_WARNs
175 static bool checkObjectCount( ::std::size_t nExpected
= 0 ) {
176 return StaticObjectRegistry::get().checkObjectCount(nExpected
);
181 StaticObjectRegistry::get().registerObject( this );
184 StaticObjectRegistry::get().revokeObject( this );
188 struct StaticObjectRegistry
189 : ::rtl::Static
<detail::ObjectRegistry
<InheritingClassT
>,
190 StaticObjectRegistry
> {};
198 #endif // ! defined( INCLUDED_OSL_DIAGNOSE_HXX)
200 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */