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