Import b9db3a010143160624f123763025ab544b69bd9a of libcxxrt. This brings in

three fixes:

- Don't treat pointers to members as pointers in catch blocks (they're usually
  fat pointers).

- Correctly catch foreign exceptions in catchalls.

- Ensure that a happens-before relationship is established when setting
  terminate handlers in one thread and calling them in another.
This commit is contained in:
David Chisnall 2013-01-11 15:00:43 +00:00
parent 60e0399a08
commit 8e59c7f592
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/libcxxrt/dist/; revision=245302
svn path=/vendor/libcxxrt/2013-01-11-b9db3a010143160624f123763025ab544b69bd9a/; revision=245303; tag=vendor/libcxxrt/2013-01-11-b9db3a010143160624f123763025ab544b69bd9a
4 changed files with 132 additions and 34 deletions

29
atomic.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#ifndef __has_feature
#define __has_feature(x) 0
#endif
/**
* Swap macro that enforces a happens-before relationship with a corresponding
* ATOMIC_LOAD.
*/
#if __has_feature(cxx_atomic)
#define ATOMIC_SWAP(addr, val)\
__atomic_exchange(addr, val, __ATOMIC_ACQ_REL)
#elif __has_builtin(__sync_swap)
#define ATOMIC_SWAP(addr, val)\
__sync_swap(addr, val)
#else
#define ATOMIC_SWAP(addr, val)\
__sync_lock_test_and_set(addr, val)
#endif
#if __has_feature(cxx_atomic)
#define ATOMIC_LOAD(addr)\
__atomic_load(addr, __ATOMIC_ACQUIRE)
#else
#define ATOMIC_LOAD(addr)\
(__sync_synchronize(), *addr)
#endif

View File

