diff --git a/build/Jamfile.v2 b/build/Jamfile.v2
new file mode 100644
index 0000000..fb47659
--- /dev/null
+++ b/build/Jamfile.v2
@@ -0,0 +1,14 @@
+# Boost Exception Library build Jamfile
+#
+# Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
+#
+# Distributed under the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+project boost/exception
+ : source-location ../src
+ : requirements static
+ ;
+
+lib boost_exception : clone_current_exception_non_intrusive.cpp ;
+boost-install boost_exception ;
diff --git a/include/boost/exception/detail/clone_current_exception.hpp b/include/boost/exception/detail/clone_current_exception.hpp
new file mode 100644
index 0000000..6fc1374
--- /dev/null
+++ b/include/boost/exception/detail/clone_current_exception.hpp
@@ -0,0 +1,56 @@
+//Copyright (c) 2006-2013 Emil Dotchevski and Reverge Studios, Inc.
+
+//Distributed under the Boost Software License, Version 1.0. (See accompanying
+//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef UUID_81522C0EB56511DFAB613DB0DFD72085
+#define UUID_81522C0EB56511DFAB613DB0DFD72085
+#if (__GNUC__*100+__GNUC_MINOR__>301) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
+#pragma GCC system_header
+#endif
+#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
+#pragma warning(push,1)
+#endif
+
+#ifdef BOOST_NO_EXCEPTIONS
+# error This header requires exception handling to be enabled.
+#endif
+
+namespace
+boost
+ {
+ namespace
+ exception_detail
+ {
+ class clone_base;
+
+#ifdef BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR
+ int clone_current_exception_non_intrusive( clone_base const * & cloned );
+#endif
+
+ namespace
+ clone_current_exception_result
+ {
+ int const success=0;
+ int const bad_alloc=1;
+ int const bad_exception=2;
+ int const not_supported=3;
+ }
+
+ inline
+ int
+ clone_current_exception( clone_base const * & cloned )
+ {
+#ifdef BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR
+ return clone_current_exception_non_intrusive(cloned);
+#else
+ return clone_current_exception_result::not_supported;
+#endif
+ }
+ }
+ }
+
+#if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
+#pragma warning(pop)
+#endif
+#endif
diff --git a/include/boost/exception/detail/exception_ptr.hpp b/include/boost/exception/detail/exception_ptr.hpp
index 24c4fba..8e19f0d 100644
--- a/include/boost/exception/detail/exception_ptr.hpp
+++ b/include/boost/exception/detail/exception_ptr.hpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#ifndef BOOST_NO_RTTI
#include
@@ -302,101 +303,131 @@ boost
exception_ptr
current_exception_impl()
{
- try
+ exception_detail::clone_base const * e=0;
+ switch(
+ exception_detail::clone_current_exception(e) )
{
- throw;
- }
- catch(
- exception_detail::clone_base & e )
- {
- return exception_ptr(shared_ptr(e.clone()));
- }
- catch(
- std::domain_error & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::invalid_argument & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::length_error & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::out_of_range & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::logic_error & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::range_error & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::overflow_error & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::underflow_error & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::ios_base::failure & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::runtime_error & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::bad_alloc & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
-#ifndef BOOST_NO_TYPEID
- catch(
- std::bad_cast & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::bad_typeid & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
-#endif
- catch(
- std::bad_exception & e )
- {
- return exception_detail::current_exception_std_exception(e);
- }
- catch(
- std::exception & e )
- {
- return exception_detail::current_exception_unknown_std_exception(e);
- }
- catch(
- boost::exception & e )
- {
- return exception_detail::current_exception_unknown_boost_exception(e);
- }
- catch(
- ... )
- {
- return exception_detail::current_exception_unknown_exception();
+ case exception_detail::clone_current_exception_result::
+ success:
+ {
+ BOOST_ASSERT(e!=0);
+ return exception_ptr(shared_ptr(e));
+ }
+ case exception_detail::clone_current_exception_result::
+ bad_alloc:
+ {
+ BOOST_ASSERT(!e);
+ return exception_detail::exception_ptr_static_exception_object::e;
+ }
+ case exception_detail::clone_current_exception_result::
+ bad_exception:
+ {
+ BOOST_ASSERT(!e);
+ return exception_detail::exception_ptr_static_exception_object::e;
+ }
+ default:
+ BOOST_ASSERT(0);
+ case exception_detail::clone_current_exception_result::
+ not_supported:
+ {
+ BOOST_ASSERT(!e);
+ try
+ {
+ throw;
+ }
+ catch(
+ exception_detail::clone_base & e )
+ {
+ return exception_ptr(shared_ptr(e.clone()));
+ }
+ catch(
+ std::domain_error & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::invalid_argument & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::length_error & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::out_of_range & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::logic_error & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::range_error & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::overflow_error & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::underflow_error & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::ios_base::failure & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::runtime_error & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::bad_alloc & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ #ifndef BOOST_NO_TYPEID
+ catch(
+ std::bad_cast & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::bad_typeid & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ #endif
+ catch(
+ std::bad_exception & e )
+ {
+ return exception_detail::current_exception_std_exception(e);
+ }
+ catch(
+ std::exception & e )
+ {
+ return exception_detail::current_exception_unknown_std_exception(e);
+ }
+ catch(
+ boost::exception & e )
+ {
+ return exception_detail::current_exception_unknown_boost_exception(e);
+ }
+ catch(
+ ... )
+ {
+ return exception_detail::current_exception_unknown_exception();
+ }
+ }
}
}
}
diff --git a/src/clone_current_exception_non_intrusive.cpp b/src/clone_current_exception_non_intrusive.cpp
new file mode 100644
index 0000000..1710cd7
--- /dev/null
+++ b/src/clone_current_exception_non_intrusive.cpp
@@ -0,0 +1,320 @@
+//Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
+
+//Distributed under the Boost Software License, Version 1.0. (See accompanying
+//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//This MSVC-specific cpp file implements non-intrusive cloning of exception objects.
+//Based on an exception_ptr implementation by Anthony Williams.
+
+#ifdef BOOST_NO_EXCEPTIONS
+#error This file requires exception handling to be enabled.
+#endif
+
+#include
+
+#if defined(BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR) && defined(_MSC_VER) && defined(_M_IX86) && !defined(_M_X64)
+
+//Non-intrusive cloning support implemented below, only for MSVC versions mentioned above.
+//Thanks Anthony Williams!
+
+#include
+#include
+#ifndef BOOST_NO_RTTI
+#include
+#endif
+#include
+#include
+
+namespace
+ {
+ unsigned const exception_maximum_parameters=15;
+ unsigned const exception_noncontinuable=1;
+
+#if _MSC_VER==1310
+ int const exception_info_offset=0x74;
+#elif (_MSC_VER==1400 || _MSC_VER==1500)
+ int const exception_info_offset=0x80;
+#else
+ int const exception_info_offset=-1;
+#endif
+
+ struct
+ exception_record
+ {
+ unsigned long ExceptionCode;
+ unsigned long ExceptionFlags;
+ exception_record * ExceptionRecord;
+ void * ExceptionAddress;
+ unsigned long NumberParameters;
+ ULONG_PTR ExceptionInformation[exception_maximum_parameters];
+ };
+
+ struct
+ exception_pointers
+ {
+ exception_record * ExceptionRecord;
+ void * ContextRecord;
+ };
+
+ unsigned const cpp_exception_code=0xE06D7363;
+ unsigned const cpp_exception_magic_flag=0x19930520;
+ unsigned const cpp_exception_parameter_count=3;
+
+ struct
+ dummy_exception_type
+ {
+ };
+
+ typedef int(dummy_exception_type::*normal_copy_constructor_ptr)(void * src);
+ typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr)(void * src,void * dst);
+ typedef void (dummy_exception_type::*destructor_ptr)();
+
+ union
+ cpp_copy_constructor
+ {
+ normal_copy_constructor_ptr normal_copy_constructor;
+ copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base;
+ };
+
+ enum
+ cpp_type_flags
+ {
+ class_is_simple_type=1,
+ class_has_virtual_base=4
+ };
+
+ struct
+ cpp_type_info
+ {
+ unsigned flags;
+#ifndef BOOST_NO_RTTI
+ void const * type_info;
+#else
+ std::type_info * type_info;
+#endif
+ int this_offset;
+ int vbase_descr;
+ int vbase_offset;
+ unsigned long size;
+ cpp_copy_constructor copy_constructor;
+ };
+
+ struct
+ cpp_type_info_table
+ {
+ unsigned count;
+ const cpp_type_info * info[1];
+ };
+
+ struct
+ cpp_exception_type
+ {
+ unsigned flags;
+ destructor_ptr destructor;
+ void(*custom_handler)();
+ cpp_type_info_table const * type_info_table;
+ };
+
+ struct
+ exception_object_deleter
+ {
+ cpp_exception_type const & et_;
+
+ exception_object_deleter( cpp_exception_type const & et ):
+ et_(et)
+ {
+ }
+
+ void
+ operator()( void * obj )
+ {
+ BOOST_ASSERT(obj!=0);
+ dummy_exception_type * dummy_exception_ptr=reinterpret_cast(obj);
+ (dummy_exception_ptr->*(et_.destructor))();
+ free(obj);
+ }
+ };
+
+ cpp_type_info const &
+ get_cpp_type_info( cpp_exception_type const & et )
+ {
+ cpp_type_info const * ti = et.type_info_table->info[0];
+ BOOST_ASSERT(ti!=0);
+ return *ti;
+ }
+
+ void
+ copy_msvc_exception( void * dst, void * src, cpp_type_info const & ti )
+ {
+ if( !(ti.flags & class_is_simple_type) && ti.copy_constructor.normal_copy_constructor )
+ {
+ dummy_exception_type * dummy_exception_ptr = reinterpret_cast(dst);
+ if( ti.flags & class_has_virtual_base )
+ (dummy_exception_ptr->*(ti.copy_constructor.copy_constructor_with_virtual_base))(src,dst);
+ else
+ (dummy_exception_ptr->*(ti.copy_constructor.normal_copy_constructor))(src);
+ }
+ else
+ memmove(dst,src,ti.size);
+ }
+
+ boost::shared_ptr
+ clone_msvc_exception( void * src, cpp_exception_type const & et )
+ {
+ assert(src!=0);
+ cpp_type_info const & ti=get_cpp_type_info(et);
+ if( void * dst = malloc(ti.size) )
+ {
+ try
+ {
+ copy_msvc_exception(dst,src,ti);
+ }
+ catch(
+ ... )
+ {
+ free(dst);
+ throw;
+ }
+ return boost::shared_ptr(dst,exception_object_deleter(et));
+ }
+ else
+ throw std::bad_alloc();
+ }
+
+ class
+ cloned_exception:
+ public boost::exception_detail::clone_base
+ {
+ cloned_exception( cloned_exception const & );
+ cloned_exception & operator=( cloned_exception const & );
+
+ cpp_exception_type const & et_;
+ boost::shared_ptr exc_;
+
+ public:
+
+ cloned_exception( void * exc, cpp_exception_type const & et ):
+ et_(et),
+ exc_(clone_msvc_exception(exc,et_))
+ {
+ }
+
+ ~cloned_exception() throw()
+ {
+ }
+
+ boost::exception_detail::clone_base const *
+ clone() const
+ {
+ return new cloned_exception(exc_.get(),et_);
+ }
+
+ void
+ rethrow() const
+ {
+ cpp_type_info const & ti=get_cpp_type_info(et_);
+ void * dst = _alloca(ti.size);
+ copy_msvc_exception(dst,exc_.get(),ti);
+ ULONG_PTR args[cpp_exception_parameter_count];
+ args[0]=cpp_exception_magic_flag;
+ args[1]=reinterpret_cast(dst);
+ args[2]=reinterpret_cast(&et_);
+ RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args);
+ }
+ };
+
+ bool
+ is_cpp_exception( EXCEPTION_RECORD const * record )
+ {
+ return record &&
+ (record->ExceptionCode==cpp_exception_code) &&
+ (record->NumberParameters==cpp_exception_parameter_count) &&
+ (record->ExceptionInformation[0]==cpp_exception_magic_flag);
+ }
+
+ unsigned long
+ exception_cloning_filter( int & result, boost::exception_detail::clone_base const * & ptr, void * info_ )
+ {
+ BOOST_ASSERT(exception_info_offset>=0);
+ BOOST_ASSERT(info_!=0);
+ EXCEPTION_POINTERS * info=reinterpret_cast(info_);
+ EXCEPTION_RECORD * record=info->ExceptionRecord;
+ if( is_cpp_exception(record) )
+ {
+ if( !record->ExceptionInformation[2] )
+ record = *reinterpret_cast(reinterpret_cast(_errno())+exception_info_offset);
+ if( is_cpp_exception(record) && record->ExceptionInformation[2] )
+ try
+ {
+ ptr = new cloned_exception(
+ reinterpret_cast(record->ExceptionInformation[1]),
+ *reinterpret_cast(record->ExceptionInformation[2]));
+ result = boost::exception_detail::clone_current_exception_result::success;
+ }
+ catch(
+ std::bad_alloc & )
+ {
+ result = boost::exception_detail::clone_current_exception_result::bad_alloc;
+ }
+ catch(
+ ... )
+ {
+ result = boost::exception_detail::clone_current_exception_result::bad_exception;
+ }
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ }
+
+namespace
+boost
+ {
+ namespace
+ exception_detail
+ {
+ int
+ clone_current_exception_non_intrusive( clone_base const * & cloned )
+ {
+ BOOST_ASSERT(!cloned);
+ int result = clone_current_exception_result::not_supported;
+ if( exception_info_offset>=0 )
+ {
+ clone_base const * ptr=0;
+ __try
+ {
+ throw;
+ }
+ __except(exception_cloning_filter(result,ptr,GetExceptionInformation()))
+ {
+ }
+ if( result==clone_current_exception_result::success )
+ cloned=ptr;
+ }
+ BOOST_ASSERT(result!=clone_current_exception_result::success || cloned);
+ return result;
+ }
+ }
+ }
+
+#else
+
+//On all other compilers, return clone_current_exception_result::not_supported.
+//On such platforms, only the intrusive enable_current_exception() cloning will work.
+
+#include
+
+namespace
+boost
+ {
+ namespace
+ exception_detail
+ {
+ int
+ clone_current_exception_non_intrusive( clone_base const * & )
+ {
+ return clone_current_exception_result::not_supported;
+ }
+ }
+ }
+
+#endif
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 97bc3ec..53d277f 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -44,6 +44,7 @@ run refcount_ptr_test.cpp ;
run current_exception_cast_test.cpp ;
run no_exceptions_test.cpp : : : off ;
run errinfos_test.cpp ;
+run exception_ptr_test.cpp/BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR ../../thread/src/tss_null.cpp /boost/exception /boost//thread : : : multi : non_intrusive_exception_ptr_test ;
run exception_ptr_test.cpp ../../thread/src/tss_null.cpp /boost//thread : : : multi ;
run N3757_test.cpp ;
diff --git a/test/cloning_test.cpp b/test/cloning_test.cpp
index 70010aa..c5a4ae9 100644
--- a/test/cloning_test.cpp
+++ b/test/cloning_test.cpp
@@ -395,6 +395,11 @@ main()
BOOST_TEST(false);
}
catch(
+ derives_std_exception & )
+ {
+ //Yay! Non-intrusive cloning supported!
+ }
+ catch(
boost::unknown_exception & e )
{
#ifndef BOOST_NO_RTTI
@@ -444,6 +449,14 @@ main()
BOOST_TEST(false);
}
catch(
+ derives_std_boost_exception & x )
+ {
+ //Yay! Non-intrusive cloning supported!
+ BOOST_TEST(boost::get_error_info(x));
+ if( int const * p=boost::get_error_info(x) )
+ BOOST_TEST(*p==42);
+ }
+ catch(
boost::unknown_exception & x )
{
BOOST_TEST(boost::get_error_info(x));
@@ -505,6 +518,14 @@ main()
BOOST_TEST(false);
}
catch(
+ derives_boost_exception & x )
+ {
+ //Yay! Non-intrusive cloning supported!
+ BOOST_TEST(boost::get_error_info(x));
+ if( int const * p=boost::get_error_info(x) )
+ BOOST_TEST(*p==42);
+ }
+ catch(
boost::unknown_exception & x )
{
BOOST_TEST(boost::get_error_info(x));
diff --git a/test/exception_ptr_test.cpp b/test/exception_ptr_test.cpp
index 4c626c5..367558c 100644
--- a/test/exception_ptr_test.cpp
+++ b/test/exception_ptr_test.cpp
@@ -123,40 +123,40 @@ check( boost::shared_ptr const & t )
void
test_deep_copy()
- {
- int const * p1=0;
- boost::exception_ptr p;
- try
- {
- BOOST_THROW_EXCEPTION(exc() << answer(42));
- BOOST_ERROR("BOOST_THROW_EXCEPTION didn't throw");
- }
- catch(
- exc & e )
- {
- p1=boost::get_error_info(e);
- p=boost::current_exception();
- }
- BOOST_TEST(p1!=0);
- BOOST_TEST(p);
- try
- {
- boost::rethrow_exception(p);
- BOOST_ERROR("rethrow_exception didn't throw");
- }
- catch(
- exc & e )
- {
- int const * p2=boost::get_error_info(e);
- BOOST_TEST(p2!=0 && *p2==42);
- BOOST_TEST(p2!=p1);
- }
- }
+ {
+ int const * p1=0;
+ boost::exception_ptr p;
+ try
+ {
+ BOOST_THROW_EXCEPTION(exc() << answer(42));
+ BOOST_ERROR("BOOST_THROW_EXCEPTION didn't throw");
+ }
+ catch(
+ exc & e )
+ {
+ p1=boost::get_error_info(e);
+ p=boost::current_exception();
+ }
+ BOOST_TEST(p1!=0);
+ BOOST_TEST(p);
+ try
+ {
+ boost::rethrow_exception(p);
+ BOOST_ERROR("rethrow_exception didn't throw");
+ }
+ catch(
+ exc & e )
+ {
+ int const * p2=boost::get_error_info(e);
+ BOOST_TEST(p2!=0 && *p2==42);
+ BOOST_TEST(p2!=p1);
+ }
+ }
int
main()
{
- test_deep_copy();
+ test_deep_copy();
BOOST_TEST(++exc_count==1);
try
{
diff --git a/test/unknown_exception_test.cpp b/test/unknown_exception_test.cpp
index 4918b44..bf474ba 100644
--- a/test/unknown_exception_test.cpp
+++ b/test/unknown_exception_test.cpp
@@ -62,6 +62,15 @@ main()
BOOST_TEST(false);
}
catch(
+ boost::exception & x )
+ {
+ //Yay! Non-intrusive cloning supported!
+ if( int const * d=boost::get_error_info(x) )
+ BOOST_TEST( 42==*d );
+ else
+ BOOST_TEST(false);
+ }
+ catch(
... )
{
BOOST_TEST(false);
@@ -101,6 +110,11 @@ main()
{
}
catch(
+ std::exception & )
+ {
+ //Yay! Non-intrusive cloning supported!
+ }
+ catch(
... )
{
BOOST_TEST(false);
@@ -114,6 +128,11 @@ main()
{
}
catch(
+ std::exception & )
+ {
+ //Yay! Non-intrusive cloning supported!
+ }
+ catch(
... )
{
BOOST_TEST(false);