Home | History | Annotate | Download | only in src
      1 //===------------------------ exception.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 #include <stdlib.h>
     10 #include <stdio.h>
     11 
     12 #include "exception"
     13 #include "new"
     14 
     15 #if defined(__APPLE__) && !defined(LIBCXXRT)
     16   #include <cxxabi.h>
     17 
     18   using namespace __cxxabiv1;
     19   #define HAVE_DEPENDENT_EH_ABI 1
     20   #ifndef _LIBCPPABI_VERSION
     21     using namespace __cxxabiapple;
     22     // On Darwin, there are two STL shared libraries and a lower level ABI
     23     // shared library.  The globals holding the current terminate handler and
     24     // current unexpected handler are in the ABI library.
     25     #define __terminate_handler  __cxxabiapple::__cxa_terminate_handler
     26     #define __unexpected_handler __cxxabiapple::__cxa_unexpected_handler
     27   #endif  // _LIBCPPABI_VERSION
     28 #elif defined(LIBCXXRT) || defined(LIBCXX_BUILDING_LIBCXXABI)
     29   #include <cxxabi.h>
     30   using namespace __cxxabiv1;
     31   #if defined(LIBCXXRT) || defined(_LIBCPPABI_VERSION)
     32     #define HAVE_DEPENDENT_EH_ABI 1
     33   #endif
     34 #elif !defined(__GLIBCXX__) // defined(LIBCXX_BUILDING_LIBCXXABI)
     35   static std::terminate_handler  __terminate_handler;
     36   static std::unexpected_handler __unexpected_handler;
     37 #endif // defined(LIBCXX_BUILDING_LIBCXXABI)
     38 
     39 namespace std
     40 {
     41 
     42 #if !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
     43 
     44 // libcxxrt provides implementations of these functions itself.
     45 unexpected_handler
     46 set_unexpected(unexpected_handler func) _NOEXCEPT
     47 {
     48     return __sync_lock_test_and_set(&__unexpected_handler, func);
     49 }
     50 
     51 unexpected_handler
     52 get_unexpected() _NOEXCEPT
     53 {
     54     return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0);
     55 }
     56 
     57 _LIBCPP_NORETURN
     58 void
     59 unexpected()
     60 {
     61     (*get_unexpected())();
     62     // unexpected handler should not return
     63     terminate();
     64 }
     65 
     66 terminate_handler
     67 set_terminate(terminate_handler func) _NOEXCEPT
     68 {
     69     return __sync_lock_test_and_set(&__terminate_handler, func);
     70 }
     71 
     72 terminate_handler
     73 get_terminate() _NOEXCEPT
     74 {
     75     return __sync_fetch_and_add(&__terminate_handler, (terminate_handler)0);
     76 }
     77 
     78 #ifndef __EMSCRIPTEN__ // We provide this in JS
     79 _LIBCPP_NORETURN
     80 void
     81 terminate() _NOEXCEPT
     82 {
     83 #ifndef _LIBCPP_NO_EXCEPTIONS
     84     try
     85     {
     86 #endif  // _LIBCPP_NO_EXCEPTIONS
     87         (*get_terminate())();
     88         // handler should not return
     89         fprintf(stderr, "terminate_handler unexpectedly returned\n");
     90         ::abort();
     91 #ifndef _LIBCPP_NO_EXCEPTIONS
     92     }
     93     catch (...)
     94     {
     95         // handler should not throw exception
     96         fprintf(stderr, "terminate_handler unexpectedly threw an exception\n");
     97         ::abort();
     98     }
     99 #endif  // _LIBCPP_NO_EXCEPTIONS
    100 }
    101 #endif // !__EMSCRIPTEN__
    102 #endif // !defined(LIBCXXRT) && !defined(_LIBCPPABI_VERSION)
    103 
    104 #if !defined(LIBCXXRT) && !defined(__GLIBCXX__) && !defined(__EMSCRIPTEN__)
    105 bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; }
    106 
    107 int uncaught_exceptions() _NOEXCEPT
    108 {
    109 #if defined(__APPLE__) || defined(_LIBCPPABI_VERSION)
    110    // on Darwin, there is a helper function so __cxa_get_globals is private
    111 # if _LIBCPPABI_VERSION > 1101
    112     return __cxa_uncaught_exceptions();
    113 # else
    114     return __cxa_uncaught_exception() ? 1 : 0;
    115 # endif
    116 #else  // __APPLE__
    117 #   if defined(_MSC_VER) && ! defined(__clang__)
    118         _LIBCPP_WARNING("uncaught_exceptions not yet implemented")
    119 #   else
    120 #       warning uncaught_exception not yet implemented
    121 #   endif
    122     fprintf(stderr, "uncaught_exceptions not yet implemented\n");
    123     ::abort();
    124 #endif  // __APPLE__
    125 }
    126 
    127 
    128 #ifndef _LIBCPPABI_VERSION
    129 
    130 exception::~exception() _NOEXCEPT
    131 {
    132 }
    133 
    134 const char* exception::what() const _NOEXCEPT
    135 {
    136   return "std::exception";
    137 }
    138 
    139 #endif  // _LIBCPPABI_VERSION
    140 #endif //LIBCXXRT
    141 #if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__)
    142 
    143 bad_exception::~bad_exception() _NOEXCEPT
    144 {
    145 }
    146 
    147 const char* bad_exception::what() const _NOEXCEPT
    148 {
    149   return "std::bad_exception";
    150 }
    151 
    152 #endif
    153 
    154 #if defined(__GLIBCXX__)
    155 
    156 // libsupc++ does not implement the dependent EH ABI and the functionality
    157 // it uses to implement std::exception_ptr (which it declares as an alias of
    158 // std::__exception_ptr::exception_ptr) is not directly exported to clients. So
    159 // we have little choice but to hijack std::__exception_ptr::exception_ptr's
    160 // (which fortunately has the same layout as our std::exception_ptr) copy
    161 // constructor, assignment operator and destructor (which are part of its
    162 // stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr)
    163 // function.
    164 
    165 namespace __exception_ptr
    166 {
    167 
    168 struct exception_ptr
    169 {
    170     void* __ptr_;
    171 
    172     exception_ptr(const exception_ptr&) _NOEXCEPT;
    173     exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
    174     ~exception_ptr() _NOEXCEPT;
    175 };
    176 
    177 }
    178 
    179 _LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr);
    180 
    181 #endif
    182 
    183 exception_ptr::~exception_ptr() _NOEXCEPT
    184 {
    185 #if HAVE_DEPENDENT_EH_ABI
    186     __cxa_decrement_exception_refcount(__ptr_);
    187 #elif defined(__GLIBCXX__)
    188     reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr();
    189 #else
    190 #   if defined(_MSC_VER) && ! defined(__clang__)
    191         _LIBCPP_WARNING("exception_ptr not yet implemented")
    192 #   else
    193 #       warning exception_ptr not yet implemented
    194 #   endif
    195     fprintf(stderr, "exception_ptr not yet implemented\n");
    196     ::abort();
    197 #endif
    198 }
    199 
    200 exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT
    201     : __ptr_(other.__ptr_)
    202 {
    203 #if HAVE_DEPENDENT_EH_ABI
    204     __cxa_increment_exception_refcount(__ptr_);
    205 #elif defined(__GLIBCXX__)
    206     new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr(
    207         reinterpret_cast<const __exception_ptr::exception_ptr&>(other));
    208 #else
    209 #   if defined(_MSC_VER) && ! defined(__clang__)
    210         _LIBCPP_WARNING("exception_ptr not yet implemented")
    211 #   else
    212 #       warning exception_ptr not yet implemented
    213 #   endif
    214     fprintf(stderr, "exception_ptr not yet implemented\n");
    215     ::abort();
    216 #endif
    217 }
    218 
    219 exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT
    220 {
    221 #if HAVE_DEPENDENT_EH_ABI
    222     if (__ptr_ != other.__ptr_)
    223     {
    224         __cxa_increment_exception_refcount(other.__ptr_);
    225         __cxa_decrement_exception_refcount(__ptr_);
    226         __ptr_ = other.__ptr_;
    227     }
    228     return *this;
    229 #elif defined(__GLIBCXX__)
    230     *reinterpret_cast<__exception_ptr::exception_ptr*>(this) =
    231         reinterpret_cast<const __exception_ptr::exception_ptr&>(other);
    232     return *this;
    233 #else
    234 #   if defined(_MSC_VER) && ! defined(__clang__)
    235         _LIBCPP_WARNING("exception_ptr not yet implemented")
    236 #   else
    237 #       warning exception_ptr not yet implemented
    238 #   endif
    239     fprintf(stderr, "exception_ptr not yet implemented\n");
    240     ::abort();
    241 #endif
    242 }
    243 
    244 nested_exception::nested_exception() _NOEXCEPT
    245     : __ptr_(current_exception())
    246 {
    247 }
    248 
    249 #if !defined(__GLIBCXX__)
    250 
    251 nested_exception::~nested_exception() _NOEXCEPT
    252 {
    253 }
    254 
    255 #endif
    256 
    257 _LIBCPP_NORETURN
    258 void
    259 nested_exception::rethrow_nested() const
    260 {
    261     if (__ptr_ == nullptr)
    262         terminate();
    263     rethrow_exception(__ptr_);
    264 }
    265 
    266 #if !defined(__GLIBCXX__)
    267 
    268 exception_ptr current_exception() _NOEXCEPT
    269 {
    270 #if HAVE_DEPENDENT_EH_ABI
    271     // be nicer if there was a constructor that took a ptr, then
    272     // this whole function would be just:
    273     //    return exception_ptr(__cxa_current_primary_exception());
    274     exception_ptr ptr;
    275     ptr.__ptr_ = __cxa_current_primary_exception();
    276     return ptr;
    277 #else
    278 #   if defined(_MSC_VER) && ! defined(__clang__)
    279         _LIBCPP_WARNING( "exception_ptr not yet implemented" )
    280 #   else
    281 #       warning exception_ptr not yet implemented
    282 #   endif
    283     fprintf(stderr, "exception_ptr not yet implemented\n");
    284     ::abort();
    285 #endif
    286 }
    287 
    288 #endif  // !__GLIBCXX__
    289 
    290 _LIBCPP_NORETURN
    291 void rethrow_exception(exception_ptr p)
    292 {
    293 #if HAVE_DEPENDENT_EH_ABI
    294     __cxa_rethrow_primary_exception(p.__ptr_);
    295     // if p.__ptr_ is NULL, above returns so we terminate
    296     terminate();
    297 #elif defined(__GLIBCXX__)
    298     rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p));
    299 #else
    300 #   if defined(_MSC_VER) && ! defined(__clang__)
    301         _LIBCPP_WARNING("exception_ptr not yet implemented")
    302 #   else
    303 #       warning exception_ptr not yet implemented
    304 #   endif
    305     fprintf(stderr, "exception_ptr not yet implemented\n");
    306     ::abort();
    307 #endif
    308 }
    309 } // std
    310