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