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 <limits.h> 29 #include <sys/mman.h> 30 31 #include <cassert> 32 #include <cstdio> 33 #include <cstdlib> 34 #include <exception> 35 #include <pthread.h> 36 37 #include "cxxabi_defines.h" 38 #include "helper_func_internal.h" 39 40 namespace { 41 42 using namespace __cxxabiv1; 43 isOurCxxException(uint64_t exc)44 bool isOurCxxException(uint64_t exc) { 45 // Compatible with GNU 46 return exc == __gxx_exception_class; 47 } 48 defaultExceptionCleanupFunc(_Unwind_Reason_Code reason,_Unwind_Exception * exc)49 void defaultExceptionCleanupFunc(_Unwind_Reason_Code reason, 50 _Unwind_Exception* exc) { 51 __cxa_free_exception(exc+1); 52 } 53 54 // Helper class used to ensure a lock is acquire immediately, and released 55 // on scope exit. Usage example: 56 // 57 // { 58 // AutoLock lock(some_mutex); // acquires the mutex. 59 // ... do stuff 60 // if (error) 61 // return; // releases mutex before returning. 62 // ... do other stuff. 63 // } // releases mutex before exiting scope. 64 // 65 class AutoLock { 66 public: AutoLock(pthread_mutex_t & lock)67 AutoLock(pthread_mutex_t& lock) : lock_(lock) { 68 pthread_mutex_lock(&lock_); 69 } 70 ~AutoLock(void)71 ~AutoLock(void) { 72 pthread_mutex_unlock(&lock_); 73 } 74 private: 75 pthread_mutex_t& lock_; 76 77 AutoLock(const AutoLock&); 78 AutoLock& operator=(const AutoLock&); 79 }; 80 81 // MMap-based memory allocator for fixed-sized items. 82 // 83 // IMPORTANT: This must be POD-struct compatible, which means: 84 // - No constructor or destructor. 85 // - No virtual methods. 86 // 87 // This allocates large blocks of memory, called 'slabs' that can contain 88 // several items of the same size. A slab contains an array of item slots, 89 // followed by a pointer, used to put all slabs in a single linked list. 90 class PageBasedAllocator { 91 public: 92 // Used to initialize this allocator to hold items of type |T|. 93 template <typename T> Init()94 void Init() { 95 InitExplicit(sizeof(T), __alignof__(T)); 96 } 97 98 // Used to initialize this instance to hold items of |item_size| bytes, 99 // with alignment |align_size|. InitExplicit(size_t item_size,size_t align_size)100 void InitExplicit(size_t item_size, size_t align_size) { 101 const size_t ptr_size = sizeof(void*); 102 if (align_size < ptr_size) 103 align_size = ptr_size; 104 item_size_ = (item_size + align_size - 1) & ~(align_size - 1); 105 slab_next_offset_ = kSlabSize - ptr_size; 106 item_slab_count_ = slab_next_offset_ / item_size_; 107 108 pthread_mutex_init(&lock_, NULL); 109 free_items_ = NULL; 110 slab_list_ = NULL; 111 } 112 113 // Call this to deallocate this instance. This releases all pages directly. 114 // Ensure that all items are freed first, or bad things could happen. Deinit()115 void Deinit() { 116 pthread_mutex_lock(&lock_); 117 while (slab_list_) { 118 void* slab = slab_list_; 119 void* next_slab = *(void**)((char*)slab + slab_next_offset_); 120 slab_list_ = next_slab; 121 ::munmap(slab, PAGE_SIZE); 122 } 123 pthread_mutex_unlock(&lock_); 124 pthread_mutex_destroy(&lock_); 125 } 126 127 // Allocate a new item, or NULL in case of failure. Alloc()128 void* Alloc() { 129 AutoLock lock(lock_); 130 131 if (!free_items_ && !AllocateSlab()) 132 return NULL; 133 134 FreeItem* item = free_items_; 135 free_items_ = item->next; 136 ::memset(item, 0, item_size_); 137 return item; 138 } 139 Release(void * obj)140 void Release(void* obj) { 141 if (!obj) 142 return; 143 144 AutoLock lock(lock_); 145 FreeItem* item = reinterpret_cast<FreeItem*>(obj); 146 item->next = free_items_; 147 free_items_ = item; 148 } 149 150 private: 151 static const size_t kSlabSize = PAGE_SIZE; 152 AllocateSlab()153 bool AllocateSlab() { 154 // No more free items, allocate a new slab with mmap(). 155 void* new_slab = mmap(NULL, kSlabSize, PROT_READ|PROT_WRITE, 156 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 157 if (new_slab == MAP_FAILED) 158 return false; 159 160 // Prepend to the slab list. 161 *((void**)((char*)new_slab + slab_next_offset_)) = slab_list_; 162 slab_list_ = new_slab; 163 164 // Put all item slots in the new slab into the free item list. 165 FreeItem** pparent = &free_items_; 166 FreeItem* item = reinterpret_cast<FreeItem*>(new_slab); 167 for (size_t n = 0; n < item_slab_count_; ++n) { 168 *pparent = item; 169 pparent = &item->next; 170 item = reinterpret_cast<FreeItem*>((char*)item + item_size_); 171 } 172 *pparent = NULL; 173 174 // Done. 175 return true; 176 } 177 178 struct FreeItem { 179 FreeItem* next; 180 }; 181 182 size_t item_size_; // size of each item in bytes. 183 size_t item_slab_count_; // number of items in each slab. 184 size_t slab_next_offset_; // offset of pointer to next slab in list. 185 pthread_mutex_t lock_; // mutex synchronizing access to data below. 186 void* slab_list_; // Linked list of slabs. 187 FreeItem* free_items_; // Linked list of free items. 188 }; 189 190 // Technical note: 191 // Use a pthread_key_t to hold the key used to store our thread-specific 192 // __cxa_eh_globals objects. The key is created and destroyed through 193 // a static C++ object. 194 // 195 196 // Due to a bug in the dynamic linker that was only fixed in Froyo, the 197 // static C++ destructor may be called with a value of NULL for the 198 // 'this' pointer. As such, any attempt to access any field in the 199 // object there will result in a crash. To work-around this, store 200 // the members of CxaThreadKey as static variables outside of the 201 // C++ object. 202 static pthread_key_t __cxa_thread_key; 203 static PageBasedAllocator __cxa_eh_globals_allocator; 204 205 class CxaThreadKey { 206 public: 207 // Called at program initialization time, or when the shared library 208 // is loaded through dlopen(). CxaThreadKey()209 CxaThreadKey() { 210 if (pthread_key_create(&__cxa_thread_key, freeObject) != 0) 211 __gabixx::__fatal_error("Can't allocate C++ runtime pthread_key_t"); 212 __cxa_eh_globals_allocator.Init<__cxa_eh_globals>(); 213 } 214 215 // Called at program exit time, or when the shared library is 216 // unloaded through dlclose(). See note above. ~CxaThreadKey()217 ~CxaThreadKey() { 218 __cxa_eh_globals_allocator.Deinit(); 219 pthread_key_delete(__cxa_thread_key); 220 } 221 getFast()222 static __cxa_eh_globals* getFast() { 223 void* obj = pthread_getspecific(__cxa_thread_key); 224 return reinterpret_cast<__cxa_eh_globals*>(obj); 225 } 226 getSlow()227 static __cxa_eh_globals* getSlow() { 228 void* obj = pthread_getspecific(__cxa_thread_key); 229 if (obj == NULL) { 230 // malloc() cannot be used here because this method is sometimes 231 // called from malloc() on Android, and this would dead-lock. 232 // 233 // More specifically, if the libc.debug.malloc system property is not 0 234 // on a userdebug or eng build of the platform, malloc() will call 235 // backtrace() to record stack traces of allocation. On ARM, this 236 // forces an unwinding operation which will call this function at 237 // some point. 238 obj = __cxa_eh_globals_allocator.Alloc(); 239 if (!obj) { 240 // Shouldn't happen, but better be safe than sorry. 241 __gabixx::__fatal_error( 242 "Can't allocate thread-specific C++ runtime info block."); 243 } 244 pthread_setspecific(__cxa_thread_key, obj); 245 } 246 return reinterpret_cast<__cxa_eh_globals*>(obj); 247 } 248 249 private: 250 // Called when a thread is destroyed. freeObject(void * obj)251 static void freeObject(void* obj) { 252 __cxa_eh_globals_allocator.Release(obj); 253 } 254 255 }; 256 257 // The single static instance, this forces the compiler to register 258 // a constructor and destructor for this object in the final library 259 // file. They handle the pthread_key_t allocation/deallocation. 260 static CxaThreadKey instance; 261 throwException(__cxa_exception * header)262 _GABIXX_NORETURN void throwException(__cxa_exception *header) { 263 __cxa_eh_globals* globals = __cxa_get_globals(); 264 header->unexpectedHandler = std::get_unexpected(); 265 header->terminateHandler = std::get_terminate(); 266 globals->uncaughtExceptions += 1; 267 268 _Unwind_RaiseException(&header->unwindHeader); 269 270 // Should not be here 271 call_terminate(&header->unwindHeader); 272 } 273 274 } // anonymous namespace 275 276 277 namespace __cxxabiv1 { ~__shim_type_info()278 __shim_type_info::~__shim_type_info() { 279 } // namespace __cxxabiv1 280 __cxa_pure_virtual()281 extern "C" void __cxa_pure_virtual() { 282 __gabixx::__fatal_error("Pure virtual function called!"); 283 } 284 __cxa_deleted_virtual()285 extern "C" void __cxa_deleted_virtual() { 286 __gabixx::__fatal_error("Deleted virtual function called!"); 287 } 288 __cxa_get_globals()289 extern "C" __cxa_eh_globals* __cxa_get_globals() _GABIXX_NOEXCEPT { 290 return CxaThreadKey::getSlow(); 291 } 292 __cxa_get_globals_fast()293 extern "C" __cxa_eh_globals* __cxa_get_globals_fast() _GABIXX_NOEXCEPT { 294 return CxaThreadKey::getFast(); 295 } 296 __cxa_allocate_exception(size_t thrown_size)297 extern "C" void *__cxa_allocate_exception(size_t thrown_size) _GABIXX_NOEXCEPT { 298 size_t size = thrown_size + sizeof(__cxa_exception); 299 __cxa_exception *buffer = static_cast<__cxa_exception*>(memalign(__alignof__(__cxa_exception), size)); 300 if (!buffer) { 301 // Since Android uses memory-overcommit, we enter here only when 302 // the exception object is VERY large. This will propably never happen. 303 // Therefore, we decide to use no emergency spaces. 304 __gabixx::__fatal_error("Not enough memory to allocate exception!"); 305 } 306 307 ::memset(buffer, 0, sizeof(__cxa_exception)); 308 return buffer + 1; 309 } 310 __cxa_free_exception(void * thrown_exception)311 extern "C" void __cxa_free_exception(void* thrown_exception) _GABIXX_NOEXCEPT { 312 __cxa_exception *exc = static_cast<__cxa_exception*>(thrown_exception)-1; 313 314 if (exc->exceptionDestructor) { 315 try { 316 exc->exceptionDestructor(thrown_exception); 317 } catch (...) { 318 __gabixx::__fatal_error("Exception destructor has thrown!"); 319 } 320 } 321 322 free(exc); 323 } 324 __cxa_throw(void * thrown_exc,std::type_info * tinfo,void (* dest)(void *))325 extern "C" void __cxa_throw(void* thrown_exc, 326 std::type_info* tinfo, 327 void (*dest)(void*)) { 328 __cxa_exception* header = static_cast<__cxa_exception*>(thrown_exc)-1; 329 header->exceptionType = tinfo; 330 header->exceptionDestructor = dest; 331 332 header->unwindHeader.exception_class = __gxx_exception_class; 333 header->unwindHeader.exception_cleanup = defaultExceptionCleanupFunc; 334 335 throwException(header); 336 } 337 __cxa_rethrow()338 extern "C" void __cxa_rethrow() { 339 __cxa_eh_globals *globals = __cxa_get_globals(); 340 __cxa_exception* header = globals->caughtExceptions; 341 _Unwind_Exception* exception = &header->unwindHeader; 342 if (!header) { 343 __gabixx::__fatal_error( 344 "Attempting to rethrow an exception that doesn't exist!"); 345 } 346 347 if (isOurCxxException(exception->exception_class)) { 348 header->handlerCount = -header->handlerCount; // Set rethrow flag 349 } else { 350 globals->caughtExceptions = 0; 351 } 352 353 throwException(header); 354 } 355 __cxa_begin_catch(void * exc)356 extern "C" void* __cxa_begin_catch(void* exc) _GABIXX_NOEXCEPT { 357 _Unwind_Exception *exception = static_cast<_Unwind_Exception*>(exc); 358 __cxa_exception* header = reinterpret_cast<__cxa_exception*>(exception+1)-1; 359 __cxa_eh_globals* globals = __cxa_get_globals(); 360 361 if (!isOurCxxException(exception->exception_class)) { 362 if (globals->caughtExceptions) { 363 __gabixx::__fatal_error("Can't handle non-C++ exception!"); 364 } 365 } 366 367 // Check rethrow flag 368 header->handlerCount = (header->handlerCount < 0) ? 369 (-header->handlerCount+1) : (header->handlerCount+1); 370 371 if (header != globals->caughtExceptions) { 372 header->nextException = globals->caughtExceptions; 373 globals->caughtExceptions = header; 374 } 375 globals->uncaughtExceptions -= 1; 376 377 return header->adjustedPtr; 378 } 379 __cxa_end_catch()380 extern "C" void __cxa_end_catch() _GABIXX_NOEXCEPT { 381 __cxa_eh_globals *globals = __cxa_get_globals_fast(); 382 __cxa_exception *header = globals->caughtExceptions; 383 _Unwind_Exception* exception = &header->unwindHeader; 384 385 if (!header) { 386 return; 387 } 388 389 if (!isOurCxxException(exception->exception_class)) { 390 globals->caughtExceptions = 0; 391 _Unwind_DeleteException(exception); 392 return; 393 } 394 395 int count = header->handlerCount; 396 if (count < 0) { // Rethrow 397 if (++count == 0) { 398 globals->caughtExceptions = header->nextException; 399 } 400 } else if (--count == 0) { 401 globals->caughtExceptions = header->nextException; 402 __cxa_free_exception(header+1); 403 return; 404 } else if (count < 0) { 405 __gabixx::__fatal_error("Internal error during exception handling!"); 406 } 407 408 header->handlerCount = count; 409 } 410 __cxa_get_exception_ptr(void * exceptionObject)411 extern "C" void* __cxa_get_exception_ptr(void* exceptionObject) _GABIXX_NOEXCEPT { 412 __cxa_exception* header = 413 reinterpret_cast<__cxa_exception*>( 414 reinterpret_cast<_Unwind_Exception *>(exceptionObject)+1)-1; 415 return header->adjustedPtr; 416 } 417 __cxa_uncaught_exception()418 extern "C" bool __cxa_uncaught_exception() _GABIXX_NOEXCEPT { 419 __cxa_eh_globals* globals = __cxa_get_globals(); 420 if (globals == NULL) 421 return false; 422 return globals->uncaughtExceptions == 0; 423 } 424 __cxa_decrement_exception_refcount(void * exceptionObject)425 extern "C" void __cxa_decrement_exception_refcount(void* exceptionObject) 426 _GABIXX_NOEXCEPT { 427 if (exceptionObject != NULL) 428 { 429 __cxa_exception* header = 430 reinterpret_cast<__cxa_exception*>(exceptionObject)-1; 431 if (__sync_sub_and_fetch(&header->referenceCount, 1) == 0) 432 __cxa_free_exception(exceptionObject); 433 } 434 } 435 __cxa_increment_exception_refcount(void * exceptionObject)436 extern "C" void __cxa_increment_exception_refcount(void* exceptionObject) 437 _GABIXX_NOEXCEPT { 438 if (exceptionObject != NULL) 439 { 440 __cxa_exception* header = 441 reinterpret_cast<__cxa_exception*>(exceptionObject)-1; 442 __sync_add_and_fetch(&header->referenceCount, 1); 443 } 444 } 445 __cxa_rethrow_primary_exception(void * primary_exception)446 extern "C" void __cxa_rethrow_primary_exception(void* primary_exception) { 447 #if defined(LIBCXXABI) 448 // Only warn if we're building for libcxx since other libraries do not use 449 // this. 450 #warning "not implemented." 451 #endif /* defined(LIBCXXABI) */ 452 } 453 __cxa_current_primary_exception()454 extern "C" void* __cxa_current_primary_exception() _GABIXX_NOEXCEPT { 455 #if defined(LIBCXXABI) 456 // Only warn if we're building for libcxx since other libraries do not use 457 // this. 458 #warning "not implemented." 459 #endif /* defined(LIBCXXABI) */ 460 return NULL; 461 } 462 463 } // namespace __cxxabiv1 464