Files
libreoffice/cppu/source/uno/lbenv.cxx
Stephan Bergmann c8eaadb5d7 Remaining loplugin:bufferadd
...that had been missing because the plugin didn't implement postRun, so it
didn't report anything when run as part of the shared plugin.  (But did report
the expected warnings when run as a standalone plugin during
CompilerTest_compilerplugins_clang.)

Most fixes are straightforward.  A noteworthy one is PreparedStatement::setBytes
in connectivity/source/drivers/postgresql/pq_preparedstatement.cxx:  The old
preallocation of a 20 character OStringBuffer might have prevented

  buf.append( reinterpret_cast<char *>(escapedString), len -1 );

from potentially throwing std::bad_alloc, which would have caused escapedString
to be leaked.  Even though that 20-character preallocation was likely just
random junk and not meant to address the potential leak, lets address it now.

Change-Id: Ib506332d061684a22a74e5e39e591539fd2c4900
Reviewed-on: https://gerrit.libreoffice.org/80925
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2019-10-17 09:03:53 +02:00

1152 lines
33 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#ifdef DISABLE_DYNLOADING
#include <config_java.h>
#endif
#include <cppu/EnvDcp.hxx>
#include <sal/log.hxx>
#include <osl/diagnose.h>
#include <osl/interlck.h>
#include <osl/mutex.hxx>
#include <osl/module.hxx>
#include <osl/process.h>
#include <rtl/process.h>
#include <rtl/string.hxx>
#include <rtl/ustring.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/instance.hxx>
#include <typelib/typedescription.h>
#include <uno/dispatcher.h>
#include <uno/environment.h>
#include <uno/lbnames.h>
#include "prim.hxx"
#include "loadmodule.hxx"
#include <unordered_map>
#include <vector>
#include <stdio.h>
namespace
{
bool td_equals( typelib_InterfaceTypeDescription const * pTD1,
typelib_InterfaceTypeDescription const * pTD2 )
{
return (pTD1 == pTD2 ||
(pTD1->aBase.pTypeName->length == pTD2->aBase.pTypeName->length &&
::rtl_ustr_compare(
pTD1->aBase.pTypeName->buffer,
pTD2->aBase.pTypeName->buffer ) == 0));
}
struct uno_DefaultEnvironment;
struct InterfaceEntry
{
sal_Int32 refCount;
void * pInterface;
uno_freeProxyFunc fpFreeProxy;
typelib_InterfaceTypeDescription * pTypeDescr;
};
struct ObjectEntry
{
OUString oid;
sal_Int32 nRef;
std::vector< InterfaceEntry > aInterfaces;
bool mixedObject;
explicit ObjectEntry( const OUString & rOId_ );
void append(
uno_DefaultEnvironment * pEnv,
void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr,
uno_freeProxyFunc fpFreeProxy );
InterfaceEntry * find(
typelib_InterfaceTypeDescription * pTypeDescr );
sal_Int32 find( void const * iface_ptr, std::size_t pos ) const;
};
struct FctPtrHash
{
std::size_t operator () ( const void * pKey ) const
{ return reinterpret_cast< std::size_t>( pKey ); }
};
// mapping from environment name to environment
typedef std::unordered_map<
OUString, uno_Environment * > OUString2EnvironmentMap;
// mapping from ptr to object entry
typedef std::unordered_map<
void *, ObjectEntry *, FctPtrHash > Ptr2ObjectMap;
// mapping from oid to object entry
typedef std::unordered_map<
OUString, ObjectEntry * > OId2ObjectMap;
struct EnvironmentsData
{
::osl::Mutex mutex;
OUString2EnvironmentMap aName2EnvMap;
EnvironmentsData() : isDisposing(false) {}
~EnvironmentsData();
void getEnvironment(
uno_Environment ** ppEnv, const OUString & rEnvDcp, void * pContext );
void registerEnvironment( uno_Environment ** ppEnv );
void getRegisteredEnvironments(
uno_Environment *** pppEnvs, sal_Int32 * pnLen,
uno_memAlloc memAlloc, const OUString & rEnvDcp );
bool isDisposing;
};
struct theEnvironmentsData : public rtl::Static< EnvironmentsData, theEnvironmentsData > {};
struct uno_DefaultEnvironment : public uno_ExtEnvironment
{
sal_Int32 nRef;
sal_Int32 nWeakRef;
::osl::Mutex mutex;
Ptr2ObjectMap aPtr2ObjectMap;
OId2ObjectMap aOId2ObjectMap;
uno_DefaultEnvironment(
const OUString & rEnvDcp_, void * pContext_ );
~uno_DefaultEnvironment();
};
ObjectEntry::ObjectEntry( OUString const & rOId_ )
: oid( rOId_ ),
nRef( 0 ),
mixedObject( false )
{
aInterfaces.reserve( 2 );
}
void ObjectEntry::append(
uno_DefaultEnvironment * pEnv,
void * pInterface, typelib_InterfaceTypeDescription * pTypeDescr,
uno_freeProxyFunc fpFreeProxy )
{
InterfaceEntry aNewEntry;
if (! fpFreeProxy)
(*pEnv->acquireInterface)( pEnv, pInterface );
aNewEntry.refCount = 1;
aNewEntry.pInterface = pInterface;
aNewEntry.fpFreeProxy = fpFreeProxy;
typelib_typedescription_acquire( &pTypeDescr->aBase );
aNewEntry.pTypeDescr = pTypeDescr;
std::pair< Ptr2ObjectMap::iterator, bool > i(
pEnv->aPtr2ObjectMap.emplace( pInterface, this ) );
SAL_WARN_IF(
!i.second && (find(pInterface, 0) == -1 || i.first->second != this),
"cppu",
"map already contains " << i.first->second << " != " << this << " for "
<< pInterface);
aInterfaces.push_back( aNewEntry );
}
InterfaceEntry * ObjectEntry::find(
typelib_InterfaceTypeDescription * pTypeDescr_ )
{
OSL_ASSERT( ! aInterfaces.empty() );
if (aInterfaces.empty())
return nullptr;
// shortcut common case:
OUString const & type_name =
OUString::unacquired( &pTypeDescr_->aBase.pTypeName );
if ( type_name == "com.sun.star.uno.XInterface" )
{
return aInterfaces.data();
}
std::size_t nSize = aInterfaces.size();
for ( std::size_t nPos = 0; nPos < nSize; ++nPos )
{
typelib_InterfaceTypeDescription * pITD =
aInterfaces[ nPos ].pTypeDescr;
while (pITD)
{
if (td_equals( pITD, pTypeDescr_ ))
return &aInterfaces[ nPos ];
pITD = pITD->pBaseTypeDescription;
}
}
return nullptr;
}
sal_Int32 ObjectEntry::find(
void const * iface_ptr, std::size_t pos ) const
{
std::size_t size = aInterfaces.size();
for ( ; pos < size; ++pos )
{
if (aInterfaces[ pos ].pInterface == iface_ptr)
return pos;
}
return -1;
}
extern "C"
{
static void defenv_registerInterface(
uno_ExtEnvironment * pEnv, void ** ppInterface,
rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
{
OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr, "### null ptr!" );
OUString const & rOId = OUString::unacquired( &pOId );
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::ClearableMutexGuard guard( that->mutex );
// try to insert dummy 0:
std::pair<OId2ObjectMap::iterator, bool> const insertion(
that->aOId2ObjectMap.emplace( rOId, nullptr ) );
if (insertion.second)
{
ObjectEntry * pOEntry = new ObjectEntry( rOId );
insertion.first->second = pOEntry;
++pOEntry->nRef; // another register call on object
pOEntry->append( that, *ppInterface, pTypeDescr, nullptr );
}
else // object entry exists
{
ObjectEntry * pOEntry = insertion.first->second;
++pOEntry->nRef; // another register call on object
InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr );
if (pIEntry) // type entry exists
{
++pIEntry->refCount;
if (pIEntry->pInterface != *ppInterface)
{
void * pInterface = pIEntry->pInterface;
(*pEnv->acquireInterface)( pEnv, pInterface );
guard.clear();
(*pEnv->releaseInterface)( pEnv, *ppInterface );
*ppInterface = pInterface;
}
}
else
{
pOEntry->append( that, *ppInterface, pTypeDescr, nullptr );
}
}
}
static void defenv_registerProxyInterface(
uno_ExtEnvironment * pEnv, void ** ppInterface, uno_freeProxyFunc freeProxy,
rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
{
OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr && freeProxy,
"### null ptr!" );
OUString const & rOId = OUString::unacquired( &pOId );
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::ClearableMutexGuard guard( that->mutex );
// try to insert dummy 0:
std::pair<OId2ObjectMap::iterator, bool> const insertion(
that->aOId2ObjectMap.emplace( rOId, nullptr ) );
if (insertion.second)
{
ObjectEntry * pOEntry = new ObjectEntry( rOId );
insertion.first->second = pOEntry;
++pOEntry->nRef; // another register call on object
pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy );
}
else // object entry exists
{
ObjectEntry * pOEntry = insertion.first->second;
// first registration was an original, then registerProxyInterface():
pOEntry->mixedObject |=
(!pOEntry->aInterfaces.empty() &&
pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr);
++pOEntry->nRef; // another register call on object
InterfaceEntry * pIEntry = pOEntry->find( pTypeDescr );
if (pIEntry) // type entry exists
{
if (pIEntry->pInterface == *ppInterface)
{
++pIEntry->refCount;
}
else
{
void * pInterface = pIEntry->pInterface;
(*pEnv->acquireInterface)( pEnv, pInterface );
--pOEntry->nRef; // manual revoke of proxy to be freed
guard.clear();
(*freeProxy)( pEnv, *ppInterface );
*ppInterface = pInterface;
}
}
else
{
pOEntry->append( that, *ppInterface, pTypeDescr, freeProxy );
}
}
}
static void s_stub_defenv_revokeInterface(va_list * pParam)
{
uno_ExtEnvironment * pEnv = va_arg(*pParam, uno_ExtEnvironment *);
void * pInterface = va_arg(*pParam, void *);
OSL_ENSURE( pEnv && pInterface, "### null ptr!" );
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::ClearableMutexGuard guard( that->mutex );
Ptr2ObjectMap::const_iterator const iFind(
that->aPtr2ObjectMap.find( pInterface ) );
OSL_ASSERT( iFind != that->aPtr2ObjectMap.end() );
ObjectEntry * pOEntry = iFind->second;
if (! --pOEntry->nRef)
{
// cleanup maps
that->aOId2ObjectMap.erase( pOEntry->oid );
sal_Int32 nPos;
for ( nPos = pOEntry->aInterfaces.size(); nPos--; )
{
that->aPtr2ObjectMap.erase( pOEntry->aInterfaces[nPos].pInterface );
}
// the last proxy interface of the environment might kill this
// environment, because of releasing its language binding!!!
guard.clear();
// release interfaces
for ( nPos = pOEntry->aInterfaces.size(); nPos--; )
{
InterfaceEntry const & rEntry = pOEntry->aInterfaces[nPos];
typelib_typedescription_release( &rEntry.pTypeDescr->aBase );
if (rEntry.fpFreeProxy) // is proxy or used interface?
{
(*rEntry.fpFreeProxy)( pEnv, rEntry.pInterface );
}
else
{
(*pEnv->releaseInterface)( pEnv, rEntry.pInterface );
}
}
delete pOEntry;
}
else if (pOEntry->mixedObject)
{
OSL_ASSERT( !pOEntry->aInterfaces.empty() &&
pOEntry->aInterfaces[ 0 ].fpFreeProxy == nullptr );
sal_Int32 index = pOEntry->find( pInterface, 1 );
OSL_ASSERT( index > 0 );
if (index > 0)
{
InterfaceEntry & entry = pOEntry->aInterfaces[ index ];
OSL_ASSERT( entry.pInterface == pInterface );
if (entry.fpFreeProxy != nullptr)
{
--entry.refCount;
if (entry.refCount == 0)
{
uno_freeProxyFunc fpFreeProxy = entry.fpFreeProxy;
typelib_TypeDescription * pTypeDescr =
reinterpret_cast< typelib_TypeDescription * >(
entry.pTypeDescr );
pOEntry->aInterfaces.erase(
pOEntry->aInterfaces.begin() + index );
if (pOEntry->find( pInterface, index ) < 0)
{
// proxy ptr not registered for another interface:
// remove from ptr map
std::size_t erased =
that->aPtr2ObjectMap.erase( pInterface );
OSL_ASSERT( erased == 1 );
}
guard.clear();
typelib_typedescription_release( pTypeDescr );
(*fpFreeProxy)( pEnv, pInterface );
}
}
}
}
}
static void defenv_revokeInterface(uno_ExtEnvironment * pEnv, void * pInterface)
{
uno_Environment_invoke(&pEnv->aBase, s_stub_defenv_revokeInterface, pEnv, pInterface);
}
static void defenv_getObjectIdentifier(
uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface )
{
OSL_ENSURE( pEnv && ppOId && pInterface, "### null ptr!" );
if (*ppOId)
{
::rtl_uString_release( *ppOId );
*ppOId = nullptr;
}
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::ClearableMutexGuard guard( that->mutex );
Ptr2ObjectMap::const_iterator const iFind(
that->aPtr2ObjectMap.find( pInterface ) );
if (iFind == that->aPtr2ObjectMap.end())
{
guard.clear();
(*pEnv->computeObjectIdentifier)( pEnv, ppOId, pInterface );
}
else
{
rtl_uString * hstr = iFind->second->oid.pData;
rtl_uString_acquire( hstr );
*ppOId = hstr;
}
}
static void defenv_getRegisteredInterface(
uno_ExtEnvironment * pEnv, void ** ppInterface,
rtl_uString * pOId, typelib_InterfaceTypeDescription * pTypeDescr )
{
OSL_ENSURE( pEnv && ppInterface && pOId && pTypeDescr, "### null ptr!" );
if (*ppInterface)
{
(*pEnv->releaseInterface)( pEnv, *ppInterface );
*ppInterface = nullptr;
}
OUString const & rOId = OUString::unacquired( &pOId );
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::MutexGuard guard( that->mutex );
OId2ObjectMap::const_iterator const iFind
( that->aOId2ObjectMap.find( rOId ) );
if (iFind != that->aOId2ObjectMap.end())
{
InterfaceEntry const * pIEntry = iFind->second->find( pTypeDescr );
if (pIEntry)
{
(*pEnv->acquireInterface)( pEnv, pIEntry->pInterface );
*ppInterface = pIEntry->pInterface;
}
}
}
static void defenv_getRegisteredInterfaces(
uno_ExtEnvironment * pEnv, void *** pppInterfaces, sal_Int32 * pnLen,
uno_memAlloc memAlloc )
{
assert(pEnv && pppInterfaces && pnLen && memAlloc && "### null ptr!");
uno_DefaultEnvironment * that =
static_cast< uno_DefaultEnvironment * >( pEnv );
::osl::MutexGuard guard( that->mutex );
sal_Int32 nLen = that->aPtr2ObjectMap.size();
sal_Int32 nPos = 0;
void ** ppInterfaces = static_cast<void **>((*memAlloc)( nLen * sizeof (void *) ));
for (const auto& rEntry : that->aPtr2ObjectMap)
{
(*pEnv->acquireInterface)( pEnv, ppInterfaces[nPos++] = rEntry.first );
}
*pppInterfaces = ppInterfaces;
*pnLen = nLen;
}
static void defenv_acquire( uno_Environment * pEnv )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
osl_atomic_increment( &that->nWeakRef );
osl_atomic_increment( &that->nRef );
}
static void defenv_release( uno_Environment * pEnv )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
if (! osl_atomic_decrement( &that->nRef ))
{
// invoke dispose callback
if (pEnv->environmentDisposing)
{
(*pEnv->environmentDisposing)( pEnv );
}
OSL_ENSURE( that->aOId2ObjectMap.empty(), "### object entries left!" );
}
// free memory if no weak refs left
if (! osl_atomic_decrement( &that->nWeakRef ))
{
delete that;
}
}
static void defenv_acquireWeak( uno_Environment * pEnv )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
osl_atomic_increment( &that->nWeakRef );
}
static void defenv_releaseWeak( uno_Environment * pEnv )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
if (! osl_atomic_decrement( &that->nWeakRef ))
{
delete that;
}
}
static void defenv_harden(
uno_Environment ** ppHardEnv, uno_Environment * pEnv )
{
if (*ppHardEnv)
{
(*(*ppHardEnv)->release)( *ppHardEnv );
*ppHardEnv = nullptr;
}
EnvironmentsData & rData = theEnvironmentsData::get();
if (rData.isDisposing)
return;
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
{
::osl::MutexGuard guard( rData.mutex );
if (1 == osl_atomic_increment( &that->nRef )) // is dead
{
that->nRef = 0;
return;
}
}
osl_atomic_increment( &that->nWeakRef );
*ppHardEnv = pEnv;
}
static void defenv_dispose( SAL_UNUSED_PARAMETER uno_Environment * )
{
}
}
uno_DefaultEnvironment::uno_DefaultEnvironment(
const OUString & rEnvDcp_, void * pContext_ )
: nRef( 0 ),
nWeakRef( 0 )
{
uno_Environment * that = reinterpret_cast< uno_Environment * >(this);
that->pReserved = nullptr;
// functions
that->acquire = defenv_acquire;
that->release = defenv_release;
that->acquireWeak = defenv_acquireWeak;
that->releaseWeak = defenv_releaseWeak;
that->harden = defenv_harden;
that->dispose = defenv_dispose;
that->pExtEnv = this;
// identifier
::rtl_uString_acquire( rEnvDcp_.pData );
that->pTypeName = rEnvDcp_.pData;
that->pContext = pContext_;
// will be late initialized
that->environmentDisposing = nullptr;
uno_ExtEnvironment::registerInterface = defenv_registerInterface;
uno_ExtEnvironment::registerProxyInterface = defenv_registerProxyInterface;
uno_ExtEnvironment::revokeInterface = defenv_revokeInterface;
uno_ExtEnvironment::getObjectIdentifier = defenv_getObjectIdentifier;
uno_ExtEnvironment::getRegisteredInterface = defenv_getRegisteredInterface;
uno_ExtEnvironment::getRegisteredInterfaces =
defenv_getRegisteredInterfaces;
}
uno_DefaultEnvironment::~uno_DefaultEnvironment()
{
::rtl_uString_release( aBase.pTypeName );
}
void writeLine(
void * stream, const sal_Char * pLine, const sal_Char * pFilter )
{
if (pFilter && *pFilter)
{
// lookup pFilter in pLine
while (*pLine)
{
if (*pLine == *pFilter)
{
sal_Int32 nPos = 1;
while (pLine[nPos] && pFilter[nPos] == pLine[nPos])
{
++nPos;
}
if (! pFilter[nPos])
{
if (stream)
{
fprintf( static_cast<FILE *>(stream), "%s\n", pLine );
}
else
{
SAL_WARN("cppu", pLine );
}
}
}
++pLine;
}
}
else
{
if (stream)
{
fprintf( static_cast<FILE *>(stream), "%s\n", pLine );
}
else
{
fprintf( stderr, "%s\n", pLine );
}
}
}
void writeLine(
void * stream, const OUString & rLine, const sal_Char * pFilter )
{
OString aLine( OUStringToOString(
rLine, RTL_TEXTENCODING_ASCII_US ) );
writeLine( stream, aLine.getStr(), pFilter );
}
}
extern "C" void SAL_CALL uno_dumpEnvironment(
void * stream, uno_Environment * pEnv, const sal_Char * pFilter )
SAL_THROW_EXTERN_C()
{
OSL_ENSURE( pEnv, "### null ptr!" );
OUStringBuffer buf;
if (! pEnv->pExtEnv)
{
writeLine( stream, "###################################"
"###########################################", pFilter );
buf.append( "environment: " );
buf.append( pEnv->pTypeName );
writeLine( stream, buf.makeStringAndClear(), pFilter );
writeLine( stream, "NO INTERFACE INFORMATION AVAILABLE!", pFilter );
return;
}
writeLine( stream, "########################################"
"######################################", pFilter );
buf.append( "environment dump: " );
buf.append( pEnv->pTypeName );
writeLine( stream, buf.makeStringAndClear(), pFilter );
uno_DefaultEnvironment * that =
reinterpret_cast< uno_DefaultEnvironment * >(pEnv);
::osl::MutexGuard guard( that->mutex );
Ptr2ObjectMap ptr2obj( that->aPtr2ObjectMap );
for (const auto& rEntry : that->aOId2ObjectMap)
{
ObjectEntry * pOEntry = rEntry.second;
buf.append( "+ " );
if (pOEntry->mixedObject)
buf.append( "mixed " );
buf.append( "object entry: nRef=" );
buf.append( pOEntry->nRef );
buf.append( "; oid=\"" );
buf.append( pOEntry->oid );
buf.append( '\"' );
writeLine( stream, buf.makeStringAndClear(), pFilter );
for ( std::size_t nPos = 0;
nPos < pOEntry->aInterfaces.size(); ++nPos )
{
const InterfaceEntry & rIEntry = pOEntry->aInterfaces[nPos];
buf.append( " - " );
buf.append( rIEntry.pTypeDescr->aBase.pTypeName );
if (rIEntry.fpFreeProxy)
{
buf.append( "; proxy free=0x" );
buf.append(
reinterpret_cast< sal_IntPtr >(rIEntry.fpFreeProxy), 16 );
}
else
{
buf.append( "; original" );
}
buf.append( "; ptr=0x" );
buf.append(
reinterpret_cast< sal_IntPtr >(rIEntry.pInterface), 16 );
if (pOEntry->find( rIEntry.pInterface, nPos + 1 ) < 0)
{
std::size_t erased = ptr2obj.erase( rIEntry.pInterface );
if (erased != 1)
{
buf.append( " (ptr not found in map!)" );
}
}
writeLine( stream, buf.makeStringAndClear(), pFilter );
}
}
if (! ptr2obj.empty())
writeLine( stream, "ptr map inconsistency!!!", pFilter );
writeLine( stream, "#####################################"
"#########################################", pFilter );
}
extern "C" void SAL_CALL uno_dumpEnvironmentByName(
void * stream, rtl_uString * pEnvDcp, const sal_Char * pFilter )
SAL_THROW_EXTERN_C()
{
uno_Environment * pEnv = nullptr;
uno_getEnvironment( &pEnv, pEnvDcp, nullptr );
if (pEnv)
{
::uno_dumpEnvironment( stream, pEnv, pFilter );
(*pEnv->release)( pEnv );
}
else
{
writeLine(
stream, "environment \"" + OUString::unacquired(&pEnvDcp) + "\" does not exist!",
pFilter );
}
}
namespace
{
class makeOIdPart
{
private:
OUString m_sOidPart;
public:
makeOIdPart()
{
OUStringBuffer aRet( 64 );
aRet.append( "];" );
// pid
oslProcessInfo info;
info.Size = sizeof(oslProcessInfo);
if (::osl_getProcessInfo( nullptr, osl_Process_IDENTIFIER, &info ) ==
osl_Process_E_None)
{
aRet.append( static_cast<sal_Int64>(info.Ident), 16 );
}
else
{
aRet.append( "unknown process id" );
}
// good guid
sal_uInt8 ar[16];
::rtl_getGlobalProcessId( ar );
aRet.append( ';' );
for (unsigned char i : ar)
aRet.append( static_cast<sal_Int32>(i), 16 );
m_sOidPart = aRet.makeStringAndClear();
}
const OUString& getOIdPart() const { return m_sOidPart; }
};
class theStaticOIdPart : public rtl::Static<makeOIdPart, theStaticOIdPart> {};
const OUString & unoenv_getStaticOIdPart()
{
return theStaticOIdPart::get().getOIdPart();
}
}
extern "C"
{
static void unoenv_computeObjectIdentifier(
uno_ExtEnvironment * pEnv, rtl_uString ** ppOId, void * pInterface )
{
assert(pEnv && ppOId && pInterface && "### null ptr!");
if (*ppOId)
{
::rtl_uString_release( *ppOId );
*ppOId = nullptr;
}
uno_Interface * pUnoI = static_cast<uno_Interface *>(
::cppu::binuno_queryInterface(
pInterface, *typelib_static_type_getByTypeClass(
typelib_TypeClass_INTERFACE ) ));
if (nullptr != pUnoI)
{
(*pUnoI->release)( pUnoI );
// interface
OUStringBuffer oid( 64 );
oid.append( reinterpret_cast< sal_Int64 >(pUnoI), 16 );
oid.append( ';' );
// environment[context]
oid.append( pEnv->aBase.pTypeName );
oid.append( '[' );
oid.append( reinterpret_cast< sal_Int64 >(
reinterpret_cast<
uno_Environment * >(pEnv)->pContext ), 16 );
// process;good guid
oid.append( unoenv_getStaticOIdPart() );
OUString aStr( oid.makeStringAndClear() );
::rtl_uString_acquire( *ppOId = aStr.pData );
}
}
static void unoenv_acquireInterface(
SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pUnoI_ )
{
uno_Interface * pUnoI = static_cast< uno_Interface * >(pUnoI_);
(*pUnoI->acquire)( pUnoI );
}
static void unoenv_releaseInterface(
SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pUnoI_ )
{
uno_Interface * pUnoI = static_cast< uno_Interface * >(pUnoI_);
(*pUnoI->release)( pUnoI );
}
}
namespace {
EnvironmentsData::~EnvironmentsData()
{
::osl::MutexGuard guard( mutex );
isDisposing = true;
for ( const auto& rEntry : aName2EnvMap )
{
uno_Environment * pWeak = rEntry.second;
uno_Environment * pHard = nullptr;
(*pWeak->harden)( &pHard, pWeak );
(*pWeak->releaseWeak)( pWeak );
if (pHard)
{
(*pHard->dispose)( pHard ); // send explicit dispose
(*pHard->release)( pHard );
}
}
}
void EnvironmentsData::getEnvironment(
uno_Environment ** ppEnv, const OUString & rEnvDcp, void * pContext )
{
if (*ppEnv)
{
(*(*ppEnv)->release)( *ppEnv );
*ppEnv = nullptr;
}
OUString aKey = OUString::number( reinterpret_cast< sal_IntPtr >(pContext) ) + rEnvDcp;
// try to find registered mapping
OUString2EnvironmentMap::const_iterator const iFind(
aName2EnvMap.find( aKey ) );
if (iFind != aName2EnvMap.end())
{
uno_Environment * pWeak = iFind->second;
(*pWeak->harden)( ppEnv, pWeak );
}
}
void EnvironmentsData::registerEnvironment( uno_Environment ** ppEnv )
{
OSL_ENSURE( ppEnv, "### null ptr!" );
uno_Environment * pEnv = *ppEnv;
OUString aKey =
OUString::number( reinterpret_cast< sal_IntPtr >(pEnv->pContext) ) +
OUString::unacquired(&pEnv->pTypeName);
// try to find registered environment
OUString2EnvironmentMap::const_iterator const iFind(
aName2EnvMap.find( aKey ) );
if (iFind == aName2EnvMap.end())
{
(*pEnv->acquireWeak)( pEnv );
std::pair< OUString2EnvironmentMap::iterator, bool > insertion (
aName2EnvMap.emplace( aKey, pEnv ) );
SAL_WARN_IF( !insertion.second, "cppu", "key " << aKey << " already in env map" );
}
else
{
uno_Environment * pHard = nullptr;
uno_Environment * pWeak = iFind->second;
(*pWeak->harden)( &pHard, pWeak );
if (pHard)
{
(*pEnv->release)( pEnv );
*ppEnv = pHard;
}
else // registered one is dead
{
(*pWeak->releaseWeak)( pWeak );
(*pEnv->acquireWeak)( pEnv );
aName2EnvMap[ aKey ] = pEnv;
}
}
}
void EnvironmentsData::getRegisteredEnvironments(
uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc,
const OUString & rEnvDcp )
{
assert(pppEnvs && pnLen && memAlloc && "### null ptr!");
// max size
std::vector<uno_Environment*> aFounds(aName2EnvMap.size());
sal_Int32 nSize = 0;
// find matching environment
for ( const auto& rEntry : aName2EnvMap )
{
uno_Environment * pWeak = rEntry.second;
if (rEnvDcp.isEmpty() ||
rEnvDcp == pWeak->pTypeName )
{
aFounds[nSize] = nullptr;
(*pWeak->harden)( &aFounds[nSize], pWeak );
if (aFounds[nSize])
++nSize;
}
}
*pnLen = nSize;
if (nSize)
{
*pppEnvs = static_cast<uno_Environment **>((*memAlloc)(
sizeof (uno_Environment *) * nSize ));
OSL_ASSERT( *pppEnvs );
while (nSize--)
{
(*pppEnvs)[nSize] = aFounds[nSize];
}
}
else
{
*pppEnvs = nullptr;
}
}
bool loadEnv(OUString const & cLibStem,
uno_Environment * pEnv)
{
#ifdef DISABLE_DYNLOADING
uno_initEnvironmentFunc fpInit;
if ( cLibStem == CPPU_CURRENT_LANGUAGE_BINDING_NAME "_uno" )
fpInit = CPPU_ENV_uno_initEnvironment;
#if HAVE_FEATURE_JAVA
else if ( cLibStem == "java_uno" )
fpInit = java_uno_initEnvironment;
#endif
else
{
SAL_INFO("cppu", ": Unhandled env: " << cLibStem);
return false;
}
#else
// late init with some code from matching uno language binding
// will be unloaded by environment
osl::Module aMod;
try {
bool bMod = cppu::detail::loadModule(aMod, cLibStem);
if (!bMod)
return false;
}
catch(...) {
// Catch everything and convert to return false
return false;
}
uno_initEnvironmentFunc fpInit = reinterpret_cast<uno_initEnvironmentFunc>(aMod.getSymbol(UNO_INIT_ENVIRONMENT));
if (!fpInit)
return false;
aMod.release();
#endif
(*fpInit)( pEnv ); // init of environment
return true;
}
}
extern "C"
{
static uno_Environment * initDefaultEnvironment(
const OUString & rEnvDcp, void * pContext )
{
// coverity[leaked_storage : FALSE] - lifetime is controlled by acquire()/release() calls
uno_Environment * pEnv = &(new uno_DefaultEnvironment( rEnvDcp, pContext ))->aBase;
(*pEnv->acquire)( pEnv );
OUString envTypeName = cppu::EnvDcp::getTypeName(rEnvDcp);
// create default environment
if ( envTypeName == UNO_LB_UNO )
{
uno_DefaultEnvironment * that = reinterpret_cast<uno_DefaultEnvironment *>(pEnv);
that->computeObjectIdentifier = unoenv_computeObjectIdentifier;
that->acquireInterface = unoenv_acquireInterface;
that->releaseInterface = unoenv_releaseInterface;
OUString envPurpose = cppu::EnvDcp::getPurpose(rEnvDcp);
if (!envPurpose.isEmpty())
{
OUString libStem(
envPurpose.copy(envPurpose.lastIndexOf(':') + 1) + "_uno_uno");
if(!loadEnv(libStem, pEnv))
{
pEnv->release(pEnv);
return nullptr;
}
}
}
else
{
// late init with some code from matching uno language binding
OUString aStr( envTypeName + "_uno" );
if (!loadEnv(aStr, pEnv))
{
pEnv->release(pEnv);
return nullptr;
}
}
return pEnv;
}
void SAL_CALL uno_createEnvironment(
uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext )
SAL_THROW_EXTERN_C()
{
assert(ppEnv && "### null ptr!");
if (*ppEnv)
(*(*ppEnv)->release)( *ppEnv );
OUString const & rEnvDcp = OUString::unacquired( &pEnvDcp );
*ppEnv = initDefaultEnvironment( rEnvDcp, pContext );
}
void SAL_CALL uno_getEnvironment(
uno_Environment ** ppEnv, rtl_uString * pEnvDcp, void * pContext )
SAL_THROW_EXTERN_C()
{
assert(ppEnv && "### null ptr!");
OUString const & rEnvDcp = OUString::unacquired( &pEnvDcp );
EnvironmentsData & rData = theEnvironmentsData::get();
::osl::MutexGuard guard( rData.mutex );
rData.getEnvironment( ppEnv, rEnvDcp, pContext );
if (! *ppEnv)
{
*ppEnv = initDefaultEnvironment( rEnvDcp, pContext );
if (*ppEnv)
{
// register new environment:
rData.registerEnvironment( ppEnv );
}
}
}
void SAL_CALL uno_getRegisteredEnvironments(
uno_Environment *** pppEnvs, sal_Int32 * pnLen, uno_memAlloc memAlloc,
rtl_uString * pEnvDcp )
SAL_THROW_EXTERN_C()
{
EnvironmentsData & rData = theEnvironmentsData::get();
::osl::MutexGuard guard( rData.mutex );
rData.getRegisteredEnvironments(
pppEnvs, pnLen, memAlloc,
(pEnvDcp ? OUString(pEnvDcp) : OUString()) );
}
} // extern "C"
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */