Home | History | Annotate | Download | only in src
      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 
     41   bool isOurCxxException(uint64_t exc) {
     42     // Compatible with GNU
     43     return exc == __gxx_exception_class;
     44   }
     45 
     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().
     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.
     76     ~CxaThreadKey() {
     77       pthread_key_delete(__cxa_thread_key);
     78     }
     79 
     80     static __cxa_eh_globals* getFast() {
     81       void* obj = pthread_getspecific(__cxa_thread_key);
     82       return reinterpret_cast<__cxa_eh_globals*>(obj);
     83     }
     84 
     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.
    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 
    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 {
    129   __shim_type_info::~__shim_type_info() {
    130   }
    131 
    132   extern "C" void __cxa_pure_virtual() {
    133     __gabixx::__fatal_error("Pure virtual function called!");
    134   }
    135 
    136   extern "C" __cxa_eh_globals* __cxa_get_globals() {
    137     return CxaThreadKey::getSlow();
    138   }
    139 
    140   extern "C" __cxa_eh_globals* __cxa_get_globals_fast() {
    141     return CxaThreadKey::getFast();
    142   }
    143 
    144 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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