1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: except.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_bridges.hxx"
34 #pragma warning( disable : 4237 )
36 #include <sal/config.h>
42 #include "rtl/alloc.h"
43 #include "rtl/strbuf.hxx"
44 #include "rtl/ustrbuf.hxx"
46 #include "com/sun/star/uno/Any.hxx"
53 using namespace ::com::sun::star::uno
;
54 using namespace ::std
;
55 using namespace ::osl
;
56 using namespace ::rtl
;
58 namespace CPPU_CURRENT_NAMESPACE
61 //==================================================================================================
62 static inline OUString
toUNOname( OUString
const & rRTTIname
) throw ()
64 OUStringBuffer
aRet( 64 );
65 OUString
aStr( rRTTIname
.copy( 4, rRTTIname
.getLength()-4-2 ) ); // filter .?AUzzz@yyy@xxx@@
66 sal_Int32 nPos
= aStr
.getLength();
69 sal_Int32 n
= aStr
.lastIndexOf( '@', nPos
);
70 aRet
.append( aStr
.copy( n
+1, nPos
-n
-1 ) );
73 aRet
.append( (sal_Unicode
)'.' );
77 return aRet
.makeStringAndClear();
79 //==================================================================================================
80 static inline OUString
toRTTIname( OUString
const & rUNOname
) throw ()
82 OUStringBuffer
aRet( 64 );
83 aRet
.appendAscii( RTL_CONSTASCII_STRINGPARAM(".?AV") ); // class ".?AV"; struct ".?AU"
84 sal_Int32 nPos
= rUNOname
.getLength();
87 sal_Int32 n
= rUNOname
.lastIndexOf( '.', nPos
);
88 aRet
.append( rUNOname
.copy( n
+1, nPos
-n
-1 ) );
89 aRet
.append( (sal_Unicode
)'@' );
92 aRet
.append( (sal_Unicode
)'@' );
93 return aRet
.makeStringAndClear();
97 //##################################################################################################
98 //#### RTTI simulation #############################################################################
99 //##################################################################################################
102 typedef hash_map
< OUString
, void *, OUStringHash
, equal_to
< OUString
> > t_string2PtrMap
;
104 //==================================================================================================
108 t_string2PtrMap _allRTTI
;
110 static OUString
toRawName( OUString
const & rUNOname
) throw ();
112 type_info
* getRTTI( OUString
const & rUNOname
) throw ();
118 //==================================================================================================
121 friend type_info
* RTTInfos::getRTTI( OUString
const & ) throw ();
122 friend int msci_filterCppException(
123 LPEXCEPTION_POINTERS
, uno_Any
*, uno_Mapping
* );
126 virtual ~__type_info() throw ();
128 inline __type_info( void * m_data
, const char * m_d_name
) throw ()
130 { ::strcpy( _m_d_name
, m_d_name
); } // #100211# - checked
136 //__________________________________________________________________________________________________
137 __type_info::~__type_info() throw ()
140 //__________________________________________________________________________________________________
141 type_info
* RTTInfos::getRTTI( OUString
const & rUNOname
) throw ()
144 OSL_ENSURE( sizeof(__type_info
) == sizeof(type_info
), "### type info structure size differ!" );
146 MutexGuard
aGuard( _aMutex
);
147 t_string2PtrMap::const_iterator
const iFind( _allRTTI
.find( rUNOname
) );
149 // check if type is already available
150 if (iFind
== _allRTTI
.end())
152 // insert new type_info
153 OString
aRawName( OUStringToOString( toRTTIname( rUNOname
), RTL_TEXTENCODING_ASCII_US
) );
154 __type_info
* pRTTI
= new( ::rtl_allocateMemory( sizeof(__type_info
) + aRawName
.getLength() ) )
155 __type_info( NULL
, aRawName
.getStr() );
158 pair
< t_string2PtrMap::iterator
, bool > insertion(
159 _allRTTI
.insert( t_string2PtrMap::value_type( rUNOname
, pRTTI
) ) );
160 OSL_ENSURE( insertion
.second
, "### rtti insertion failed?!" );
162 return (type_info
*)pRTTI
;
166 return (type_info
*)iFind
->second
;
169 //__________________________________________________________________________________________________
170 RTTInfos::RTTInfos() throw ()
173 //__________________________________________________________________________________________________
174 RTTInfos::~RTTInfos() throw ()
176 #if OSL_DEBUG_LEVEL > 1
177 OSL_TRACE( "> freeing generated RTTI infos... <\n" );
180 MutexGuard
aGuard( _aMutex
);
181 for ( t_string2PtrMap::const_iterator
iPos( _allRTTI
.begin() );
182 iPos
!= _allRTTI
.end(); ++iPos
)
184 __type_info
* pType
= (__type_info
*)iPos
->second
;
185 pType
->~__type_info(); // obsolete, but good style...
186 ::rtl_freeMemory( pType
);
191 //##################################################################################################
192 //#### Exception raising ###########################################################################
193 //##################################################################################################
196 //==================================================================================================
197 struct ObjectFunction
200 typelib_TypeDescription
* _pTypeDescr
; // type of object
202 inline static void * operator new ( size_t nSize
);
203 inline static void operator delete ( void * pMem
);
205 ObjectFunction( typelib_TypeDescription
* pTypeDescr
, void * fpFunc
) throw ();
206 ~ObjectFunction() throw ();
209 inline void * ObjectFunction::operator new ( size_t nSize
)
211 void * pMem
= rtl_allocateMemory( nSize
);
215 #if OSL_DEBUG_LEVEL > 0
218 VirtualProtect( pMem
, nSize
, PAGE_EXECUTE_READWRITE
, &old_protect
);
219 OSL_ENSURE( success
, "VirtualProtect() failed!" );
224 inline void ObjectFunction::operator delete ( void * pMem
)
226 rtl_freeMemory( pMem
);
229 //__________________________________________________________________________________________________
230 ObjectFunction::ObjectFunction( typelib_TypeDescription
* pTypeDescr
, void * fpFunc
) throw ()
231 : _pTypeDescr( pTypeDescr
)
233 ::typelib_typedescription_acquire( _pTypeDescr
);
235 unsigned char * pCode
= (unsigned char *)somecode
;
237 OSL_ENSURE( (void *)this == (void *)pCode
, "### unexpected!" );
239 // push ObjectFunction this
241 *(void **)pCode
= this;
242 pCode
+= sizeof(void *);
245 *(sal_Int32
*)pCode
= ((unsigned char *)fpFunc
) - pCode
- sizeof(sal_Int32
);
247 //__________________________________________________________________________________________________
248 ObjectFunction::~ObjectFunction() throw ()
250 ::typelib_typedescription_release( _pTypeDescr
);
253 //==================================================================================================
254 static void * __cdecl
__copyConstruct( void * pExcThis
, void * pSource
, ObjectFunction
* pThis
)
257 ::uno_copyData( pExcThis
, pSource
, pThis
->_pTypeDescr
, cpp_acquire
);
260 //==================================================================================================
261 static void * __cdecl
__destruct( void * pExcThis
, ObjectFunction
* pThis
)
264 ::uno_destructData( pExcThis
, pThis
->_pTypeDescr
, cpp_release
);
268 // these are non virtual object methods; there is no this ptr on stack => ecx supplies _this_ ptr
270 //==================================================================================================
271 static __declspec(naked
) void copyConstruct() throw ()
275 // ObjectFunction this already on stack
276 push
[esp
+8] // source exc object this
277 push ecx
// exc object
279 add esp
, 12 // + ObjectFunction this
283 //==================================================================================================
284 static __declspec(naked
) void destruct() throw ()
288 // ObjectFunction this already on stack
289 push ecx
// exc object
291 add esp
, 8 // + ObjectFunction this
296 //==================================================================================================
300 type_info
* _pTypeInfo
;
301 sal_Int32 _n1
, _n2
, _n3
, _n4
;
302 ObjectFunction
* _pCopyCtor
;
305 inline ExceptionType( typelib_TypeDescription
* pTypeDescr
) throw ()
310 , _n4( pTypeDescr
->nSize
)
311 , _pCopyCtor( new ObjectFunction( pTypeDescr
, copyConstruct
) )
313 { _pTypeInfo
= msci_getRTTI( pTypeDescr
->pTypeName
); }
314 inline ~ExceptionType() throw ()
315 { delete _pCopyCtor
; }
317 //==================================================================================================
321 ObjectFunction
* _pDtor
;
326 RaiseInfo( typelib_TypeDescription
* pTypeDescr
) throw ();
327 ~RaiseInfo() throw ();
329 //__________________________________________________________________________________________________
330 RaiseInfo::RaiseInfo( typelib_TypeDescription
* pTypeDescr
) throw ()
332 , _pDtor( new ObjectFunction( pTypeDescr
, destruct
) )
338 OSL_ENSURE( sizeof(sal_Int32
) == sizeof(ExceptionType
*), "### pointer size differs from sal_Int32!" );
340 typelib_CompoundTypeDescription
* pCompTypeDescr
;
344 for ( pCompTypeDescr
= (typelib_CompoundTypeDescription
*)pTypeDescr
;
345 pCompTypeDescr
; pCompTypeDescr
= pCompTypeDescr
->pBaseTypeDescription
)
350 // info count accompanied by type info ptrs: type, base type, base base type, ...
351 _types
= ::rtl_allocateMemory( sizeof(sal_Int32
) + (sizeof(ExceptionType
*) * nLen
) );
352 *(sal_Int32
*)_types
= nLen
;
354 ExceptionType
** ppTypes
= (ExceptionType
**)((sal_Int32
*)_types
+ 1);
357 for ( pCompTypeDescr
= (typelib_CompoundTypeDescription
*)pTypeDescr
;
358 pCompTypeDescr
; pCompTypeDescr
= pCompTypeDescr
->pBaseTypeDescription
)
360 ppTypes
[nPos
++] = new ExceptionType( (typelib_TypeDescription
*)pCompTypeDescr
);
363 //__________________________________________________________________________________________________
364 RaiseInfo::~RaiseInfo() throw ()
366 ExceptionType
** ppTypes
= (ExceptionType
**)((sal_Int32
*)_types
+ 1);
367 for ( sal_Int32 nTypes
= *(sal_Int32
*)_types
; nTypes
--; )
369 delete ppTypes
[nTypes
];
371 ::rtl_freeMemory( _types
);
376 //==================================================================================================
380 t_string2PtrMap _allRaiseInfos
;
383 static void * getRaiseInfo( typelib_TypeDescription
* pTypeDescr
) throw ();
385 ExceptionInfos() throw ();
386 ~ExceptionInfos() throw ();
388 //__________________________________________________________________________________________________
389 ExceptionInfos::ExceptionInfos() throw ()
392 //__________________________________________________________________________________________________
393 ExceptionInfos::~ExceptionInfos() throw ()
395 #if OSL_DEBUG_LEVEL > 1
396 OSL_TRACE( "> freeing exception infos... <\n" );
399 MutexGuard
aGuard( _aMutex
);
400 for ( t_string2PtrMap::const_iterator
iPos( _allRaiseInfos
.begin() );
401 iPos
!= _allRaiseInfos
.end(); ++iPos
)
403 delete (RaiseInfo
*)iPos
->second
;
406 //__________________________________________________________________________________________________
407 void * ExceptionInfos::getRaiseInfo( typelib_TypeDescription
* pTypeDescr
) throw ()
409 static ExceptionInfos
* s_pInfos
= 0;
412 MutexGuard
aGuard( Mutex::getGlobalMutex() );
415 #ifdef LEAK_STATIC_DATA
416 s_pInfos
= new ExceptionInfos();
418 static ExceptionInfos s_allExceptionInfos
;
419 s_pInfos
= &s_allExceptionInfos
;
424 OSL_ASSERT( pTypeDescr
&&
425 (pTypeDescr
->eTypeClass
== typelib_TypeClass_STRUCT
||
426 pTypeDescr
->eTypeClass
== typelib_TypeClass_EXCEPTION
) );
430 OUString
const & rTypeName
= *reinterpret_cast< OUString
* >( &pTypeDescr
->pTypeName
);
431 MutexGuard
aGuard( s_pInfos
->_aMutex
);
432 t_string2PtrMap::const_iterator
const iFind(
433 s_pInfos
->_allRaiseInfos
.find( rTypeName
) );
434 if (iFind
== s_pInfos
->_allRaiseInfos
.end())
436 pRaiseInfo
= new RaiseInfo( pTypeDescr
);
438 pair
< t_string2PtrMap::iterator
, bool > insertion(
439 s_pInfos
->_allRaiseInfos
.insert( t_string2PtrMap::value_type( rTypeName
, pRaiseInfo
) ) );
440 OSL_ENSURE( insertion
.second
, "### raise info insertion failed?!" );
444 // reuse existing info
445 pRaiseInfo
= iFind
->second
;
452 //##################################################################################################
453 //#### exported ####################################################################################
454 //##################################################################################################
457 //##################################################################################################
458 type_info
* msci_getRTTI( OUString
const & rUNOname
)
460 static RTTInfos
* s_pRTTIs
= 0;
463 MutexGuard
aGuard( Mutex::getGlobalMutex() );
466 #ifdef LEAK_STATIC_DATA
467 s_pRTTIs
= new RTTInfos();
469 static RTTInfos s_aRTTIs
;
470 s_pRTTIs
= &s_aRTTIs
;
474 return s_pRTTIs
->getRTTI( rUNOname
);
477 //##################################################################################################
478 void msci_raiseException( uno_Any
* pUnoExc
, uno_Mapping
* pUno2Cpp
)
480 // no ctor/dtor in here: this leads to dtors called twice upon RaiseException()!
481 // thus this obj file will be compiled without opt, so no inling of
482 // ExceptionInfos::getRaiseInfo()
484 // construct cpp exception object
485 typelib_TypeDescription
* pTypeDescr
= 0;
486 TYPELIB_DANGER_GET( &pTypeDescr
, pUnoExc
->pType
);
488 void * pCppExc
= alloca( pTypeDescr
->nSize
);
489 ::uno_copyAndConvertData( pCppExc
, pUnoExc
->pData
, pTypeDescr
, pUno2Cpp
);
493 sizeof(sal_Int32
) == sizeof(void *),
494 "### pointer size differs from sal_Int32!" );
495 DWORD arFilterArgs
[3];
496 arFilterArgs
[0] = MSVC_magic_number
;
497 arFilterArgs
[1] = (DWORD
)pCppExc
;
498 arFilterArgs
[2] = (DWORD
)ExceptionInfos::getRaiseInfo( pTypeDescr
);
500 // destruct uno exception
501 ::uno_any_destruct( pUnoExc
, 0 );
502 TYPELIB_DANGER_RELEASE( pTypeDescr
);
504 // last point to release anything not affected by stack unwinding
505 RaiseException( MSVC_ExceptionCode
, EXCEPTION_NONCONTINUABLE
, 3, arFilterArgs
);
508 //##############################################################################
509 int msci_filterCppException(
510 EXCEPTION_POINTERS
* pPointers
, uno_Any
* pUnoExc
, uno_Mapping
* pCpp2Uno
)
513 return EXCEPTION_CONTINUE_SEARCH
;
514 EXCEPTION_RECORD
* pRecord
= pPointers
->ExceptionRecord
;
515 // handle only C++ exceptions:
516 if (pRecord
== 0 || pRecord
->ExceptionCode
!= MSVC_ExceptionCode
)
517 return EXCEPTION_CONTINUE_SEARCH
;
519 #if _MSC_VER < 1300 // MSVC -6
520 bool rethrow
= (pRecord
->NumberParameters
< 3 ||
521 pRecord
->ExceptionInformation
[ 2 ] == 0);
523 bool rethrow
= __CxxDetectRethrow( &pRecord
);
524 OSL_ASSERT( pRecord
== pPointers
->ExceptionRecord
);
526 if (rethrow
&& pRecord
== pPointers
->ExceptionRecord
)
528 // hack to get msvcrt internal _curexception field:
529 pRecord
= *reinterpret_cast< EXCEPTION_RECORD
** >(
530 reinterpret_cast< char * >( __pxcptinfoptrs() ) +
531 // as long as we don't demand msvcr source as build prerequisite
532 // (->platform sdk), we have to code those offsets here.
535 // offsetof (_tiddata, _curexception) -
536 // offsetof (_tiddata, _tpxcptinfoptrs):
539 #elif _MSC_VER < 1310
541 #elif _MSC_VER < 1400
548 // rethrow: handle only C++ exceptions:
549 if (pRecord
== 0 || pRecord
->ExceptionCode
!= MSVC_ExceptionCode
)
550 return EXCEPTION_CONTINUE_SEARCH
;
552 if (pRecord
->NumberParameters
== 3 &&
553 // pRecord->ExceptionInformation[ 0 ] == MSVC_magic_number &&
554 pRecord
->ExceptionInformation
[ 1 ] != 0 &&
555 pRecord
->ExceptionInformation
[ 2 ] != 0)
557 void * types
= reinterpret_cast< RaiseInfo
* >(
558 pRecord
->ExceptionInformation
[ 2 ] )->_types
;
559 if (types
!= 0 && *reinterpret_cast< DWORD
* >( types
) > 0) // count
561 ExceptionType
* pType
= *reinterpret_cast< ExceptionType
** >(
562 reinterpret_cast< DWORD
* >( types
) + 1 );
563 if (pType
!= 0 && pType
->_pTypeInfo
!= 0)
567 reinterpret_cast< __type_info
* >(
568 pType
->_pTypeInfo
)->_m_d_name
,
569 RTL_TEXTENCODING_ASCII_US
) );
570 OUString
aUNOname( toUNOname( aRTTIname
) );
572 typelib_TypeDescription
* pExcTypeDescr
= 0;
573 typelib_typedescription_getByName(
574 &pExcTypeDescr
, aUNOname
.pData
);
575 if (pExcTypeDescr
== 0)
579 RTL_CONSTASCII_STRINGPARAM(
580 "[msci_uno bridge error] UNO type of "
581 "C++ exception unknown: \"") );
582 buf
.append( aUNOname
);
583 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(
584 "\", RTTI-name=\"") );
585 buf
.append( aRTTIname
);
586 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
587 RuntimeException
exc(
588 buf
.makeStringAndClear(), Reference
< XInterface
>() );
589 uno_type_any_constructAndConvert(
591 ::getCppuType( &exc
).getTypeLibType(), pCpp2Uno
);
592 #if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs
594 // though this unknown exception leaks now, no user-defined
595 // exception is ever thrown thru the binary C-UNO dispatcher
601 // construct uno exception any
602 uno_any_constructAndConvert(
603 pUnoExc
, (void *) pRecord
->ExceptionInformation
[1],
604 pExcTypeDescr
, pCpp2Uno
);
605 #if _MSC_VER < 1400 // msvcr80.dll cleans up, different from former msvcrs
609 (void *) pRecord
->ExceptionInformation
[1],
610 pExcTypeDescr
, cpp_release
);
613 typelib_typedescription_release( pExcTypeDescr
);
616 return EXCEPTION_EXECUTE_HANDLER
;
620 // though this unknown exception leaks now, no user-defined exception
621 // is ever thrown thru the binary C-UNO dispatcher call stack.
622 RuntimeException
exc(
623 OUString( RTL_CONSTASCII_USTRINGPARAM(
624 "[msci_uno bridge error] unexpected "
625 "C++ exception occured!") ),
626 Reference
< XInterface
>() );
627 uno_type_any_constructAndConvert(
628 pUnoExc
, &exc
, ::getCppuType( &exc
).getTypeLibType(), pCpp2Uno
);
629 return EXCEPTION_EXECUTE_HANDLER
;