Coverage Report

Created: 2026-10-14 09:33

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
451k
WeakComponentImplHelperBase::~WeakComponentImplHelperBase() {}
18
19
// css::lang::XComponent
20
void SAL_CALL WeakComponentImplHelperBase::dispose()
21
93.5k
{
22
93.5k
    std::unique_lock aGuard(m_aMutex);
23
93.5k
    if (m_bDisposed)
24
0
        return;
25
93.5k
    m_bDisposed = true;
26
93.5k
    disposing(aGuard);
27
93.5k
    if (!aGuard.owns_lock())
28
0
        aGuard.lock();
29
93.5k
    css::lang::EventObject aEvt(static_cast<OWeakObject*>(this));
30
93.5k
    maEventListeners.disposeAndClear(aGuard, aEvt);
31
93.5k
}
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
21.3k
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
36.0k
{
53
36.0k
    std::unique_lock aGuard(m_aMutex);
54
36.0k
    if (m_bDisposed)
55
0
        return;
56
36.0k
    maEventListeners.addInterface(aGuard, rxListener);
57
36.0k
}
58
59
void SAL_CALL WeakComponentImplHelperBase::removeEventListener(
60
    css::uno::Reference<css::lang::XEventListener> const& rxListener)
61
18.9k
{
62
18.9k
    std::unique_lock aGuard(m_aMutex);
63
18.9k
    maEventListeners.removeInterface(aGuard, rxListener);
64
18.9k
}
65
66
css::uno::Any SAL_CALL WeakComponentImplHelperBase::queryInterface(css::uno::Type const& rType)
67
96.2k
{
68
96.2k
    css::uno::Any aReturn = ::cppu::queryInterface(rType, static_cast<css::uno::XWeak*>(this),
69
96.2k
                                                   static_cast<css::lang::XComponent*>(this));
70
96.2k
    if (aReturn.hasValue())
71
63.3k
        return aReturn;
72
32.9k
    return OWeakObject::queryInterface(rType);
73
96.2k
}
74
75
static void checkInterface(css::uno::Type const& rType)
76
2.39M
{
77
2.39M
    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
2.39M
}
84
85
static bool isXInterface(typelib_TypeDescriptionReference const* pTypeLibType)
86
2.39M
{
87
2.39M
    return OUString::unacquired(&pTypeLibType->pTypeName) == "com.sun.star.uno.XInterface";
88
2.39M
}
89
90
static bool td_equals(typelib_TypeDescriptionReference const* pTDR1,
91
                      typelib_TypeDescriptionReference const* pTDR2)
92
7.99M
{
93
7.99M
    return ((pTDR1 == pTDR2)
94
6.26M
            || OUString::unacquired(&pTDR1->pTypeName) == OUString::unacquired(&pTDR2->pTypeName));
95
7.99M
}
96
97
static cppu::type_entry* getTypeEntries(cppu::class_data* cd)
98
1.82M
{
99
1.82M
    cppu::type_entry* pEntries = cd->m_typeEntries;
100
1.82M
    if (!cd->m_storedTypeRefs) // not inited?
101
74
    {
102
74
        static std::mutex aMutex;
103
74
        std::scoped_lock guard(aMutex);
104
74
        if (!cd->m_storedTypeRefs) // not inited?
105
74
        {
106
            // get all types
107
481
            for (sal_Int32 n = cd->m_nTypes; n--;)
108
407
            {
109
407
                cppu::type_entry* pEntry = &pEntries[n];
110
407
                css::uno::Type const& rType = (*pEntry->m_type.getCppuType)(nullptr);
111
407
                OSL_ENSURE(rType.getTypeClass() == css::uno::TypeClass_INTERFACE,
112
407
                           "### wrong helper init: expected interface!");
113
407
                OSL_ENSURE(
114
407
                    !isXInterface(rType.getTypeLibType()),
115
407
                    "### want to implement XInterface: template argument is XInterface?!?!?!");
116
407
                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
407
                pEntry->m_type.typeRef = rType.getTypeLibType();
124
407
            }
125
74
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
126
74
            cd->m_storedTypeRefs = true;
127
74
        }
128
74
    }
129
1.82M
    else
130
1.82M
    {
131
1.82M
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
132
1.82M
    }
133
1.82M
    return pEntries;
134
1.82M
}
135
136
static void* makeInterface(sal_IntPtr nOffset, void* that)
137
1.72M
{
138
1.72M
    return (static_cast<char*>(that) + nOffset);
139
1.72M
}
140
141
static bool recursivelyFindType(typelib_TypeDescriptionReference const* demandedType,
142
                                typelib_InterfaceTypeDescription const* type, sal_IntPtr* offset)
143
1.56M
{
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.87M
next:
150
3.10M
    for (sal_Int32 i = 0; i < type->nBaseTypes; ++i)
151
1.87M
    {
152
1.87M
        if (i > 0)
153
4.00k
        {
154
4.00k
            *offset += sizeof(void*);
155
4.00k
        }
156
1.87M
        typelib_InterfaceTypeDescription const* base = type->ppBaseTypes[i];
157
        // ignore XInterface:
158
1.87M
        if (base->nBaseTypes > 0)
159
649k
        {
160
649k
            if (td_equals(reinterpret_cast<typelib_TypeDescriptionReference const*>(base),
161
649k
                          demandedType))
162
342k
            {
163
342k
                return true;
164
342k
            }
165
            // Profiling showed that it is important to speed up the common case
166
            // of only one base:
167
307k
            if (type->nBaseTypes == 1)
168
303k
            {
169
303k
                type = base;
170
303k
                goto next;
171
303k
            }
172
4.01k
            if (recursivelyFindType(demandedType, base, offset))
173
5
            {
174
5
                return true;
175
5
            }
176
4.01k
        }
177
1.87M
    }
178
1.22M
    return false;
179
1.87M
}
180
181
static void* queryDeepNoXInterface(typelib_TypeDescriptionReference const* pDemandedTDR,
182
                                   cppu::class_data* cd, void* that)
183
2.39M
{
184
2.39M
    if (isXInterface(pDemandedTDR))
185
570k
        return nullptr;
186
187
1.82M
    cppu::type_entry* pEntries = getTypeEntries(cd);
188
1.82M
    sal_Int32 nTypes = cd->m_nTypes;
189
1.82M
    sal_Int32 n;
190
191
    // try top interfaces without getting td
192
7.78M
    for (n = 0; n < nTypes; ++n)
193
7.34M
    {
194
7.34M
        if (td_equals(pEntries[n].m_type.typeRef, pDemandedTDR))
195
1.38M
        {
196
1.38M
            return makeInterface(pEntries[n].m_offset, that);
197
1.38M
        }
198
7.34M
    }
199
    // query deep getting td
200
1.66M
    for (n = 0; n < nTypes; ++n)
201
1.56M
    {
202
1.56M
        typelib_TypeDescription* pTD = nullptr;
203
1.56M
        TYPELIB_DANGER_GET(&pTD, pEntries[n].m_type.typeRef);
204
1.56M
        if (pTD)
205
1.56M
        {
206
            // exclude top (already tested) and bottom (XInterface) interface
207
1.56M
            OSL_ENSURE(reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD)->nBaseTypes > 0,
208
1.56M
                       "### want to implement XInterface:"
209
1.56M
                       " template argument is XInterface?!?!?!");
210
1.56M
            sal_IntPtr offset = pEntries[n].m_offset;
211
1.56M
            bool found = recursivelyFindType(
212
1.56M
                pDemandedTDR, reinterpret_cast<typelib_InterfaceTypeDescription*>(pTD), &offset);
213
1.56M
            TYPELIB_DANGER_RELEASE(pTD);
214
1.56M
            if (found)
215
342k
            {
216
342k
                return makeInterface(offset, that);
217
342k
            }
218
1.56M
        }
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
1.56M
    }
227
95.8k
    return nullptr;
228
438k
}
229
230
css::uno::Any WeakComponentImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
231
                                            WeakComponentImplHelperBase* pBase)
232
739k
{
233
739k
    checkInterface(rType);
234
739k
    typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
235
236
    // shortcut XInterface to WeakComponentImplHelperBase
237
739k
    if (void* p = queryDeepNoXInterface(pTDR, cd, pBase))
238
643k
        return css::uno::Any(&p, pTDR);
239
96.2k
    return pBase->comphelper::WeakComponentImplHelperBase::queryInterface(rType);
240
739k
}
241
242
305k
WeakImplHelperBase::~WeakImplHelperBase() {}
243
244
css::uno::Any WeakImplHelper_query(css::uno::Type const& rType, cppu::class_data* cd,
245
                                   WeakImplHelperBase* pBase)
246
1.65M
{
247
1.65M
    checkInterface(rType);
248
1.65M
    typelib_TypeDescriptionReference* pTDR = rType.getTypeLibType();
249
250
    // shortcut XInterface to WeakImplHelperBase
251
1.65M
    if (void* p = queryDeepNoXInterface(pTDR, cd, pBase))
252
1.08M
        return css::uno::Any(&p, pTDR);
253
569k
    return pBase->comphelper::WeakImplHelperBase::queryInterface(rType);
254
1.65M
}
255
256
} // namespace comphelper
257
258
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */