Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/misc/compbase.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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
10
#include <comphelper/compbase.hxx>
11
#include <cppuhelper/queryinterface.hxx>
12
#include <sal/log.hxx>
13
#include <osl/diagnose.h>
14
15
namespace comphelper
16
{
17
290k
WeakComponentImplHelperBase::~WeakComponentImplHelperBase() {}
18
19
// css::lang::XComponent
20
void SAL_CALL WeakComponentImplHelperBase::dispose()
21
20.8k
{
22
20.8k
    std::unique_lock aGuard(m_aMutex);
23
20.8k
    if (m_bDisposed)
24
0
        return;
25
20.8k
    m_bDisposed = true;
26
20.8k
    disposing(aGuard);
27
20.8k
    if (!aGuard.owns_lock())
28
0
        aGuard.lock();
29
20.8k
    css::lang::EventObject aEvt(static_cast<OWeakObject*>(this));
30
20.8k
    maEventListeners.disposeAndClear(aGuard, aEvt);
31
20.8k
}
32
33
// This is only called from the destructor to do cleanup that
34
// might not have occurred
35
void WeakComponentImplHelperBase::disposeOnDestruct()
36
0
{
37
0
    std::unique_lock aGuard(m_aMutex);
38
0
    assert(m_refCount == 0 && "only supposed to be called from the destructor");
39
0
    if (m_bDisposed)
40
0
        return;
41
0
    m_bDisposed = true;
42
    // bump the ref-count so we don't accidentally do a double delete
43
    // if something else increases and then decreases our ref-count
44
0
    cppu::OWeakObject::acquire();
45
0
    disposing(aGuard);
46
0
}
47
48
13.9k
void WeakComponentImplHelperBase::disposing(std::unique_lock<std::mutex>&) {}
49
50
void SAL_CALL WeakComponentImplHelperBase::addEventListener(
51
    css::uno::Reference<css::lang::XEventListener> const& rxListener)
52
32.3k
{
53
32.3k
    std::unique_lock aGuard(m_aMutex);
54
32.3k
    if (m_bDisposed)
55
0
        return;
56
32.3k
    maEventListeners.addInterface(aGuard, rxListener);
57
32.3k
}
58
59
void SAL_CALL WeakComponentImplHelperBase::removeEventListener(
60
    css::uno::Reference<css::lang::XEventListener> const& rxListener)
61
17.5k
{
62
17.5k
    std::unique_lock aGuard(m_aMutex);
63
17.5k
    maEventListeners.removeInterface(aGuard, rxListener);
64
17.5k
}
65
66
css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType)
67
41.7k
{
68
41.7k
    css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
69
41.7k
                                                   static_cast<css::lang::XComponent*>(this));
70
41.7k
    if (aReturn.hasValue())
71
11.3k
        return aReturn;
72
30.3k
    return OWeakObject::queryInterface(rType);
73
41.7k
}
74
75
static void checkInterface(css::uno::Type const& rType)
76
1.47M
{
77
1.47M
    if (css::uno::TypeClass_INTERFACE != rType.getTypeClass())
78
0
    {
79
0
        OUString msg("querying for interface \"" + rType.getTypeName() + "\": no interface type!");
80
0
        SAL_WARN("cppuhelper", msg);
81
0
        throw css::uno::RuntimeException(msg);
82
0
    }
83
1.47M
}
84
85
static bool isXInterface(typelib_TypeDescriptionReference const* pTypeLibType)
86
1.47M
{
87
1.47M
    return OUString::unacquired(&pTypeLibType->pTypeName) == "com.sun.star.uno.XInterface";
88
1.47M
}
89
90
static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
91
                      typelib_TypeDescriptionReference const* pTDR2)
92
5.09M
{
93
5.09M
    return ((pTDR1 == pTDR2)
94
3.98M
            || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
95
5.09M
}
96
97
static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
98
1.15M
{
99
1.15M
    cppu::type_entry* pEntries = cd->m_typeEntries;
100
1.15M
    if (!cd->m_storedTypeRefs) // not inited?
101
93
    {
102
93
        static std::mutex aMutex;
103
93
        std::scoped_lock guard(aMutex);
104
93
        if (!cd->m_storedTypeRefs) // not inited?
105
93
        {
106
            // get all types
107
593
            for (sal_Int32 n = cd->m_nTypes; n--;)
108
500
            {
109
500
                cppu::type_entry* pEntry = &pEntries[n];
110
500
                css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
111
500
                OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
112
500
                           "### wrong helper init: expected interface!");
113
500
                OSL_ENSURE(
114
500
                    !isXInterface(rType.getTypeLibType()),
115
500
                    "### want to implement XInterface: template argument is XInterface?!?!?!");
116
500
                if (rType.getTypeClass() != css::uno::TypeClass_INTERFACE)
117
0
                {
118
0
                    OUString msg("type \"" + rType.getTypeName() + "\" is no interface type!");
119
0
                    SAL_WARN("cppuhelper", msg);
120
0
                    throw css::uno::RuntimeException(msg);
121
0
                }
122
                // ref is statically held by getCppuType()
123
500
                pEntry->m_type.typeRef = rType.getTypeLibType();
124
500
            }
125
93
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
126
93
            cd->m_storedTypeRefs = true;
127
93
        }
128
93
    }
129
1.15M
    else
130
1.15M
    {
131
1.15M
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
132
1.15M
    }
133
1.15M
    return pEntries;
134
1.15M
}
135
136
static void* makeInterface(sal_IntPtr nOffset, void* that)
137
1.11M
{
138
1.11M
    return (static_cast<char*>(that) + nOffset);
139
1.11M
}
140
141
static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
142
                                typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
