xref: /AOO41X/main/bridges/source/cpp_uno/msvc_win32_intel/except.cxx (revision 8809db7a87f97847b57a57f4cd2b0104b2b83182)
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 #include <new.h>
32 #include <typeinfo.h>
33 #include <signal.h>
34 
35 #include "rtl/alloc.h"
36 #include "rtl/strbuf.hxx"
37 #include "rtl/ustrbuf.hxx"
38 
39 #include "com/sun/star/uno/Any.hxx"
40 
41 #include "msci.hxx"
42 
43 
44 #pragma pack(push, 8)
45 
46 using namespace ::com::sun::star::uno;
47 using namespace ::std;
48 using namespace ::osl;
49 using namespace ::rtl;
50 
51 namespace CPPU_CURRENT_NAMESPACE
52 {
53 
54 //==================================================================================================
55 static inline OUString toUNOname( OUString const & rRTTIname ) throw ()
56 {
57     OUStringBuffer aRet( 64 );
58     OUString aStr( rRTTIname.copy( 4, rRTTIname.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@
59     sal_Int32 nPos = aStr.getLength();
60     while (nPos > 0)
61     {
62         sal_Int32 n = aStr.lastIndexOf( '@', nPos );
63         aRet.append( aStr.copy( n +1, nPos -n -1 ) );
64         if (n >= 0)
65         {
66             aRet.append( (sal_Unicode)'.' );
67         }
68         nPos = n;
69     }
70     return aRet.makeStringAndClear();
71 }
72 //==================================================================================================
73 static inline OUString toRTTIname( OUString const & rUNOname ) throw ()
74 {
75     OUStringBuffer aRet( 64 );
76     aRet.appendAscii( RTL_CONSTASCII_STRINGPARAM(".?AV") ); // class ".?AV"; struct ".?AU"
77     sal_Int32 nPos = rUNOname.getLength();
78     while (nPos > 0)
79     {
80         sal_Int32 n = rUNOname.lastIndexOf( '.', nPos );
81         aRet.append( rUNOname.copy( n +1, nPos -n -1 ) );
82         aRet.append( (sal_Unicode)'@' );
83         nPos = n;
84     }
85     aRet.append( (sal_Unicode)'@' );
86     return aRet.makeStringAndClear();
87 }
88 
89 
90 //##################################################################################################
91 //#### RTTI simulation #############################################################################
92 //##################################################################################################
93 
94 
95 typedef hash_map< OUString, void *, OUStringHash, equal_to< OUString > > t_string2PtrMap;
96 
97 //==================================================================================================
98 class RTTInfos
99 {
100     Mutex               _aMutex;
101     t_string2PtrMap     _allRTTI;
102 
103     static OUString toRawName( OUString const & rUNOname ) throw ();
104 public:
105     type_info * getRTTI( OUString const & rUNOname ) throw ();
106 
107     RTTInfos();
108     ~RTTInfos();
109 };
110 
111 //==================================================================================================
112 class __type_info
113 {
114     friend type_info * RTTInfos::getRTTI( OUString const & ) throw ();
115     friend int msci_filterCppException(
116         LPEXCEPTION_POINTERS, uno_Any *, uno_Mapping * );
117 
118 public:
119     virtual ~__type_info() throw ();
120 
121     inline __type_info( void * m_data, const char * m_d_name ) throw ()
122         : _m_data( m_data )
123         { ::strcpy( _m_d_name, m_d_name ); } // #100211# - checked
124 
125 private:
126     void * _m_data;
127     char _m_d_name[1];
128 };
129 //__________________________________________________________________________________________________
130 __type_info::~__type_info() throw ()
131 {
132 }
133 //__________________________________________________________________________________________________
134 type_info * RTTInfos::getRTTI( OUString const & rUNOname ) throw ()
135 {
136     // a must be
137     OSL_ENSURE( sizeof(__type_info) == sizeof(type_info), "### type info structure size differ!" );
138 
139     MutexGuard aGuard( _aMutex );
140     t_string2PtrMap::const_iterator const iFind( _allRTTI.find( rUNOname ) );
141 
142     // check if type is already available
143     if (iFind == _allRTTI.end())
144     {
145         // insert new type_info
146         OString aRawName( OUStringToOString( toRTTIname( rUNOname ), RTL_TEXTENCODING_ASCII_US ) );
147         __type_info * pRTTI = new( ::rtl_allocateMemory( sizeof(__type_info) + aRawName.getLength() ) )
148             __type_info( NULL, aRawName.getStr() );
149 
150         // put into map
151         pair< t_string2PtrMap::iterator, bool > insertion(
152             _allRTTI.insert( t_string2PtrMap::value_type( rUNOname, pRTTI ) ) );
153         OSL_ENSURE( insertion.second, "### rtti insertion failed?!" );
154 
155         return (type_info *)pRTTI;
156     }
157     else
158     {
159         return (type_info *)iFind->second;
160     }
161 }
162 //__________________________________________________________________________________________________
163 RTTInfos::RTTInfos() throw ()
164 {
165 }
166 //__________________________________________________________________________________________________
167 RTTInfos::~RTTInfos() throw ()
168 {
169 #if OSL_DEBUG_LEVEL > 1
170     OSL_TRACE( "> freeing generated RTTI infos... <\n" );
171 #endif
172 
173     MutexGuard aGuard( _aMutex );
174     for ( t_string2PtrMap::const_iterator iPos( _allRTTI.begin() );
175           iPos != _allRTTI.end(); ++iPos )
176     {
177         __type_info * pType = (__type_info *)iPos->second;
178         pType->~__type_info(); // obsolete, but good style...
179         ::rtl_freeMemory( pType );
180     }
181 }
182 
183 
184 //##################################################################################################
185 //#### Exception raising ###########################################################################
186 //##################################################################################################
187 
188 
189 //==================================================================================================
190 struct ObjectFunction
191 {
192     char somecode[12];
193     typelib_TypeDescription * _pTypeDescr; // type of object
194 
195     inline static void * operator new ( size_t nSize );
196     inline static void operator delete ( void * pMem );
197 
198     ObjectFunction( typelib_TypeDescription * pTypeDescr, void * fpFunc ) throw ();
199     ~ObjectFunction() throw ();
200 };
201 
202 inline void * ObjectFunction::operator new ( size_t nSize )
203 {
204     void * pMem = rtl_allocateMemory( nSize );
205     if (pMem != 0)
206     {
207         DWORD old_protect;
208 #if OSL_DEBUG_LEVEL > 0
209         BOOL success =
210 #endif
211         VirtualProtect( pMem, nSize, PAGE_EXECUTE_READWRITE, &old_protect );
212         OSL_ENSURE( success, "VirtualProtect() failed!" );
213     }
214     return pMem;
215 }
216 
217 inline void ObjectFunction::operator delete ( void * pMem )
218 {
219     rtl_freeMemory( pMem );
220 }
221 
222 //__________________________________________________________________________________________________
223 ObjectFunction::ObjectFunction( typelib_TypeDescription * pTypeDescr, void * fpFunc ) throw ()
224     : _pTypeDescr( pTypeDescr )
225 {
226     ::typelib_typedescription_acquire( _pTypeDescr );
227 
228     unsigned char * pCode = (unsigned char *)somecode;
229     // a must be!
230     OSL_ENSURE( (void *)this == (void *)pCode, "### unexpected!" );
231 
232     // push ObjectFunction this
233     *pCode++ = 0x68;
234     *(void **)pCode = this;
235     pCode += sizeof(void *);
236     // jmp rel32 fpFunc
237     *pCode++ = 0xe9;
238     *(sal_Int32 *)pCode = ((unsigned char *)fpFunc) - pCode - sizeof(sal_Int32);
239 }
240 //__________________________________________________________________________________________________
241 ObjectFunction::~ObjectFunction() throw ()
242 {
243     ::typelib_typedescription_release( _pTypeDescr );
244 }
245 
246 //==================================================================================================
247 static void * __cdecl __copyConstruct( void * pExcThis, void * pSource, ObjectFunction * pThis )
248     throw ()
249 {
250     ::uno_copyData( pExcThis, pSource, pThis->_pTypeDescr, cpp_acquire );
251     return pExcThis;
252 }
253 //==================================================================================================
254 static void * __cdecl __destruct( void * pExcThis, ObjectFunction * pThis )
255     throw ()
256 {
257     ::uno_destructData( pExcThis, pThis->_pTypeDescr, cpp_release );
258     return pExcThis;
259 }
260 
261 // these are non virtual object methods; there is no this ptr on stack => ecx supplies _this_ ptr
262 
263 //==================================================================================================
264 static __declspec(naked) void copyConstruct() throw ()
265 {
266     __asm
267     {
268         // ObjectFunction this already on stack
269         push [esp+8]  // source exc object this
270         push ecx      // exc object
271         call __copyConstruct
272         add  esp, 12  // + ObjectFunction this
273         ret  4
274     }
275 }
276 //==================================================================================================
277 static __declspec(naked) void destruct() throw ()
278 {
279     __asm
280     {
281         // ObjectFunction this already on stack
282         push ecx    // exc object
283         call __destruct
284         add  esp, 8 // + ObjectFunction this
285         ret
286     }
287 }
288 
289 //==================================================================================================
290 struct ExceptionType
291 {
292     sal_Int32           _n0;
293     type_info *         _pTypeInfo;
294     sal_Int32           _n1, _n2, _n3, _n4;
295     ObjectFunction *    _pCopyCtor;
296     sal_Int32           _n5;
297 
298     inline ExceptionType( typelib_TypeDescription * pTypeDescr ) throw ()
299         : _n0( 0 )
300         , _n1( 0 )
301         , _n2( -1 )
302         , _n3( 0 )
303         , _n4( pTypeDescr->nSize )
304         , _pCopyCtor( new ObjectFunction( pTypeDescr, copyConstruct ) )
305         , _n5( 0 )
306         { _pTypeInfo = msci_getRTTI( pTypeDescr->pTypeName ); }
307     inline ~ExceptionType() throw ()
308         { delete _pCopyCtor; }
309 };
310 //==================================================================================================
311 struct RaiseInfo
312 {
313     sal_Int32           _n0;
314     ObjectFunction *    _pDtor;
315     sal_Int32           _n2;
316     void *              _types;
317     sal_Int32           _n3, _n4;
318 
319     RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ();
320     ~RaiseInfo() throw ();
321 };
322 //__________________________________________________________________________________________________
323 RaiseInfo::RaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
324     : _n0( 0 )
325     , _pDtor( new ObjectFunction( pTypeDescr, destruct ) )
326     , _n2( 0 )
327     , _n3( 0 )
328     , _n4( 0 )
329 {
330     // a must be
331     OSL_ENSURE( sizeof(sal_Int32) == sizeof(ExceptionType *), "### pointer size differs from sal_Int32!" );
332 
333     typelib_CompoundTypeDescription * pCompTypeDescr;
334 
335     // info count
336     sal_Int32 nLen = 0;
337     for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
338           pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
339     {
340         ++nLen;
341     }
342 
343     // info count accompanied by type info ptrs: type, base type, base base type, ...
344     _types = ::rtl_allocateMemory( sizeof(sal_Int32) + (sizeof(ExceptionType *) * nLen) );
345     *(sal_Int32 *)_types = nLen;
346 
347     ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1);
348 
349     sal_Int32 nPos = 0;
350     for ( pCompTypeDescr = (typelib_CompoundTypeDescription*)pTypeDescr;
351           pCompTypeDescr; pCompTypeDescr = pCompTypeDescr->pBaseTypeDescription )
352     {
353         ppTypes[nPos++] = new ExceptionType( (typelib_TypeDescription *)pCompTypeDescr );
354     }
355 }
356 //__________________________________________________________________________________________________
357 RaiseInfo::~RaiseInfo() throw ()
358 {
359     ExceptionType ** ppTypes = (ExceptionType **)((sal_Int32 *)_types + 1);
360     for ( sal_Int32 nTypes = *(sal_Int32 *)_types; nTypes--; )
361     {
362         delete ppTypes[nTypes];
363     }
364     ::rtl_freeMemory( _types );
365 
366     delete _pDtor;
367 }
368 
369 //==================================================================================================
370 class ExceptionInfos
371 {
372     Mutex           _aMutex;
373     t_string2PtrMap _allRaiseInfos;
374 
375 public:
376     static void * getRaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ();
377 
378     ExceptionInfos() throw ();
379     ~ExceptionInfos() throw ();
380 };
381 //__________________________________________________________________________________________________
382 ExceptionInfos::ExceptionInfos() throw ()
383 {
384 }
385 //__________________________________________________________________________________________________
386 ExceptionInfos::~ExceptionInfos() throw ()
387 {
388 #if OSL_DEBUG_LEVEL > 1
389     OSL_TRACE( "> freeing exception infos... <\n" );
390 #endif
391 
392     MutexGuard aGuard( _aMutex );
393     for ( t_string2PtrMap::const_iterator iPos( _allRaiseInfos.begin() );
394           iPos != _allRaiseInfos.end(); ++iPos )
395     {
396         delete (RaiseInfo *)iPos->second;
397     }
398 }
399 //__________________________________________________________________________________________________
400 void * ExceptionInfos::getRaiseInfo( typelib_TypeDescription * pTypeDescr ) throw ()
401 {
402     static ExceptionInfos * s_pInfos = 0;
403     if (! s_pInfos)
404     {
405         MutexGuard aGuard( Mutex::getGlobalMutex() );
406         if (! s_pInfos)
407         {
408 #ifdef LEAK_STATIC_DATA
409             s_pInfos = new ExceptionInfos();
410 #else
411             static ExceptionInfos s_allExceptionInfos;
412             s_pInfos = &s_allExceptionInfos;
413 #endif
414         }
415     }
416 
417     OSL_ASSERT( pTypeDescr &&
418                 (pTypeDescr->eTypeClass == typelib_TypeClass_STRUCT ||
419                  pTypeDescr->eTypeClass == typelib_TypeClass_EXCEPTION) );
420 
421     void * pRaiseInfo;
422 
423     OUString const & rTypeName = *reinterpret_cast< OUString * >( &pTypeDescr->pTypeName );
424     MutexGuard aGuard( s_pInfos->_aMutex );
425     t_string2PtrMap::const_iterator const iFind(
426         s_pInfos->_allRaiseInfos.find( rTypeName ) );
427     if (iFind == s_pInfos->_allRaiseInfos.end())
428     {
429         pRaiseInfo = new RaiseInfo( pTypeDescr );
430         // put into map
431         pair< t_string2PtrMap::iterator, bool > insertion(
432             s_pInfos->_allRaiseInfos.insert( t_string2PtrMap::value_type( rTypeName, pRaiseInfo ) ) );
433         OSL_ENSURE( insertion.second, "### raise info insertion failed?!" );
434     }
435     else
436     {
437         // reuse existing info
438         pRaiseInfo = iFind->second;
439     }
440 
441     return pRaiseInfo;
442 }
443 
444 
445 //##################################################################################################
446 //#### exported ####################################################################################
447 //##################################################################################################
448 
449 
450 //##################################################################################################
451 type_info * msci_getRTTI( OUString const & rUNOname )
452 {
453     static RTTInfos * s_pRTTIs = 0;
454     if (! s_pRTTIs)
455     {
456         MutexGuard aGuard( Mutex::getGlobalMutex() );
457         if (! s_pRTTIs)
458         {
459 #ifdef LEAK_STATIC_DATA
460             s_pRTTIs = new RTTInfos();
461 #else
462             static RTTInfos s_aRTTIs;
463             s_pRTTIs = &s_aRTTIs;
464 #endif
465         }
466     }
467     return s_pRTTIs->getRTTI( rUNOname );
468 }
469 
470 //##################################################################################################
471 void msci_raiseException( uno_Any * pUnoExc, uno_Mapping * pUno2Cpp )
472 {
473     // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()!
474     // thus this obj file will be compiled without opt, so no inling of
475     // ExceptionInfos::getRaiseInfo()
476 
477     // construct cpp exception object
478     typelib_TypeDescription * pTypeDescr = 0;
479     TYPELIB_DANGER_GET( &pTypeDescr, pUnoExc->pType );
480 
481     void * pCppExc = alloca( pTypeDescr->nSize );
482     ::uno_copyAndConvertData( pCppExc, pUnoExc->pData, pTypeDescr, pUno2Cpp );
483 
484     // a must be
485     OSL_ENSURE(
486         sizeof(sal_Int32) == sizeof(void *),
487         "### pointer size differs from sal_Int32!" );
488     DWORD arFilterArgs[3];
489     arFilterArgs[0] = MSVC_magic_number;
490     arFilterArgs[1] = (DWORD)pCppExc;
491     arFilterArgs[2] = (DWORD)ExceptionInfos::getRaiseInfo( pTypeDescr );
492 
493     // destruct uno exception
494     ::uno_any_destruct( pUnoExc, 0 );
495     TYPELIB_DANGER_RELEASE( pTypeDescr );
496 
497     // last point to release anything not affected by stack unwinding
498     RaiseException( MSVC_ExceptionCode, EXCEPTION_NONCONTINUABLE, 3, arFilterArgs );
499 }
500 
501 //##############################################################################
502 int msci_filterCppException(
503     EXCEPTION_POINTERS * pPointers, uno_Any * pUnoExc, uno_Mapping * pCpp2Uno )
504 {
505     if (pPointers == 0)
506         return EXCEPTION_CONTINUE_SEARCH;
507     EXCEPTION_RECORD * pRecord = pPointers->ExceptionRecord;
508     // handle only C++ exceptions:
509     if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
510         return EXCEPTION_CONTINUE_SEARCH;
511 
512 #if _MSC_VER < 1300 // MSVC -6
513     bool rethrow = (pRecord->NumberParameters < 3 ||
514                     pRecord->ExceptionInformation[ 2 ] == 0);
515 #else
516     bool rethrow = __CxxDetectRethrow( &pRecord );
517     OSL_ASSERT( pRecord == pPointers->ExceptionRecord );
518 #endif
519     if (rethrow && pRecord == pPointers->ExceptionRecord)
520     {
521         // hack to get msvcrt internal _curexception field:
522         pRecord = *reinterpret_cast< EXCEPTION_RECORD ** >(
523             reinterpret_cast< char * >( __pxcptinfoptrs() ) +
524             // as long as we don't demand msvcr source as build prerequisite
525             // (->platform sdk), we have to code those offsets here.
526             //
527             // crt\src\mtdll.h:
528             // offsetof (_tiddata, _curexception) -
529             // offsetof (_tiddata, _tpxcptinfoptrs):
530 #if _MSC_VER < 1300
531             0x18 // msvcrt,dll
532 #elif _MSC_VER < 1310
533             0x20 // msvcr70.dll
534 #elif _MSC_VER < 1400
535             0x24 // msvcr71.dll
536 #else
537             0x28 // msvcr80.dll
538 #endif
539             );
540     }
541     // rethrow: handle only C++ exceptions:
542     if (pRecord == 0 || pRecord->ExceptionCode != MSVC_ExceptionCode)
543         return EXCEPTION_CONTINUE_SEARCH;
544 
545     if (pRecord->NumberParameters == 3 &&
546 //          pRecord->ExceptionInformation[ 0 ] == MSVC_magic_number &&
547         pRecord->ExceptionInformation[ 1 ] != 0 &&
548         pRecord->ExceptionInformation[ 2 ] != 0)
549     {
550         void * types = reinterpret_cast< RaiseInfo * >(
551             pRecord->ExceptionInformation[ 2 ] )->_types;
552         if (types != 0 && *reinterpret_cast< DWORD * >( types ) > 0) // count
553         {
554             ExceptionType * pType = *reinterpret_cast< ExceptionType ** >(
555                 reinterpret_cast< DWORD * >( types ) + 1 );
556             if (pType != 0 && pType->_pTypeInfo != 0)
557             {
558                 OUString aRTTIname(
559                     OStringToOUString(
560                         reinterpret_cast< __type_info * >(
561                             pType->_pTypeInfo )->_m_d_name,
562                         RTL_TEXTENCODING_ASCII_US ) );
563                 OUString aUNOname( toUNOname( aRTTIname ) );
564 
565                 typelib_TypeDescription * pExcTypeDescr = 0;
566                 typelib_typedescription_getByName(
567                     &pExcTypeDescr, aUNOname.pData );
568                 if (pExcTypeDescr == 0)
569                 {
570                     OUStringBuffer buf;
571                     buf.appendAscii(
572                         RTL_CONSTASCII_STRINGPARAM(
573                             "[msci_uno bridge error] UNO type of "
574                             "C++ exception unknown: \"") );
575                     buf.append( aUNOname );
576                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
577                                          "\", RTTI-name=\"") );
578                     buf.append( aRTTIname );
579                     buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
580                     RuntimeException exc(
581                         buf.makeStringAndClear(), Reference< XInterface >() );
582                     uno_type_any_constructAndConvert(
583                         pUnoExc, &exc,
584                         ::getCppuType( &exc ).getTypeLibType(), pCpp2Uno );
585 #if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs
586                     // if (! rethrow):
587                     // though this unknown exception leaks now, no user-defined
588                     // exception is ever thrown thru the binary C-UNO dispatcher
589                     // call stack.
590 #endif
591                 }
592                 else
593                 {
594                     // construct uno exception any
595                     uno_any_constructAndConvert(
596                         pUnoExc, (void *) pRecord->ExceptionInformation[1],
597                         pExcTypeDescr, pCpp2Uno );
598 #if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs
599                     if (! rethrow)
600                     {
601                         uno_destructData(
602                             (void *) pRecord->ExceptionInformation[1],
603                             pExcTypeDescr, cpp_release );
604                     }
605 #endif
606                     typelib_typedescription_release( pExcTypeDescr );
607                 }
608 
609                 return EXCEPTION_EXECUTE_HANDLER;
610             }
611         }
612     }
613     // though this unknown exception leaks now, no user-defined exception
614     // is ever thrown thru the binary C-UNO dispatcher call stack.
615     RuntimeException exc(
616         OUString( RTL_CONSTASCII_USTRINGPARAM(
617                       "[msci_uno bridge error] unexpected "
618                       "C++ exception occured!") ),
619         Reference< XInterface >() );
620     uno_type_any_constructAndConvert(
621         pUnoExc, &exc, ::getCppuType( &exc ).getTypeLibType(), pCpp2Uno );
622     return EXCEPTION_EXECUTE_HANDLER;
623 }
624 
625 }
626 
627 #pragma pack(pop)
628 
629