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