cxa_exception.cpp revision 8ca7603d21b85b03a57d703feb9e8e8bcd6dcfd0
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//    TODO:  This must return the *adjusted* pointer to the exception object.
218    return exception_from_exception_object(exceptionObject);
219}
220
221
222/*
223This routine:
224* Increment's the exception's handler count.
225* Places the exception on the stack of currently-caught exceptions if it is not
226  already there, linking the exception to the previous top of the stack.
227* Decrements the uncaught_exception count.
228* Returns the adjusted pointer to the exception object.
229*/
230void * __cxa_begin_catch(void * exceptionObject) throw() {
231    __cxa_eh_globals *globals = __cxa_get_globals();
232    __cxa_exception *exception = exception_from_exception_object(exceptionObject);
233
234// TODO:  Handle foreign exceptions?  How?
235
236//  Increment the handler count, removing the flag about being rethrown
237    exception->handlerCount = exception->handlerCount < 0 ?
238        -exception->handlerCount + 1 : exception->handlerCount + 1;
239
240//  place the exception on the top of the stack if it's not there.
241    if (exception != globals->caughtExceptions) {
242        exception->nextException = globals->caughtExceptions;
243        globals->caughtExceptions = exception;
244    }
245
246    globals->uncaughtExceptions -= 1;   // Not atomically, since globals are thread-local
247    return __cxa_get_exception_ptr(exceptionObject);
248}
249
250
251/*
252Upon exit for any reason, a handler must call:
253    void __cxa_end_catch ();
254
255This routine:
256* Locates the most recently caught exception and decrements its handler count.
257* Removes the exception from the caught exception stack, if the handler count goes to zero.
258* If the handler count goes down to zero, and the exception was not re-thrown
259  by throw, it locates the primary exception (which may be the same as the one
260  it's handling) and decrements its reference count. If that reference count
261  goes to zero, the function destroys the exception. In any case, if the current
262  exception is a dependent exception, it destroys that.
263*/
264void __cxa_end_catch() {
265    __cxa_eh_globals *globals = __cxa_get_globals_fast(); // __cxa_get_globals called in __cxa_begin_catch
266    __cxa_exception *current_exception = globals->caughtExceptions;
267
268    if (NULL != current_exception) {
269        // TODO:  Handle foreign exceptions?  How?
270        if (current_exception->handlerCount < 0) {
271        //  The exception has been rethrown
272            if (0 == incrementHandlerCount(current_exception)) {
273                //  Remove from the chain of uncaught exceptions
274                globals->caughtExceptions = current_exception->nextException;
275                // but don't destroy
276            }
277        }
278        else {  // The exception has not been rethrown
279            if (0 == decrementHandlerCount(current_exception)) {
280                //  Remove from the chain of uncaught exceptions
281                globals->caughtExceptions = current_exception->nextException;
282                if (isDependentException(&current_exception->unwindHeader)) {
283                    // Reset current_exception to primaryException and deallocate the dependent exception
284                    __cxa_dependent_exception* deh =
285                        reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1;
286                    current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1;
287                    __cxa_free_dependent_exception(deh);
288                }
289                // Destroy the primary exception only if its referenceCount goes to 0
290                //    (this decrement must be atomic)
291                __cxa_decrement_exception_refcount(thrown_object_from_exception(current_exception));
292            }
293        }
294    }
295}
296
297
298std::type_info * __cxa_current_exception_type() {
299// FIXME:  I don't think we need to drill down into __cxa_dependent_exception
300//         because the exceptionType is replicated in the __cxa_dependent_exception
301//  get the current exception
302    __cxa_eh_globals *globals = __cxa_get_globals_fast();
303    if (NULL == globals)
304        return NULL;     //  If there have never been any exceptions, there are none now.
305    __cxa_exception *current_exception = globals->caughtExceptions;
306    if (NULL == current_exception)
307        return NULL;        //  No current exception
308    if (isDependentException(&current_exception->unwindHeader)) {
309        __cxa_dependent_exception* deh =
310            reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1;
311        current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1;
312    }
313    return current_exception->exceptionType;
314}
315
316// 2.5.4 Rethrowing Exceptions
317/*  This routine
318* marks the exception object on top of the caughtExceptions stack
319  (in an implementation-defined way) as being rethrown.
320* If the caughtExceptions stack is empty, it calls terminate()
321  (see [C++FDIS] [except.throw], 15.1.8).
322* It then calls _Unwind_Resume_or_Rethrow which should not return
323   (terminate if it does).
324*/
325extern LIBCXXABI_NORETURN void __cxa_rethrow() {
326    __cxa_eh_globals *globals = __cxa_get_globals();
327    __cxa_exception *exception = globals->caughtExceptions;
328
329    if (NULL == exception)   // there's no current exception!
330        std::terminate ();
331
332// TODO:  Handle foreign exceptions?  How?
333
334//  Mark the exception as being rethrown (reverse the effects of __cxa_begin_catch)
335    exception->handlerCount = -exception->handlerCount;
336    globals->uncaughtExceptions += 1;
337//  __cxa_end_catch will remove this exception from the caughtExceptions stack if necessary
338
339#if __arm__
340    (void) _Unwind_SjLj_Resume_or_Rethrow(&exception->unwindHeader);
341#else
342    (void) _Unwind_Resume_or_Rethrow     (&exception->unwindHeader);
343#endif
344
345//  If we get here, some kind of unwinding error has occurred.
346    failed_throw(exception);
347}
348
349/*
350    If p is not null, atomically increment the referenceCount field of the
351    __cxa_exception header associated with the thrown object referred to by p.
352*/
353void
354__cxa_increment_exception_refcount(void* p) throw()
355{
356    if (p != NULL )
357    {
358        __cxa_exception* header = exception_from_thrown_object(p);
359        __sync_add_and_fetch(&header->referenceCount, 1);
360    }
361}
362
363/*
364    If p is not null, atomically decrement the referenceCount field of the
365    __cxa_exception header associated with the thrown object referred to by p.
366    If the referenceCount drops to zero, destroy and deallocate the exception.
367*/
368void
369__cxa_decrement_exception_refcount(void* thrown_object) throw()
370{
371    if (thrown_object != NULL )
372    {
373        __cxa_exception* header = exception_from_thrown_object(thrown_object);
374        if (__sync_sub_and_fetch(&header->referenceCount, size_t(1)) == 0)
375        {
376            if (NULL != header->exceptionDestructor)
377                header->exceptionDestructor(thrown_object);
378            __cxa_free_exception(thrown_object);
379        }
380    }
381}
382
383/*
384    Returns a pointer to the thrown object (if any) at the top of the
385    caughtExceptions stack.  Atommically increment the exception's referenceCount.
386    If there is no such thrown object, returns null.
387
388    We can use __cxa_get_globals_fast here to get the globals because if there have
389    been no exceptions thrown, ever, on this thread, we can return NULL without
390    the need to allocate the exception-handling globals.
391*/
392void*
393__cxa_current_primary_exception() throw()
394{
395//  get the current exception
396    __cxa_eh_globals* globals = __cxa_get_globals_fast();
397    if (NULL == globals)
398        return NULL;        //  If there are no globals, there is no exception
399    __cxa_exception* current_exception = globals->caughtExceptions;
400    if (NULL == current_exception)
401        return NULL;        //  No current exception
402    if (isDependentException(&current_exception->unwindHeader)) {
403        __cxa_dependent_exception* deh =
404            reinterpret_cast<__cxa_dependent_exception*>(current_exception + 1) - 1;
405        current_exception = static_cast<__cxa_exception*>(deh->primaryException) - 1;
406    }
407    void* thrown_object = thrown_object_from_exception(current_exception);
408    __cxa_increment_exception_refcount(thrown_object);
409    return thrown_object;
410}
411
412/*
413    If reason isn't _URC_FOREIGN_EXCEPTION_CAUGHT, then the terminateHandler
414    stored in exc is called.  Otherwise the referenceCount stored in the
415    primary exception is decremented, destroying the primary if necessary.
416    Finally the dependent exception is destroyed.
417*/
418static
419void
420dependent_exception_cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception* exc)
421{
422    __cxa_dependent_exception* deh =
423                      reinterpret_cast<__cxa_dependent_exception*>(exc + 1) - 1;
424    if (_URC_FOREIGN_EXCEPTION_CAUGHT != reason)
425        std::__terminate(deh->terminateHandler);
426    __cxa_decrement_exception_refcount(deh->primaryException);
427    __cxa_free_dependent_exception(deh);
428}
429
430/*
431    If thrown_object is not null, allocate, initialize and thow a dependent
432    exception.
433*/
434void
435__cxa_rethrow_primary_exception(void* thrown_object)
436{
437    if ( thrown_object != NULL )
438    {
439        __cxa_exception* header = exception_from_thrown_object(thrown_object);
440        __cxa_dependent_exception* deh =
441            (__cxa_dependent_exception*)__cxa_allocate_dependent_exception();
442        deh->primaryException = thrown_object;
443        __cxa_increment_exception_refcount(thrown_object);
444        deh->exceptionType = header->exceptionType;
445        deh->unexpectedHandler = std::get_unexpected();
446        deh->terminateHandler = std::get_terminate();
447        setDependentExceptionClass(&deh->unwindHeader);
448        __cxa_get_globals()->uncaughtExceptions += 1;
449        deh->unwindHeader.exception_cleanup = dependent_exception_cleanup;
450#if __arm__
451        _Unwind_SjLj_RaiseException(&deh->unwindHeader);
452#else
453        _Unwind_RaiseException(&deh->unwindHeader);
454#endif
455        // Some sort of unwinding error.  Note that terminate is a handler.
456        __cxa_begin_catch(&deh->unwindHeader);
457    }
458    // If we return client will call terminate()
459}
460
461}  // extern "C"
462
463}  // abi
464