bump product version to 6.3.0.0.beta1
[LibreOffice.git] / bridges / source / cpp_uno / msvc_win32_x86-64 / except.cxx
blob8d49ff6dafd1cac8813dd2d0f2cb402cb342f97b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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:
22 // MSDN, obviously
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:
36 #if 0
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
66 * distribution.
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
82 template<typename T>
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)) )
90 + vbtable_offset;
92 return reinterpret_cast<T*>(ptr);
96 struct eobject
98 typedef void (* dtor_ptr )(eobject*);
99 typedef void (* ctor_ptr )(eobject*, eobject*);
100 typedef void (* ctor_ptr2)(eobject*, eobject*, int);
103 struct catchabletype
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 */
112 rva_t typeinfo;
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;
119 union
121 rva_t copyctor;
122 rva_t copyctor2;
126 #pragma pack(push, 4)
127 struct catchabletypearray
129 uint32_t size;
130 rva_t type[1];
132 #pragma pack(pop)
134 #pragma pack(push, 4)
135 struct throwinfo
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.
147 #pragma pack(pop)
149 /// This type represents the catch clause
150 struct ehandler
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;
158 uint32_t :27;
159 uint32_t ishz : 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
177 void
178 constructcatchobject(
179 cxxregistration * cxxreg,
180 const ehandler * const catchblock,
181 catchabletype * const convertible,
182 const dispatcher_context* const dispatch
184 const
186 _EH_TRACE_ENTER();
187 // build helper
188 __try {
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){
198 // just ref/pointer
199 *objplace = adjust_pointer(get_object(), convertible);
200 }else if(convertible->memmoveable){
201 // POD
202 std::memcpy(objplace, get_object(), convertible->object_size);
203 if(convertible->object_size == sizeof(void*) && *objplace)
204 *objplace = adjust_pointer((void*)*objplace, convertible);
205 }else{
206 // if copy ctor exists, call it; binary copy otherwise
207 if(convertible->copyctor){
208 cinfo = convertible->hasvirtbase ? civirtual : cicomplex;
209 }else{
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);
223 else
224 (eobject::ctor_ptr2(copyctor))(objthis, copyarg, 1);
227 __except(cxxregistration::unwindfilter(static_cast<nt::ntstatus>(_exception_code())))
229 nt::exception::inconsistency();
231 _EH_TRACE_LEAVE();
234 #endif // 0
237 #include <sal/config.h>
239 #include <memory>
241 #include <malloc.h>
242 #include <new.h>
243 #include <typeinfo.h>
244 #include <signal.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>
254 #include "mscx.hxx"
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 )
270 throw ()
272 OUStringBuffer aRet( 64 );
273 OUString aStr( rRTTIname.copy( 4, rRTTIname.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@
274 sal_Int32 nPos = aStr.getLength();
275 while (nPos > 0)
277 sal_Int32 n = aStr.lastIndexOf( '@', nPos );
278 aRet.append( aStr.copy( n +1, nPos -n -1 ) );
279 if (n >= 0)
281 aRet.append( '.' );
283 nPos = n;
285 return aRet.makeStringAndClear();
288 static OUString toRTTIname(
289 OUString const & rUNOname )
290 throw ()
292 OUStringBuffer aRet( 64 );
293 aRet.append( ".?AV" ); // class ".?AV"; struct ".?AU"
294 sal_Int32 nPos = rUNOname.getLength();
295 while (nPos > 0)
297 sal_Int32 n = rUNOname.lastIndexOf( '.', nPos );
298 aRet.append( rUNOname.copy( n +1, nPos -n -1 ) );
299 aRet.append( '@' );
300 nPos = n;
302 aRet.append( '@' );
303 return aRet.makeStringAndClear();
306 //RTTI simulation
308 typedef std::unordered_map< OUString, void * > t_string2PtrMap;
309 class type_info_descriptor;
311 class RTTInfos
313 Mutex _aMutex;
314 t_string2PtrMap _allRTTI;
316 public:
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);
321 RTTInfos() throw ();
323 class type_info_
325 friend type_info * RTTInfos::getRTTI( OUString const & ) throw ();
326 friend int mscx_filterCppException(
327 EXCEPTION_POINTERS *, uno_Any *, uno_Mapping * );
329 public:
330 virtual ~type_info_() throw ();
332 type_info_( void * m_data, const char * m_d_name ) throw ()
333 : _m_data( m_data )
334 { ::strcpy( _m_d_name, m_d_name ); } // #100211# - checked
336 private:
337 void * _m_data;
338 char _m_d_name[1];
341 type_info_::~type_info_() throw ()
343 (void)_m_data;
346 class type_info_descriptor
348 private:
349 int type_info_size;
350 type_info_ info;
352 public:
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());
377 // put into map
378 pair< t_string2PtrMap::iterator, bool > insertion(
379 _allRTTI.insert(t_string2PtrMap::value_type(rUNOname, pRTTI)));
380 assert(insertion.second && "### rtti insertion failed?!");
382 return pRTTI;
384 type_info * RTTInfos::getRTTI( OUString const & rUNOname ) throw ()
386 // a must be
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();
399 else
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();
418 else
420 return static_cast<type_info_descriptor *>(iFind->second)->get_type_info_size();
424 RTTInfos::RTTInfos() throw ()
428 static void * __cdecl copyConstruct(
429 void * pExcThis,
430 void * pSource,
431 typelib_TypeDescription * pTD ) throw ()
433 ::uno_copyData( pExcThis, pSource, pTD, cpp_acquire );
434 return pExcThis;
437 static void * __cdecl destruct(
438 void * pExcThis,
439 typelib_TypeDescription * pTD ) throw ()
441 ::uno_destructData( pExcThis, pTD, cpp_release );
442 return pExcThis;
445 const int codeSnippetSize = 40;
447 static void GenerateConstructorTrampoline(
448 unsigned char * code,
449 typelib_TypeDescription * pTD ) throw ()
451 unsigned char *p = code;
453 // mov r8, pTD
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 *>(&copyConstruct); p += 8;
461 // jmp r11
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;
473 // mov rdx, pTD
474 *p++ = 0x48; *p++ = 0xBA;
475 *reinterpret_cast<void **>(p) = pTD; p += 8;
477 // mov r11, destruct
478 *p++ = 0x49; *p++ = 0xBB;
479 *reinterpret_cast<void **>(p) = reinterpret_cast<void *>(&destruct); p += 8;
481 // jmp r11
482 *p++ = 0x41; *p++ = 0xFF; *p++ = 0xE3;
484 assert( p < code + codeSnippetSize );
487 // This looks like it is the struct catchabletype above
489 struct ExceptionType
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;
499 ExceptionType(
500 unsigned char * pCode,
501 sal_uInt64 pCodeBase,
502 typelib_TypeDescription * pTD ) throw ()
503 : _n0( 0 )
504 , _n1( 0 )
505 , _n2( -1 )
506 , _n3( 0 )
507 , _n4( pTD->nSize)
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 );
517 assert(
518 pCodeBase <= reinterpret_cast<sal_uInt64>(pCode)
519 && (reinterpret_cast<sal_uInt64>(pCode) - pCodeBase
520 < 0x100000000));
521 _pCopyCtor = static_cast<sal_uInt32>(
522 reinterpret_cast<sal_uInt64>(pCode) - pCodeBase);
526 struct RaiseInfo;
528 class ExceptionInfos
530 Mutex _aMutex;
531 t_string2PtrMap _allRaiseInfos;
533 public:
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.
545 struct RaiseInfo
547 sal_Int32 _n0;
548 sal_uInt32 _pDtor;
549 sal_Int32 _n2;
550 sal_uInt32 _types;
552 // Additional fields
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 ()
573 : _n0(0)
574 , _n2(0)
575 , _pTD(pTD)
577 typelib_CompoundTypeDescription * pCompTD;
579 // Count how many trampolines we need
580 int codeSize = codeSnippetSize;
581 // Info count
582 int nLen = 0;
583 for (pCompTD = reinterpret_cast<typelib_CompoundTypeDescription*>(pTD);
584 pCompTD; pCompTD = pCompTD->pBaseTypeDescription)
586 ++nLen;
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);
598 nLen = 0;
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;
607 n++;
608 typeInfoLen = n*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
621 // 32 bit offsets
622 const int totalSize = codeSize + typeInfoArraySize + excTypeAddLen;
623 unsigned char * pCode = _code =
624 static_cast<unsigned char *>(std::malloc(totalSize));
625 int pCodeOffset = 0;
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;
632 int etMemOffset = 0;
634 _codeBase = reinterpret_cast<sal_uInt64>(pCode)
635 & ~static_cast<sal_uInt64>(ExceptionInfos::allocationGranularity - 1);
637 DWORD old_protect;
638 BOOL success =
639 VirtualProtect(pCode, codeSize, PAGE_EXECUTE_READWRITE, &old_protect);
640 (void) success;
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, ...)
655 types[0] = nLen;
657 int nPos = 1;
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
671 types[nPos++]
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();
690 }();
692 assert( pTD &&
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 );
706 // Put into map
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?!");
711 else
713 // Reuse existing info
714 pRaiseInfo = static_cast<RaiseInfo *>(iFind->second);
717 return pRaiseInfo;
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(
735 uno_Any * pUnoExc,
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);
763 namespace
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
774 DWORD ExceptionCode;
775 DWORD ExceptionFlags;
776 struct _EXCEPTION_RECORD* ExceptionRecord;
777 PVOID ExceptionAddress;
778 DWORD NumberParameters;
779 struct alignas(8) EHParameters
781 DWORD magicNumber;
782 PVOID pExceptionObject;
783 PVOID pThrowInfo;
784 PVOID pThrowImageBase;
785 } params;
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;
807 if (!ppExcept)
808 return false;
809 pExcept = *static_cast<EHExceptionRecord**>(ppExcept);
810 if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == nullptr)
812 return true;
814 return false;
818 int mscx_filterCppException(
819 EXCEPTION_POINTERS * pPointers,
820 uno_Any * pUnoExc,
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 *>(
860 base
861 + (reinterpret_cast<RaiseInfo *>(pRecord->ExceptionInformation[2])
862 ->_types));
863 if (types != nullptr && types[0] != 0)
865 DWORD pType = types[1];
866 ExceptionType * et
867 = reinterpret_cast<ExceptionType *>(base + pType);
868 if (pType != 0 && et->_pTypeInfo != 0)
870 OUString aRTTIname(
871 OStringToOUString(
872 (reinterpret_cast<type_info_ *>(base + et->_pTypeInfo)
873 ->_m_d_name),
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=\""
885 + aRTTIname + "\"!";
887 RuntimeException exc( sMsg );
888 uno_type_any_constructAndConvert(
889 pUnoExc, &exc,
890 cppu::UnoType<decltype(exc)>::get().getTypeLibType(), pCpp2Uno );
892 else
894 // construct uno exception any
895 uno_any_constructAndConvert(
896 pUnoExc, reinterpret_cast<void *>(pRecord->ExceptionInformation[1]),
897 pExcTD, pCpp2Uno );
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;
916 #pragma pack(pop)
918 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */