Coverage Report

Created: 2026-02-14 09:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/cppu/source/uno/lbenv.cxx
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
20
#ifdef DISABLE_DYNLOADING
21
#include <config_java.h>
22
#endif
23
24
#include <cppu/EnvDcp.hxx>
25
26
#include <sal/log.hxx>
27
#include <osl/diagnose.h>
28
#include <osl/interlck.h>
29
#include <osl/mutex.hxx>
30
#include <osl/module.hxx>
31
#include <osl/process.h>
32
#include <rtl/process.h>
33
#include <rtl/string.hxx>
34
#include <rtl/ustring.hxx>
35
#include <rtl/ustrbuf.hxx>
36
#include <typelib/typedescription.h>
37
#include <uno/dispatcher.h>
38
#include <uno/environment.h>
39
#include <uno/lbnames.h>
40
#include "prim.hxx"
41
#include "loadmodule.hxx"
42
43
#include <string_view>
44
#include <unordered_map>
45
#include <utility>
46
#include <vector>
47
#include <stdio.h>
48
49
50
namespace
51
{
52
53
54
bool td_equals( typelib_InterfaceTypeDescription const * pTD1,
55
                       typelib_InterfaceTypeDescription const * pTD2 )
56
21.3k
{
57
21.3k
    return (pTD1 == pTD2 ||
58
0
            (pTD1->aBase.pTypeName->length == pTD2->aBase.pTypeName->length &&
59
0
             ::rtl_ustr_compare(
60
0
                 pTD1->aBase.pTypeName->buffer,
61
0
                 pTD2->aBase.pTypeName->buffer ) == 0));
62
21.3k
}
63
64
struct uno_DefaultEnvironment;
65
66
67
struct InterfaceEntry
68
{
69
    sal_Int32 refCount;
70
    void * pInterface;
71
    uno_freeProxyFunc fpFreeProxy;
72
    typelib_InterfaceTypeDescription * pTypeDescr;
73
};
74
75
struct ObjectEntry
76
{
77
    OUString oid;
78
    std::vector< InterfaceEntry > aInterfaces;
79
    sal_Int32 nRef;
80
    bool mixedObject;
81
82
    explicit ObjectEntry( OUString aOId_ );
83
84
    void append(
85
        uno_DefaultEnvironment * pEnv,
86
        void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr,
87
        uno_freeProxyFunc fpFreeProxy );
88
    InterfaceEntry * find(
89
        typelib_InterfaceTypeDescription * pTypeDescr );
90
    sal_Int32 find( void const * iface_ptr, std::size_t pos ) const;
91
};
92
93
94
struct FctPtrHash
95
{
96
    std::size_t operator () ( const void * pKey ) const
97
716k
        { return reinterpret_cast< std::size_t>( pKey ); }
98
};
99
100
101
// mapping from environment name to environment
102
typedef std::unordered_map<
103
    OUString, uno_Environment * > OUString2EnvironmentMap;
104
105
// mapping from ptr to object entry
106
typedef std::unordered_map<
107
    void *, ObjectEntry *, FctPtrHash > Ptr2ObjectMap;
108
// mapping from oid to object entry
109
typedef std::unordered_map<
110
    OUString, ObjectEntry * > OId2ObjectMap;
111
112
struct EnvironmentsData
113
{
114
    ::osl::Mutex mutex;
115
    OUString2EnvironmentMap aName2EnvMap;
116
117
108
    EnvironmentsData() : isDisposing(false) {}
118
    ~EnvironmentsData();
119
120
    void getEnvironment(
121
        uno_Environment ** ppEnv, std::u16string_view rEnvDcp, void * pContext );
122
    void registerEnvironment( uno_Environment ** ppEnv );
123
    void getRegisteredEnvironments(
124
        uno_Environment *** pppEnvs, sal_Int32 * pnLen,
125
        uno_memAlloc memAlloc, std::u16string_view rEnvDcp );
126
127
    bool isDisposing;
128
};
129
130
EnvironmentsData& theEnvironmentsData()
131
657k
{
132
657k
    static EnvironmentsData SINGLETON;
133
657k
    return SINGLETON;
134
657k
}
135
136
struct uno_DefaultEnvironment : public uno_ExtEnvironment
137
{
138
    sal_Int32 nRef;
139
    sal_Int32 nWeakRef;
140
141
    ::osl::Mutex mutex;
142
    Ptr2ObjectMap aPtr2ObjectMap;
143
    OId2ObjectMap aOId2ObjectMap;
144
145
    uno_DefaultEnvironment(
146
        const OUString & rEnvDcp_, void * pContext_ );
147
    ~uno_DefaultEnvironment();
148
};
149
150
151
ObjectEntry::ObjectEntry( OUString aOId_ )
152
222k
    : oid(std::move( aOId_ )),
153
222k
      nRef( 0 ),
154
222k
      mixedObject( false )
155
222k
{
156
222k
    aInterfaces.reserve( 2 );
157
222k
}
158
159
160
void ObjectEntry::append(
161
    uno_DefaultEnvironment * pEnv,
162
    void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr,
163
    uno_freeProxyFunc fpFreeProxy )
164
222k
{
165
222k
    InterfaceEntry aNewEntry;
166
222k
    if (! fpFreeProxy)
167
111k
        (*pEnv->acquireInterface)( pEnv, pInterface );
168
222k
    aNewEntry.refCount = 1;
169
222k
    aNewEntry.pInterface = pInterface;
170
222k
    aNewEntry.fpFreeProxy = fpFreeProxy;
171
222k
    typelib_typedescription_acquire( &pTypeDescr->aBase );
172
222k
    aNewEntry.pTypeDescr = pTypeDescr;
173
174
222k
    std::pair< Ptr2ObjectMap::iterator, bool > i(
175
222k
        pEnv->aPtr2ObjectMap.emplace( pInterface, this ) );
176
222k
    SAL_WARN_IF(
177
222k
        !i.second && (find(pInterface, 0) == -1 || i.first->second != this),
178
222k
        "cppu",
179
222k
        "map already contains " << i.first->second << " != " << this << " for "
180
222k
            << pInterface);
181
222k
    aInterfaces.push_back( aNewEntry );
182
222k
}
183
184
185
InterfaceEntry * ObjectEntry::find(
186
    typelib_InterfaceTypeDescription * pTypeDescr_ )
187
23.8k
{
188
23.8k
    OSL_ASSERT( ! aInterfaces.empty() );
189
23.8k
    if (aInterfaces.empty())
190
0
        return nullptr;
191
192
    // shortcut common case:
193
23.8k
    OUString const & type_name =
194
23.8k
        OUString::unacquired( &pTypeDescr_->aBase.pTypeName );
195
23.8k
    if ( type_name == "com.sun.star.uno.XInterface" )
196
2.50k
    {
197
2.50k
        return aInterfaces.data();
198
2.50k
    }
199
200
21.3k
    std::size_t nSize = aInterfaces.size();
201
21.3k
    for ( std::size_t nPos = 0; nPos < nSize; ++nPos )
202
21.3k
    {
203
21.3k
        typelib_InterfaceTypeDescription * pITD =
204
21.3k
            aInterfaces[ nPos ].pTypeDescr;
205
21.3k
        while (pITD)
206
21.3k
        {
207
21.3k
            if (td_equals( pITD, pTypeDescr_ ))
208
21.3k
                return &aInterfaces[ nPos ];
209
0
            pITD = pITD->pBaseTypeDescription;
210
0
        }
211
21.3k
    }
212
0
    return nullptr;
213
21.3k
}
214
215
216
sal_Int32 ObjectEntry::find(
217
    void const * iface_ptr, std::size_t pos ) const
218
0
{
219
0
    std::size_t size = aInterfaces.size();
220
0
    for ( ; pos < size; ++pos )
221
0
    {
222
0
        if (aInterfaces[ pos ].pInterface == iface_ptr)
223
0
            return pos;
224
0
    }
225
0
    return -1;
226
0
}
227
228
extern "C"
229
{
230
231
232
static void defenv_registerInterface(
233
    uno_ExtEnvironment * pEnv, void ** ppInterface,
234
    rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
235
111k
{
236
111k
    assert(pEnv && ppInterface && pOId && pTypeDescr && "### null ptr!");
237
111k
    OUString const & rOId = OUString::unacquired( &pOId );
238
239
111k
    uno_DefaultEnvironment * that =
240
111k
        static_cast< uno_DefaultEnvironment * >( pEnv );
241
111k
    ::osl::ClearableMutexGuard guard( that->mutex );
242
243
    // try to insert dummy 0:
244
111k
    std::pair<OId2ObjectMap::iterator, bool> const insertion(
245
111k
        that->aOId2ObjectMap.emplace(  rOId, nullptr ) );
246
111k
    if (insertion.second)
247
111k
    {
248
111k
        ObjectEntry * pOEntry = new ObjectEntry( rOId );
249
111k
        insertion.first->second = pOEntry;
250
111k
        ++pOEntry->nRef; // another register call on object
251
111k
        pOEntry->append( that, *ppInterface, pTypeDescr, nullptr );
252
111k
    }
253
0
    else // object entry exists
254
0
    {
255
0
        ObjectEntry * pOEntry = insertion.first->second;
256
0
        ++pOEntry->nRef; // another register call on object
257
0
        InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr );
258
259
0
        if (pIEntry) // type entry exists
260
0
        {
261
0
            ++pIEntry->refCount;
262
0
            if (pIEntry->pInterface != *ppInterface)
263
0
            {
264
0
                void * pInterface = pIEntry->pInterface;
265
0
                (*pEnv->acquireInterface)( pEnv, pInterface );
266
0
                guard.clear();
267
0
                (*pEnv->releaseInterface)( pEnv, *ppInterface );
268
0
                *ppInterface = pInterface;
269
0
            }
270
0
        }
271
0
        else
272
0
        {
273
0
            pOEntry->append( that, *ppInterface, pTypeDescr, nullptr );
274
0
        }
275
0
    }
276
111k
}
277
278
static void defenv_registerProxyInterface(
279
    uno_ExtEnvironment * pEnv, void ** ppInterface, uno_freeProxyFunc freeProxy,
280
    rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
281
111k
{
282
111k
    assert(pEnv && ppInterface && pOId && pTypeDescr && freeProxy && "### null ptr!");
283
111k
    OUString const & rOId = OUString::unacquired( &pOId );
284
285
111k
    uno_DefaultEnvironment * that =
286
111k
        static_cast< uno_DefaultEnvironment * >( pEnv );
287
111k
    ::osl::ClearableMutexGuard guard( that->mutex );
288
289
    // try to insert dummy 0:
290
111k
    std::pair<OId2ObjectMap::iterator, bool> const insertion(
291
111k
        that->aOId2ObjectMap.emplace(  rOId, nullptr ) );
292
111k
    if (insertion.second)
293
111k
    {
294
111k
        ObjectEntry * pOEntry = new ObjectEntry( rOId );
295
111k
        insertion.first->second = pOEntry;
296
111k
        ++pOEntry->nRef; // another register call on object
297
111k
        pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy );
298
111k
    }
299
0
    else // object entry exists
300
0
    {
301
0
        ObjectEntry * pOEntry = insertion.first->second;
302
303
        // first registration was an original, then registerProxyInterface():
304
0
        pOEntry->mixedObject |=
305
0
            (!pOEntry->aInterfaces.empty() &&
306
0
             pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr);
307
308
0
        ++pOEntry->nRef; // another register call on object
309
0
        InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr );
310
311
0
        if (pIEntry) // type entry exists
312
0
        {
313
0
            if (pIEntry->pInterface == *ppInterface)
314
0
            {
315
0
                ++pIEntry->refCount;
316
0
            }
317
0
            else
318
0
            {
319
0
                void * pInterface = pIEntry->pInterface;
320
0
                (*pEnv->acquireInterface)( pEnv, pInterface );
321
0
                --pOEntry->nRef; // manual revoke of proxy to be freed
322
0
                guard.clear();
323
0
                (*freeProxy)( pEnv, *ppInterface );
324
0
                *ppInterface = pInterface;
325
0
            }
326
0
        }
327
0
        else
328
0
        {
329
0
            pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy );
330
0
        }
331
0
    }
332
111k
}
333
334
static void s_stub_defenv_revokeInterface(va_list * pParam)
335
222k
{
336
222k
    uno_ExtEnvironment * pEnv       = va_arg(*pParam, uno_ExtEnvironment *);
337
222k
    void               * pInterface = va_arg(*pParam, void *);
338
339
222k
    assert(pEnv && pInterface && "### null ptr!");
340
222k
    uno_DefaultEnvironment * that =
341
222k
        static_cast< uno_DefaultEnvironment * >( pEnv );
342
222k
    ::osl::ClearableMutexGuard guard( that->mutex );
343
344
222k
    Ptr2ObjectMap::const_iterator const iFind(
345
222k
        that->aPtr2ObjectMap.find( pInterface ) );
346
222k
    assert(iFind != that->aPtr2ObjectMap.end());
347
222k
    ObjectEntry * pOEntry = iFind->second;
348
222k
    if (! --pOEntry->nRef)
349
222k
    {
350
        // cleanup maps
351
222k
        that->aOId2ObjectMap.erase( pOEntry->oid );
352
222k
        sal_Int32 nPos;
353
445k
        for ( nPos = pOEntry->aInterfaces.size(); nPos--; )
354
222k
        {
355
222k
            that->aPtr2ObjectMap.erase( pOEntry->aInterfaces[nPos].pInterface );
356
222k
        }
357
358
        // the last proxy interface of the environment might kill this
359
        // environment, because of releasing its language binding!!!
360
222k
        guard.clear();
361
362
        // release interfaces
363
445k
        for ( nPos = pOEntry->aInterfaces.size(); nPos--; )
364
222k
        {
365
222k
            InterfaceEntry const & rEntry = pOEntry->aInterfaces[nPos];
366
222k
            typelib_typedescription_release( &rEntry.pTypeDescr->aBase );
367
222k
            if (rEntry.fpFreeProxy) // is proxy or used interface?
368
111k
            {
369
111k
                (*rEntry.fpFreeProxy)( pEnv, rEntry.pInterface );
370
111k
            }
371
111k
            else
372
111k
            {
373
111k
                (*pEnv->releaseInterface)( pEnv, rEntry.pInterface );
374
111k
            }
375
222k
        }
376
377
222k
        delete pOEntry;
378
222k
    }
379
0
    else if (pOEntry->mixedObject)
380
0
    {
381
0
        OSL_ASSERT( !pOEntry->aInterfaces.empty() &&
382
0
                    pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr );
383
384
0
        sal_Int32 index = pOEntry->find( pInterface, 1 );
385
0
        OSL_ASSERT( index > 0 );
386
0
        if (index > 0)
387
0
        {
388
0
            InterfaceEntry & entry = pOEntry->aInterfaces[ index ];
389
0
            OSL_ASSERT( entry.pInterface == pInterface );
390
0
            if (entry.fpFreeProxy != nullptr)
391
0
            {
392
0
                --entry.refCount;
393
0
                if (entry.refCount == 0)
394
0
                {
395
0
                    uno_freeProxyFunc fpFreeProxy = entry.fpFreeProxy;
396
0
                    typelib_TypeDescription * pTypeDescr =
397
0
                        reinterpret_cast< typelib_TypeDescription * >(
398
0
                            entry.pTypeDescr );
399
400
0
                    pOEntry->aInterfaces.erase(
401
0
                        pOEntry->aInterfaces.begin() + index );
402
0
                    if (pOEntry->find( pInterface, index ) < 0)
403
0
                    {
404
                        // proxy ptr not registered for another interface:
405
                        // remove from ptr map
406
0
                        std::size_t erased =
407
0
                              that->aPtr2ObjectMap.erase( pInterface );
408
0
                        OSL_ASSERT( erased == 1 );
409
0
                    }
410
411
0
                    guard.clear();
412
413
0
                    typelib_typedescription_release( pTypeDescr );
414
0
                    (*fpFreeProxy)( pEnv, pInterface );
415
0
                }
416
0
            }
417
0
        }
418
0
    }
419
222k
}
420
421
static void defenv_revokeInterface(uno_ExtEnvironment * pEnv, void * pInterface)
422
222k
{
423
222k
    uno_Environment_invoke(&pEnv->aBase, s_stub_defenv_revokeInterface, pEnv, pInterface);
424
222k
}
425
426
427
static void defenv_getObjectIdentifier(
428
    uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface )
