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