1 // Copyright (C) 2012 The Android Open Source Project 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions 6 // are met: 7 // 1. Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // 2. Redistributions in binary form must reproduce the above copyright 10 // notice, this list of conditions and the following disclaimer in the 11 // documentation and/or other materials provided with the distribution. 12 // 3. Neither the name of the project nor the names of its contributors 13 // may be used to endorse or promote products derived from this software 14 // without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 // ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 // SUCH DAMAGE. 27 28 #include <cassert> 29 #include <cstdio> 30 #include <cstdlib> 31 #include <cxxabi.h> 32 #include <exception> 33 #include <pthread.h> 34 35 #include "helper_func_internal.h" 36 37 namespace { 38 39 using namespace __cxxabiv1; 40 isOurCxxException(uint64_t exc)41 bool isOurCxxException(uint64_t exc) { 42 // Compatible with GNU 43 return exc == __gxx_exception_class; 44 } 45 defaultExceptionCleanupFunc(_Unwind_Reason_Code reason,_Unwind_Exception * exc)46 void defaultExceptionCleanupFunc(_Unwind_Reason_Code reason, _Unwind_Exception* exc) { 47 __cxa_free_exception(exc+1); 48 } 49 50 // Technical note: 51 // Use a pthread_key_t to hold the key used to store our thread-specific 52 // __cxa_thread_info objects. The key is created and destroyed through 53 // a static C++ object. 54 // 55 56 // Due to a bug in the dynamic linker that was only fixed in Froyo, the 57 // static C++ destructor may be called with a value of NULL for the 58 // 'this' pointer. As such, any attempt to access any field in the 59 // object there will result in a crash. To work-around this, store 60 // the key object as a 'static' variable outside of the C++ object. 61 static pthread_key_t __cxa_thread_key; 62 63 class CxaThreadKey { 64 public: 65 // Called at program initialization time, or when the shared library 66 // is loaded through dlopen(). CxaThreadKey()67 CxaThreadKey() { 68 if (pthread_key_create(&__cxa_thread_key, freeObject) != 0) { 69 fatalError("Can't allocate C++ runtime pthread_key_t"); 70 } 71 } 72 73 // Called at program exit time, or when the shared library is 74 // unloaded through dlclose(). See note above. ~CxaThreadKey()75 ~CxaThreadKey() { 76 pthread_key_delete(__cxa_thread_key); 77 } 78 getFast()79 static __cxa_thread_info* getFast() { 80 void* obj = pthread_getspecific(__cxa_thread_key); 81 return reinterpret_cast<__cxa_thread_info*>(obj); 82 } 83 getSlow()84 static __cxa_thread_info* getSlow() { 85 void* obj = pthread_getspecific(__cxa_thread_key); 86 if (obj == NULL) { 87 obj = malloc(sizeof(__cxa_thread_info)); 88 if (!obj) { 89 // Shouldn't happen, but better be safe than sorry. 90 fatalError("Can't allocate thread-specific C++ runtime info block."); 91 } 92 memset(obj, 0, sizeof(__cxa_thread_info)); 93 pthread_setspecific(__cxa_thread_key, obj); 94 } 95 return reinterpret_cast<__cxa_thread_info*>(obj); 96 } 97 98 private: 99 // Called when a thread is destroyed. freeObject(void * obj)100 static void freeObject(void* obj) { 101 free(obj); 102 } 103 104 }; 105 106 // The single static instance, this forces the compiler to register 107 // a constructor and destructor for this object in the final library 108 // file. They handle the pthread_key_t allocation/deallocation. 109 static CxaThreadKey instance; 110 throwException(__cxa_exception * header)111 void throwException(__cxa_exception *header) { 112 __cxa_thread_info *info = CxaThreadKey::getSlow(); 113 header->unexpectedHandler = info->unexpectedHandler; 114 if (!header->unexpectedHandler) { 115 header->unexpectedHandler = std::get_unexpected(); 116 } 117 header->terminateHandler = info->terminateHandler; 118 if (!header->terminateHandler) { 119 header->terminateHandler = std::get_terminate(); 120 } 121 info->globals.uncaughtExceptions += 1; 122 123 _Unwind_Reason_Code ret = _Unwind_RaiseException(&header->unwindHeader); 124 125 // Should not be here 126 call_terminate(&header->unwindHeader); 127 } 128 129 } // anonymous namespace 130 131 132 namespace __cxxabiv1 { ~__shim_type_info()133 __shim_type_info::~__shim_type_info() { 134 } 135 __cxa_pure_virtual()136 extern "C" void __cxa_pure_virtual() { 137 fatalError("Pure virtual function called!"); 138 } 139 __cxa_get_globals()140 extern "C" __cxa_eh_globals* __cxa_get_globals() { 141 __cxa_thread_info* info = CxaThreadKey::getSlow(); 142 return &info->globals; 143 } 144 __cxa_get_globals_fast()145 extern "C" __cxa_eh_globals* __cxa_get_globals_fast() { 146 __cxa_thread_info* info = CxaThreadKey::getFast(); 147 return &info->globals; 148 } 149 150 __cxa_allocate_exception(size_t thrown_size)151 extern "C" void *__cxa_allocate_exception(size_t thrown_size) { 152 size_t size = thrown_size + sizeof(__cxa_exception); 153 __cxa_exception *buffer = static_cast<__cxa_exception*>(malloc(size)); 154 if (!buffer) { 155 // Since Android uses memory-overcommit, we enter here only when 156 // the exception object is VERY large. This will propably never happen. 157 // Therefore, we decide to use no emergency spaces. 158 fatalError("Not enough memory to allocate exception!"); 159 } 160 161 memset(buffer, 0, sizeof(__cxa_exception)); 162 return buffer + 1; 163 } 164 __cxa_free_exception(void * thrown_exception)165 extern "C" void __cxa_free_exception(void* thrown_exception) { 166 __cxa_exception *exc = static_cast<__cxa_exception*>(thrown_exception)-1; 167 168 if (exc->exceptionDestructor) { 169 try { 170 exc->exceptionDestructor(thrown_exception); 171 } catch (...) { 172 fatalError("Exception destructor has thrown!"); 173 } 174 } 175 176 free(exc); 177 } 178 179 __cxa_throw(void * thrown_exc,std::type_info * tinfo,void (* dest)(void *))180 extern "C" void __cxa_throw(void* thrown_exc, 181 std::type_info* tinfo, 182 void (*dest)(void*)) { 183 __cxa_exception* header = static_cast<__cxa_exception*>(thrown_exc)-1; 184 header->exceptionType = tinfo; 185 header->exceptionDestructor = dest; 186 187 header->unwindHeader.exception_class = __gxx_exception_class; 188 header->unwindHeader.exception_cleanup = defaultExceptionCleanupFunc; 189 190 throwException(header); 191 } 192 __cxa_rethrow()193 extern "C" void __cxa_rethrow() { 194 __cxa_eh_globals *globals = __cxa_get_globals(); 195 __cxa_exception* header = globals->caughtExceptions; 196 _Unwind_Exception* exception = &header->unwindHeader; 197 if (!header) { 198 fatalError("Attempting to rethrow an exception that doesn't exist!"); 199 } 200 201 if (isOurCxxException(exception->exception_class)) { 202 header->handlerCount = -header->handlerCount; // Set rethrow flag 203 } else { 204 globals->caughtExceptions = 0; 205 } 206 207 throwException(header); 208 } 209 210 __cxa_begin_catch(void * exc)211 extern "C" void* __cxa_begin_catch(void* exc) { 212 _Unwind_Exception *exception = static_cast<_Unwind_Exception*>(exc); 213 __cxa_exception* header = reinterpret_cast<__cxa_exception*>(exception+1)-1; 214 __cxa_eh_globals* globals = __cxa_get_globals(); 215 216 if (!isOurCxxException(exception->exception_class)) { 217 if (globals->caughtExceptions) { 218 fatalError("Can't handle non-C++ exception!"); 219 } 220 } 221 222 // Check rethrow flag 223 header->handlerCount = (header->handlerCount < 0) ? 224 (-header->handlerCount+1) : (header->handlerCount+1); 225 226 if (header != globals->caughtExceptions) { 227 header->nextException = globals->caughtExceptions; 228 globals->caughtExceptions = header; 229 } 230 globals->uncaughtExceptions -= 1; 231 232 return header->adjustedPtr; 233 } 234 __cxa_end_catch()235 extern "C" void __cxa_end_catch() { 236 __cxa_eh_globals *globals = __cxa_get_globals_fast(); 237 __cxa_exception *header = globals->caughtExceptions; 238 _Unwind_Exception* exception = &header->unwindHeader; 239 240 if (!header) { 241 return; 242 } 243 244 if (!isOurCxxException(exception->exception_class)) { 245 globals->caughtExceptions = 0; 246 _Unwind_DeleteException(exception); 247 return; 248 } 249 250 int count = header->handlerCount; 251 if (count < 0) { // Rethrow 252 if (++count == 0) { 253 globals->caughtExceptions = header->nextException; 254 } 255 } else if (--count == 0) { 256 globals->caughtExceptions = header->nextException; 257 __cxa_free_exception(header+1); 258 return; 259 } else if (count < 0) { 260 fatalError("Internal error during exception handling!"); 261 } 262 263 header->handlerCount = count; 264 } 265 __cxa_get_exception_ptr(void * exceptionObject)266 extern "C" void* __cxa_get_exception_ptr(void* exceptionObject) { 267 __cxa_exception* header = 268 reinterpret_cast<__cxa_exception*>( 269 reinterpret_cast<_Unwind_Exception *>(exceptionObject)+1)-1; 270 return header->adjustedPtr; 271 } 272 __cxa_uncaught_exception()273 extern "C" bool __cxa_uncaught_exception() throw() { 274 __cxa_eh_globals* globals = __cxa_get_globals(); 275 if (globals == NULL) 276 return false; 277 return globals->uncaughtExceptions == 0; 278 } 279 __cxa_decrement_exception_refcount(void * exceptionObject)280 extern "C" void __cxa_decrement_exception_refcount(void* exceptionObject) throw() { 281 if (exceptionObject != NULL) 282 { 283 __cxa_exception* header = 284 reinterpret_cast<__cxa_exception*>(exceptionObject)-1; 285 if (__sync_sub_and_fetch(&header->referenceCount, 1) == 0) 286 __cxa_free_exception(exceptionObject); 287 } 288 } 289 __cxa_increment_exception_refcount(void * exceptionObject)290 extern "C" void __cxa_increment_exception_refcount(void* exceptionObject) throw() { 291 if (exceptionObject != NULL) 292 { 293 __cxa_exception* header = 294 reinterpret_cast<__cxa_exception*>(exceptionObject)-1; 295 __sync_add_and_fetch(&header->referenceCount, 1); 296 } 297 } 298 __cxa_rethrow_primary_exception(void * primary_exception)299 extern "C" void __cxa_rethrow_primary_exception(void* primary_exception) { 300 #if defined(GABIXX_LIBCXX) 301 // Only warn if we're building for libcxx since other libraries do not use 302 // this. 303 #warning "not implemented." 304 #endif /* defined(GABIXX_LIBCXX) */ 305 } 306 __cxa_current_primary_exception()307 extern "C" void* __cxa_current_primary_exception() throw() { 308 #if defined(GABIXX_LIBCXX) 309 // Only warn if we're building for libcxx since other libraries do not use 310 // this. 311 #warning "not implemented." 312 #endif /* defined(GABIXX_LIBCXX) */ 313 } 314 315 } // namespace __cxxabiv1 316