Home | History | Annotate | Download | only in src
      1 //===------------------------- cxa_handlers.cpp ---------------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is dual licensed under the MIT and the University of Illinois Open
      6 // Source Licenses. See LICENSE.TXT for details.
      7 //
      8 //
      9 // This file implements the functionality associated with the terminate_handler,
     10 //   unexpected_handler, and new_handler.
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include <stdexcept>
     14 #include <new>
     15 #include <exception>
     16 #include "abort_message.h"
     17 #include "cxxabi.h"
     18 #include "cxa_handlers.hpp"
     19 #include "cxa_exception.hpp"
     20 #include "private_typeinfo.h"
     21 
     22 namespace std
     23 {
     24 
     25 unexpected_handler
     26 get_unexpected() _NOEXCEPT
     27 {
     28     return __sync_fetch_and_add(&__cxa_unexpected_handler, (unexpected_handler)0);
     29 //  The above is safe but overkill on x86
     30 //  Using of C++11 atomics this should be rewritten
     31 //  return __cxa_unexpected_handler.load(memory_order_acq);
     32 }
     33 
     34 void
     35 __unexpected(unexpected_handler func)
     36 {
     37     func();
     38     // unexpected handler should not return
     39     abort_message("unexpected_handler unexpectedly returned");
     40 }
     41 
     42 __attribute__((noreturn))
     43 void
     44 unexpected()
     45 {
     46     __unexpected(get_unexpected());
     47 }
     48 
     49 terminate_handler
     50 get_terminate() _NOEXCEPT
     51 {
     52     return __sync_fetch_and_add(&__cxa_terminate_handler, (terminate_handler)0);
     53 //  The above is safe but overkill on x86
     54 //  Using of C++11 atomics this should be rewritten
     55 //  return __cxa_terminate_handler.load(memory_order_acq);
     56 }
     57 
     58 void
     59 __terminate(terminate_handler func) _NOEXCEPT
     60 {
     61 #ifndef _LIBCXXABI_NO_EXCEPTIONS
     62     try
     63     {
     64 #endif  // _LIBCXXABI_NO_EXCEPTIONS
     65         func();
     66         // handler should not return
     67         abort_message("terminate_handler unexpectedly returned");
     68 #ifndef _LIBCXXABI_NO_EXCEPTIONS
     69     }
     70     catch (...)
     71     {
     72         // handler should not throw exception
     73         abort_message("terminate_handler unexpectedly threw an exception");
     74     }
     75 #endif  // _LIBCXXABI_NO_EXCEPTIONS
     76 }
     77 
     78 __attribute__((noreturn))
     79 void
     80 terminate() _NOEXCEPT
     81 {
     82     // If there might be an uncaught exception
     83     using namespace __cxxabiv1;
     84     __cxa_eh_globals* globals = __cxa_get_globals_fast();
     85     if (globals)
     86     {
     87         __cxa_exception* exception_header = globals->caughtExceptions;
     88         if (exception_header)
     89         {
     90             _Unwind_Exception* unwind_exception =
     91                 reinterpret_cast<_Unwind_Exception*>(exception_header + 1) - 1;
     92             bool native_exception =
     93                 (unwind_exception->exception_class & get_vendor_and_language) ==
     94                                (kOurExceptionClass & get_vendor_and_language);
     95             if (native_exception)
     96                 __terminate(exception_header->terminateHandler);
     97         }
     98     }
     99     __terminate(get_terminate());
    100 }
    101 
    102 // In the future this will become:
    103 // std::atomic<std::new_handler>  __cxa_new_handler(0);
    104 extern "C" {
    105 new_handler __cxa_new_handler = 0;
    106 }
    107 
    108 new_handler
    109 set_new_handler(new_handler handler) _NOEXCEPT
    110 {
    111     return __atomic_exchange_n(&__cxa_new_handler, handler, __ATOMIC_ACQ_REL);
    112 //  Using of C++11 atomics this should be rewritten
    113 //  return __cxa_new_handler.exchange(handler, memory_order_acq_rel);
    114 }
    115 
    116 new_handler
    117 get_new_handler() _NOEXCEPT
    118 {
    119     return __sync_fetch_and_add(&__cxa_new_handler, (new_handler)0);
    120 //  The above is safe but overkill on x86
    121 //  Using of C++11 atomics this should be rewritten
    122 //  return __cxa_new_handler.load(memory_order_acq);
    123 }
    124 
    125 }  // std
    126