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) || defined(LIBCXX_BUILDING_LIBCXXABI) || __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 50 set_unexpected(unexpected_handler func) _NOEXCEPT 51 { 52 return __sync_lock_test_and_set(&__unexpected_handler, func); 53 } 54 55 unexpected_handler 56 get_unexpected() _NOEXCEPT 57 { 58 return __sync_fetch_and_add(&__unexpected_handler, (unexpected_handler)0); 59 } 60 61 _LIBCPP_NORETURN 62 void 63 unexpected() 64 { 65 (*get_unexpected())(); 66 // unexpected handler should not return 67 terminate(); 68 } 69 70 terminate_handler 71 set_terminate(terminate_handler func) _NOEXCEPT 72 { 73 return __sync_lock_test_and_set(&__terminate_handler, func); 74 } 75 76 terminate_handler 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 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 fprintf(stderr, "terminate_handler unexpectedly returned\n"); 94 ::abort(); 95 #ifndef _LIBCPP_NO_EXCEPTIONS 96 } 97 catch (...) 98 { 99 // handler should not throw exception 100 fprintf(stderr, "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__) 109 bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; } 110 111 int uncaught_exceptions() _NOEXCEPT 112 { 113 #if defined(__APPLE__) || defined(_LIBCPPABI_VERSION) 114 // on Darwin, there is a helper function so __cxa_get_globals is private 115 # if _LIBCPPABI_VERSION > 1101 116 return __cxa_uncaught_exceptions(); 117 # else 118 return __cxa_uncaught_exception() ? 1 : 0; 119 # endif 120 #else // __APPLE__ 121 # if defined(_MSC_VER) && ! defined(__clang__) 122 _LIBCPP_WARNING("uncaught_exceptions not yet implemented") 123 # else 124 # warning uncaught_exception not yet implemented 125 # endif 126 fprintf(stderr, "uncaught_exceptions not yet implemented\n"); 127 ::abort(); 128 #endif // __APPLE__ 129 } 130 131 132 #ifndef _LIBCPPABI_VERSION 133 134 exception::~exception() _NOEXCEPT 135 { 136 } 137 138 const char* exception::what() const _NOEXCEPT 139 { 140 return "std::exception"; 141 } 142 143 #endif // _LIBCPPABI_VERSION 144 #endif //LIBCXXRT 145 #if !defined(_LIBCPPABI_VERSION) && !defined(__GLIBCXX__) 146 147 bad_exception::~bad_exception() _NOEXCEPT 148 { 149 } 150 151 const char* bad_exception::what() const _NOEXCEPT 152 { 153 return "std::bad_exception"; 154 } 155 156 #endif 157 158 #if defined(__GLIBCXX__) 159 160 // libsupc++ does not implement the dependent EH ABI and the functionality 161 // it uses to implement std::exception_ptr (which it declares as an alias of 162 // std::__exception_ptr::exception_ptr) is not directly exported to clients. So 163 // we have little choice but to hijack std::__exception_ptr::exception_ptr's 164 // (which fortunately has the same layout as our std::exception_ptr) copy 165 // constructor, assignment operator and destructor (which are part of its 166 // stable ABI), and its rethrow_exception(std::__exception_ptr::exception_ptr) 167 // function. 168 169 namespace __exception_ptr 170 { 171 172 struct exception_ptr 173 { 174 void* __ptr_; 175 176 exception_ptr(const exception_ptr&) _NOEXCEPT; 177 exception_ptr& operator=(const exception_ptr&) _NOEXCEPT; 178 ~exception_ptr() _NOEXCEPT; 179 }; 180 181 } 182 183 _LIBCPP_NORETURN void rethrow_exception(__exception_ptr::exception_ptr); 184 185 #endif 186 187 exception_ptr::~exception_ptr() _NOEXCEPT 188 { 189 #if HAVE_DEPENDENT_EH_ABI 190 __cxa_decrement_exception_refcount(__ptr_); 191 #elif defined(__GLIBCXX__) 192 reinterpret_cast<__exception_ptr::exception_ptr*>(this)->~exception_ptr(); 193 #else 194 # if defined(_MSC_VER) && ! defined(__clang__) 195 _LIBCPP_WARNING("exception_ptr not yet implemented") 196 # else 197 # warning exception_ptr not yet implemented 198 # endif 199 fprintf(stderr, "exception_ptr not yet implemented\n"); 200 ::abort(); 201 #endif 202 } 203 204 exception_ptr::exception_ptr(const exception_ptr& other) _NOEXCEPT 205 : __ptr_(other.__ptr_) 206 { 207 #if HAVE_DEPENDENT_EH_ABI 208 __cxa_increment_exception_refcount(__ptr_); 209 #elif defined(__GLIBCXX__) 210 new (reinterpret_cast<void*>(this)) __exception_ptr::exception_ptr( 211 reinterpret_cast<const __exception_ptr::exception_ptr&>(other)); 212 #else 213 # if defined(_MSC_VER) && ! defined(__clang__) 214 _LIBCPP_WARNING("exception_ptr not yet implemented") 215 # else 216 # warning exception_ptr not yet implemented 217 # endif 218 fprintf(stderr, "exception_ptr not yet implemented\n"); 219 ::abort(); 220 #endif 221 } 222 223 exception_ptr& exception_ptr::operator=(const exception_ptr& other) _NOEXCEPT 224 { 225 #if HAVE_DEPENDENT_EH_ABI 226 if (__ptr_ != other.__ptr_) 227 { 228 __cxa_increment_exception_refcount(other.__ptr_); 229 __cxa_decrement_exception_refcount(__ptr_); 230 __ptr_ = other.__ptr_; 231 } 232 return *this; 233 #elif defined(__GLIBCXX__) 234 *reinterpret_cast<__exception_ptr::exception_ptr*>(this) = 235 reinterpret_cast<const __exception_ptr::exception_ptr&>(other); 236 return *this; 237 #else 238 # if defined(_MSC_VER) && ! defined(__clang__) 239 _LIBCPP_WARNING("exception_ptr not yet implemented") 240 # else 241 # warning exception_ptr not yet implemented 242 # endif 243 fprintf(stderr, "exception_ptr not yet implemented\n"); 244 ::abort(); 245 #endif 246 } 247 248 nested_exception::nested_exception() _NOEXCEPT 249 : __ptr_(current_exception()) 250 { 251 } 252 253 #if !defined(__GLIBCXX__) 254 255 nested_exception::~nested_exception() _NOEXCEPT 256 { 257 } 258 259 #endif 260 261 _LIBCPP_NORETURN 262 void 263 nested_exception::rethrow_nested() const 264 { 265 if (__ptr_ == nullptr) 266 terminate(); 267 rethrow_exception(__ptr_); 268 } 269 270 #if !defined(__GLIBCXX__) 271 272 exception_ptr current_exception() _NOEXCEPT 273 { 274 #if HAVE_DEPENDENT_EH_ABI 275 // be nicer if there was a constructor that took a ptr, then 276 // this whole function would be just: 277 // return exception_ptr(__cxa_current_primary_exception()); 278 exception_ptr ptr; 279 ptr.__ptr_ = __cxa_current_primary_exception(); 280 return ptr; 281 #else 282 # if defined(_MSC_VER) && ! defined(__clang__) 283 _LIBCPP_WARNING( "exception_ptr not yet implemented" ) 284 # else 285 # warning exception_ptr not yet implemented 286 # endif 287 fprintf(stderr, "exception_ptr not yet implemented\n"); 288 ::abort(); 289 #endif 290 } 291 292 #endif // !__GLIBCXX__ 293 294 _LIBCPP_NORETURN 295 void rethrow_exception(exception_ptr p) 296 { 297 #if HAVE_DEPENDENT_EH_ABI 298 __cxa_rethrow_primary_exception(p.__ptr_); 299 // if p.__ptr_ is NULL, above returns so we terminate 300 terminate(); 301 #elif defined(__GLIBCXX__) 302 rethrow_exception(reinterpret_cast<__exception_ptr::exception_ptr&>(p)); 303 #else 304 # if defined(_MSC_VER) && ! defined(__clang__) 305 _LIBCPP_WARNING("exception_ptr not yet implemented") 306 # else 307 # warning exception_ptr not yet implemented 308 # endif 309 fprintf(stderr, "exception_ptr not yet implemented\n"); 310 ::abort(); 311 #endif 312 } 313 } // std 314