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