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