429
135k
{
430
135k
    assert(pEnv && ppOId && pInterface && "### null ptr!");
431
135k
    if (*ppOId)
432
0
    {
433
0
        ::rtl_uString_release( *ppOId );
434
0
        *ppOId = nullptr;
435
0
    }
436
437
135k
    uno_DefaultEnvironment * that =
438
135k
        static_cast< uno_DefaultEnvironment * >( pEnv );
439
135k
    ::osl::ClearableMutexGuard guard( that->mutex );
440
441
135k
    Ptr2ObjectMap::const_iterator const iFind(
442
135k
        that->aPtr2ObjectMap.find( pInterface ) );
443
135k
    if (iFind == that->aPtr2ObjectMap.end())
444
111k
    {
445
111k
        guard.clear();
446
111k
        (*pEnv->computeObjectIdentifier)( pEnv, ppOId, pInterface );
447
111k
    }
448
23.8k
    else
449
23.8k
    {
450
23.8k
        rtl_uString * hstr = iFind->second->oid.pData;
451
23.8k
        rtl_uString_acquire( hstr );
452
23.8k
        *ppOId = hstr;
453
23.8k
    }
454
135k
}
455
456
static void defenv_getRegisteredInterface(
457
    uno_ExtEnvironment * pEnv, void ** ppInterface,
458
    rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
459
135k
{
460
135k
    assert(pEnv && ppInterface && pOId && pTypeDescr && "### null ptr!");
461
135k
    if (*ppInterface)
462
0
    {
463
0
        (*pEnv->releaseInterface)( pEnv, *ppInterface );
464
0
        *ppInterface = nullptr;
465
0
    }
466
467
135k
    OUString const & rOId = OUString::unacquired( &pOId );
468
135k
    uno_DefaultEnvironment * that =
469
135k
        static_cast< uno_DefaultEnvironment * >( pEnv );
470
135k
    ::osl::MutexGuard guard( that->mutex );
471
472
135k
    OId2ObjectMap::const_iterator const iFind
473
135k
        ( that->aOId2ObjectMap.find( rOId ) );
474
135k
    if (iFind != that->aOId2ObjectMap.end())
475
23.8k
    {
476
23.8k
        InterfaceEntry const * pIEntry = iFind->second->find( pTypeDescr );
477
23.8k
        if (pIEntry)
478
23.8k
        {
479
23.8k
            (*pEnv->acquireInterface)( pEnv, pIEntry->pInterface );
480
23.8k
            *ppInterface = pIEntry->pInterface;
481
23.8k
        }
482
23.8k
    }
483
135k
}
484
485
static void defenv_getRegisteredInterfaces(
486
    uno_ExtEnvironment * pEnv, void *** pppInterfaces, sal_Int32 * pnLen,
487
    uno_memAlloc memAlloc )
488
0
{
489
0
    assert(pEnv && pppInterfaces && pnLen && memAlloc && "### null ptr!");
490
0
    uno_DefaultEnvironment * that =
491
0
        static_cast< uno_DefaultEnvironment * >( pEnv );
492
0
    ::osl::MutexGuard guard( that->mutex );
493
494
0
    sal_Int32 nLen = that->aPtr2ObjectMap.size();
495
0
    sal_Int32 nPos = 0;
496
0
    void ** ppInterfaces = static_cast<void **>((*memAlloc)( nLen * sizeof (void *) ));
497
498
0
    for (const auto& rEntry : that->aPtr2ObjectMap)
499
0
    {
500
0
        ppInterfaces[nPos] = rEntry.first;
501
0
        (*pEnv->acquireInterface)( pEnv, ppInterfaces[nPos] );
502
0
        nPos++;
503
0
    }
504
505
0
    *pppInterfaces = ppInterfaces;
506
0
    *pnLen = nLen;
507
0
}
508
509
510
static void defenv_acquire( uno_Environment * pEnv )
511
1.03M
{
512
1.03M
    uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
513
1.03M
    osl_atomic_increment( &that->nWeakRef );
514
1.03M
    osl_atomic_increment( &that->nRef );
515
1.03M
}
516
517
518
static void defenv_release( uno_Environment * pEnv )
519
1.17M
{
520
1.17M
    uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
521
1.17M
    if (! osl_atomic_decrement( &that->nRef ))
522
127k
    {
523
        // invoke dispose callback
524
127k
        if (pEnv->environmentDisposing)
525
63.8k
        {
526
63.8k
            (*pEnv->environmentDisposing)( pEnv );
527
63.8k
        }
528
529
127k
        OSL_ENSURE( that->aOId2ObjectMap.empty(), "### object entries left!" );
530
127k
    }
531
    // free memory if no weak refs left
532
1.17M
    if (! osl_atomic_decrement( &that->nWeakRef ))
533
0
    {
534
0
        delete that;
535
0
    }
536
1.17M
}
537
538
539
static void defenv_acquireWeak( uno_Environment * pEnv )
540
127k
{
541
127k
    uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
542
127k
    osl_atomic_increment( &that->nWeakRef );
543
127k
}
544
545
546
static void defenv_releaseWeak( uno_Environment * pEnv )
547
127k
{
548
127k
    uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
549
127k
    if (! osl_atomic_decrement( &that->nWeakRef ))
550
127k
    {
551
127k
        delete that;
552
127k
    }
553
127k
}
554
555
556
static void defenv_harden(
557
    uno_Environment ** ppHardEnv, uno_Environment * pEnv )
558
392k
{
559
392k
    if (*ppHardEnv)
560
0
    {
561
0
        (*(*ppHardEnv)->release)( *ppHardEnv );
562
0
        *ppHardEnv = nullptr;
563
0
    }
564
565
392k
    EnvironmentsData & rData = theEnvironmentsData();
566
567
392k
    if (rData.isDisposing)
568
121
        return;
569
570
392k
    uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
571
392k
    {
572
392k
    ::osl::MutexGuard guard( rData.mutex );
573
392k
    if (1 == osl_atomic_increment( &that->nRef )) // is dead
574
254k
    {
575
254k
        that->nRef = 0;
576
254k
        return;
577
254k
    }
578
392k
    }
579
137k
    osl_atomic_increment( &that->nWeakRef );
580
137k
    *ppHardEnv = pEnv;
581
137k
}
582
583
584
static void defenv_dispose( SAL_UNUSED_PARAMETER uno_Environment * )
585
0
{
586
0
}
587
}
588
589
590
uno_DefaultEnvironment::uno_DefaultEnvironment(
591
    const OUString & rEnvDcp_, void * pContext_ )
