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 <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 
     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, _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().
     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.
     75     ~CxaThreadKey() {
     76       pthread_key_delete(__cxa_thread_key);
     77     }
     78 
     79     static __cxa_thread_info* getFast() {
     80       void* obj = pthread_getspecific(__cxa_thread_key);
     81       return reinterpret_cast<__cxa_thread_info*>(obj);
     82     }
     83 
     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.
    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 
    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 {
    133   __shim_type_info::~__shim_type_info() {
    134   }
    135 
    136   extern "C" void __cxa_pure_virtual() {
    137     fatalError("Pure virtual function called!");
    138   }
    139 
    140   extern "C" __cxa_eh_globals* __cxa_get_globals() {
    141     __cxa_thread_info* info = CxaThreadKey::getSlow();
    142     return &info->globals;
    143   }
    144 
    145   extern "C" __cxa_eh_globals* __cxa_get_globals_fast() {
    146     __cxa_thread_info* info = CxaThreadKey::getFast();
    147     return &info->globals;
    148   }
    149 
    150 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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