cxa_exception.cpp revision dd47ca4f1c0252fbdfd1d6338eaac9c42cade3b8
1//===------------------------- cxa_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// This file implements the "Exception Handling APIs" 10// http://www.codesourcery.com/public/cxx-abi/abi-eh.html 11// 12//===----------------------------------------------------------------------===// 13 14#include "cxxabi.h" 15 16#include <exception> // for std::terminate 17#include <cstdlib> // for malloc, free 18#include <string> // for memset 19#include <pthread.h> 20 21#include "cxa_exception.hpp" 22#include "cxa_handlers.hpp" 23 24namespace __cxxabiv1 { 25static const uint64_t kOurExceptionClass = 0x434C4E47432B2B00; // CLNGC++\0 26static const uint64_t kOurDependentExceptionClass = 0x434C4E47432B2B01; // CLNGC++\1 27 28// Utility routines 29static inline __cxa_exception *exception_from_thrown_object(void *p) throw() { 30 return ((__cxa_exception *) p) - 1; 31} 32 33static inline void * thrown_object_from_exception(void *p) throw() { 34 return (void *) (((__cxa_exception *) p) + 1 ); 35} 36 37static inline size_t object_size_from_exception_size(size_t size) throw() { 38 return size + sizeof (__cxa_exception); 39} 40 41// Get the exception object from the unwind pointer. 42// Relies on the structure layout, where the unwind pointer is right in 43// front of the user's exception object 44static __cxa_exception * 45exception_from_exception_object(void *ptr) throw() { 46 _Unwind_Exception *p = reinterpret_cast<_Unwind_Exception *>(ptr); 47 return exception_from_thrown_object(p + 1 ); 48} 49 50static void setExceptionClass(_Unwind_Exception *unwind) throw() { 51 unwind->exception_class = kOurExceptionClass; 52} 53 54static void setDependentExceptionClass(_Unwind_Exception *unwind) throw() { 55 unwind->exception_class = kOurDependentExceptionClass; 56} 57 58// Is it one of ours? 59static bool isOurExceptionClass(_Unwind_Exception *unwind) throw() { 60 return(unwind->exception_class == kOurExceptionClass)|| 61 (unwind->exception_class == kOurDependentExceptionClass); 62} 63 64static bool isDependentException(_Unwind_Exception *unwind) throw() { 65 return (unwind->exception_class & 0xFF) == 0x01; 66} 67 68// This does not need to be atomic 69static inline int incrementHandlerCount(__cxa_exception *exception) throw() { 70 return ++exception->handlerCount; 71} 72 73// This does not need to be atomic 74static inline int decrementHandlerCount(__cxa_exception *exception) throw() { 75 return --exception->handlerCount; 76} 77 78#include "fallback_malloc.cpp" 79 80// Allocate some memory from _somewhere_ 81static void *do_malloc(size_t size) throw() { 82 void *ptr = std::malloc(size); 83 if (NULL == ptr) // if malloc fails, fall back to emergency stash 84 ptr = fallback_malloc(size); 85 return ptr; 86} 87 88// Didn't know you could "return <expression>" from a void function, did you? 89// Well, you can, if the type of the expression is "void" also. 90static void do_free(void *ptr) throw() { 91 return is_fallback_ptr(ptr) ? fallback_free(ptr) : std::free(ptr); 92} 93 94/* 95 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler 96 stored in exc is called. Otherwise the exceptionDestructor stored in 97 exc is called, and then the memory for the exception is deallocated. 98*/ 99static void exception_cleanup_func(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc) { 100 __cxa_exception *exception = exception_from_exception_object(exc); 101 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) 102 std::__terminate(exception->terminateHandler); 103 104 void * thrown_object = thrown_object_from_exception(exception); 105 if (NULL != exception->exceptionDestructor) 106 exception->exceptionDestructor(thrown_object); 107 __cxa_free_exception(thrown_object); 108} 109 110static LIBCXXABI_NORETURN void failed_throw(__cxa_exception *exception) throw() { 111// Section 2.5.3 says: 112// * For purposes of this ABI, several things are considered exception handlers: 113// ** A terminate() call due to a throw. 114// and 115// * Upon entry, Following initialization of the catch parameter, 116// a handler must call: 117// * void *__cxa_begin_catch(void *exceptionObject ); 118 (void) __cxa_begin_catch(&exception->unwindHeader); 119 std::__terminate(exception->terminateHandler); 120} 121 122extern "C" { 123 124// Allocate a __cxa_exception object, and zero-fill it. 125// Reserve "thrown_size" bytes on the end for the user's exception 126// object. Zero-fill the object. If memory can't be allocated, call 127// std::terminate. Return a pointer to the memory to be used for the 128// user's exception object. 129void * __cxa_allocate_exception (size_t thrown_size) throw() { 130 size_t actual_size = object_size_from_exception_size(thrown_size); 131 void *ptr = do_malloc(actual_size); 132 if (NULL == ptr) 133 std::terminate(); 134 std::memset(ptr, 0, actual_size); 135 return thrown_object_from_exception(ptr); 136} 137 138 139// Free a __cxa_exception object allocated with __cxa_allocate_exception. 140void __cxa_free_exception (void * thrown_exception) throw() { 141 do_free(exception_from_thrown_object(thrown_exception)); 142} 143 144 145// This function shall allocate a __cxa_dependent_exception and 146// return a pointer to it. (Really to the object, not past its' end). 147// Otherwise, it will work like __cxa_allocate_exception. 148void * __cxa_allocate_dependent_exception () throw() { 149 size_t actual_size = sizeof(__cxa_dependent_exception); 150 void *ptr = do_malloc(actual_size); 151 if (NULL == ptr) 152 std::terminate(); 153 std::memset(ptr, 0, actual_size); 154 return ptr; 155} 156 157 158// This function shall free a dependent_exception. 159// It does not affect the reference count of the primary exception. 160void __cxa_free_dependent_exception (void * dependent_exception) throw() { 161 do_free(dependent_exception); 162} 163 164 165// 2.4.3 Throwing the Exception Object 166/* 167After constructing the exception object with the throw argument value, 168the generated code calls the __cxa_throw runtime library routine. This 169routine never returns. 170 171The __cxa_throw routine will do the following: 172 173* Obtain the __cxa_exception header from the thrown exception object address, 174which can be computed as follows: 175 __cxa_exception *header = ((__cxa_exception *) thrown_exception - 1); 176* Save the current unexpected_handler and terminate_handler in the __cxa_exception header. 177* Save the tinfo and dest arguments in the __cxa_exception header. 178* Set the exception_class field in the unwind header. This is a 64-bit value 179representing the ASCII string "XXXXC++\0", where "XXXX" is a 180vendor-dependent string. That is, for implementations conforming to this 181ABI, the low-order 4 bytes of this 64-bit value will be "C++\0". 182* Increment the uncaught_exception flag. 183* Call _Unwind_RaiseException in the system unwind library, Its argument is the 184pointer to the thrown exception, which __cxa_throw itself received as an argument. 185__Unwind_RaiseException begins the process of stack unwinding, described 186in Section 2.5. In special cases, such as an inability to find a 187handler, _Unwind_RaiseException may return. In that case, __cxa_throw 188will call terminate, assuming that there was no handler for the 189exception. 190*/ 191LIBCXXABI_NORETURN void 192__cxa_throw(void * thrown_exception, std::type_info * tinfo, void (*dest)(void *)) { 193 __cxa_eh_globals *globals = __cxa_get_globals(); 194 __cxa_exception *exception = exception_from_thrown_object(thrown_exception); 195 196 exception->unexpectedHandler = std::get_unexpected(); 197 exception->terminateHandler = std::get_terminate(); 198 exception->exceptionType = tinfo; 199 exception->exceptionDestructor = dest; 200 setExceptionClass(&exception->unwindHeader); 201 exception->referenceCount = 1; // This is a newly allocated exception, no need for thread safety. 202 globals->uncaughtExceptions += 1; // Not atomically, since globals are thread-local 203 204 exception->unwindHeader.exception_cleanup = exception_cleanup_func; 205#if __arm__ 206 _Unwind_SjLj_RaiseException(&exception->unwindHeader); 207#else 208 _Unwind_RaiseException(&exception->unwindHeader); 209#endif 210// If we get here, some kind of unwinding error has occurred. 211 failed_throw(exception); 212} 213 214 215// 2.5.3 Exception Handlers 216extern void * __cxa_get_exception_ptr(void * exceptionObject) throw() { 217 return exception_from_exception_object(exceptionObject); 218} 219 220 221/* 222This routine: 223* Increment's the exception's handler count. 224* Places the exception on the stack of currently-caught exceptions if it is not 225 already there, linking the exception to the previous top of the stack. 226* Decrements the uncaught_exception count. 227* Returns the adjusted pointer to the exception object. 228*/ 229void * __cxa_begin_catch(void * exceptionObject) throw() { 230 __cxa_eh_globals *globals = __cxa_get_globals(); 231 __cxa_exception *exception = exception_from_exception_object(exceptionObject); 232 233// TODO: Handle foreign exceptions? How? 234 235// Increment the handler count, removing the flag about being rethrown 236 exception->handlerCount = exception->handlerCount < 0 ? 237 -exception->handlerCount + 1 : exception->handlerCount + 1; 238 239// place the exception on the top of the stack if it's not there. 240 if (exception != globals->caughtExceptions) { 241 exception->nextException = globals->caughtExceptions; 242 globals->caughtExceptions = exception; 243 } 244 245 globals->uncaughtExceptions -= 1; // Not atomically, since globals are thread-local 246 return thrown_object_from_exception(exception); 247} 248 249 250/* 251Upon exit for any reason, a handler must call: 252 void __cxa_end_catch (); 253 254This routine: 255* Locates the most recently caught exception and decrements its handler count. 256* Removes the exception from the caught exception stack, if the handler count goes to zero. 257* If the handler count goes down to zero, and the exception was not re-thrown 258 by throw, it locates the primary exception (which may be the same as the one 259 it's handling) and decrements its reference count. If that reference count 260 goes to zero, the function destroys the exception. In any case, if the current 261 exception is a dependent exception, it destroys that. 262*/ 263void __cxa_end_catch() { 264 __cxa_eh_globals *globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch 265 __cxa_exception *current_exception = globals->caughtExceptions; 266 267 if (NULL != current_exception) { 268 // TODO: Handle foreign exceptions? How? 269 if (current_exception->handlerCount < 0) { 270 // The exception has been rethrown 271 if (0 == incrementHandlerCount(current_exception)) { 272 // Remove from the chain of uncaught exceptions 273 globals->caughtExceptions = current_exception->nextException; 274 // but don't destroy 275 } 276 } 277 else { // The exception has not been rethrown 278 if (0 == decrementHandlerCount(current_exception)) { 279 // Remove from the chain of uncaught exceptions 280 globals->caughtExceptions = current_exception->nextException; 281 if (isDependentException(¤t_exception->unwindHeader)) { 282 // Reset current_exception to primaryException and deallocate the dependent exception 283 __cxa_dependent_exception* deh = 284 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1; 285 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1; 286 __cxa_free_dependent_exception(deh); 287 } 288 // Destroy the primary exception only if its referenceCount goes to 0 289 // (this decrement must be atomic) 290 __cxa_decrement_exception_refcount(thrown_object_from_exception(current_exception)); 291 } 292 } 293 } 294} 295 296 297std::type_info * __cxa_current_exception_type() { 298// get the current exception 299 __cxa_eh_globals *globals = __cxa_get_globals(); 300 __cxa_exception *current_exception = globals->caughtExceptions; 301 if (NULL == current_exception) 302 return NULL; // No current exception 303 if (isDependentException(¤t_exception->unwindHeader)) { 304 __cxa_dependent_exception* deh = 305 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1; 306 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1; 307 } 308 return current_exception->exceptionType; 309} 310 311// 2.5.4 Rethrowing Exceptions 312/* This routine 313* marks the exception object on top of the caughtExceptions stack 314 (in an implementation-defined way) as being rethrown. 315* If the caughtExceptions stack is empty, it calls terminate() 316 (see [C++FDIS] [except.throw], 15.1.8). 317* It then calls _Unwind_Resume_or_Rethrow which should not return 318 (terminate if it does). 319*/ 320extern LIBCXXABI_NORETURN void __cxa_rethrow() { 321 __cxa_eh_globals *globals = __cxa_get_globals(); 322 __cxa_exception *exception = globals->caughtExceptions; 323 324 if (NULL == exception) // there's no current exception! 325 std::terminate (); 326 327// TODO: Handle foreign exceptions? How? 328 329// Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch) 330 exception->handlerCount = -exception->handlerCount; 331 globals->uncaughtExceptions += 1; 332// __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary 333 334#if __arm__ 335 (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader); 336#else 337 (void) _Unwind_Resume_or_Rethrow (&exception->unwindHeader); 338#endif 339 340// If we get here, some kind of unwinding error has occurred. 341 failed_throw(exception); 342} 343 344/* 345 If p is not null, atomically increment the referenceCount field of the 346 __cxa_exception header associated with the thrown object referred to by p. 347*/ 348void 349__cxa_increment_exception_refcount(void* p) throw() 350{ 351 if (p != NULL ) 352 { 353 __cxa_exception* header = exception_from_thrown_object(p); 354 __sync_add_and_fetch(&header->referenceCount, 1); 355 } 356} 357 358/* 359 If p is not null, atomically decrement the referenceCount field of the 360 __cxa_exception header associated with the thrown object referred to by p. 361 If the referenceCount drops to zero, destroy and deallocate the exception. 362*/ 363void 364__cxa_decrement_exception_refcount(void* thrown_object) throw() 365{ 366 if (thrown_object != NULL ) 367 { 368 __cxa_exception* header = exception_from_thrown_object(thrown_object); 369 if (__sync_sub_and_fetch(&header->referenceCount, size_t(1)) == 0) 370 { 371 if (NULL != header->exceptionDestructor) 372 header->exceptionDestructor(thrown_object); 373 __cxa_free_exception(thrown_object); 374 } 375 } 376} 377 378/* 379 Returns a pointer to the thrown object (if any) at the top of the 380 caughtExceptions stack. Atommically increment the exception's referenceCount. 381 If there is no such thrown object, returns null. 382*/ 383void* 384__cxa_current_primary_exception() throw() 385{ 386// get the current exception 387 __cxa_eh_globals* globals = __cxa_get_globals(); 388 __cxa_exception* current_exception = globals->caughtExceptions; 389 if (NULL == current_exception) 390 return NULL; // No current exception 391 if (isDependentException(¤t_exception->unwindHeader)) { 392 __cxa_dependent_exception* deh = 393 reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1; 394 current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1; 395 } 396 void* thrown_object = thrown_object_from_exception(current_exception); 397 __cxa_increment_exception_refcount(thrown_object); 398 return thrown_object; 399} 400 401/* 402 If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler 403 stored in exc is called. Otherwise the referenceCount stored in the 404 primary exception is decremented, destroying the primary if necessary. 405 Finally the dependent exception is destroyed. 406*/ 407static 408void 409dependent_exception_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc) 410{ 411 __cxa_dependent_exception* deh = 412 reinterpret_cast<__cxa_dependent_exception*>(exc + 1) - 1; 413 if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason) 414 std::__terminate(deh->terminateHandler); 415 __cxa_decrement_exception_refcount(deh->primaryException); 416 __cxa_free_dependent_exception(deh); 417} 418 419/* 420 If thrown_object is not null, allocate, initialize and thow a dependent 421 exception. 422*/ 423void 424__cxa_rethrow_primary_exception(void* thrown_object) 425{ 426 if ( thrown_object != NULL ) 427 { 428 __cxa_exception* header = exception_from_thrown_object(thrown_object); 429 __cxa_dependent_exception* deh = 430 (__cxa_dependent_exception*)__cxa_allocate_dependent_exception(); 431 deh->primaryException = thrown_object; 432 __cxa_increment_exception_refcount(thrown_object); 433 deh->exceptionType = header->exceptionType; 434 deh->unexpectedHandler = std::get_unexpected(); 435 deh->terminateHandler = std::get_terminate(); 436 setDependentExceptionClass(&deh->unwindHeader); 437 __cxa_get_globals()->uncaughtExceptions += 1; 438 deh->unwindHeader.exception_cleanup = dependent_exception_cleanup; 439#if __arm__ 440 _Unwind_SjLj_RaiseException(&deh->unwindHeader); 441#else 442 _Unwind_RaiseException(&deh->unwindHeader); 443#endif 444 // Some sort of unwinding error. Note that terminate is a handler. 445 __cxa_begin_catch(&deh->unwindHeader); 446 } 447 // If we return client will call terminate() 448} 449 450} // extern "C" 451 452} // abi 453