592
127k
    : nRef( 0 ),
593
127k
      nWeakRef( 0 )
594
127k
{
595
127k
    uno_Environment * that = reinterpret_cast< uno_Environment * >(this);
596
127k
    that->pReserved = nullptr;
597
    // functions
598
127k
    that->acquire = defenv_acquire;
599
127k
    that->release = defenv_release;
600
127k
    that->acquireWeak = defenv_acquireWeak;
601
127k
    that->releaseWeak = defenv_releaseWeak;
602
127k
    that->harden = defenv_harden;
603
127k
    that->dispose = defenv_dispose;
604
127k
    that->pExtEnv = this;
605
    // identifier
606
127k
    ::rtl_uString_acquire( rEnvDcp_.pData );
607
127k
    that->pTypeName = rEnvDcp_.pData;
608
127k
    that->pContext = pContext_;
609
610
    // will be late initialized
611
127k
    that->environmentDisposing = nullptr;
612
613
127k
    uno_ExtEnvironment::registerInterface = defenv_registerInterface;
614
127k
    uno_ExtEnvironment::registerProxyInterface = defenv_registerProxyInterface;
615
127k
    uno_ExtEnvironment::revokeInterface = defenv_revokeInterface;
616
127k
    uno_ExtEnvironment::getObjectIdentifier = defenv_getObjectIdentifier;
617
127k
    uno_ExtEnvironment::getRegisteredInterface = defenv_getRegisteredInterface;
618
127k
    uno_ExtEnvironment::getRegisteredInterfaces =
619
127k
        defenv_getRegisteredInterfaces;
620
621
127k
}
622
623
624
uno_DefaultEnvironment::~uno_DefaultEnvironment()
625
127k
{
626
127k
    ::rtl_uString_release( aBase.pTypeName );
627
127k
}
628
629
630
void writeLine(
631
    void * stream, const char * pLine, const char * pFilter )
632
0
{
633
0
    if (pFilter && *pFilter)
634
0
    {
635
        // lookup pFilter in pLine
636
0
        while (*pLine)
637
0
        {
638
0
            if (*pLine == *pFilter)
639
0
            {
640
0
                sal_Int32 nPos = 1;
641
0
                while (pLine[nPos] && pFilter[nPos] == pLine[nPos])
642
0
                {
643
0
                    ++nPos;
644
0
                }
645
0
                if (! pFilter[nPos])
646
0
                {
647
0
                    if (stream)
648
0
                    {
649
0
                        fprintf( static_cast<FILE *>(stream), "%s\n", pLine );
650
0
                    }
651
0
                    else
652
0
                    {
653
0
                        SAL_WARN("cppu", pLine );
654
0
                    }
655
0
                }
656
0
            }
657
0
            ++pLine;
658
0
        }
659
0
    }
660
0
    else
661
0
    {
662
0
        if (stream)
663
0
        {
664
0
            fprintf( static_cast<FILE *>(stream), "%s\n", pLine );
665
0
        }
666
0
        else
667
0
        {
668
0
            fprintf( stderr, "%s\n", pLine );
669
0
        }
670
0
    }
671
0
}
672
673
674
void writeLine(
675
    void * stream, std::u16string_view rLine, const char * pFilter )
676
0
{
677
0
    OString aLine( OUStringToOString(
678
0
                              rLine, RTL_TEXTENCODING_ASCII_US ) );
679
0
    writeLine( stream, aLine.getStr(), pFilter );
680
0
}
681
682
}
683
684
extern "C" void SAL_CALL uno_dumpEnvironment(
685
    void * stream, uno_Environment * pEnv, const char * pFilter ) noexcept
686
0
{
687
0
    assert(pEnv && "### null ptr!");
688
0
    OUStringBuffer buf;
689
690
0
    if (! pEnv->pExtEnv)
691
0
    {
692
0
        writeLine( stream, "###################################"
693
0
                   "###########################################", pFilter );
694
0
        buf.append( OUString::Concat("environment: ") + OUString::unacquired(&pEnv->pTypeName) );
695
0
        writeLine( stream, buf, pFilter );
696
0
        buf.setLength(0);
697
0
        writeLine( stream, "NO INTERFACE INFORMATION AVAILABLE!", pFilter );
698
0
        return;
699
0
    }
700
701
0
    writeLine( stream, "########################################"
702
0
               "######################################", pFilter );
703
0
    buf.append( OUString::Concat("environment dump: ") + OUString::unacquired(&pEnv->pTypeName) );
704
0
    writeLine( stream, buf, pFilter );
705
0
    buf.setLength(0);
706
707
0
    uno_DefaultEnvironment * that =
708
0
        reinterpret_cast< uno_DefaultEnvironment * >(pEnv);
709
0
    ::osl::MutexGuard guard( that->mutex );
710
711
0
    Ptr2ObjectMap ptr2obj( that->aPtr2ObjectMap );
712
0
    for (const auto& rEntry : that->aOId2ObjectMap)
713
0
    {
714
0
        ObjectEntry * pOEntry = rEntry.second;
715
716
0
        buf.append( "+ " );
717
0
        if (pOEntry->mixedObject)
718
0
            buf.append( "mixed " );
719
0
        buf.append( "object entry: nRef="
720
0
                + OUString::number(pOEntry->nRef)
721
0
                + "; oid=\""
722
0
                + pOEntry->oid
723
0
                + "\"" );
724
0
        writeLine( stream, buf, pFilter );
725
0
        buf.setLength(0);
726
727
0
        for ( std::size_t nPos = 0;
728
0
              nPos < pOEntry->aInterfaces.size(); ++nPos )
729
0
        {
730
0
            const InterfaceEntry & rIEntry = pOEntry->aInterfaces[nPos];
731
732
0
            buf.append( OUString::Concat("  - ")
733
0
                + OUString::unacquired(&rIEntry.pTypeDescr->aBase.pTypeName) );
734
0
            if (rIEntry.fpFreeProxy)
735
0
            {
736
0
                buf.append( "; proxy free=0x"
737
0
                    + OUString::number( reinterpret_cast< sal_IntPtr >(rIEntry.fpFreeProxy), 16 ) );
738
0
            }
739
0
            else
740
0
            {
741
0
                buf.append( "; original" );
742
0
            }
743
0
            buf.append( "; ptr=0x"
744
0
                + OUString::number(reinterpret_cast< sal_IntPtr >(rIEntry.pInterface), 16 ) );
745
746
0
            if (pOEntry->find( rIEntry.pInterface, nPos + 1 ) < 0)
747
0
            {
748
0
                std::size_t erased = ptr2obj.erase( rIEntry.pInterface );
749
0
                if (erased != 1)
750
0
                {
751
0
                    buf.append( " (ptr not found in map!)" );
752
0
                }
753
0
            }
754
0
            writeLine( stream, buf, pFilter );
755
0
            buf.setLength(0);
756
0
        }
757
0
    }
758
0
    if (! ptr2obj.empty())
759
0
        writeLine( stream, "ptr map inconsistency!!!", pFilter );
760
0
    writeLine( stream, "#####################################"
761
0
               "#########################################", pFilter );
762
0
}
763
764
765
extern "C" void SAL_CALL uno_dumpEnvironmentByName(
766
    void * stream, rtl_uString * pEnvDcp, const char * pFilter ) noexcept
767
0
{
768
0
    uno_Environment * pEnv = nullptr;
769
0
    uno_getEnvironment( &pEnv, pEnvDcp, nullptr );
770
0
    if (pEnv)
771
0
    {
772
0
        ::uno_dumpEnvironment( stream, pEnv, pFilter );
773
0
        (*pEnv->release)( pEnv );
774
0
    }
775
0
    else
776
0
    {
777
0
        writeLine(
778
0
            stream,
779
0
            Concat2View("environment \"" + OUString::unacquired(&pEnvDcp) + "\" does not exist!"),
780
0
            pFilter );
781
0
    }
782
0
}
783
784
namespace
785
{
786
787
const OUString & unoenv_getStaticOIdPart()
788
0
{
789
0
    static auto const theStaticOIdPart = [] {
790
0
            OUStringBuffer aRet( 64 );
791
0
            aRet.append( "];" );
792
            // pid
793
0
            oslProcessInfo info;
794
0
            info.Size = sizeof(oslProcessInfo);
795
0
            if (::osl_getProcessInfo( nullptr, osl_Process_IDENTIFIER, &info ) ==
796
0
                osl_Process_E_None)
797
0
            {
798
0
                aRet.append( static_cast<sal_Int64>(info.Ident), 16 );
799
0
            }
800
0
            else
801
0
            {
802
0
                aRet.append( "unknown process id" );
803
0
            }
804
            // good guid
805
0
            sal_uInt8 ar[16];
806
0
            ::rtl_getGlobalProcessId( ar );
807
0
            aRet.append( ';' );
808
0
            for (unsigned char i : ar)
809
0
                aRet.append( static_cast<sal_Int32>(i), 16 );
810
811
0
            return aRet.makeStringAndClear();
812
0
        }();
813
0
    return theStaticOIdPart;
814
0
}
815
816
}
817
818
extern "C"
819
{
820
821
822
static void unoenv_computeObjectIdentifier(
823
    uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface )
824
0
{
825
0
    assert(pEnv && ppOId && pInterface && "### null ptr!");
826
0
    if (*ppOId)
827
0
    {
828
0
        ::rtl_uString_release( *ppOId );
829
0
        *ppOId = nullptr;
830
0
    }
831
832
0
    uno_Interface * pUnoI = static_cast<uno_Interface *>(
833
0
        ::cppu::binuno_queryInterface(
834
0
            pInterface, *typelib_static_type_getByTypeClass(
835
0
                typelib_TypeClass_INTERFACE ) ));
836
0
    if (nullptr == pUnoI)
837
0
        return;
838
839
0
    (*pUnoI->release)( pUnoI );
840
0
    OUString aStr(
841
        // interface
842
0
        OUString::number( reinterpret_cast< sal_IntPtr >(pUnoI), 16 ) + ";"
843
        // environment[context]
844
0
        + OUString::unacquired(&pEnv->aBase.pTypeName) + "["
845
0
        + OUString::number( reinterpret_cast< sal_IntPtr >(
846
0
                    reinterpret_cast<
847
0
                    uno_Environment * >(pEnv)->pContext ), 16 )
848
        // process;good guid
849
0
        + unoenv_getStaticOIdPart() );
850
0
    *ppOId = aStr.pData;
851
0
    ::rtl_uString_acquire( *ppOId );
852
0
}
853
854
855
static void unoenv_acquireInterface(
856
    SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pUnoI_ )
857
0
{
858
0
    uno_Interface * pUnoI = static_cast< uno_Interface * >(pUnoI_);
859
0
    (*pUnoI->acquire)( pUnoI );
860
0
}
861
862
863
static void unoenv_releaseInterface(
864
    SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pUnoI_ )
865
0
{
866
0
    uno_Interface * pUnoI = static_cast< uno_Interface * >(pUnoI_);
867
0
    (*pUnoI->release)( pUnoI );
868
0
}
869
}
870
871
namespace {
872
873
EnvironmentsData::~EnvironmentsData()
874
108
{
875
108
    ::osl::MutexGuard guard( mutex );
876
108
    isDisposing = true;
877
878
108
    for ( const auto& rEntry : aName2EnvMap )
879
121
    {
880
121
        uno_Environment * pWeak = rEntry.second;
881
121
        uno_Environment * pHard = nullptr;
882
121
        (*pWeak->harden)( &pHard, pWeak );
883
121
        (*pWeak->releaseWeak)( pWeak );
884
885
121
        if (pHard)
886
0
        {
887
0
            (*pHard->dispose)( pHard ); // send explicit dispose
888
0
            (*pHard->release)( pHard );
889
0
        }
890
121
    }
891
108
}
892
893
894
void EnvironmentsData::getEnvironment(
895
    uno_Environment ** ppEnv, std::u16string_view rEnvDcp, void * pContext )
896
265k
{
897
265k
    if (*ppEnv)
898
0
    {
899
0
        (*(*ppEnv)->release)( *ppEnv );
900
0
        *ppEnv = nullptr;
901
0
    }
902
903
265k
    OUString aKey = OUString::number( reinterpret_cast< sal_IntPtr >(pContext) ) + rEnvDcp;
904
905
    // try to find registered mapping
906
265k
    OUString2EnvironmentMap::const_iterator const iFind(
907
265k
        aName2EnvMap.find( aKey ) );
908
265k
    if (iFind != aName2EnvMap.end())
909
265k
    {
910
265k
        uno_Environment * pWeak = iFind->second;
911
265k
        (*pWeak->harden)( ppEnv, pWeak );
912
265k
    }
913
265k
}
914
915
void EnvironmentsData::registerEnvironment( uno_Environment ** ppEnv )
916
127k
{
917
127k
    assert(ppEnv && "### null ptr!");
918
127k
    uno_Environment * pEnv =  *ppEnv;
919
920
127k
    OUString aKey =
921
127k
        OUString::number( reinterpret_cast< sal_IntPtr >(pEnv->pContext) ) +
922
127k
        OUString::unacquired(&pEnv->pTypeName);
923
924
    // try to find registered environment
925
127k
    OUString2EnvironmentMap::const_iterator const iFind(
926
127k
        aName2EnvMap.find( aKey ) );
927
127k
    if (iFind == aName2EnvMap.end())
928
121
    {
929
121
        (*pEnv->acquireWeak)( pEnv );
930
121
        std::pair< OUString2EnvironmentMap::iterator, bool > insertion (
931
121
            aName2EnvMap.emplace( aKey, pEnv ) );
932
121
        SAL_WARN_IF( !insertion.second, "cppu", "key " << aKey << " already in env map" );
933
121
    }
934
127k
    else
935
127k
    {
936
127k
        uno_Environment * pHard = nullptr;
937
127k
        uno_Environment * pWeak = iFind->second;
938
127k
        (*pWeak->harden)( &pHard, pWeak );
939
127k
        if (pHard)
940
0
        {
941
0
            (*pEnv->release)( pEnv );
942
0
            *ppEnv = pHard;
943
0
        }
944
127k
        else // registered one is dead
945
127k
        {
946
127k
            (*pWeak->releaseWeak)( pWeak );
947
127k
            (*pEnv->acquireWeak)( pEnv );
948
127k
            aName2EnvMap[ aKey ] = pEnv;
949
127k
        }
950
127k
    }
951
127k
}
952
953
void EnvironmentsData::getRegisteredEnvironments(
954
    uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc,
955
    std::u16string_view rEnvDcp )
956
0
{
957
0
    assert(pppEnvs && pnLen && memAlloc && "### null ptr!");
958
959
    // max size
960
0
    std::vector<uno_Environment*> aFounds(aName2EnvMap.size());
961
0
    sal_Int32 nSize = 0;
962
963
    // find matching environment
964
0
    for ( const auto& rEntry : aName2EnvMap )
965
0
    {
966
0
        uno_Environment * pWeak = rEntry.second;
967
0
        if (rEnvDcp.empty() ||
968
0
            rEnvDcp == OUString::unacquired(&pWeak->pTypeName) )
969
0
        {
970
0
            aFounds[nSize] = nullptr;
971
0
            (*pWeak->harden)( &aFounds[nSize], pWeak );
972
0
            if (aFounds[nSize])
973
0
                ++nSize;
974
0
        }
975
0
    }
976
977
0
    *pnLen = nSize;
978
0
    if (nSize)
979
0
    {
980
0
        *pppEnvs = static_cast<uno_Environment **>((*memAlloc)(
981
0
            sizeof (uno_Environment *) * nSize ));
982
0
        OSL_ASSERT( *pppEnvs );
983
0
        while (nSize--)
984
0
        {
985
0
            (*pppEnvs)[nSize] = aFounds[nSize];
986
0
        }
987
0
    }
988
0
    else
989
0
    {
990
0
        *pppEnvs = nullptr;
991
0
    }
992
0
}
993
994
bool loadEnv(OUString const  & cLibStem,
995
                    uno_Environment * pEnv)
996
63.8k
{
997
63.8k
#ifdef DISABLE_DYNLOADING
998
63.8k
    uno_initEnvironmentFunc fpInit;
999
1000
63.8k
    if ( cLibStem == CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" )
1001
63.8k
        fpInit = CPPU_ENV_uno_initEnvironment;
1002
#if HAVE_FEATURE_JAVA
1003
    else if ( cLibStem == "java_uno" )
1004
        fpInit = java_uno_initEnvironment;
1005
#endif
1006
0
    else
1007
0
    {
1008
0
        SAL_INFO("cppu", ": Unhandled env: " << cLibStem);
1009
0
        return false;
1010
0
    }
1011
#else
1012
    // late init with some code from matching uno language binding
1013
    // will be unloaded by environment
1014
    osl::Module aMod;
1015
    try {
1016
        bool bMod = cppu::detail::loadModule(aMod, cLibStem);
1017
        if (!bMod)
1018
            return false;
1019
    }
1020
    catch(...) {
1021
        // Catch everything and convert to return false
1022
        return false;
1023
    }
1024
1025
1026
    uno_initEnvironmentFunc fpInit = reinterpret_cast<uno_initEnvironmentFunc>(aMod.getSymbol(u"" UNO_INIT_ENVIRONMENT ""_ustr));
1027
1028
    if (!fpInit)
1029
        return false;
1030
1031
    aMod.release();
1032
#endif
1033
1034
63.8k
    (*fpInit)( pEnv ); // init of environment
1035
63.8k
    return true;
1036
63.8k
}
1037
1038
}
1039
1040
extern "C"
1041
{
1042
1043
1044
static uno_Environment * initDefaultEnvironment(
1045
    const OUString & rEnvDcp, void * pContext )
1046
127k
{
1047
    // coverity[leaked_storage : FALSE] - lifetime is controlled by acquire()/release() calls
1048
127k
    uno_Environment * pEnv = &(new uno_DefaultEnvironment( rEnvDcp, pContext ))->aBase;
1049
127k
    (*pEnv->acquire)( pEnv );
1050
1051
127k
    OUString envTypeName = cppu::EnvDcp::getTypeName(rEnvDcp);
1052
1053
    // create default environment
1054
127k
    if ( envTypeName == UNO_LB_UNO )
1055
63.4k
    {
1056
63.4k
        uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
1057
63.4k
        that->computeObjectIdentifier = unoenv_computeObjectIdentifier;
1058
63.4k
        that->acquireInterface = unoenv_acquireInterface;
1059
63.4k
        that->releaseInterface = unoenv_releaseInterface;
1060
1061
63.4k
        OUString envPurpose = cppu::EnvDcp::getPurpose(rEnvDcp);
1062
63.4k
        if (!envPurpose.isEmpty())
1063
0
        {
1064
0
            OUString libStem(
1065
0
                OUString::Concat(envPurpose.subView(envPurpose.lastIndexOf(':') + 1)) + "_uno_uno");
1066
0
            if(!loadEnv(libStem, pEnv))
1067
0
            {
1068
0
                pEnv->release(pEnv);
1069
0
                return nullptr;
1070
0
            }
1071
0
        }
1072
63.4k
    }
1073
63.8k
    else
1074
63.8k
    {
1075
        // late init with some code from matching uno language binding
1076
63.8k
        OUString aStr( envTypeName + "_uno" );
1077
1078
63.8k
        if (!loadEnv(aStr, pEnv))
1079
0
        {
1080
0
            pEnv->release(pEnv);
1081
0
            return nullptr;
1082
0
        }
1083
63.8k
    }
1084
1085
127k
    return pEnv;
1086
127k
}
1087
1088
1089
void SAL_CALL uno_createEnvironment(
1090
    uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext ) noexcept
1091
0
{
1092
0
    assert(ppEnv && "### null ptr!");
1093
0
    if (*ppEnv)
1094
0
        (*(*ppEnv)->release)( *ppEnv );
1095
1096
0
    OUString const & rEnvDcp = OUString::unacquired( &pEnvDcp );
1097
0
    *ppEnv = initDefaultEnvironment( rEnvDcp, pContext );
1098
0
}
1099
1100
void SAL_CALL uno_getEnvironment(
1101
    uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext ) noexcept
1102
265k
{
1103
265k
    assert(ppEnv && "### null ptr!");
1104
265k
    OUString const & rEnvDcp = OUString::unacquired( &pEnvDcp );
1105
1106
265k
    EnvironmentsData & rData = theEnvironmentsData();
1107
1108
265k
    ::osl::MutexGuard guard( rData.mutex );
1109
265k
    rData.getEnvironment( ppEnv, rEnvDcp, pContext );
1110
265k
    if (! *ppEnv)
1111
127k
    {
1112
127k
        *ppEnv = initDefaultEnvironment( rEnvDcp, pContext );
1113
127k
        if (*ppEnv)
1114
127k
        {
1115
            // register new environment:
1116
127k
            rData.registerEnvironment( ppEnv );
1117
127k
        }
1118
127k
    }
1119
265k
}
1120
1121
void SAL_CALL uno_getRegisteredEnvironments(
1122
    uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc,
1123
    rtl_uString * pEnvDcp ) noexcept
1124
0
{
1125
0
    EnvironmentsData & rData = theEnvironmentsData();
1126
1127
0
    ::osl::MutexGuard guard( rData.mutex );
1128
0
    rData.getRegisteredEnvironments(
1129
0
        pppEnvs, pnLen, memAlloc,
1130
0
        (pEnvDcp ? OUString(pEnvDcp) : OUString()) );
1131
0
}
1132
1133
} // extern "C"
1134
1135
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */