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