@ -32,6 +32,7 @@
#include <pthread.h>
#include "typeinfo.h"
#include "dwarf_eh.h"
#include "atomic.h"
#include "cxxabi.h"
#pragma weak pthread_key_create
@ -154,6 +155,17 @@ struct __cxa_thread_info
* The exception currently running in a cleanup.
*/
_Unwind_Exception *currentCleanup;
/**
* Our state with respect to foreign exceptions. Usually none, set to
* caught if we have just caught an exception and rethrown if we are
* rethrowing it.
*/
enum
{
none,
caught,
rethrown
} foreign_exception_state;
/**
* The public part of this structure, accessible from outside of this
* module.
@ -308,7 +320,16 @@ static void thread_cleanup(void* thread_info)
__cxa_thread_info *info = (__cxa_thread_info*)thread_info;
if (info->globals.caughtExceptions)
{
free_exception_list(info->globals.caughtExceptions);
// If this is a foreign exception, ask it to clean itself up.
if (info->foreign_exception_state != __cxa_thread_info::none)
{
_Unwind_Exception *e = (_Unwind_Exception*)info->globals.caughtExceptions;
e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
}
else
{
free_exception_list(info->globals.caughtExceptions);
}
}
free(thread_info);
}
@ -780,7 +801,8 @@ extern "C" void __cxa_decrement_exception_refcount(void* thrown_exception)
*/
extern "C" void __cxa_rethrow()
{
__cxa_eh_globals *globals = __cxa_get_globals();
__cxa_thread_info *ti = thread_info_fast();
__cxa_eh_globals *globals = &ti->globals;
// Note: We don't remove this from the caught list here, because
// __cxa_end_catch will be called when we unwind out of the try block. We
// could probably make this faster by providing an alternative rethrow
@ -795,6 +817,15 @@ extern "C" void __cxa_rethrow()
std::terminate();
}
if (ti->foreign_exception_state != __cxa_thread_info::none)
{
ti->foreign_exception_state = __cxa_thread_info::rethrown;
_Unwind_Exception *e = (_Unwind_Exception*)ex;
_Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e);
report_failure(err, ex);
return;
}
assert(ex->handlerCount > 0 && "Rethrowing uncaught exception!");
// ex->handlerCount will be decremented in __cxa_end_catch in enclosing
@ -848,9 +879,9 @@ static bool check_type_signature(__cxa_exception *ex,
void *&adjustedPtr)
{
void *exception_ptr = (void*)(ex+1);
const std::type_info *ex_type = ex->exceptionType;
const std::type_info *ex_type = ex ? ex->exceptionType : 0;
bool is_ptr = ex_type->__is_pointer_p();
bool is_ptr = ex ? ex_type->__is_pointer_p() : false;
if (is_ptr)
{
exception_ptr = *(void**)exception_ptr;
@ -911,8 +942,8 @@ static handler_type check_action_record(_Unwind_Context *context,
action_record = displacement ?
action_record_offset_base + displacement : 0;
// We only check handler types for C++ exceptions - foreign exceptions
// are only allowed for cleanup.
if (filter > 0 && 0 != ex)
// are only allowed for cleanups and catchalls.
if (filter > 0)
{
std::type_info *handler_type = get_type_info_entry(context, lsda, filter);
if (check_type_signature(ex, handler_type, adjustedPtr))
@ -1133,8 +1164,10 @@ extern "C" void *__cxa_begin_catch(void *e) throw()
extern "C" void *__cxa_begin_catch(void *e)
#endif
{
// Decrement the uncaught exceptions count
__cxa_eh_globals *globals = __cxa_get_globals();
// We can't call the fast version here, because if the first exception that
// we see is a foreign exception then we won't have called it yet.
__cxa_thread_info *ti = thread_info();
__cxa_eh_globals *globals = &ti->globals;
globals->uncaughtExceptions--;
_Unwind_Exception *exceptionObject = (_Unwind_Exception*)e;
@ -1177,9 +1210,22 @@ extern "C" void *__cxa_begin_catch(void *e)
{
ex->handlerCount++;
}
ti->foreign_exception_state = __cxa_thread_info::none;
return ex->adjustedPtr;
}
else
{
// If this is a foreign exception, then we need to be able to
// store it. We can't chain foreign exceptions, so we give up
// if there are already some outstanding ones.
if (globals->caughtExceptions != 0)
{
std::terminate();
}
globals->caughtExceptions = (__cxa_exception*)exceptionObject;
ti->foreign_exception_state = __cxa_thread_info::caught;
}
// exceptionObject is the pointer to the _Unwind_Exception within the
// __cxa_exception. The throw object is after this
return ((char*)exceptionObject + sizeof(_Unwind_Exception));
@ -1195,10 +1241,23 @@ extern "C" void __cxa_end_catch()
{
// We can call the fast version here because the slow version is called in
// __cxa_throw(), which must have been called before we end a catch block
__cxa_eh_globals *globals = __cxa_get_globals_fast();
__cxa_thread_info *ti = thread_info_fast();
__cxa_eh_globals *globals = &ti->globals;
__cxa_exception *ex = globals->caughtExceptions;
assert(0 != ex && "Ending catch when no exception is on the stack!");
if (ti->foreign_exception_state != __cxa_thread_info::none)
{
globals->caughtExceptions = 0;
if (ti->foreign_exception_state != __cxa_thread_info::rethrown)
{
_Unwind_Exception *e = (_Unwind_Exception*)ti->globals.caughtExceptions;
e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
}
ti->foreign_exception_state = __cxa_thread_info::none;
return;
}
bool deleteException = true;
@ -1328,7 +1387,7 @@ namespace std
{
if (thread_local_handlers) { return pathscale::set_unexpected(f); }
return __sync_lock_test_and_set(&unexpectedHandler, f);
return ATOMIC_SWAP(&terminateHandler, f);
}
/**
* Sets the function that is called to terminate the program.
@ -1336,7 +1395,8 @@ namespace std
terminate_handler set_terminate(terminate_handler f) throw()
{
if (thread_local_handlers) { return pathscale::set_terminate(f); }
return __sync_lock_test_and_set(&terminateHandler, f);
return ATOMIC_SWAP(&terminateHandler, f);
}
/**
* Terminates the program, calling a custom terminate implementation if
@ -1390,7 +1450,7 @@ namespace std
{
return info->unexpectedHandler;
}
return unexpectedHandler;
return ATOMIC_LOAD(&unexpectedHandler);
}
/**
* Returns the current terminate handler.
@ -1402,7 +1462,7 @@ namespace std
{
return info->terminateHandler;
}
return terminateHandler;
return ATOMIC_LOAD(&terminateHandler);
}
}
#ifdef __arm__

View File

@ -36,14 +36,8 @@
#include <stddef.h>
#include <stdlib.h>
#include "stdexcept.h"
#include "atomic.h"
#ifndef __has_builtin
#define __has_builtin(x) 0
#endif
#if !__has_builtin(__sync_swap)
#define __sync_swap __sync_lock_test_and_set
#endif
namespace std
{
@ -67,7 +61,12 @@ namespace std
__attribute__((weak))
new_handler set_new_handler(new_handler handler)
{
return __sync_swap(&new_handl, handler);
return ATOMIC_SWAP(&new_handl, handler);
}
__attribute__((weak))
new_handler get_new_handler(void)
{
return ATOMIC_LOAD(&new_handl);
}
}
@ -75,12 +74,17 @@ namespace std
__attribute__((weak))
void* operator new(size_t size)
{
if (0 == size)
{
size = 1;
}
void * mem = malloc(size);
while (0 == mem)
{
if (0 != new_handl)
new_handler h = std::get_new_handler();
if (0 != h)
{
new_handl();
h();
}
else
{
@ -95,14 +99,19 @@ void* operator new(size_t size)
__attribute__((weak))
void* operator new(size_t size, const std::nothrow_t &) throw()
{
if (0 == size)
{
size = 1;
}
void *mem = malloc(size);
while (0 == mem)
{
if (0 != new_handl)
new_handler h = std::get_new_handler();
if (0 != h)
{
try
{
new_handl();
h();
}
catch (...)
{

View File

@ -69,6 +69,14 @@ namespace std
* type_info and correctly fill in the values in the vtables.
*/
public:
/**
* Returns true if this is some pointer type, false otherwise.
*/
virtual bool __is_pointer_p() const { return false; }
/**
* Returns true if this is some function type, false otherwise.
*/
virtual bool __is_function_p() const { return false; }
/**
* Catch function. Allows external libraries to implement
* their own basic types. This is used, for example, in the
@ -95,14 +103,6 @@ namespace std
{
return false;
}
/**
* Returns true if this is some pointer type, false otherwise.
*/
virtual bool __is_pointer_p() const { return false; }
/**
* Returns true if this is some function type, false otherwise.
*/
virtual bool __is_function_p() const { return false; }
};
}
@ -284,7 +284,6 @@ namespace ABI_NAMESPACE
/** Pointer is a pointer to a member of an incomplete class. */
__incomplete_class_mask = 0x10
};
virtual bool __is_pointer_p() const { return true; }
virtual bool __do_catch(const type_info *thrown_type,
void **thrown_object,
unsigned outer) const;
@ -296,6 +295,7 @@ namespace ABI_NAMESPACE
struct __pointer_type_info : public __pbase_type_info
{
virtual ~__pointer_type_info();
virtual bool __is_pointer_p() const { return true; }
};
/**