xref: /trunk/main/bridges/source/cpp_uno/msvc_win64_x86-64/except.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_bridges.hxx"
26 
27 #pragma warning( disable : 4237 )
28 #include <hash_map>
29 #include <sal/config.h>
30 #include <malloc.h>
31 // <typeinfo.h> was a Microsoft compatibility header, removed in VS2015+.
32 // The standard spelling works on VC9 too, so this needs no guard.
33 #include <typeinfo>
34 #include <signal.h>
35 
36 #include "rtl/alloc.h"
37 #include "rtl/strbuf.hxx"
38 #include "rtl/ustrbuf.hxx"
39 
40 #include "com/sun/star/uno/Any.hxx"
41 
42 #include "mscx.hxx"
43 
44 #if defined _MSC_VER && _MSC_VER >= 1900
45 // The UCRT's own accessor for the field the hack below reaches into by offset.
46 // vcruntime exports it and no public header declares it; the CRT's internal
47 // ehdata.h spells _pCurrentException as exactly this dereference.
48 extern "C" void ** __cdecl __current_exception();
49 #endif
50 
51 
52 #pragma pack(push, 8)
53 
54 using namespace ::com::sun::star::uno;
55 using namespace ::std;
56 using namespace ::osl;
57 using namespace ::rtl;
58 
59 //##############################################################################
60 // Windows's C++ exception  handling is built on top of SEH (Structured Exception Handling).
61 //
62 // SEH documentation:
63 // https://web.archive.org/web/20060114142024/https://www.microsoft.com/msj/0197/exception/exception.aspx
64 //
65 // See this excellent article,
66 // "Decoding the parameters of a thrown C++ exception (0xE06D7363)"
67 // by Raymond Chen:
68 // https://devblogs.microsoft.com/oldnewthing/20100730-00/?p=13273
69 //
70 // Then this one with more details on ExceptionInformation:
71 // http://workblog.pilin.name/2014/03/decoding-parameters-of-thrown-c.html
72 //
73 // Others:
74 // https://github.com/icestudent/ontl/blob/master/ntl/nt/exception.hxx
75 // https://www.openrce.org/articles/full_view/21
76 // https://www.openrce.org/articles/full_view/23
77 //
78 // For a C++ exception in SEH, on AMD64:
79 //
80 // +-----------------------------------+            +-------------------------------------------------------------+
81 // |EXCEPTION_POINTERS                 |            |EXCEPTION_RECORD                                             |
82 // +-----------------------------------+            +-------------------------------------------------------------+
83 // |PEXCEPTION_RECORD  ExceptionRecord;|----------->|DWORD ExceptionCode; // == 0xE06D7363 for C++ exception      |
84 // |PCONTEXT           ContextRecord;  |            |DWORD ExceptionFlags;                                        |
85 // +-----------------------------------+            |struct  _EXCEPTION_RECORD *ExceptionRecord;                  |
86 //                                                  |PVOID ExceptionAddress;                                      |
87 //                                                  |DWORD NumberParameters; // == 4 on AMD64, 3 on i386          |
88 //                                                  |ULONG_PTR ExceptionInformation[0];                           |
89 //               C++ object being thrown <----------|ULONG_PTR ExceptionInformation[1];                           |
90 //   +----------------------------------------------|ULONG_PTR ExceptionInformation[2];                           |
91 //   |    HINSTANCE of the EXE/DLL where <----------|ULONG_PTR ExceptionInformation[3];                           |
92 //   |    where the exception was thrown            |ULONG_PTR ExceptionInformation[...];                         |
93 //   |                                              |ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];|
94 //   | offset from HINSTANCE                        +-------------------------------------------------------------+
95 //   | to:
96 //   |     +------------------------------+
97 //   |     |ThrowInfo                     |
98 //   |     +------------------------------+
99 //   +---->|unsigned int attributes;      |                             +----------------------------------+
100 //         |PMFN   pmfnUnwind;            |                             |CatchableTypeArray                |
101 //         |__int32   pForwardCompat;     | offset from HINSTANCE to:   +----------------------------------+
102 //         |__int32   pCatchableTypeArray;|---------------------------->|int nCatchableTypes;              |
103 //         +------------------------------+                    +--------|__int32   arrayOfCatchableTypes[];|
104 //                                                             |        +----------------------------------+
105 //        +------------------------+                           |
106 //        |CatchableType           |                           |
107 //        +------------------------+ offsets from HINSTANCE to |
108 //        |unsigned int properties;|<--------------------------+        +--------------------------------+
109 //        |__int32   pType;        |---------+                          |TypeDescriptor                  |
110 //        |PMD    thisDisplacement;|         | offset from HINSTANCE to +--------------------------------+
111 //        |int    sizeOrOffset;    |         +------------------------->|const void * _EH_PTR64 pVFTable;|
112 //        |PMFN   copyFunction;    |                                    |void * _EH_PTR64   spare;       |
113 //        +------------------------+                                    |char name[];                    |
114 //                                                                      +--------------------------------+
115 //
116 //
117 //
118 //
119 
120 namespace CPPU_CURRENT_NAMESPACE
121 {
122 
123 //==================================================================================================
toUNOname(OUString const & rRTTIname)124 static inline OUString toUNOname( OUString const & rRTTIname ) throw ()
125 {
126     OUStringBuffer aRet( 64 );
127     OUString aStr( rRTTIname.copy( 4, rRTTIname.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@
128     sal_Int32 nPos = aStr.getLength();
129     while (nPos > 0)
130     {
131         sal_Int32 n = aStr.lastIndexOf( '@', nPos );
132         aRet.append( aStr.copy( n +1, nPos -n -1 ) );
133         if (n >= 0)
134         {
135             aRet.append( (sal_Unicode)'.' );
136         }
137         nPos = n;
138     }
139     return aRet.makeStringAndClear();
140 }
141 //==================================================================================================
toRTTIname(OUString const & rUNOname)142 static inline OUString toRTTIname( OUString const & rUNOname ) throw ()
143 {
144     OUStringBuffer aRet( 64 );
145     aRet.appendAscii( RTL_CONSTASCII_STRINGPARAM(".?AV") ); // class ".?AV"; struct ".?AU"
146     sal_Int32 nPos = rUNOname.getLength();
147     while (nPos > 0)
148     {
149         sal_Int32 n = rUNOname.lastIndexOf( '.', nPos );
150         aRet.append( rUNOname.copy( n +1, nPos -n -1 ) );
151         aRet.append( (sal_Unicode)'@' );
152         nPos = n;
153     }
154     aRet.append( (sal_Unicode)'@' );
155     return aRet.makeStringAndClear();
156 }
157 
158 
159 //##################################################################################################
160 //#### RTTI simulation #############################################################################
161 //##################################################################################################
162 
163 
164 typedef hash_map< OUString, void *, OUStringHash, equal_to< OUString > > t_string2PtrMap;
165 
166 //==================================================================================================
167 class RTTInfos
168 {
169     Mutex               _aMutex;
170     t_string2PtrMap     _allRTTI;
171 
172     static OUString toRawName( OUString const & rUNOname ) throw ();
173 public:
174     type_info * getRTTI( OUString const & rUNOname ) throw ();
175 
176     RTTInfos();
177     ~RTTInfos();
178 };
179 
180 //==================================================================================================
181 class __type_info
182 {
183     friend type_info * RTTInfos::getRTTI( OUString const & ) throw ();
184     friend int mscx_filterCppException(
185         LPEXCEPTION_POINTERS, uno_Any *, uno_Mapping * );
186 
187 public:
188     virtual ~__type_info() throw ();
189 
__type_info(void * m_data,const char * m_d_name)190     inline __type_info( void * m_data, const char * m_d_name ) throw ()
191         : _m_data( m_data )
192         { ::strcpy( _m_d_name, m_d_name ); } // #100211# - checked
193 
length() const194     size_t length() const
195     {
196         return sizeof(__type_info) + strlen(_m_d_name);
197     }
198 
199 private:
200     void * _m_data;
201     char _m_d_name[1];  // mangled name
202 };
203 //__________________________________________________________________________________________________
~__type_info()204 __type_info::~__type_info() throw ()
205 {
206 }
207 //__________________________________________________________________________________________________
getRTTI(OUString const & rUNOname)208 type_info * RTTInfos::getRTTI( OUString const & rUNOname ) throw ()
209 {
210     // a must be
211     OSL_ENSURE( sizeof(__type_info) == sizeof(type_info), "### type info structure size differ!" );
212 
213     MutexGuard aGuard( _aMutex );
214     t_string2PtrMap::const_iterator const iFind( _allRTTI.find( rUNOname ) );
215 
216     // check if type is already available
217     if (iFind == _allRTTI.end())
218     {
219         // insert new type_info
220         OString aRawName( OUStringToOString( toRTTIname( rUNOname ), RTL_TEXTENCODING_ASCII_US ) );
221         __type_info * pRTTI = new( ::rtl_allocateMemory( sizeof(__type_info) + aRawName.getLength() ) )
222             __type_info( NULL, aRawName.getStr() );
223 
224         // put into map
225         pair< t_string2PtrMap::iterator, bool > insertion(
226             _allRTTI.insert( t_string2PtrMap::value_type( rUNOname, pRTTI ) ) );
227         OSL_ENSURE( insertion.second, "### rtti insertion failed?!" );
228 
229         return (type_info *)pRTTI;
230     }
231     else
232     {
233         return (type_info *)iFind->second;
234     }
235 }
236 //__________________________________________________________________________________________________
RTTInfos()237 RTTInfos::RTTInfos() throw ()
238 {
239 }
240 //__________________________________________________________________________________________________
~RTTInfos()241 RTTInfos::~RTTInfos() throw ()
242 {
243 #if OSL_DEBUG_LEVEL > 1
244     OSL_TRACE( "> freeing generated RTTI infos... <\n" );
245 #endif
246 
247     MutexGuard aGuard( _aMutex );
248     for ( t_string2PtrMap::const_iterator iPos( _allRTTI.begin() );
249           iPos != _allRTTI.end(); ++iPos )
250     {
251         __type_info * pType = (__type_info *)iPos->second;
252         pType->~__type_info(); // obsolete, but good style...
253         ::rtl_freeMemory( pType );
254     }
255 }
256 
257 
258 //##################################################################################################
259 //#### Exception raising ###########################################################################
260 //##################################################################################################
261 
262 
263 //==================================================================================================
__copyConstruct(void * pExcThis,void * pSource,typelib_TypeDescription * pTypeDescr)264 static void * __copyConstruct( void * pExcThis, void * pSource, typelib_TypeDescription *pTypeDescr )
265     throw ()
266 {
267     ::uno_copyData( pExcThis, pSource, pTypeDescr, cpp_acquire );
268     return pExcThis;
269 }
270 //==================================================================================================
__destruct(void * pExcThis,typelib_TypeDescription * pTypeDescr)271 static void * __destruct( void * pExcThis, typelib_TypeDescription *pTypeDescr )
272     throw ()
273 {
274     ::uno_destructData( pExcThis, pTypeDescr, cpp_release );
275     return pExcThis;
276 }
277 
278 //==================================================================================================
279 
280 int const codeSnippetSize = 32;
281 
copyConstructCodeSnippet(unsigned char * code,typelib_TypeDescription * pTypeDescr)282 void copyConstructCodeSnippet( unsigned char * code, typelib_TypeDescription * pTypeDescr )
283     throw ()
284 {
285     unsigned char * p = code;
286 
287     // mov r8, pTypeDescr
288     *p++ = 0x49;
289     *p++ = 0xb8;
290     *p++ = ((sal_uIntPtr)(pTypeDescr)) & 0xff;
291     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 8) & 0xff;
292     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 16) & 0xff;
293     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 24) & 0xff;
294     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 32) & 0xff;
295     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 40) & 0xff;
296     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 48) & 0xff;
297     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 56) & 0xff;
298 
299     // mov r9, __copyConstruct
300     *p++ = 0x49;
301     *p++ = 0xb9;
302     *p++ = ((sal_uIntPtr)(&__copyConstruct)) & 0xff;
303     *p++ = (((sal_uIntPtr)(&__copyConstruct)) >> 8) & 0xff;
304     *p++ = (((sal_uIntPtr)(&__copyConstruct)) >> 16) & 0xff;
305     *p++ = (((sal_uIntPtr)(&__copyConstruct)) >> 24) & 0xff;
306     *p++ = (((sal_uIntPtr)(&__copyConstruct)) >> 32) & 0xff;
307     *p++ = (((sal_uIntPtr)(&__copyConstruct)) >> 40) & 0xff;
308     *p++ = (((sal_uIntPtr)(&__copyConstruct)) >> 48) & 0xff;
309     *p++ = (((sal_uIntPtr)(&__copyConstruct)) >> 56) & 0xff;
310 
311     // jmp r9
312     *p++ = 0x41;
313     *p++ = 0xff;
314     *p++ = 0xe1;
315 
316     OSL_ASSERT(p - code <= codeSnippetSize);
317 }
318 
319 //==================================================================================================
destructCodeSnippet(unsigned char * code,typelib_TypeDescription * pTypeDescr)320 void destructCodeSnippet( unsigned char * code, typelib_TypeDescription * pTypeDescr )
321     throw ()
322 {
323     unsigned char * p = code;
324 
325     // mov rdx, pTypeDescr
326     *p++ = 0x48;
327     *p++ = 0xba;
328     *p++ = ((sal_uIntPtr)(pTypeDescr)) & 0xff;
329     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 8) & 0xff;
330     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 16) & 0xff;
331     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 24) & 0xff;
332     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 32) & 0xff;
333     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 40) & 0xff;
334     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 48) & 0xff;
335     *p++ = (((sal_uIntPtr)(pTypeDescr)) >> 56) & 0xff;
336 
337     // mov r9, __destruct
338     *p++ = 0x49;
339     *p++ = 0xb9;
340     *p++ = ((sal_uIntPtr)(&__destruct)) & 0xff;
341     *p++ = (((sal_uIntPtr)(&__destruct)) >> 8) & 0xff;
342     *p++ = (((sal_uIntPtr)(&__destruct)) >> 16) & 0xff;
343     *p++ = (((sal_uIntPtr)(&__destruct)) >> 24) & 0xff;
344     *p++ = (((sal_uIntPtr)(&__destruct)) >> 32) & 0xff;
345     *p++ = (((sal_uIntPtr)(&__destruct)) >> 40) & 0xff;
346     *p++ = (((sal_uIntPtr)(&__destruct)) >> 48) & 0xff;
347     *p++ = (((sal_uIntPtr)(&__destruct)) >> 56) & 0xff;
348 
349     // jmp r9
350     *p++ = 0x41;
351     *p++ = 0xff;
352     *p++ = 0xe1;
353 
354     OSL_ASSERT(p - code <= codeSnippetSize);
355 }
356 
357 //==================================================================================================
align16(size_t size)358 static size_t align16(size_t size)
359 {
360     return ((size + 15) >> 4) << 4;
361 }
362 
363 //==================================================================================================
364 // Known as "catchabletype" in https://github.com/icestudent/ontl/blob/master/ntl/nt/exception.hxx
365 struct ExceptionType
366 {
367     sal_Int32           _n0;
368     sal_uInt32          _pTypeInfo;    // type_info *, RVA on Win64
369     sal_Int32           _n1, _n2, _n3; // pointer to member descriptor, 12 bytes.
370     sal_uInt32          _n4;
371     sal_uInt32          _pCopyCtor;    // RVA on Win64
372     sal_Int32           _n5;
373 
initializeCPPU_CURRENT_NAMESPACE::ExceptionType374     static void initialize( unsigned char *p, sal_uInt32 typeInfoRVA, typelib_TypeDescription * pTypeDescr, sal_uInt32 copyConstructorRVA ) throw ()
375     {
376         ExceptionType *e = (ExceptionType*)p;
377         e->_n0 = 0;
378         e->_pTypeInfo = typeInfoRVA;
379         e->_n1 = 0;
380         e->_n2 = -1;
381         e->_n3 = 0;
382         e->_n4 = pTypeDescr->nSize;
383         e->_pCopyCtor = copyConstructorRVA;
384         e->_n5 = 0;
385     }
386 };
387 
388 //==================================================================================================
389 // Known as "throwinfo" in https://github.com/icestudent/ontl/blob/master/ntl/nt/exception.hxx
390 struct RaiseInfo
391 {
392     // Microsoft's fields:
393     sal_uInt32          _n0;
394     sal_uInt32          _pDtor; // RVA on Win64
395     sal_uInt32          _n2;
396     sal_uInt32          _types; // void *, RVA on Win64
397 
398     // Our additional fields:
399     typelib_TypeDescription * pTypeDescr;
400     unsigned char       *baseAddress; // The RVAs are relative to this field
401 
402     RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ();
403     ~RaiseInfo() throw ();
404 };
405 //__________________________________________________________________________________________________
RaiseInfo(typelib_TypeDescription * pTypeDescr)406 RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
407     : _n0( 0 )
408     , _n2( 0 )
409 {
410     // a must be
411     OSL_ENSURE( sizeof(sal_Int64) == sizeof(ExceptionType *), "### pointer size differs from sal_Int64!" );
412 
413     ::typelib_typedescription_acquire( pTypeDescr );
414     this->pTypeDescr = pTypeDescr;
415 
416     typelib_CompoundTypeDescription * pCompTypeDescr;
417 
418     size_t bytesNeeded = codeSnippetSize; // destructCodeSnippet for _pDtor
419     sal_uInt32 typeCount = 0;
420     for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
421           pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
422     {
423         ++typeCount;
424         bytesNeeded += align16( sizeof( ExceptionType ) );
425         __type_info *typeInfo = (__type_info*) mscx_getRTTI( ((typelib_TypeDescription *)pCompTypeDescr)->pTypeName );
426         bytesNeeded += align16( typeInfo->length() );
427         bytesNeeded += codeSnippetSize; // copyConstructCodeSnippet for its _pCopyCtor
428     }
429     // type info count accompanied by RVAs of type info ptrs: type, base type, base base type, ...
430     bytesNeeded += align16( sizeof( sal_uInt32 ) + (typeCount * sizeof( sal_uInt32 )) );
431 
432     unsigned char *p = (unsigned char*) ::rtl_allocateMemory( bytesNeeded );
433     DWORD old_protect;
434 #if OSL_DEBUG_LEVEL > 0
435     BOOL success =
436 #endif
437     VirtualProtect( p, bytesNeeded, PAGE_EXECUTE_READWRITE, &old_protect );
438     OSL_ENSURE( success, "VirtualProtect() failed!" );
439     baseAddress = p;
440 
441     destructCodeSnippet( p, pTypeDescr );
442     _pDtor = (sal_uInt32)(p - baseAddress);
443     p += codeSnippetSize;
444 
445     sal_uInt32 *types = (sal_uInt32*)p;
446     _types = (sal_uInt32)(p - baseAddress);
447     p += align16( sizeof( sal_uInt32 ) + (typeCount * sizeof( sal_uInt32 )) );
448     types[0] = typeCount;
449     int next = 1;
450     for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
451           pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
452     {
453         __type_info *typeInfo = (__type_info*) mscx_getRTTI( ((typelib_TypeDescription *)pCompTypeDescr)->pTypeName );
454         memcpy(p, typeInfo, typeInfo->length() );
455         sal_uInt32 typeInfoRVA = (sal_uInt32)(p - baseAddress);
456         p += align16( typeInfo->length() );
457 
458         copyConstructCodeSnippet( p, (typelib_TypeDescription *)pCompTypeDescr );
459         sal_uInt32 copyConstructorRVA = (sal_uInt32)(p - baseAddress);
460         p += codeSnippetSize;
461 
462         ExceptionType::initialize( p, typeInfoRVA, (typelib_TypeDescription *)pCompTypeDescr, copyConstructorRVA );
463         types[next++] = (sal_uInt32)(p - baseAddress);
464         p += align16( sizeof(ExceptionType) );
465     }
466 
467     OSL_ASSERT(p - baseAddress <= bytesNeeded);
468 }
469 //__________________________________________________________________________________________________
~RaiseInfo()470 RaiseInfo::~RaiseInfo() throw ()
471 {
472     ::rtl_freeMemory( baseAddress );
473     ::typelib_typedescription_release( pTypeDescr );
474 }
475 
476 //==================================================================================================
477 class ExceptionInfos
478 {
479     Mutex           _aMutex;
480     t_string2PtrMap _allRaiseInfos;
481 
482 public:
483     static RaiseInfo * getRaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ();
484 
485     ExceptionInfos() throw ();
486     ~ExceptionInfos() throw ();
487 };
488 //__________________________________________________________________________________________________
ExceptionInfos()489 ExceptionInfos::ExceptionInfos() throw ()
490 {
491 }
492 //__________________________________________________________________________________________________
~ExceptionInfos()493 ExceptionInfos::~ExceptionInfos() throw ()
494 {
495 #if OSL_DEBUG_LEVEL > 1
496     OSL_TRACE( "> freeing exception infos... <\n" );
497 #endif
498 
499     MutexGuard aGuard( _aMutex );
500     for ( t_string2PtrMap::const_iterator iPos( _allRaiseInfos.begin() );
501           iPos != _allRaiseInfos.end(); ++iPos )
502     {
503         delete (RaiseInfo *)iPos->second;
504     }
505 }
506 //__________________________________________________________________________________________________
getRaiseInfo(typelib_TypeDescription * pTypeDescr)507 RaiseInfo * ExceptionInfos::getRaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
508 {
509     static ExceptionInfos * s_pInfos = 0;
510     if (! s_pInfos)
511     {
512         MutexGuard aGuard( Mutex::getGlobalMutex() );
513         if (! s_pInfos)
514         {
515 #ifdef LEAK_STATIC_DATA
516             s_pInfos = new ExceptionInfos();
517 #else
518             static ExceptionInfos s_allExceptionInfos;
519             s_pInfos = &s_allExceptionInfos;
520 #endif
521         }
522     }
523 
524     OSL_ASSERT( pTypeDescr &&
525                 (pTypeDescr->eTypeClass == typelib_TypeClass_STRUCT ||
526                  pTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION) );
527 
528     void * pRaiseInfo;
529 
530     OUString const & rTypeName = *reinterpret_cast< OUString * >( &pTypeDescr->pTypeName );
531     MutexGuard aGuard( s_pInfos->_aMutex );
532     t_string2PtrMap::const_iterator const iFind(
533         s_pInfos->_allRaiseInfos.find( rTypeName ) );
534     if (iFind == s_pInfos->_allRaiseInfos.end())
535     {
536         pRaiseInfo = new RaiseInfo( pTypeDescr );
537         // put into map
538         pair< t_string2PtrMap::iterator, bool > insertion(
539             s_pInfos->_allRaiseInfos.insert( t_string2PtrMap::value_type( rTypeName, pRaiseInfo ) ) );
540         OSL_ENSURE( insertion.second, "### raise info insertion failed?!" );
541     }
542     else
543     {
544         // reuse existing info
545         pRaiseInfo = iFind->second;
546     }
547 
548     return (RaiseInfo*) pRaiseInfo;
549 }
550 
551 
552 //##################################################################################################
553 //#### exported ####################################################################################
554 //##################################################################################################
555 
556 
557 //##################################################################################################
mscx_getRTTI(OUString const & rUNOname)558 type_info * mscx_getRTTI( OUString const & rUNOname )
559 {
560     static RTTInfos * s_pRTTIs = 0;
561     if (! s_pRTTIs)
562     {
563         MutexGuard aGuard( Mutex::getGlobalMutex() );
564         if (! s_pRTTIs)
565         {
566 #ifdef LEAK_STATIC_DATA
567             s_pRTTIs = new RTTInfos();
568 #else
569             static RTTInfos s_aRTTIs;
570             s_pRTTIs = &s_aRTTIs;
571 #endif
572         }
573     }
574     return s_pRTTIs->getRTTI( rUNOname );
575 }
576 
577 //##################################################################################################
mscx_raiseException(uno_Any * pUnoExc,uno_Mapping * pUno2Cpp)578 void mscx_raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
579 {
580     // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()!
581     // thus this obj file will be compiled without opt, so no inling of
582     // ExceptionInfos::getRaiseInfo()
583 
584     // construct cpp exception object
585     typelib_TypeDescription * pTypeDescr = 0;
586     TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
587 
588     void * pCppExc = alloca( pTypeDescr->nSize );
589     ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
590 
591     // a must be
592     OSL_ENSURE(
593         sizeof(sal_Int64) == sizeof(void *),
594         "### pointer size differs from sal_Int64!" );
595     RaiseInfo *raiseInfo = ExceptionInfos::getRaiseInfo( pTypeDescr );
596     ULONG_PTR arFilterArgs[4];
597     arFilterArgs[0] = MSVC_magic_number;
598     arFilterArgs[1] = (ULONG_PTR)pCppExc;
599     arFilterArgs[2] = (ULONG_PTR)raiseInfo;
600     arFilterArgs[3] = (ULONG_PTR)raiseInfo->baseAddress;
601 
602     // destruct uno exception
603     ::uno_any_destruct( pUnoExc, 0 );
604     TYPELIB_DANGER_RELEASE( pTypeDescr );
605 
606     // last point to release anything not affected by stack unwinding
607     RaiseException( MSVC_ExceptionCode, EXCEPTION_NONCONTINUABLE, 4, arFilterArgs );
608 }
609 
610 //##############################################################################
mscx_filterCppException(EXCEPTION_POINTERS * pPointers,uno_Any * pUnoExc,uno_Mapping * pCpp2Uno)611 int mscx_filterCppException(
612     EXCEPTION_POINTERS * pPointers, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
613 {
614     if (pPointers == 0)
615         return EXCEPTION_CONTINUE_SEARCH;
616     EXCEPTION_RECORD * pRecord = pPointers->ExceptionRecord;
617     // handle only C++ exceptions:
618     if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
619         return EXCEPTION_CONTINUE_SEARCH;
620 
621 #if _MSC_VER < 1300 // MSVC -6
622     bool rethrow = (pRecord->NumberParameters < 4 ||
623                     pRecord->ExceptionInformation[ 2 ] == 0);
624 #else
625     bool rethrow = __CxxDetectRethrow( &pRecord );
626     OSL_ASSERT( pRecord == pPointers->ExceptionRecord );
627 #endif
628     if (rethrow && pRecord == pPointers->ExceptionRecord)
629     {
630 #if defined _MSC_VER && _MSC_VER >= 1900
631         // Ask the CRT, rather than guessing where it keeps the answer.  See
632         // the same change in msvc_win32_intel/except.cxx for the reasoning;
633         // the offset below is _tiddata's on msvcr80 and is not the UCRT's.
634         //
635         // NOTE: this half is UNTESTED.  The branch builds x86 only, so the
636         // x86 twin is the one a run has exercised.  It is changed here anyway
637         // because leaving a known-wrong copy behind is how the <typeinfo.h>
638         // miss happened.
639         pRecord = *reinterpret_cast< EXCEPTION_RECORD ** >(
640             __current_exception() );
641 #else
642         // hack to get msvcrt internal _curexception field:
643         pRecord = *reinterpret_cast< EXCEPTION_RECORD ** >(
644             reinterpret_cast< char * >( __pxcptinfoptrs() ) +
645             // as long as we don't demand msvcr source as build prerequisite
646             // (->platform sdk), we have to code those offsets here.
647             //
648             // crt\src\mtdll.h:
649             // offsetof (_tiddata, _curexception) -
650             // offsetof (_tiddata, _tpxcptinfoptrs):
651             48
652             );
653 #endif
654     }
655     // rethrow: handle only C++ exceptions:
656     if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
657         return EXCEPTION_CONTINUE_SEARCH;
658 
659     if (pRecord->NumberParameters == 4 &&
660 //          pRecord->ExceptionInformation[ 0 ] == MSVC_magic_number &&
661         pRecord->ExceptionInformation[ 1 ] != 0 &&
662         pRecord->ExceptionInformation[ 2 ] != 0 &&
663         pRecord->ExceptionInformation[ 3 ] != 0)
664     {
665         unsigned char *baseAddress = (unsigned char*) pRecord->ExceptionInformation[ 3 ];
666         sal_uInt32 * types = (sal_uInt32*)(baseAddress + reinterpret_cast< RaiseInfo * >(
667             pRecord->ExceptionInformation[ 2 ] )->_types );
668         if (types != 0 && (sal_uInt32)(types[0]) > 0) // count
669         {
670             ExceptionType * pType = reinterpret_cast< ExceptionType * >(
671                 baseAddress + types[ 1 ] );
672             if (pType != 0 && pType->_pTypeInfo != 0)
673             {
674                 OUString aRTTIname(
675                     OStringToOUString(
676                         reinterpret_cast< __type_info * >(
677                             baseAddress + pType->_pTypeInfo )->_m_d_name,
678                         RTL_TEXTENCODING_ASCII_US ) );
679                 OUString aUNOname( toUNOname( aRTTIname ) );
680 
681                 typelib_TypeDescription * pExcTypeDescr = 0;
682                 typelib_typedescription_getByName(
683                     &pExcTypeDescr, aUNOname.pData );
684                 if (pExcTypeDescr == 0)
685                 {
686                     OUStringBuffer buf;
687                     buf.appendAscii(
688                         RTL_CONSTASCII_STRINGPARAM(
689                             "[mscx_uno bridge error] UNO type of "
690                             "C++ exception unknown: \"") );
691                     buf.append( aUNOname );
692                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
693                                          "\", RTTI-name=\"") );
694                     buf.append( aRTTIname );
695                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
696                     RuntimeException exc(
697                         buf.makeStringAndClear(), Reference< XInterface >() );
698                     uno_type_any_constructAndConvert(
699                         pUnoExc, &exc,
700                         ::getCppuType( &exc ).getTypeLibType(), pCpp2Uno );
701 #if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs
702                     // if (! rethrow):
703                     // though this unknown exception leaks now, no user-defined
704                     // exception is ever thrown through the binary C-UNO dispatcher
705                     // call stack.
706 #endif
707                 }
708                 else
709                 {
710                     // construct uno exception any
711                     uno_any_constructAndConvert(
712                         pUnoExc, (void *) pRecord->ExceptionInformation[1],
713                         pExcTypeDescr, pCpp2Uno );
714 #if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs
715                     if (! rethrow)
716                     {
717                         uno_destructData(
718                             (void *) pRecord->ExceptionInformation[1],
719                             pExcTypeDescr, cpp_release );
720                     }
721 #endif
722                     typelib_typedescription_release( pExcTypeDescr );
723                 }
724 
725                 return EXCEPTION_EXECUTE_HANDLER;
726             }
727         }
728     }
729     // though this unknown exception leaks now, no user-defined exception
730     // is ever thrown through the binary C-UNO dispatcher call stack.
731     RuntimeException exc(
732         OUString( RTL_CONSTASCII_USTRINGPARAM(
733                       "[mscx_uno bridge error] unexpected "
734                       "C++ exception occurred!") ),
735         Reference< XInterface >() );
736     uno_type_any_constructAndConvert(
737         pUnoExc, &exc, ::getCppuType( &exc ).getTypeLibType(), pCpp2Uno );
738     return EXCEPTION_EXECUTE_HANDLER;
739 }
740 
741 }
742 
743 #pragma pack(pop)
744