Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 11 Jan 2013 15:00:43 +0000 (UTC)
From:      David Chisnall <theraven@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-vendor@freebsd.org
Subject:   svn commit: r245302 - vendor/libcxxrt/dist
Message-ID:  <201301111500.r0BF0h5K037612@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: theraven
Date: Fri Jan 11 15:00:43 2013
New Revision: 245302
URL: http://svnweb.freebsd.org/changeset/base/245302

Log:
  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.

Added:
  vendor/libcxxrt/dist/atomic.h
Modified:
  vendor/libcxxrt/dist/exception.cc
  vendor/libcxxrt/dist/memory.cc
  vendor/libcxxrt/dist/typeinfo.h

Added: vendor/libcxxrt/dist/atomic.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ vendor/libcxxrt/dist/atomic.h	Fri Jan 11 15:00:43 2013	(r245302)
@@ -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

Modified: vendor/libcxxrt/dist/exception.cc
==============================================================================
--- vendor/libcxxrt/dist/exception.cc	Fri Jan 11 14:01:07 2013	(r245301)
+++ vendor/libcxxrt/dist/exception.cc	Fri Jan 11 15:00:43 2013	(r245302)
@@ -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
@@ -155,6 +156,17 @@ struct __cxa_thread_info
 	 */
 	_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_
 	__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_exceptio
  */
 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_e
                                  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(
 		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 
 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 
 		{
 			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__

Modified: vendor/libcxxrt/dist/memory.cc
==============================================================================
--- vendor/libcxxrt/dist/memory.cc	Fri Jan 11 14:01:07 2013	(r245301)
+++ vendor/libcxxrt/dist/memory.cc	Fri Jan 11 15:00:43 2013	(r245302)
@@ -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 (...)
 			{

Modified: vendor/libcxxrt/dist/typeinfo.h
==============================================================================
--- vendor/libcxxrt/dist/typeinfo.h	Fri Jan 11 14:01:07 2013	(r245301)
+++ vendor/libcxxrt/dist/typeinfo.h	Fri Jan 11 15:00:43 2013	(r245302)
@@ -70,6 +70,14 @@ namespace std
 		 */
 		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
 		 * GNUstep Objective-C runtime to allow Objective-C types to be
@@ -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; }
 	};
 
 	/**



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201301111500.r0BF0h5K037612>