1*9c15e1abSPedro Giffuni /*
2*9c15e1abSPedro Giffuni * Licensed to the Apache Software Foundation (ASF) under one
3*9c15e1abSPedro Giffuni * or more contributor license agreements. See the NOTICE file
4*9c15e1abSPedro Giffuni * distributed with this work for additional information
5*9c15e1abSPedro Giffuni * regarding copyright ownership. The ASF licenses this file
6*9c15e1abSPedro Giffuni * to you under the Apache License, Version 2.0 (the
7*9c15e1abSPedro Giffuni * "License"); you may not use this file except in compliance
8*9c15e1abSPedro Giffuni * with the License. You may obtain a copy of the License at
9*9c15e1abSPedro Giffuni *
10*9c15e1abSPedro Giffuni * http://www.apache.org/licenses/LICENSE-2.0
11*9c15e1abSPedro Giffuni *
12*9c15e1abSPedro Giffuni * Unless required by applicable law or agreed to in writing,
13*9c15e1abSPedro Giffuni * software distributed under the License is distributed on an
14*9c15e1abSPedro Giffuni * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*9c15e1abSPedro Giffuni * KIND, either express or implied. See the License for the
16*9c15e1abSPedro Giffuni * specific language governing permissions and limitations
17*9c15e1abSPedro Giffuni * under the License.
18*9c15e1abSPedro Giffuni */
19*9c15e1abSPedro Giffuni
20*9c15e1abSPedro Giffuni
21*9c15e1abSPedro Giffuni // MARKER(update_precomp.py): autogen include statement, do not remove
22*9c15e1abSPedro Giffuni #include "precompiled_bridges.hxx"
23*9c15e1abSPedro Giffuni
24*9c15e1abSPedro Giffuni #if ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
25*9c15e1abSPedro Giffuni #include <exception>
26*9c15e1abSPedro Giffuni #endif
27*9c15e1abSPedro Giffuni
28*9c15e1abSPedro Giffuni #include <stdio.h>
29*9c15e1abSPedro Giffuni #include <stdlib.h>
30*9c15e1abSPedro Giffuni #include <string.h>
31*9c15e1abSPedro Giffuni #include <dlfcn.h>
32*9c15e1abSPedro Giffuni #include <cxxabi.h>
33*9c15e1abSPedro Giffuni #include <hash_map>
34*9c15e1abSPedro Giffuni #include <sys/param.h>
35*9c15e1abSPedro Giffuni
36*9c15e1abSPedro Giffuni #include <rtl/strbuf.hxx>
37*9c15e1abSPedro Giffuni #include <rtl/ustrbuf.hxx>
38*9c15e1abSPedro Giffuni #include <osl/diagnose.h>
39*9c15e1abSPedro Giffuni #include <osl/mutex.hxx>
40*9c15e1abSPedro Giffuni
41*9c15e1abSPedro Giffuni #include <com/sun/star/uno/genfunc.hxx>
42*9c15e1abSPedro Giffuni #include "com/sun/star/uno/RuntimeException.hpp"
43*9c15e1abSPedro Giffuni #include <typelib/typedescription.hxx>
44*9c15e1abSPedro Giffuni #include <uno/any2.h>
45*9c15e1abSPedro Giffuni
46*9c15e1abSPedro Giffuni #include "share.hxx"
47*9c15e1abSPedro Giffuni
48*9c15e1abSPedro Giffuni
49*9c15e1abSPedro Giffuni using namespace ::std;
50*9c15e1abSPedro Giffuni using namespace ::osl;
51*9c15e1abSPedro Giffuni using namespace ::rtl;
52*9c15e1abSPedro Giffuni using namespace ::com::sun::star::uno;
53*9c15e1abSPedro Giffuni using namespace ::__cxxabiv1;
54*9c15e1abSPedro Giffuni
55*9c15e1abSPedro Giffuni
56*9c15e1abSPedro Giffuni namespace CPPU_CURRENT_NAMESPACE
57*9c15e1abSPedro Giffuni {
58*9c15e1abSPedro Giffuni
59*9c15e1abSPedro Giffuni namespace {
60*9c15e1abSPedro Giffuni
61*9c15e1abSPedro Giffuni typedef hash_map< void *, typelib_TypeDescription * > ThrownTypes;
62*9c15e1abSPedro Giffuni typedef hash_map< OUString, type_info *, OUStringHash > ObservedRttiMap;
63*9c15e1abSPedro Giffuni
thrownTypes()64*9c15e1abSPedro Giffuni ThrownTypes & thrownTypes()
65*9c15e1abSPedro Giffuni {
66*9c15e1abSPedro Giffuni static ThrownTypes types;
67*9c15e1abSPedro Giffuni return types;
68*9c15e1abSPedro Giffuni }
69*9c15e1abSPedro Giffuni
observedRttis()70*9c15e1abSPedro Giffuni ObservedRttiMap & observedRttis()
71*9c15e1abSPedro Giffuni {
72*9c15e1abSPedro Giffuni static ObservedRttiMap map;
73*9c15e1abSPedro Giffuni return map;
74*9c15e1abSPedro Giffuni }
75*9c15e1abSPedro Giffuni
76*9c15e1abSPedro Giffuni // Guards BOTH thrownTypes() and observedRttis(). Every access to either map
77*9c15e1abSPedro Giffuni // must hold this one mutex; they are plain hash_maps, so an insertion racing a
78*9c15e1abSPedro Giffuni // find or erase is undefined behaviour. RTTI::m_mutex may be held while
79*9c15e1abSPedro Giffuni // acquiring this one (see RTTI::getRTTI), never the other way round.
exceptionMapsMutex()80*9c15e1abSPedro Giffuni Mutex & exceptionMapsMutex()
81*9c15e1abSPedro Giffuni {
82*9c15e1abSPedro Giffuni static Mutex mutex;
83*9c15e1abSPedro Giffuni return mutex;
84*9c15e1abSPedro Giffuni }
85*9c15e1abSPedro Giffuni
86*9c15e1abSPedro Giffuni // libc++ marks a type_info whose object is not unique across images by setting
87*9c15e1abSPedro Giffuni // the top bit of type_info::__type_name; comparison then falls back to strcmp
88*9c15e1abSPedro Giffuni // of the mangled name (see __non_unique_arm_rtti_bit_impl in <typeinfo>). On
89*9c15e1abSPedro Giffuni // arm64 Darwin clang emits the typeinfo of every keyless class -- which is every
90*9c15e1abSPedro Giffuni // UNO exception -- hidden and therefore non-unique, so a synthesised object must
91*9c15e1abSPedro Giffuni // set the bit too, or std::type_info::operator== degenerates to an address
92*9c15e1abSPedro Giffuni // comparison and never matches the handler's real typeinfo.
93*9c15e1abSPedro Giffuni sal_uIntPtr const NON_UNIQUE_RTTI_BIT =
94*9c15e1abSPedro Giffuni static_cast< sal_uIntPtr >(1) << (8 * sizeof (sal_uIntPtr) - 1);
95*9c15e1abSPedro Giffuni
siDonor()96*9c15e1abSPedro Giffuni RttiSiClassLayout const * siDonor()
97*9c15e1abSPedro Giffuni {
98*9c15e1abSPedro Giffuni return reinterpret_cast< RttiSiClassLayout const * >( &typeid(RttiDonorDerived) );
99*9c15e1abSPedro Giffuni }
classDonor()100*9c15e1abSPedro Giffuni RttiClassLayout const * classDonor()
101*9c15e1abSPedro Giffuni {
102*9c15e1abSPedro Giffuni return reinterpret_cast< RttiClassLayout const * >( &typeid(RttiDonorBase) );
103*9c15e1abSPedro Giffuni }
104*9c15e1abSPedro Giffuni
105*9c15e1abSPedro Giffuni // Refuse to synthesise unless the donors really have the layout we assume.
rttiDonorsUsable()106*9c15e1abSPedro Giffuni bool rttiDonorsUsable()
107*9c15e1abSPedro Giffuni {
108*9c15e1abSPedro Giffuni return sizeof (void *) == 8
109*9c15e1abSPedro Giffuni && siDonor()->pBase == static_cast< void const * >( classDonor() );
110*9c15e1abSPedro Giffuni }
111*9c15e1abSPedro Giffuni
112*9c15e1abSPedro Giffuni // Mirror the platform's own convention rather than assuming it.
rttiIsNonUnique()113*9c15e1abSPedro Giffuni bool rttiIsNonUnique()
114*9c15e1abSPedro Giffuni {
115*9c15e1abSPedro Giffuni return (siDonor()->nName & NON_UNIQUE_RTTI_BIT) != 0;
116*9c15e1abSPedro Giffuni }
117*9c15e1abSPedro Giffuni
118*9c15e1abSPedro Giffuni }
119*9c15e1abSPedro Giffuni
dummy_can_throw_anything(char const *)120*9c15e1abSPedro Giffuni void dummy_can_throw_anything( char const * )
121*9c15e1abSPedro Giffuni {
122*9c15e1abSPedro Giffuni }
123*9c15e1abSPedro Giffuni
124*9c15e1abSPedro Giffuni //==================================================================================================
toUNOname(char const * p)125*9c15e1abSPedro Giffuni static OUString toUNOname( char const * p ) SAL_THROW( () )
126*9c15e1abSPedro Giffuni {
127*9c15e1abSPedro Giffuni #if OSL_DEBUG_LEVEL > 1
128*9c15e1abSPedro Giffuni char const * start = p;
129*9c15e1abSPedro Giffuni #endif
130*9c15e1abSPedro Giffuni
131*9c15e1abSPedro Giffuni // example: N3com3sun4star4lang24IllegalArgumentExceptionE
132*9c15e1abSPedro Giffuni
133*9c15e1abSPedro Giffuni OUStringBuffer buf( 64 );
134*9c15e1abSPedro Giffuni OSL_ASSERT( 'N' == *p );
135*9c15e1abSPedro Giffuni ++p; // skip N
136*9c15e1abSPedro Giffuni
137*9c15e1abSPedro Giffuni while ('E' != *p)
138*9c15e1abSPedro Giffuni {
139*9c15e1abSPedro Giffuni // read chars count
140*9c15e1abSPedro Giffuni long n = (*p++ - '0');
141*9c15e1abSPedro Giffuni while ('0' <= *p && '9' >= *p)
142*9c15e1abSPedro Giffuni {
143*9c15e1abSPedro Giffuni n *= 10;
144*9c15e1abSPedro Giffuni n += (*p++ - '0');
145*9c15e1abSPedro Giffuni }
146*9c15e1abSPedro Giffuni buf.appendAscii( p, n );
147*9c15e1abSPedro Giffuni p += n;
148*9c15e1abSPedro Giffuni if ('E' != *p)
149*9c15e1abSPedro Giffuni buf.append( (sal_Unicode)'.' );
150*9c15e1abSPedro Giffuni }
151*9c15e1abSPedro Giffuni
152*9c15e1abSPedro Giffuni #if OSL_DEBUG_LEVEL > 1
153*9c15e1abSPedro Giffuni OUString ret( buf.makeStringAndClear() );
154*9c15e1abSPedro Giffuni OString c_ret( OUStringToOString( ret, RTL_TEXTENCODING_ASCII_US ) );
155*9c15e1abSPedro Giffuni fprintf( stderr, "> toUNOname(): %s => %s\n", start, c_ret.getStr() );
156*9c15e1abSPedro Giffuni return ret;
157*9c15e1abSPedro Giffuni #else
158*9c15e1abSPedro Giffuni return buf.makeStringAndClear();
159*9c15e1abSPedro Giffuni #endif
160*9c15e1abSPedro Giffuni }
161*9c15e1abSPedro Giffuni
162*9c15e1abSPedro Giffuni //==================================================================================================
mangledRttiSymbol(OUString const & unoName)163*9c15e1abSPedro Giffuni static OString mangledRttiSymbol( OUString const & unoName ) SAL_THROW( () )
164*9c15e1abSPedro Giffuni {
165*9c15e1abSPedro Giffuni OStringBuffer buf( 64 );
166*9c15e1abSPedro Giffuni buf.append( RTL_CONSTASCII_STRINGPARAM("_ZTIN") );
167*9c15e1abSPedro Giffuni sal_Int32 index = 0;
168*9c15e1abSPedro Giffuni do
169*9c15e1abSPedro Giffuni {
170*9c15e1abSPedro Giffuni OUString token( unoName.getToken( 0, '.', index ) );
171*9c15e1abSPedro Giffuni buf.append( token.getLength() );
172*9c15e1abSPedro Giffuni OString c_token( OUStringToOString( token, RTL_TEXTENCODING_ASCII_US ) );
173*9c15e1abSPedro Giffuni buf.append( c_token );
174*9c15e1abSPedro Giffuni }
175*9c15e1abSPedro Giffuni while (index >= 0);
176*9c15e1abSPedro Giffuni buf.append( 'E' );
177*9c15e1abSPedro Giffuni return buf.makeStringAndClear();
178*9c15e1abSPedro Giffuni }
179*9c15e1abSPedro Giffuni
180*9c15e1abSPedro Giffuni //==================================================================================================
181*9c15e1abSPedro Giffuni class RTTI
182*9c15e1abSPedro Giffuni {
183*9c15e1abSPedro Giffuni typedef hash_map< OUString, type_info *, OUStringHash > t_rtti_map;
184*9c15e1abSPedro Giffuni
185*9c15e1abSPedro Giffuni Mutex m_mutex;
186*9c15e1abSPedro Giffuni t_rtti_map m_rttis;
187*9c15e1abSPedro Giffuni t_rtti_map m_generatedRttis;
188*9c15e1abSPedro Giffuni
189*9c15e1abSPedro Giffuni type_info * synthesiseRTTI(
190*9c15e1abSPedro Giffuni OString const & rSymbolName,
191*9c15e1abSPedro Giffuni typelib_CompoundTypeDescription * pTypeDescr ) SAL_THROW( () );
192*9c15e1abSPedro Giffuni
193*9c15e1abSPedro Giffuni public:
194*9c15e1abSPedro Giffuni RTTI() SAL_THROW( () );
195*9c15e1abSPedro Giffuni ~RTTI() SAL_THROW( () );
196*9c15e1abSPedro Giffuni
197*9c15e1abSPedro Giffuni type_info * getRTTI( typelib_CompoundTypeDescription * ) SAL_THROW( () );
198*9c15e1abSPedro Giffuni };
199*9c15e1abSPedro Giffuni
200*9c15e1abSPedro Giffuni //__________________________________________________________________________________________________
RTTI()201*9c15e1abSPedro Giffuni RTTI::RTTI() SAL_THROW( () )
202*9c15e1abSPedro Giffuni {
203*9c15e1abSPedro Giffuni }
204*9c15e1abSPedro Giffuni
205*9c15e1abSPedro Giffuni //__________________________________________________________________________________________________
~RTTI()206*9c15e1abSPedro Giffuni RTTI::~RTTI() SAL_THROW( () )
207*9c15e1abSPedro Giffuni {
208*9c15e1abSPedro Giffuni }
209*9c15e1abSPedro Giffuni
210*9c15e1abSPedro Giffuni //__________________________________________________________________________________________________
getRTTI(typelib_CompoundTypeDescription * pTypeDescr)211*9c15e1abSPedro Giffuni type_info * RTTI::getRTTI( typelib_CompoundTypeDescription *pTypeDescr ) SAL_THROW( () )
212*9c15e1abSPedro Giffuni {
213*9c15e1abSPedro Giffuni OUString const & unoName = *(OUString const *)&pTypeDescr->aBase.pTypeName;
214*9c15e1abSPedro Giffuni
215*9c15e1abSPedro Giffuni // Recursive: synthesiseRTTI() re-enters getRTTI() for the base chain.
216*9c15e1abSPedro Giffuni // osl::Mutex is a PTHREAD_MUTEX_RECURSIVE (sal/osl/unx/mutex.c), so this
217*9c15e1abSPedro Giffuni // is safe. Lock order against exceptionMapsMutex() is unchanged.
218*9c15e1abSPedro Giffuni MutexGuard guard( m_mutex );
219*9c15e1abSPedro Giffuni
220*9c15e1abSPedro Giffuni {
221*9c15e1abSPedro Giffuni MutexGuard observedGuard( exceptionMapsMutex() );
222*9c15e1abSPedro Giffuni ObservedRttiMap::const_iterator observed( observedRttis().find( unoName ) );
223*9c15e1abSPedro Giffuni if ( observed != observedRttis().end() )
224*9c15e1abSPedro Giffuni return observed->second;
225*9c15e1abSPedro Giffuni }
226*9c15e1abSPedro Giffuni
227*9c15e1abSPedro Giffuni t_rtti_map::const_iterator it = m_rttis.find( unoName );
228*9c15e1abSPedro Giffuni if ( it != m_rttis.end() )
229*9c15e1abSPedro Giffuni return it->second;
230*9c15e1abSPedro Giffuni
231*9c15e1abSPedro Giffuni OString mangled = mangledRttiSymbol( unoName );
232*9c15e1abSPedro Giffuni
233*9c15e1abSPedro Giffuni type_info * p = 0;
234*9c15e1abSPedro Giffuni {
235*9c15e1abSPedro Giffuni void * sym = dlsym( RTLD_DEFAULT, mangled.getStr() );
236*9c15e1abSPedro Giffuni if ( sym )
237*9c15e1abSPedro Giffuni p = *reinterpret_cast< type_info ** >( sym );
238*9c15e1abSPedro Giffuni }
239*9c15e1abSPedro Giffuni
240*9c15e1abSPedro Giffuni if ( p )
241*9c15e1abSPedro Giffuni {
242*9c15e1abSPedro Giffuni m_rttis[ unoName ] = p;
243*9c15e1abSPedro Giffuni return p;
244*9c15e1abSPedro Giffuni }
245*9c15e1abSPedro Giffuni
246*9c15e1abSPedro Giffuni // Fallback: synthesise a type_info object.
247*9c15e1abSPedro Giffuni OString symName = mangled;
248*9c15e1abSPedro Giffuni p = synthesiseRTTI( symName, pTypeDescr );
249*9c15e1abSPedro Giffuni m_rttis[ unoName ] = p;
250*9c15e1abSPedro Giffuni return p;
251*9c15e1abSPedro Giffuni }
252*9c15e1abSPedro Giffuni
253*9c15e1abSPedro Giffuni } // namespace CPPU_CURRENT_NAMESPACE
254