1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 // Interesting info can be found in:
24 // http://www.osronline.com/article.cfm?article=469
26 // ONTL, "Open NT Native Template Library", a C++ STL-like library
27 // that can be used even when writing Windows drivers. This is some
28 // quite badass code. The author has done impressive heavy spelunking
29 // of MSVCR structures. http://code.google.com/p/ontl/
31 // Geoff Chappell's pages:
32 // http://www.geoffchappell.com/studies/msvc/language/index.htm
34 // The below is from ONTL's ntl/nt/exception.hxx, cleaned up to keep just the _M_X64 parts:
38 /* This information until the corresponding '#endif // 0' is covered
39 * by ONTL's license, which is said to be the "zlib/libpng license"
40 * below, which as far as I see is permissive enough to allow this
41 * information to be included here in this source file. Note that no
42 * actual code from ONTL below gets compiled into the object file.
46 * Copyright (c) 2011 <copyright holders> (The ONTL main
47 * developer(s) don't tell their real name(s) on the ONTL site.)
49 * This software is provided 'as-is', without any express or implied
50 * warranty. In no event will the authors be held liable for any damages
51 * arising from the use of this software.
53 * Permission is granted to anyone to use this software for any purpose,
54 * including commercial applications, and to alter it and redistribute it
55 * freely, subject to the following restrictions:
57 * 1. The origin of this software must not be misrepresented; you must not
58 * claim that you wrote the original software. If you use this software
59 * in a product, an acknowledgment in the product documentation would be
60 * appreciated but is not required.
62 * 2. Altered source versions must be plainly marked as such, and must not be
63 * misrepresented as being the original software.
65 * 3. This notice may not be removed or altered from any source
70 typedef uint32_t rva_t
;
72 ///\note the calling convention should not matter since this has no arguments
73 typedef void generic_function_t();
75 struct ptrtomember
// _PMD
77 typedef __w64
int32_t mdiff_t
;
78 mdiff_t member_offset
;
79 mdiff_t vbtable_offset
; // -1 if not a virtual base
80 mdiff_t vdisp_offset
; // offset to the displacement value inside the vbtable
83 T
* operator()(T
* const thisptr
) const
85 uintptr_t tp
= reinterpret_cast<uintptr_t>(thisptr
);
86 uintptr_t ptr
= tp
+ member_offset
;
87 if ( vbtable_offset
!= -1 ) // !(vbtable_offset < 0)
89 ptr
+= *reinterpret_cast<mdiff_t
*>( static_cast<intptr_t>(vdisp_offset
+ *reinterpret_cast<mdiff_t
*>(tp
+ vbtable_offset
)) )
92 return reinterpret_cast<T
*>(ptr
);
98 typedef void (* dtor_ptr
)(eobject
*);
99 typedef void (* ctor_ptr
)(eobject
*, eobject
*);
100 typedef void (* ctor_ptr2
)(eobject
*, eobject
*, int);
105 /** is simple type */
106 uint32_t memmoveable
: 1;
107 /** catchable as reference only */
108 uint32_t refonly
: 1;
109 /** class with virtual base */
110 uint32_t hasvirtbase
: 1;
111 /** offset to the type descriptor */
114 /** catch type instance location within a thrown object */
115 ptrtomember thiscast
;
116 /** size of the simple type or offset into buffer of \c this pointer for catch object */
117 uint32_t object_size
;
126 #pragma pack(push, 4)
127 struct catchabletypearray
134 #pragma pack(push, 4)
137 typedef exception_disposition __cdecl
forwardcompathandler_t(...);
139 /* 0x00 */ uint32_t econst
: 1;
140 /* 0x00 */ uint32_t evolatile
: 1;
141 /* 0x00 */ uint32_t : 1;
142 /* 0x00 */ uint32_t e8
: 1;
143 /* 0x04 */ rva_t exception_dtor
;
144 /* 0x08 */ rva_t forwardcompathandler
;
145 /* 0x0C */ rva_t catchabletypearray
; ///< types able to catch the exception.
149 /// This type represents the catch clause
152 // union { uint32_t adjectives; void * ptr; };
153 uint32_t isconst
: 1;
154 uint32_t isvolatile
: 1;
155 uint32_t isunaligned
: 1;// guess it is not used on x86
156 uint32_t isreference
: 1;
161 /** offset to the type descriptor of this catch object */
162 /*0x04*/ rva_t typeinfo
; // dispType
163 /*0x08*/ int eobject_bpoffset
; // dispCatchObj
164 /** offset to the catch clause funclet */
165 /*0x0C*/ rva_t handler
; // dispOfHandler
166 /*0x10*/ uint32_t frame
; // dispFrame
169 // ___BuildCatchObject
170 /// 15.3/16 When the exception-declaration specifies a class type, a copy
171 /// constructor is used to initialize either the object declared
172 /// in the exception-declaration or,
173 /// if the exception-declaration does not specify a name,
174 /// a temporary object of that type.
175 ///\note This is the question may we optimize out the last case.
176 ///\warning If the copy constructor throws an exception, std::unexpected would be called
178 constructcatchobject(
179 cxxregistration
* cxxreg
,
180 const ehandler
* const catchblock
,
181 catchabletype
* const convertible
,
182 const dispatcher_context
* const dispatch
189 struct typeinfo_t
{ void* vtbl
; void* spare
; char name
[1]; };
190 enum catchable_info
{ cidefault
, cicomplex
, civirtual
} cinfo
= cidefault
;
192 const typeinfo_t
* ti
= catchblock
->typeinfo
? dispatch
->va
<typeinfo_t
*>(catchblock
->typeinfo
) : NULL
;
193 if(ti
&& *ti
->name
&& (catchblock
->eobject_bpoffset
|| catchblock
->ishz
)){
194 eobject
** objplace
= catchblock
->ishz
195 ? reinterpret_cast<eobject
**>(cxxreg
)
196 : reinterpret_cast<eobject
**>(catchblock
->eobject_bpoffset
+ cxxreg
->fp
.FramePointers
);
197 if(catchblock
->isreference
){
199 *objplace
= adjust_pointer(get_object(), convertible
);
200 }else if(convertible
->memmoveable
){
202 std::memcpy(objplace
, get_object(), convertible
->object_size
);
203 if(convertible
->object_size
== sizeof(void*) && *objplace
)
204 *objplace
= adjust_pointer((void*)*objplace
, convertible
);
206 // if copy ctor exists, call it; binary copy otherwise
207 if(convertible
->copyctor
){
208 cinfo
= convertible
->hasvirtbase
? civirtual
: cicomplex
;
210 std::memcpy(objplace
, (const void*)adjust_pointer(get_object(), convertible
), convertible
->object_size
);
214 // end of build helper
215 if(cinfo
!= cidefault
){
216 eobject
* objthis
= catchblock
->ishz
217 ? reinterpret_cast<eobject
*>(cxxreg
)
218 : reinterpret_cast<eobject
*>(catchblock
->eobject_bpoffset
+ cxxreg
->fp
.FramePointers
);
219 void* copyctor
= thrown_va(convertible
->copyctor
);
220 eobject
* copyarg
= adjust_pointer(get_object(), convertible
);
221 if(cinfo
== cicomplex
)
222 (eobject::ctor_ptr (copyctor
))(objthis
, copyarg
);
224 (eobject::ctor_ptr2(copyctor
))(objthis
, copyarg
, 1);
227 __except(cxxregistration::unwindfilter(static_cast<nt::ntstatus
>(_exception_code())))
229 nt::exception::inconsistency();
237 #include <sal/config.h>
243 #include <typeinfo.h>
246 #include <rtl/alloc.h>
247 #include <rtl/strbuf.hxx>
248 #include <rtl/ustrbuf.hxx>
249 #include <sal/log.hxx>
250 #include <osl/mutex.hxx>
252 #include <com/sun/star/uno/Any.hxx>
253 #include <unordered_map>
255 #include <except.hxx>
257 #pragma pack(push, 8)
259 using namespace ::com::sun::star::uno
;
260 using namespace ::std
;
261 using namespace ::osl
;
263 namespace CPPU_CURRENT_NAMESPACE
265 static int mscx_getRTTI_len(OUString
const & rUNOname
);
268 static OUString
toUNOname(
269 OUString
const & rRTTIname
)
272 OUStringBuffer
aRet( 64 );
273 OUString
aStr( rRTTIname
.copy( 4, rRTTIname
.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@
274 sal_Int32 nPos
= aStr
.getLength();
277 sal_Int32 n
= aStr
.lastIndexOf( '@', nPos
);
278 aRet
.append( aStr
.copy( n
+1, nPos
-n
-1 ) );
285 return aRet
.makeStringAndClear();
288 static OUString
toRTTIname(
289 OUString
const & rUNOname
)
292 OUStringBuffer
aRet( 64 );
293 aRet
.append( ".?AV" ); // class ".?AV"; struct ".?AU"
294 sal_Int32 nPos
= rUNOname
.getLength();
297 sal_Int32 n
= rUNOname
.lastIndexOf( '.', nPos
);
298 aRet
.append( rUNOname
.copy( n
+1, nPos
-n
-1 ) );
303 return aRet
.makeStringAndClear();
308 typedef std::unordered_map
< OUString
, void * > t_string2PtrMap
;
309 class type_info_descriptor
;
314 t_string2PtrMap _allRTTI
;
317 type_info
* getRTTI( OUString
const & rUNOname
) throw ();
318 int getRTTI_len(OUString
const & rUNOname
) throw ();
319 type_info_descriptor
* insert_new_type_info_descriptor(OUString
const & rUNOname
);
325 friend type_info
* RTTInfos::getRTTI( OUString
const & ) throw ();
326 friend int mscx_filterCppException(
327 EXCEPTION_POINTERS
*, uno_Any
*, uno_Mapping
* );
330 virtual ~type_info_() throw ();
332 type_info_( void * m_data
, const char * m_d_name
) throw ()
334 { ::strcpy( _m_d_name
, m_d_name
); } // #100211# - checked
341 type_info_::~type_info_() throw ()
346 class type_info_descriptor
354 type_info_descriptor(void * m_data
, const char * m_d_name
) throw ()
355 : info(m_data
, m_d_name
)
357 type_info_size
= sizeof(type_info_
) + strlen(m_d_name
);
360 type_info
* get_type_info()
362 return reinterpret_cast<type_info
*>(&info
);
364 int get_type_info_size()
366 return type_info_size
;
370 type_info_descriptor
* RTTInfos::insert_new_type_info_descriptor(OUString
const & rUNOname
) {
372 // insert new type_info
373 OString
aRawName(OUStringToOString(toRTTIname(rUNOname
), RTL_TEXTENCODING_ASCII_US
));
374 type_info_descriptor
* pRTTI
= new(std::malloc(sizeof(type_info_descriptor
) + aRawName
.getLength()))
375 type_info_descriptor(nullptr, aRawName
.getStr());
378 pair
< t_string2PtrMap::iterator
, bool > insertion(
379 _allRTTI
.insert(t_string2PtrMap::value_type(rUNOname
, pRTTI
)));
380 assert(insertion
.second
&& "### rtti insertion failed?!");
384 type_info
* RTTInfos::getRTTI( OUString
const & rUNOname
) throw ()
387 static_assert(sizeof(type_info_
) == sizeof(type_info
), "### type info structure size differ!");
389 MutexGuard
aGuard( _aMutex
);
390 t_string2PtrMap::const_iterator
const iFind( _allRTTI
.find( rUNOname
) );
392 // check if type is already available
393 if (iFind
== _allRTTI
.end())
395 // Wrap new type_info_ in type_info_descriptor to preserve length info
396 type_info_descriptor
* pRTTI
= insert_new_type_info_descriptor(rUNOname
);
397 return pRTTI
->get_type_info();
401 return static_cast<type_info_descriptor
*>(iFind
->second
)->get_type_info();
405 int RTTInfos::getRTTI_len(OUString
const & rUNOname
) throw ()
407 MutexGuard
aGuard(_aMutex
);
408 t_string2PtrMap::const_iterator
const iFind(_allRTTI
.find(rUNOname
));
410 // Wrap new type_info_ in type_info_descriptor to preserve length info
411 // check if type is already available
412 if (iFind
== _allRTTI
.end())
414 // Wrap new type_info_ in type_info_descriptor to preserve length info
415 type_info_descriptor
* pRTTI
= insert_new_type_info_descriptor(rUNOname
);
416 return pRTTI
->get_type_info_size();
420 return static_cast<type_info_descriptor
*>(iFind
->second
)->get_type_info_size();
424 RTTInfos::RTTInfos() throw ()
428 static void * __cdecl
copyConstruct(
431 typelib_TypeDescription
* pTD
) throw ()
433 ::uno_copyData( pExcThis
, pSource
, pTD
, cpp_acquire
);
437 static void * __cdecl
destruct(
439 typelib_TypeDescription
* pTD
) throw ()
441 ::uno_destructData( pExcThis
, pTD
, cpp_release
);
445 const int codeSnippetSize
= 40;
447 static void GenerateConstructorTrampoline(
448 unsigned char * code
,
449 typelib_TypeDescription
* pTD
) throw ()
451 unsigned char *p
= code
;
454 *p
++ = 0x49; *p
++ = 0xB8;
455 *reinterpret_cast<void **>(p
) = pTD
; p
+= 8;
457 // mov r11, copyConstruct
458 *p
++ = 0x49; *p
++ = 0xBB;
459 *reinterpret_cast<void **>(p
) = reinterpret_cast<void *>(©Construct
); p
+= 8;
462 *p
++ = 0x41; *p
++ = 0xFF; *p
++ = 0xE3;
464 assert( p
< code
+ codeSnippetSize
);
467 static void GenerateDestructorTrampoline(
468 unsigned char * code
,
469 typelib_TypeDescription
* pTD
) throw ()
471 unsigned char *p
= code
;
474 *p
++ = 0x48; *p
++ = 0xBA;
475 *reinterpret_cast<void **>(p
) = pTD
; p
+= 8;
478 *p
++ = 0x49; *p
++ = 0xBB;
479 *reinterpret_cast<void **>(p
) = reinterpret_cast<void *>(&destruct
); p
+= 8;
482 *p
++ = 0x41; *p
++ = 0xFF; *p
++ = 0xE3;
484 assert( p
< code
+ codeSnippetSize
);
487 // This looks like it is the struct catchabletype above
491 sal_Int32 _n0
; // flags
492 sal_uInt32 _pTypeInfo
; // typeinfo
493 sal_Int32 _n1
, _n2
, _n3
; // thiscast
494 sal_Int32 _n4
; // object_size
495 sal_uInt32 _pCopyCtor
; // copyctor
496 type_info_ type_info
;
500 unsigned char * pCode
,
501 sal_uInt64 pCodeBase
,
502 typelib_TypeDescription
* pTD
) throw ()
508 , type_info(nullptr, "")
510 // As _n0 is always initialized to zero, that means the
511 // hasvirtbase flag (see the ONTL catchabletype struct) is
512 // off, and thus the copyctor is of the ctor_ptr kind.
513 memcpy(static_cast<void *>(&type_info
), static_cast<void *>(mscx_getRTTI(pTD
->pTypeName
)), mscx_getRTTI_len(pTD
->pTypeName
));
514 _pTypeInfo
= static_cast<sal_uInt32
>(
515 reinterpret_cast<sal_uInt64
>(&type_info
) - pCodeBase
);
516 GenerateConstructorTrampoline( pCode
, pTD
);
518 pCodeBase
<= reinterpret_cast<sal_uInt64
>(pCode
)
519 && (reinterpret_cast<sal_uInt64
>(pCode
) - pCodeBase
521 _pCopyCtor
= static_cast<sal_uInt32
>(
522 reinterpret_cast<sal_uInt64
>(pCode
) - pCodeBase
);
531 t_string2PtrMap _allRaiseInfos
;
534 static RaiseInfo
* getRaiseInfo( typelib_TypeDescription
* pTD
) throw ();
536 static DWORD allocationGranularity
;
538 ExceptionInfos() throw ();
541 DWORD
ExceptionInfos::allocationGranularity
= 0;
543 // This corresponds to the struct throwinfo described above.
553 typelib_TypeDescription
* _pTD
;
554 unsigned char * _code
;
555 sal_uInt64 _codeBase
;
557 explicit RaiseInfo(typelib_TypeDescription
* pTD
) throw ();
560 /* Rewrite of 32-Bit-Code to work under 64 Bit:
561 * To use the 32 Bit offset values in the ExceptionType we have to
562 * allocate a single allocation block and use it for all code and date
563 * all offsets inside this area are guaranteed to be in 32 bit address range.
564 * So we have to calc total memory allocation size for D-tor, C-Tors,
565 * ExceptionType and type_info. ExceptionType is allocated via placement new
566 * to locate everything inside our mem block.
567 * There is one caveat: Struct type_info is kept in
568 * a map and was referenced from class ExceptionType. Therefore type_info now
569 * is also member of ExceptionType and can be referenced via 32 bit offset.
572 RaiseInfo::RaiseInfo(typelib_TypeDescription
* pTD
)throw ()
577 typelib_CompoundTypeDescription
* pCompTD
;
579 // Count how many trampolines we need
580 int codeSize
= codeSnippetSize
;
583 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
);
584 pCompTD
; pCompTD
= pCompTD
->pBaseTypeDescription
)
587 codeSize
+= codeSnippetSize
;
590 // Array with size (4) and all _pTypeInfo (4*nLen)
591 int typeInfoArraySize
= 4 + 4 * nLen
;
593 // 2.Pass: Get the total needed memory for class ExceptionType
594 // (with embedded type_info) and keep the sizes for each instance
595 // is stored in allocated int array
596 auto exceptionTypeSizeArray
= std::make_unique
<int[]>(nLen
);
599 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
);
600 pCompTD
; pCompTD
= pCompTD
->pBaseTypeDescription
)
602 int typeInfoLen
= mscx_getRTTI_len(pCompTD
->aBase
.pTypeName
);
603 // Mem has to be on 4-byte Boundary
604 if (typeInfoLen
% 4 != 0)
606 int n
= typeInfoLen
/ 4;
610 exceptionTypeSizeArray
[nLen
++] = typeInfoLen
+ sizeof(ExceptionType
);
613 // Total ExceptionType related mem
614 int excTypeAddLen
= 0;
615 for (int i
= 0; i
< nLen
; i
++)
617 excTypeAddLen
+= exceptionTypeSizeArray
[i
];
620 // Allocate mem for code and all dynamic data in one chunk to guarantee
622 const int totalSize
= codeSize
+ typeInfoArraySize
+ excTypeAddLen
;
623 unsigned char * pCode
= _code
=
624 static_cast<unsigned char *>(std::malloc(totalSize
));
627 // New base of types array, starts after Trampoline D-Tor / C-Tors
628 DWORD
* types
= reinterpret_cast<DWORD
*>(pCode
+ codeSize
);
630 // New base of ExceptionType array, starts after types array
631 unsigned char *etMem
= pCode
+ codeSize
+ typeInfoArraySize
;
634 _codeBase
= reinterpret_cast<sal_uInt64
>(pCode
)
635 & ~static_cast<sal_uInt64
>(ExceptionInfos::allocationGranularity
- 1);
639 VirtualProtect(pCode
, codeSize
, PAGE_EXECUTE_READWRITE
, &old_protect
);
641 assert(success
&& "VirtualProtect() failed!");
643 ::typelib_typedescription_acquire(pTD
);
645 // Fill pCode with D-Tor code
646 GenerateDestructorTrampoline(pCode
, pTD
);
647 _pDtor
= static_cast<sal_Int32
>(reinterpret_cast<sal_uInt64
>(pCode
) - _codeBase
);
648 pCodeOffset
+= codeSnippetSize
;
650 // Info count accompanied by type info ptrs: type, base type, base base type, ...
651 // Keep offset of types_array
652 _types
= static_cast<sal_Int32
>(
653 reinterpret_cast<sal_uInt64
>(types
)-_codeBase
);
654 // Fill types: (nLen, _offset to ExceptionType1, ...ExceptionType2, ...)
658 for (pCompTD
= reinterpret_cast<typelib_CompoundTypeDescription
*>(pTD
);
659 pCompTD
; pCompTD
= pCompTD
->pBaseTypeDescription
)
661 // Create instance in mem block with placement new
662 ExceptionType
* et
= new(etMem
+ etMemOffset
)ExceptionType(
663 pCode
+ pCodeOffset
, _codeBase
, reinterpret_cast<typelib_TypeDescription
*>(pCompTD
));
665 // Next trampoline entry offset
666 pCodeOffset
+= codeSnippetSize
;
667 // Next ExceptionType placement offset
668 etMemOffset
+= exceptionTypeSizeArray
[nPos
- 1];
670 // Keep offset of addresses of ET for D-Tor call in ~RaiseInfo
672 = static_cast<DWORD
>(reinterpret_cast<sal_uInt64
>(et
)-_codeBase
);
674 // Final check: end of address calculation must be end of mem
675 assert(etMem
+ etMemOffset
== pCode
+ totalSize
);
678 ExceptionInfos::ExceptionInfos() throw ()
682 RaiseInfo
* ExceptionInfos::getRaiseInfo( typelib_TypeDescription
* pTD
) throw ()
684 static ExceptionInfos
* s_pInfos
= []() {
685 SYSTEM_INFO systemInfo
;
686 GetSystemInfo(&systemInfo
);
687 allocationGranularity
= systemInfo
.dwAllocationGranularity
;
689 return new ExceptionInfos();
693 (pTD
->eTypeClass
== typelib_TypeClass_STRUCT
||
694 pTD
->eTypeClass
== typelib_TypeClass_EXCEPTION
) );
696 RaiseInfo
* pRaiseInfo
;
698 OUString
const & rTypeName
= OUString::unacquired( &pTD
->pTypeName
);
699 MutexGuard
aGuard( s_pInfos
->_aMutex
);
700 t_string2PtrMap::const_iterator
const iFind(
701 s_pInfos
->_allRaiseInfos
.find( rTypeName
) );
702 if (iFind
== s_pInfos
->_allRaiseInfos
.end())
704 pRaiseInfo
= new RaiseInfo( pTD
);
707 pair
< t_string2PtrMap::iterator
, bool > insertion(
708 s_pInfos
->_allRaiseInfos
.insert( t_string2PtrMap::value_type( rTypeName
, static_cast<void *>(pRaiseInfo
) ) ) );
709 assert(insertion
.second
&& "### raise info insertion failed?!");
713 // Reuse existing info
714 pRaiseInfo
= static_cast<RaiseInfo
*>(iFind
->second
);
720 type_info
* mscx_getRTTI(
721 OUString
const & rUNOname
)
723 static RTTInfos
* s_pRTTIs
= new RTTInfos();
724 return s_pRTTIs
->getRTTI( rUNOname
);
726 int mscx_getRTTI_len(
727 OUString
const & rUNOname
)
729 static RTTInfos
* s_pRTTIs
= new RTTInfos();
730 return s_pRTTIs
->getRTTI_len(rUNOname
);
734 void mscx_raiseException(
736 uno_Mapping
* pUno2Cpp
)
738 // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()!
739 // thus this obj file will be compiled without opt, so no inlining of
740 // ExceptionInfos::getRaiseInfo()
742 // construct cpp exception object
743 typelib_TypeDescription
* pTD
= nullptr;
744 TYPELIB_DANGER_GET( &pTD
, pUnoExc
->pType
);
746 void * pCppExc
= alloca( pTD
->nSize
);
747 ::uno_copyAndConvertData( pCppExc
, pUnoExc
->pData
, pTD
, pUno2Cpp
);
749 ULONG_PTR arFilterArgs
[4];
750 arFilterArgs
[0] = MSVC_magic_number
;
751 arFilterArgs
[1] = reinterpret_cast<ULONG_PTR
>(pCppExc
);
752 arFilterArgs
[2] = reinterpret_cast<ULONG_PTR
>(ExceptionInfos::getRaiseInfo( pTD
));
753 arFilterArgs
[3] = reinterpret_cast<RaiseInfo
*>(arFilterArgs
[2])->_codeBase
;
755 // Destruct uno exception
756 ::uno_any_destruct( pUnoExc
, nullptr );
757 TYPELIB_DANGER_RELEASE( pTD
);
759 // last point to release anything not affected by stack unwinding
760 RaiseException( MSVC_ExceptionCode
, EXCEPTION_NONCONTINUABLE
, 4, arFilterArgs
);
765 // This function does the same check as __CxxDetectRethrow from msvcrt (see its
766 // crt/src/vcruntime/mgdframe.cpp). But it does not alter the global state, i.e. it does not
767 // increment __ProcessingThrow, and so does not break following exception handling. We rely on the
768 // definition of EHExceptionRecord, PER_IS_MSVC_EH and PER_PTHROW, that are current as of msvcrt
769 // 2017 (14.14.26428).
770 bool DetectRethrow(void* ppExcept
)
772 struct EHExceptionRecord
775 DWORD ExceptionFlags
;
776 struct _EXCEPTION_RECORD
* ExceptionRecord
;
777 PVOID ExceptionAddress
;
778 DWORD NumberParameters
;
779 struct alignas(8) EHParameters
782 PVOID pExceptionObject
;
784 PVOID pThrowImageBase
;
788 constexpr auto PER_IS_MSVC_EH
= [](EHExceptionRecord
* p
) {
789 constexpr DWORD EH_EXCEPTION_NUMBER
= 0xE06D7363; // The NT Exception # that msvcrt uses ('msc' | 0xE0000000)
790 constexpr DWORD EH_MAGIC_NUMBER1
= 0x19930520; // latest magic # in thrown object
791 constexpr DWORD EH_MAGIC_NUMBER2
= 0x19930521; // latest magic # in func info for exception specs
792 constexpr DWORD EH_MAGIC_NUMBER3
= 0x19930522; // latest magic #
793 constexpr DWORD EH_EXCEPTION_PARAMETERS
= 4; // Number of parameters in exception record for AMD64
795 return p
->ExceptionCode
== EH_EXCEPTION_NUMBER
796 && p
->NumberParameters
== EH_EXCEPTION_PARAMETERS
797 && (p
->params
.magicNumber
== EH_MAGIC_NUMBER1
798 || p
->params
.magicNumber
== EH_MAGIC_NUMBER2
799 || p
->params
.magicNumber
== EH_MAGIC_NUMBER3
);
802 constexpr auto PER_PTHROW
= [](EHExceptionRecord
* p
) {
803 return p
->params
.pThrowInfo
;
806 EHExceptionRecord
* pExcept
;
809 pExcept
= *static_cast<EHExceptionRecord
**>(ppExcept
);
810 if (PER_IS_MSVC_EH(pExcept
) && PER_PTHROW(pExcept
) == nullptr)
818 int mscx_filterCppException(
819 EXCEPTION_POINTERS
* pPointers
,
821 uno_Mapping
* pCpp2Uno
)
823 if (pPointers
== nullptr)
824 return EXCEPTION_CONTINUE_SEARCH
;
826 EXCEPTION_RECORD
* pRecord
= pPointers
->ExceptionRecord
;
828 // Handle only C++ exceptions:
829 if (pRecord
== nullptr || pRecord
->ExceptionCode
!= MSVC_ExceptionCode
)
830 return EXCEPTION_CONTINUE_SEARCH
;
832 const bool rethrow
= DetectRethrow(&pRecord
);
833 assert(pRecord
== pPointers
->ExceptionRecord
);
835 if (rethrow
&& pRecord
== pPointers
->ExceptionRecord
)
837 pRecord
= *reinterpret_cast< EXCEPTION_RECORD
** >(__current_exception());
840 // Rethrow: handle only C++ exceptions:
841 if (pRecord
== nullptr || pRecord
->ExceptionCode
!= MSVC_ExceptionCode
)
842 return EXCEPTION_CONTINUE_SEARCH
;
844 if (pRecord
->NumberParameters
== 4 &&
845 pRecord
->ExceptionInformation
[0] == MSVC_magic_number
&&
846 pRecord
->ExceptionInformation
[1] != 0 &&
847 pRecord
->ExceptionInformation
[2] != 0 &&
848 pRecord
->ExceptionInformation
[3] != 0)
850 // ExceptionInformation[1] is the address of the thrown object
851 // (or the address of a pointer to it, in most cases when it
852 // is a C++ class, obviously).
854 // [2] is the throwinfo pointer
856 // [3] is the image base address which is added the 32-bit
857 // rva_t fields in throwinfo to get actual 64-bit addresses
858 ULONG_PTR base
= pRecord
->ExceptionInformation
[3];
859 DWORD
* types
= reinterpret_cast<DWORD
*>(
861 + (reinterpret_cast<RaiseInfo
*>(pRecord
->ExceptionInformation
[2])
863 if (types
!= nullptr && types
[0] != 0)
865 DWORD pType
= types
[1];
867 = reinterpret_cast<ExceptionType
*>(base
+ pType
);
868 if (pType
!= 0 && et
->_pTypeInfo
!= 0)
872 (reinterpret_cast<type_info_
*>(base
+ et
->_pTypeInfo
)
874 RTL_TEXTENCODING_ASCII_US
));
875 OUString
aUNOname( toUNOname( aRTTIname
) );
877 typelib_TypeDescription
* pExcTD
= nullptr;
878 typelib_typedescription_getByName(
879 &pExcTD
, aUNOname
.pData
);
880 if (pExcTD
== nullptr)
882 OUString sMsg
= "[mscx_uno bridge error] UNO type of "
883 "C++ exception unknown: \""
884 + aUNOname
+ "\", RTTI-name=\""
887 RuntimeException
exc( sMsg
);
888 uno_type_any_constructAndConvert(
890 cppu::UnoType
<decltype(exc
)>::get().getTypeLibType(), pCpp2Uno
);
894 // construct uno exception any
895 uno_any_constructAndConvert(
896 pUnoExc
, reinterpret_cast<void *>(pRecord
->ExceptionInformation
[1]),
898 typelib_typedescription_release( pExcTD
);
901 return EXCEPTION_EXECUTE_HANDLER
;
905 // though this unknown exception leaks now, no user-defined exception
906 // is ever thrown through the binary C-UNO dispatcher call stack.
907 RuntimeException
exc( "[mscx_uno bridge error] unexpected "
908 "C++ exception occurred!" );
909 uno_type_any_constructAndConvert(
910 pUnoExc
, &exc
, cppu::UnoType
<decltype(exc
)>::get().getTypeLibType(), pCpp2Uno
);
911 return EXCEPTION_EXECUTE_HANDLER
;
918 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */