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 <exception> 32 #include <pthread.h> 33 34 #include "cxxabi_defines.h" 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, 47 _Unwind_Exception* exc) { 48 __cxa_free_exception(exc+1); 49 } 50 51 // Technical note: 52 // Use a pthread_key_t to hold the key used to store our thread-specific 53 // __cxa_eh_globals objects. The key is created and destroyed through 54 // a static C++ object. 55 // 56 57 // Due to a bug in the dynamic linker that was only fixed in Froyo, the 58 // static C++ destructor may be called with a value of NULL for the 59 // 'this' pointer. As such, any attempt to access any field in the 60 // object there will result in a crash. To work-around this, store 61 // the key object as a 'static' variable outside of the C++ object. 62 static pthread_key_t __cxa_thread_key; 63 64 class CxaThreadKey { 65 public: 66 // Called at program initialization time, or when the shared library 67 // is loaded through dlopen(). CxaThreadKey()68 CxaThreadKey() { 69 if (pthread_key_create(&__cxa_thread_key, freeObject) != 0) { 70 __gabixx::__fatal_error("Can't allocate C++ runtime pthread_key_t"); 71 } 72 } 73 74 // Called at program exit time, or when the shared library is 75 // unloaded through dlclose(). See note above. ~CxaThreadKey()76 ~CxaThreadKey() { 77 pthread_key_delete(__cxa_thread_key); 78 } 79 getFast()80 static __cxa_eh_globals* getFast() { 81 void* obj = pthread_getspecific(__cxa_thread_key); 82 return reinterpret_cast<__cxa_eh_globals*>(obj); 83 } 84 getSlow()85 static __cxa_eh_globals* getSlow() { 86 void* obj = pthread_getspecific(__cxa_thread_key); 87 if (obj == NULL) { 88 obj = malloc(sizeof(__cxa_eh_globals)); 89 if (!obj) { 90 // Shouldn't happen, but better be safe than sorry. 91 __gabixx::__fatal_error( 92 "Can't allocate thread-specific C++ runtime info block."); 93 } 94 memset(obj, 0, sizeof(__cxa_eh_globals)); 95 pthread_setspecific(__cxa_thread_key, obj); 96 } 97 return reinterpret_cast<__cxa_eh_globals*>(obj); 98 } 99 100 private: 101 // Called when a thread is destroyed. freeObject(void * obj)102 static void freeObject(void* obj) { 103 free(obj); 104 } 105 106 }; 107 108 // The single static instance, this forces the compiler to register 109 // a constructor and destructor for this object in the final library 110 // file. They handle the pthread_key_t allocation/deallocation. 111 static CxaThreadKey instance; 112 throwException(__cxa_exception * header)113 void throwException(__cxa_exception *header) { 114 __cxa_eh_globals* globals = __cxa_get_globals(); 115 header->unexpectedHandler = std::get_unexpected(); 116 header->terminateHandler = std::get_terminate(); 117 globals->uncaughtExceptions += 1; 118 119 _Unwind_RaiseException(&header->unwindHeader); 120 121 // Should not be here 122 call_terminate(&header->unwindHeader); 123 } 124 125 } // anonymous namespace 126 127 128 namespace __cxxabiv1 { ~__shim_type_info()129 __shim_type_info::~__shim_type_info() { 130 } 131 __cxa_pure_virtual()132 extern "C" void __cxa_pure_virtual() { 133 __gabixx::__fatal_error("Pure virtual function called!"); 134 } 135 __cxa_get_globals()136 extern "C" __cxa_eh_globals* __cxa_get_globals() { 137 return CxaThreadKey::getSlow(); 138 } 139 __cxa_get_globals_fast()140 extern "C" __cxa_eh_globals* __cxa_get_globals_fast() { 141 return CxaThreadKey::getFast(); 142 } 143 144 __cxa_allocate_exception(size_t thrown_size)145 extern "C" void *__cxa_allocate_exception(size_t thrown_size) { 146 size_t size = thrown_size + sizeof(__cxa_exception); 147 __cxa_exception *buffer = static_cast<__cxa_exception*>(malloc(size)); 148 if (!buffer) { 149 // Since Android uses memory-overcommit, we enter here only when 150 // the exception object is VERY large. This will propably never happen. 151 // Therefore, we decide to use no emergency spaces. 152 __gabixx::__fatal_error("Not enough memory to allocate exception!"); 153 } 154 155 memset(buffer, 0, sizeof(__cxa_exception)); 156 return buffer + 1; 157 } 158 __cxa_free_exception(void * thrown_exception)159 extern "C" void __cxa_free_exception(void* thrown_exception) { 160 __cxa_exception *exc = static_cast<__cxa_exception*>(thrown_exception)-1; 161 162 if (exc->exceptionDestructor) { 163 try { 164 exc->exceptionDestructor(thrown_exception); 165 } catch (...) { 166 __gabixx::__fatal_error("Exception destructor has thrown!"); 167 } 168 } 169 170 free(exc); 171 } 172 173 __cxa_throw(void * thrown_exc,std::type_info * tinfo,void (* dest)(void *))174 extern "C" void __cxa_throw(void* thrown_exc, 175 std::type_info* tinfo, 176 void (*dest)(void*)) { 177 __cxa_exception* header = static_cast<__cxa_exception*>(thrown_exc)-1; 178 header->exceptionType = tinfo; 179 header->exceptionDestructor = dest; 180 181 header->unwindHeader.exception_class = __gxx_exception_class; 182 header->unwindHeader.exception_cleanup = defaultExceptionCleanupFunc; 183 184 throwException(header); 185 } 186 __cxa_rethrow()187 extern "C" void __cxa_rethrow() { 188 __cxa_eh_globals *globals = __cxa_get_globals(); 189 __cxa_exception* header = globals->caughtExceptions; 190 _Unwind_Exception* exception = &header->unwindHeader; 191 if (!header) { 192 __gabixx::__fatal_error( 193 "Attempting to rethrow an exception that doesn't exist!"); 194 } 195 196 if (isOurCxxException(exception->exception_class)) { 197 header->handlerCount = -header->handlerCount; // Set rethrow flag 198 } else { 199 globals->caughtExceptions = 0; 200 } 201 202 throwException(header); 203 } 204 205 __cxa_begin_catch(void * exc)206 extern "C" void* __cxa_begin_catch(void* exc) { 207 _Unwind_Exception *exception = static_cast<_Unwind_Exception*>(exc); 208 __cxa_exception* header = reinterpret_cast<__cxa_exception*>(exception+1)-1; 209 __cxa_eh_globals* globals = __cxa_get_globals(); 210 211 if (!isOurCxxException(exception->exception_class)) { 212 if (globals->caughtExceptions) { 213 __gabixx::__fatal_error("Can't handle non-C++ exception!"); 214 } 215 } 216 217 // Check rethrow flag 218 header->handlerCount = (header->handlerCount < 0) ? 219 (-header->handlerCount+1) : (header->handlerCount+1); 220 221 if (header != globals->caughtExceptions) { 222 header->nextException = globals->caughtExceptions; 223 globals->caughtExceptions = header; 224 } 225 globals->uncaughtExceptions -= 1; 226 227 return header->adjustedPtr; 228 } 229 __cxa_end_catch()230 extern "C" void __cxa_end_catch() { 231 __cxa_eh_globals *globals = __cxa_get_globals_fast(); 232 __cxa_exception *header = globals->caughtExceptions; 233 _Unwind_Exception* exception = &header->unwindHeader; 234 235 if (!header) { 236 return; 237 } 238 239 if (!isOurCxxException(exception->exception_class)) { 240 globals->caughtExceptions = 0; 241 _Unwind_DeleteException(exception); 242 return; 243 } 244 245 int count = header->handlerCount; 246 if (count < 0) { // Rethrow 247 if (++count == 0) { 248 globals->caughtExceptions = header->nextException; 249 } 250 } else if (--count == 0) { 251 globals->caughtExceptions = header->nextException; 252 __cxa_free_exception(header+1); 253 return; 254 } else if (count < 0) { 255 __gabixx::__fatal_error("Internal error during exception handling!"); 256 } 257 258 header->handlerCount = count; 259 } 260 __cxa_get_exception_ptr(void * exceptionObject)261 extern "C" void* __cxa_get_exception_ptr(void* exceptionObject) { 262 __cxa_exception* header = 263 reinterpret_cast<__cxa_exception*>( 264 reinterpret_cast<_Unwind_Exception *>(exceptionObject)+1)-1; 265 return header->adjustedPtr; 266 } 267 __cxa_uncaught_exception()268 extern "C" bool __cxa_uncaught_exception() _GABIXX_NOEXCEPT { 269 __cxa_eh_globals* globals = __cxa_get_globals(); 270 if (globals == NULL) 271 return false; 272 return globals->uncaughtExceptions == 0; 273 } 274 __cxa_decrement_exception_refcount(void * exceptionObject)275 extern "C" void __cxa_decrement_exception_refcount(void* exceptionObject) 276 _GABIXX_NOEXCEPT { 277 if (exceptionObject != NULL) 278 { 279 __cxa_exception* header = 280 reinterpret_cast<__cxa_exception*>(exceptionObject)-1; 281 if (__sync_sub_and_fetch(&header->referenceCount, 1) == 0) 282 __cxa_free_exception(exceptionObject); 283 } 284 } 285 __cxa_increment_exception_refcount(void * exceptionObject)286 extern "C" void __cxa_increment_exception_refcount(void* exceptionObject) 287 _GABIXX_NOEXCEPT { 288 if (exceptionObject != NULL) 289 { 290 __cxa_exception* header = 291 reinterpret_cast<__cxa_exception*>(exceptionObject)-1; 292 __sync_add_and_fetch(&header->referenceCount, 1); 293 } 294 } 295 __cxa_rethrow_primary_exception(void * primary_exception)296 extern "C" void __cxa_rethrow_primary_exception(void* primary_exception) { 297 #if defined(GABIXX_LIBCXX) 298 // Only warn if we're building for libcxx since other libraries do not use 299 // this. 300 #warning "not implemented." 301 #endif /* defined(GABIXX_LIBCXX) */ 302 } 303 __cxa_current_primary_exception()304 extern "C" void* __cxa_current_primary_exception() _GABIXX_NOEXCEPT { 305 #if defined(GABIXX_LIBCXX) 306 // Only warn if we're building for libcxx since other libraries do not use 307 // this. 308 #warning "not implemented." 309 #endif /* defined(GABIXX_LIBCXX) */ 310 } 311 312 } // namespace __cxxabiv1 313