143
871k
{
144
    // This code assumes that the vtables of a multiple-inheritance class (the
145
    // offset amount by which to adjust the this pointer) follow one another in
146
    // the object layout, and that they contain slots for the inherited classes
147
    // in a specific order.  In theory, that need not hold for any given
148
    // platform; in practice, it seems to work well on all supported platforms:
149
1.09M
next:
150
1.70M
    for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
151
1.09M
    {
152
1.09M
        if (i > 0)
153
3.64k
        {
154
3.64k
            *offset += sizeof(void*);
155
3.64k
        }
156
1.09M
        typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
157
        // ignore XInterface:
158
1.09M
        if (base->nBaseTypes > 0)
159
489k
        {
160
489k
            if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
161
489k
                          demandedType))
162
265k
            {
163
265k
                return true;
164
265k
            }
165
            // Profiling showed that it is important to speed up the common case
166
            // of only one base:
167
224k
            if (type->nBaseTypes == 1)
168
220k
            {
169
220k
                type = base;
170
220k
                goto next;
171
220k
            }
172
3.64k
            if (recursivelyFindType(demandedType, base, offset))
173
6
            {
174
6
                return true;
175
6
            }
176
3.64k
        }
177
1.09M
    }
178
605k
    return false;
179
1.09M
}
180
181
static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
182
                                   cppu::class_data* cd, void* that)
183
1.47M
{
184
1.47M
    if (isXInterface(pDemandedTDR))
185
320k
        return nullptr;
186
187
1.15M
    cppu::type_entry* pEntries = getTypeEntries(cd);
188
1.15M
    sal_Int32 nTypes = cd->m_nTypes;
189
1.15M
    sal_Int32 n;
190
191
    // try top interfaces without getting td
192
4.91M
    for (n = 0; n < nTypes; ++n)
193
4.61M
    {
194
4.61M
        if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
195
846k
        {
196
846k
            return makeInterface(pEntries[n].m_offset, that);
197
846k
        }
198
4.61M
    }
199
    // query deep getting td
200
908k
    for (n = 0; n < nTypes; ++n)
201
867k
    {
202
867k
        typelib_TypeDescription* pTD = nullptr;
203
867k
        TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
204
867k
        if (pTD)
205
867k
        {
206
            // exclude top (already tested) and bottom (XInterface) interface
207
867k
            OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
208
867k
                       "### want to implement XInterface:"
209
867k
                       " template argument is XInterface?!?!?!");
210
867k
            sal_IntPtr offset = pEntries[n].m_offset;
211
867k
            bool found = recursivelyFindType(
212
867k
                pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
213
867k
            TYPELIB_DANGER_RELEASE(pTD);
214
867k
            if (found)
215
265k
            {
216
265k
                return makeInterface(offset, that);
217
265k
            }
218
867k
        }
219
0
        else
220
0
        {
221
0
            OUString msg("cannot get type description for type \""
222
0
                         + OUString::unacquired(&pEntries[n].m_type.typeRef->pTypeName) + "\"!");
223
0
            SAL_WARN("cppuhelper", msg);
224
0
            throw css::uno::RuntimeException(msg);
225
0
        }
226
867k
    }
227
41.0k
    return nullptr;
228
306k
}
229
230
css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
231
                                            WeakComponentImplHelperBase* pBase)
232
516k
{
233
516k
    checkInterface(rType);
234
516k
    typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
235
236
    // shortcut XInterface to WeakComponentImplHelperBase
237
516k
    if (void* p = queryDeepNoXInterface(pTDR, cd, pBase))
238
475k
        return css::uno::Any(&p, pTDR);
239
41.7k
    return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType);
240
516k
}
241
242
108k
WeakImplHelperBase::~WeakImplHelperBase() {}
243
244
css::uno::Any WeakImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
245
                                   WeakImplHelperBase* pBase)
246
956k
{
247
956k
    checkInterface(rType);
248
956k
    typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
249
250
    // shortcut XInterface to WeakImplHelperBase
251
956k
    if (void* p = queryDeepNoXInterface(pTDR, cd, pBase))
252
636k
        return css::uno::Any(&p, pTDR);
253
319k
    return pBase->comphelper::WeakImplHelperBase::queryInterface(rType);
254
956k
}
255
256
} // namespace comphelper
257
258
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */