summaryrefslogtreecommitdiffstats
path: root/bridges/source/cpp_uno/msvc_win32_intel/except.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'bridges/source/cpp_uno/msvc_win32_intel/except.cxx')
-rw-r--r--bridges/source/cpp_uno/msvc_win32_intel/except.cxx593
1 files changed, 593 insertions, 0 deletions
diff --git a/bridges/source/cpp_uno/msvc_win32_intel/except.cxx b/bridges/source/cpp_uno/msvc_win32_intel/except.cxx
new file mode 100644
index 000000000..360abb038
--- /dev/null
+++ b/bridges/source/cpp_uno/msvc_win32_intel/except.cxx
@@ -0,0 +1,593 @@
+/* -*- 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 .
+ */
+
+
+#include <sal/config.h>
+#include <malloc.h>
+#include <typeinfo>
+#include <signal.h>
+
+#include <rtl/alloc.h>
+#include <rtl/strbuf.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+#include <unordered_map>
+#include "msci.hxx"
+#include <except.hxx>
+
+
+#pragma pack(push, 8)
+
+using namespace ::com::sun::star::uno;
+using namespace ::std;
+using namespace ::osl;
+
+namespace CPPU_CURRENT_NAMESPACE
+{
+
+static inline OUString toUNOname( OUString const & rRTTIname ) throw ()
+{
+ OUStringBuffer aRet( 64 );
+ OUString aStr( rRTTIname.copy( 4, rRTTIname.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@
+ sal_Int32 nPos = aStr.getLength();
+ while (nPos > 0)
+ {
+ sal_Int32 n = aStr.lastIndexOf( '@', nPos );
+ aRet.append( aStr.copy( n +1, nPos -n -1 ) );
+ if (n >= 0)
+ {
+ aRet.append( '.' );
+ }
+ nPos = n;
+ }
+ return aRet.makeStringAndClear();
+}
+
+static inline OUString toRTTIname( OUString const & rUNOname ) throw ()
+{
+ OUStringBuffer aRet( 64 );
+ aRet.appendAscii( ".?AV" ); // class ".?AV"; struct ".?AU"
+ sal_Int32 nPos = rUNOname.getLength();
+ while (nPos > 0)
+ {
+ sal_Int32 n = rUNOname.lastIndexOf( '.', nPos );
+ aRet.append( rUNOname.copy( n +1, nPos -n -1 ) );
+ aRet.append( '@' );
+ nPos = n;
+ }
+ aRet.append( '@' );
+ return aRet.makeStringAndClear();
+}
+
+
+//#### RTTI simulation #############################################################################
+
+
+typedef std::unordered_map< OUString, void * > t_string2PtrMap;
+
+class RTTInfos
+{
+ Mutex _aMutex;
+ t_string2PtrMap _allRTTI;
+
+ static OUString toRawName( OUString const & rUNOname ) throw ();
+public:
+ type_info * getRTTI( OUString const & rUNOname ) throw ();
+
+ RTTInfos();
+ ~RTTInfos();
+};
+
+class __type_info
+{
+ friend type_info * RTTInfos::getRTTI( OUString const & ) throw ();
+ friend int msci_filterCppException(
+ LPEXCEPTION_POINTERS, uno_Any *, uno_Mapping * );
+
+public:
+ virtual ~__type_info() throw ();
+
+ inline __type_info( void * m_data, const char * m_d_name ) throw ()
+ : _m_data( m_data )
+ { ::strcpy( _m_d_name, m_d_name ); } // #100211# - checked
+
+private:
+ void * _m_data;
+ char _m_d_name[1];
+};
+
+__type_info::~__type_info() throw ()
+{
+}
+
+type_info * RTTInfos::getRTTI( OUString const & rUNOname ) throw ()
+{
+ // a must be
+ static_assert(sizeof(__type_info) == sizeof(type_info), "### type info structure size differ!");
+
+ MutexGuard aGuard( _aMutex );
+ t_string2PtrMap::const_iterator const iFind( _allRTTI.find( rUNOname ) );
+
+ // check if type is already available
+ if (iFind == _allRTTI.end())
+ {
+ // insert new type_info
+ OString aRawName( OUStringToOString( toRTTIname( rUNOname ), RTL_TEXTENCODING_ASCII_US ) );
+ __type_info * pRTTI = new( std::malloc( sizeof(__type_info) + aRawName.getLength() ) )
+ __type_info( NULL, aRawName.getStr() );
+
+ // put into map
+ pair< t_string2PtrMap::iterator, bool > insertion(
+ _allRTTI.insert( t_string2PtrMap::value_type( rUNOname, pRTTI ) ) );
+ assert(insertion.second && "### rtti insertion failed?!");
+
+ return reinterpret_cast<type_info*>(pRTTI);
+ }
+ else
+ {
+ return reinterpret_cast<type_info*>(iFind->second);
+ }
+}
+
+RTTInfos::RTTInfos() throw ()
+{
+}
+
+RTTInfos::~RTTInfos() throw ()
+{
+ SAL_INFO("bridges", "> freeing generated RTTI infos... <");
+
+ MutexGuard aGuard( _aMutex );
+ for ( auto& rEntry : _allRTTI )
+ {
+ __type_info * pType = reinterpret_cast<__type_info*>(rEntry.second);
+ pType->~__type_info(); // obsolete, but good style...
+ std::free( pType );
+ }
+}
+
+
+//#### Exception raising ###########################################################################
+
+
+struct ObjectFunction
+{
+ char somecode[12];
+ typelib_TypeDescription * _pTypeDescr; // type of object
+
+ inline static void * operator new ( size_t nSize );
+ inline static void operator delete ( void * pMem );
+
+ ObjectFunction( typelib_TypeDescription * pTypeDescr, void * fpFunc ) throw ();
+ ~ObjectFunction() throw ();
+};
+
+inline void * ObjectFunction::operator new ( size_t nSize )
+{
+ void * pMem = std::malloc( nSize );
+ if (pMem != 0)
+ {
+ DWORD old_protect;
+ BOOL success =
+ VirtualProtect(pMem, nSize, PAGE_EXECUTE_READWRITE, &old_protect);
+ (void) success;
+ assert(success && "VirtualProtect() failed!");
+ }
+ return pMem;
+}
+
+inline void ObjectFunction::operator delete ( void * pMem )
+{
+ std::free( pMem );
+}
+
+
+ObjectFunction::ObjectFunction( typelib_TypeDescription * pTypeDescr, void * fpFunc ) throw ()
+ : _pTypeDescr( pTypeDescr )
+{
+ ::typelib_typedescription_acquire( _pTypeDescr );
+
+ unsigned char * pCode = (unsigned char *)somecode;
+ // a must be!
+ assert((void *)this == (void *)pCode);
+
+ // push ObjectFunction this
+ *pCode++ = 0x68;
+ *(void **)pCode = this;
+ pCode += sizeof(void *);
+ // jmp rel32 fpFunc
+ *pCode++ = 0xe9;
+ *(sal_Int32 *)pCode = ((unsigned char *)fpFunc) - pCode - sizeof(sal_Int32);
+}
+
+ObjectFunction::~ObjectFunction() throw ()
+{
+ ::typelib_typedescription_release( _pTypeDescr );
+}
+
+static void * __cdecl __copyConstruct( void * pExcThis, void * pSource, ObjectFunction * pThis )
+ throw ()
+{
+ ::uno_copyData( pExcThis, pSource, pThis->_pTypeDescr, cpp_acquire );
+ return pExcThis;
+}
+
+static void * __cdecl __destruct( void * pExcThis, ObjectFunction * pThis )
+ throw ()
+{
+ ::uno_destructData( pExcThis, pThis->_pTypeDescr, cpp_release );
+ return pExcThis;
+}
+
+// these are non virtual object methods; there is no this ptr on stack => ecx supplies _this_ ptr
+
+static __declspec(naked) void copyConstruct() throw ()
+{
+ __asm
+ {
+ // ObjectFunction this already on stack
+ push [esp+8] // source exc object this
+ push ecx // exc object
+ call __copyConstruct
+ add esp, 12 // + ObjectFunction this
+ ret 4
+ }
+}
+
+static __declspec(naked) void destruct() throw ()
+{
+ __asm
+ {
+ // ObjectFunction this already on stack
+ push ecx // exc object
+ call __destruct
+ add esp, 8 // + ObjectFunction this
+ ret
+ }
+}
+
+struct ExceptionType
+{
+ sal_Int32 _n0;
+ type_info * _pTypeInfo;
+ sal_Int32 _n1, _n2, _n3, _n4;
+ ObjectFunction * _pCopyCtor;
+ sal_Int32 _n5;
+
+ explicit ExceptionType( typelib_TypeDescription * pTypeDescr ) throw ()
+ : _n0( 0 )
+ , _n1( 0 )
+ , _n2( -1 )
+ , _n3( 0 )
+ , _n4( pTypeDescr->nSize )
+ , _pCopyCtor( new ObjectFunction( pTypeDescr, copyConstruct ) )
+ , _n5( 0 )
+ {
+ _pTypeInfo = msci_getRTTI( pTypeDescr->pTypeName );
+ }
+
+ ~ExceptionType() throw ()
+ {
+ delete _pCopyCtor;
+ }
+
+ // Copy assignment is forbidden and not implemented.
+ ExceptionType (const ExceptionType &) = delete;
+ ExceptionType & operator= (const ExceptionType &) = delete;
+};
+
+struct RaiseInfo
+{
+ sal_Int32 _n0;
+ ObjectFunction * _pDtor;
+ sal_Int32 _n2;
+ void * _types;
+ sal_Int32 _n3, _n4;
+
+ explicit RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ();
+ ~RaiseInfo() throw ();
+};
+
+RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
+ : _n0( 0 )
+ , _pDtor( new ObjectFunction( pTypeDescr, destruct ) )
+ , _n2( 0 )
+ , _n3( 0 )
+ , _n4( 0 )
+{
+ // a must be
+ static_assert(sizeof(sal_Int32) == sizeof(ExceptionType *), "### pointer size differs from sal_Int32!");
+
+ typelib_CompoundTypeDescription * pCompTypeDescr;
+
+ // info count
+ sal_Int32 nLen = 0;
+ for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
+ pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ {
+ ++nLen;
+ }
+
+ // info count accompanied by type info ptrs: type, base type, base base type, ...
+ _types = std::malloc( sizeof(sal_Int32) + (sizeof(ExceptionType *) * nLen) );
+ *(sal_Int32 *)_types = nLen;
+
+ ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1);
+
+ sal_Int32 nPos = 0;
+ for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
+ pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
+ {
+ ppTypes[nPos++] = new ExceptionType( (typelib_TypeDescription *)pCompTypeDescr );
+ }
+}
+
+RaiseInfo::~RaiseInfo() throw ()
+{
+ ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1);
+ for ( sal_Int32 nTypes = *(sal_Int32 *)_types; nTypes--; )
+ {
+ delete ppTypes[nTypes];
+ }
+ std::free( _types );
+
+ delete _pDtor;
+}
+
+class ExceptionInfos
+{
+ Mutex _aMutex;
+ t_string2PtrMap _allRaiseInfos;
+
+public:
+ static void * getRaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ();
+
+ ExceptionInfos() throw ();
+ ~ExceptionInfos() throw ();
+};
+
+ExceptionInfos::ExceptionInfos() throw ()
+{
+}
+
+ExceptionInfos::~ExceptionInfos() throw ()
+{
+ SAL_INFO("bridges", "> freeing exception infos... <");
+
+ MutexGuard aGuard( _aMutex );
+ for ( auto& rEntry : _allRaiseInfos )
+ {
+ delete reinterpret_cast<RaiseInfo*>(rEntry.second);
+ }
+}
+
+void * ExceptionInfos::getRaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
+{
+ static ExceptionInfos* s_pInfos = new ExceptionInfos();
+
+ assert( pTypeDescr &&
+ (pTypeDescr->eTypeClass == typelib_TypeClass_STRUCT ||
+ pTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION) );
+
+ void * pRaiseInfo;
+
+ OUString const & rTypeName = OUString::unacquired( &pTypeDescr->pTypeName );
+ MutexGuard aGuard( s_pInfos->_aMutex );
+ t_string2PtrMap::const_iterator const iFind(
+ s_pInfos->_allRaiseInfos.find( rTypeName ) );
+ if (iFind == s_pInfos->_allRaiseInfos.end())
+ {
+ pRaiseInfo = new RaiseInfo( pTypeDescr );
+ // put into map
+ pair< t_string2PtrMap::iterator, bool > insertion(
+ s_pInfos->_allRaiseInfos.insert( t_string2PtrMap::value_type( rTypeName, pRaiseInfo ) ) );
+ assert(insertion.second && "### raise info insertion failed?!");
+ }
+ else
+ {
+ // reuse existing info
+ pRaiseInfo = iFind->second;
+ }
+
+ return pRaiseInfo;
+}
+
+
+//#### exported ####################################################################################
+
+
+type_info * msci_getRTTI( OUString const & rUNOname )
+{
+ static RTTInfos* s_pRTTIs = new RTTInfos();
+ return s_pRTTIs->getRTTI( rUNOname );
+}
+
+void msci_raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
+{
+ // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()!
+ // thus this obj file will be compiled without opt, so no inlining of
+ // ExceptionInfos::getRaiseInfo()
+
+ // construct cpp exception object
+ typelib_TypeDescription * pTypeDescr = 0;
+ TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
+
+ void * pCppExc = alloca( pTypeDescr->nSize );
+ ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
+
+ // a must be
+ static_assert(sizeof(sal_Int32) == sizeof(void *),
+ "### pointer size differs from sal_Int32!" );
+ DWORD arFilterArgs[3];
+ arFilterArgs[0] = MSVC_magic_number;
+ arFilterArgs[1] = (DWORD)pCppExc;
+ arFilterArgs[2] = (DWORD)ExceptionInfos::getRaiseInfo( pTypeDescr );
+
+ // destruct uno exception
+ ::uno_any_destruct( pUnoExc, 0 );
+ TYPELIB_DANGER_RELEASE( pTypeDescr );
+
+ // last point to release anything not affected by stack unwinding
+ RaiseException( MSVC_ExceptionCode, EXCEPTION_NONCONTINUABLE, 3, arFilterArgs );
+}
+
+namespace
+{
+// This function does the same check as __CxxDetectRethrow from msvcrt (see its
+// crt/src/vcruntime/mgdframe.cpp). But it does not alter the global state, i.e. it does not
+// increment __ProcessingThrow, and so does not break following exception handling. We rely on the
+// definition of EHExceptionRecord, PER_IS_MSVC_EH and PER_PTHROW, that are current as of msvcrt
+// 2017 (14.14.26428).
+bool DetectRethrow(void* ppExcept)
+{
+ struct EHExceptionRecord
+ {
+ DWORD ExceptionCode;
+ DWORD ExceptionFlags;
+ struct _EXCEPTION_RECORD* ExceptionRecord;
+ PVOID ExceptionAddress;
+ DWORD NumberParameters;
+ struct EHParameters
+ {
+ DWORD magicNumber;
+ PVOID pExceptionObject;
+ PVOID pThrowInfo;
+ } params;
+ };
+
+ constexpr auto PER_IS_MSVC_EH = [](EHExceptionRecord* p) {
+ constexpr DWORD EH_EXCEPTION_NUMBER = 0xE06D7363; // The NT Exception # that msvcrt uses ('msc' | 0xE0000000)
+ constexpr DWORD EH_MAGIC_NUMBER1 = 0x19930520; // latest magic # in thrown object
+ constexpr DWORD EH_MAGIC_NUMBER2 = 0x19930521; // latest magic # in func info for exception specs
+ constexpr DWORD EH_MAGIC_NUMBER3 = 0x19930522; // latest magic #
+ constexpr DWORD EH_EXCEPTION_PARAMETERS = 3; // Number of parameters in exception record for x86
+
+ return p->ExceptionCode == EH_EXCEPTION_NUMBER
+ && p->NumberParameters == EH_EXCEPTION_PARAMETERS
+ && (p->params.magicNumber == EH_MAGIC_NUMBER1
+ || p->params.magicNumber == EH_MAGIC_NUMBER2
+ || p->params.magicNumber == EH_MAGIC_NUMBER3);
+ };
+
+ constexpr auto PER_PTHROW = [](EHExceptionRecord* p) {
+ return p->params.pThrowInfo;
+ };
+
+ EHExceptionRecord* pExcept;
+ if (!ppExcept)
+ return false;
+ pExcept = *static_cast<EHExceptionRecord**>(ppExcept);
+ if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == nullptr)
+ {
+ return true;
+ }
+ return false;
+}
+}
+
+int msci_filterCppException(
+ EXCEPTION_POINTERS * pPointers, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
+{
+ if (pPointers == 0)
+ return EXCEPTION_CONTINUE_SEARCH;
+ EXCEPTION_RECORD * pRecord = pPointers->ExceptionRecord;
+ // handle only C++ exceptions:
+ if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ const bool rethrow = DetectRethrow(&pRecord);
+ assert(pRecord == pPointers->ExceptionRecord);
+
+ if (rethrow && pRecord == pPointers->ExceptionRecord)
+ {
+ pRecord = *reinterpret_cast< EXCEPTION_RECORD ** >(__current_exception());
+ }
+ // rethrow: handle only C++ exceptions:
+ if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ if (pRecord->NumberParameters == 3 &&
+// pRecord->ExceptionInformation[ 0 ] == MSVC_magic_number &&
+ pRecord->ExceptionInformation[ 1 ] != 0 &&
+ pRecord->ExceptionInformation[ 2 ] != 0)
+ {
+ void * types = reinterpret_cast< RaiseInfo * >(
+ pRecord->ExceptionInformation[ 2 ] )->_types;
+ if (types != 0 && *reinterpret_cast< DWORD * >( types ) > 0) // count
+ {
+ ExceptionType * pType = *reinterpret_cast< ExceptionType ** >(
+ reinterpret_cast< DWORD * >( types ) + 1 );
+ if (pType != 0 && pType->_pTypeInfo != 0)
+ {
+ OUString aRTTIname(
+ OStringToOUString(
+ reinterpret_cast< __type_info * >(
+ pType->_pTypeInfo )->_m_d_name,
+ RTL_TEXTENCODING_ASCII_US ) );
+ OUString aUNOname( toUNOname( aRTTIname ) );
+
+ typelib_TypeDescription * pExcTypeDescr = 0;
+ typelib_typedescription_getByName(
+ &pExcTypeDescr, aUNOname.pData );
+ if (pExcTypeDescr == 0)
+ {
+ OUString sMsg = "[msci_uno bridge error] UNO type of "
+ "C++ exception unknown: \""
+ + aUNOname + "\", RTTI-name=\""
+ + aRTTIname + "\"!";
+ RuntimeException exc( sMsg );
+ uno_type_any_constructAndConvert(
+ pUnoExc, &exc,
+ cppu::UnoType<decltype(exc)>::get().getTypeLibType(), pCpp2Uno );
+ // msvcr80.dll cleans up, different from former msvcrs
+ // if (! rethrow):
+ // though this unknown exception leaks now, no user-defined
+ // exception is ever thrown through the binary C-UNO dispatcher
+ // call stack.
+ }
+ else
+ {
+ // construct uno exception any
+ uno_any_constructAndConvert(
+ pUnoExc, (void *) pRecord->ExceptionInformation[1],
+ pExcTypeDescr, pCpp2Uno );
+ typelib_typedescription_release( pExcTypeDescr );
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ }
+ }
+ // though this unknown exception leaks now, no user-defined exception
+ // is ever thrown through the binary C-UNO dispatcher call stack.
+ RuntimeException exc( "[msci_uno bridge error] unexpected "
+ "C++ exception occurred!" );
+ uno_type_any_constructAndConvert(
+ pUnoExc, &exc, cppu::UnoType<decltype(exc)>::get().getTypeLibType(), pCpp2Uno );
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+}
+
+#pragma pack(pop)
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */