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