Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/include/osl/diagnose.hxx
Line
Count
Source
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 <cstddef>
27
#include <typeinfo>
28
#include <unordered_set>
29
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"
37
38
namespace osl {
39
namespace detail {
40
41
struct ObjectRegistryData;
42
43
} // namespace detail
44
} // namespace osl
45
46
extern "C" {
47
48
SAL_DLLPUBLIC bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses(
49
        char const* pName )
50
    SAL_THROW_EXTERN_C();
51
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();
55
56
SAL_DLLPUBLIC void SAL_CALL osl_detail_ObjectRegistry_registerObject(
57
    ::osl::detail::ObjectRegistryData & rData, void const* pObj )
58
    SAL_THROW_EXTERN_C();
59
60
SAL_DLLPUBLIC void SAL_CALL osl_detail_ObjectRegistry_revokeObject(
61
    ::osl::detail::ObjectRegistryData & rData, void const* pObj )
62
    SAL_THROW_EXTERN_C();
63
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
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
69
#endif
70
71
SAL_DLLPUBLIC ::osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex()
72
    SAL_THROW_EXTERN_C();
73
74
#ifdef __clang__
75
#pragma clang diagnostic pop
76
#endif
77
78
} // extern "C"
79
80
namespace osl {
81
82
namespace detail {
83
84
struct VoidPtrHash {
85
0
    ::std::size_t operator()( void const* p ) const {
86
0
        ::std::size_t const d = static_cast< ::std::size_t >(
87
0
            reinterpret_cast< ::std::ptrdiff_t >(p) );
88
0
        return d + (d >> 3);
89
0
    }
90
};
91
92
typedef ::std::unordered_set<void const*, VoidPtrHash > VoidPointerSet;
93
94
struct ObjectRegistryData {
95
    ObjectRegistryData( ::std::type_info const& rTypeInfo )
96
        : m_pName(rTypeInfo.name()), m_nCount(0),
97
0
          m_bStoreAddresses(osl_detail_ObjectRegistry_storeAddresses(m_pName)) {}
98
99
    char const* const m_pName;
100
    oslInterlockedCount m_nCount;
101
    VoidPointerSet m_addresses;
102
    bool const m_bStoreAddresses;
103
};
104
105
template <typename T>
106
class ObjectRegistry
107
{
108
public:
109
    ObjectRegistry() : m_data( typeid(T) ) {}
110
    ~ObjectRegistry() { checkObjectCount(0); }
111
112
    bool checkObjectCount( ::std::size_t nExpected ) const {
113
        bool const bRet = osl_detail_ObjectRegistry_checkObjectCount(
114
            m_data, nExpected );
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" );
122
            }
123
        }
124
        return bRet;
125
    }
126
127
    void registerObject( void const* pObj ) {
128
        osl_detail_ObjectRegistry_registerObject(m_data, pObj);
129
    }
130
131
    void revokeObject( void const* pObj ) {
132
        osl_detail_ObjectRegistry_revokeObject(m_data, pObj);
133
    }
134
135
private:
136
    ObjectRegistry( ObjectRegistry const& ) SAL_DELETED_FUNCTION;
137
    ObjectRegistry const& operator=( ObjectRegistry const& ) SAL_DELETED_FUNCTION;
138
139
    ObjectRegistryData m_data;
140
};
141
142
} // namespace detail
143
144
/** Helper class which indicates leaking object(s) of a particular class in
145
    non-pro builds; use e.g.
146
147
    @code{.cpp}
148
    class MyClass : private osl::DebugBase<MyClass> {...};
149
    @endcode
150
151
    Using the environment variable
152
153
    OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;...
154
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.
159
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
163
              in the future!
164
*/
165
template <typename InheritingClassT>
166
class DebugBase
167
{
168
public:
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
174
    */
175
    static bool checkObjectCount( ::std::size_t nExpected = 0 ) {
176
        return StaticObjectRegistry::get().checkObjectCount(nExpected);
177
    }
178
179
protected:
180
    DebugBase() {
181
        StaticObjectRegistry::get().registerObject( this );
182
    }
183
    ~DebugBase() {
184
        StaticObjectRegistry::get().revokeObject( this );
185
    }
186
187
private:
188
    struct StaticObjectRegistry
189
        : ::rtl::Static<detail::ObjectRegistry<InheritingClassT>,
190
                        StaticObjectRegistry> {};
191
#endif
192
};
193
194
} // namespace osl
195
196
/// @endcond
197
198
#endif // ! defined( INCLUDED_OSL_DIAGNOSE_HXX)
199
200
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */