diff --git a/include/boost/exception/detail/clone_current_exception.hpp b/include/boost/exception/detail/clone_current_exception.hpp index 07ee66f..06355c8 100644 --- a/include/boost/exception/detail/clone_current_exception.hpp +++ b/include/boost/exception/detail/clone_current_exception.hpp @@ -21,7 +21,8 @@ boost { int const success=0; int const bad_alloc=1; - int const not_supported=2; + int const bad_exception=2; + int const not_supported=3; } class clone_base; diff --git a/include/boost/exception/detail/exception_ptr.hpp b/include/boost/exception/detail/exception_ptr.hpp index cf7b735..85ad5a0 100644 --- a/include/boost/exception/detail/exception_ptr.hpp +++ b/include/boost/exception/detail/exception_ptr.hpp @@ -70,31 +70,38 @@ boost { }; - template + struct + bad_exception_: + boost::exception, + std::bad_exception + { + }; + + template exception_ptr - get_bad_alloc() + get_static_exception_object() { - bad_alloc_ ba; - exception_detail::clone_impl c(ba); + Exception ba; + exception_detail::clone_impl c(ba); c << throw_function(BOOST_CURRENT_FUNCTION) << throw_file(__FILE__) << throw_line(__LINE__); - static exception_ptr ep(new exception_detail::clone_impl(c)); + static exception_ptr ep(new exception_detail::clone_impl(c)); return ep; } - template + template struct - exception_ptr_bad_alloc + exception_ptr_static_exception_object { static exception_ptr const e; }; - template + template exception_ptr const - exception_ptr_bad_alloc:: - e = get_bad_alloc(); + exception_ptr_static_exception_object:: + e = get_static_exception_object(); } class @@ -259,7 +266,13 @@ boost bad_alloc: { BOOST_ASSERT(!e); - return exception_detail::exception_ptr_bad_alloc<42>::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); @@ -346,7 +359,7 @@ boost catch( std::bad_exception & e ) { - return exception_detail::current_exception_std_exception(e); + return exception_detail::exception_ptr_static_exception_object::e; } catch( std::exception & e ) @@ -380,25 +393,12 @@ boost catch( std::bad_alloc & ) { - ret=exception_detail::exception_ptr_bad_alloc<42>::e; + ret=exception_detail::exception_ptr_static_exception_object::e; } catch( ... ) { - try - { - ret=exception_detail::current_exception_std_exception(std::bad_exception()); - } - catch( - std::bad_alloc & ) - { - ret=exception_detail::exception_ptr_bad_alloc<42>::e; - } - catch( - ... ) - { - BOOST_ASSERT(0); - } + ret=exception_detail::exception_ptr_static_exception_object::e; } BOOST_ASSERT(ret); return ret; diff --git a/src/clone_current_exception_msvc.cpp b/src/clone_current_exception_msvc.cpp index 6e3b242..f0fc493 100644 --- a/src/clone_current_exception_msvc.cpp +++ b/src/clone_current_exception_msvc.cpp @@ -12,6 +12,9 @@ #include #include #include +#ifndef BOOST_NO_RTTI +#include +#endif #include namespace @@ -21,7 +24,7 @@ namespace #if _MSC_VER==1310 int const exception_info_offset=0x74; -#elif _MSC_VER==1400 +#elif (_MSC_VER==1400 || _MSC_VER==1500) int const exception_info_offset=0x80; #else int const exception_info_offset=-1; @@ -55,7 +58,7 @@ namespace }; 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 * dest); + typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr)(void * src,void * dst); typedef void (dummy_exception_type::*destructor_ptr)(); union @@ -76,7 +79,11 @@ namespace cpp_type_info { unsigned flags; - void const * type_info; //std::type_info * type_info; +#ifndef BOOST_NO_RTTI + void const * type_info; +#else + std::type_info * type_info; +#endif int this_offset; int vbase_descr; int vbase_offset; @@ -103,47 +110,56 @@ namespace struct exception_object_deleter { - cpp_exception_type const * exception_type_; - bool run_destructor_; + cpp_exception_type const & et_; - exception_object_deleter( cpp_exception_type const * exception_type, bool run_destructor ): - exception_type_(exception_type), - run_destructor_(run_destructor) + exception_object_deleter( cpp_exception_type const & et ): + et_(et) { - BOOST_ASSERT(exception_type_!=0); } void - operator()( void * exception_object ) + operator()( void * obj ) { - BOOST_ASSERT(exception_object!=0); - if( run_destructor_ ) - { - dummy_exception_type * dummy_exception_ptr=reinterpret_cast(exception_object); - (dummy_exception_ptr->*(exception_type_->destructor))(); - } - free(exception_object); + BOOST_ASSERT(obj!=0); + dummy_exception_type * dummy_exception_ptr=reinterpret_cast(obj); + (dummy_exception_ptr->*(et_.destructor))(); + free(obj); } }; - boost::shared_ptr - copy_msvc_exception( void * source_object, cpp_exception_type const * exception_type, bool run_destructor ) + cpp_type_info const & + get_cpp_type_info( cpp_exception_type const & et ) { - void * exception_object = malloc(exception_type->type_info_table->info[0]->size); - if( !exception_object ) - throw std::bad_alloc(); - cpp_type_info const * type = exception_type->type_info_table->info[0]; - if( !(type->flags & class_is_simple_type) && type->copy_constructor.normal_copy_constructor ) + 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(exception_object); - if( type->flags & class_has_virtual_base ) - (dummy_exception_ptr->*(type->copy_constructor.copy_constructor_with_virtual_base))(source_object,exception_object); + 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->*(type->copy_constructor.normal_copy_constructor))(source_object); + (dummy_exception_ptr->*(ti.copy_constructor.normal_copy_constructor))(src); } else - memmove(exception_object,source_object,type->size); - return boost::shared_ptr(exception_object,exception_object_deleter(exception_type,run_destructor)); + 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); + void * dst = malloc(ti.size); + if( !dst ) + throw std::bad_alloc(); + copy_msvc_exception(dst,src,ti); + return boost::shared_ptr(dst,exception_object_deleter(et)); } class @@ -153,14 +169,14 @@ namespace cloned_exception( cloned_exception const & ); cloned_exception & operator=( cloned_exception const & ); - cpp_exception_type const * exception_type_; - boost::shared_ptr exception_object_; + cpp_exception_type const & et_; + boost::shared_ptr exc_; public: - cloned_exception( void * source_object, cpp_exception_type const * exception_type ): - exception_type_(exception_type), - exception_object_(copy_msvc_exception(source_object,exception_type_,true)) + cloned_exception( void * exc, cpp_exception_type const & et ): + et_(et), + exc_(clone_msvc_exception(exc,et_)) { } @@ -171,17 +187,19 @@ namespace boost::exception_detail::clone_base const * clone() const { - return new cloned_exception(exception_object_.get(),exception_type_); + return new cloned_exception(exc_.get(),et_); } void rethrow() const { - boost::shared_ptr clone=copy_msvc_exception(exception_object_.get(),exception_type_,false); + 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(clone.get()); - args[2]=reinterpret_cast(exception_type_); + args[1]=reinterpret_cast(dst); + args[2]=reinterpret_cast(&et_); RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args); } }; @@ -198,6 +216,7 @@ namespace 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; @@ -210,7 +229,7 @@ namespace { ptr = new cloned_exception( reinterpret_cast(record->ExceptionInformation[1]), - reinterpret_cast(record->ExceptionInformation[2])); + *reinterpret_cast(record->ExceptionInformation[2])); result = boost::exception_detail::clone_current_exception_result::success; } catch( @@ -221,7 +240,7 @@ namespace catch( ... ) { - BOOST_ASSERT(0); + result = boost::exception_detail::clone_current_exception_result::bad_exception; } } return EXCEPTION_EXECUTE_HANDLER; @@ -257,271 +276,3 @@ boost } } } - -#if 0 -//This is the original Anthony Williams implementation -#ifndef EXCEPTION_PTR_HPP -#define EXCEPTION_PTR_HPP -#include -#include "thread_heap_alloc.hpp" -#include -#include "thread_primitives.hpp" -#include - -namespace -boost - { - namespace - exception_detail - { - namespace - win32 - { - unsigned const exception_maximum_parameters=15; - unsigned const exception_noncontinuable=1; - - 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; - }; - - extern "C" - { - __declspec(dllimport) void __stdcall RaiseException(unsigned long,unsigned long,unsigned long,ulong_ptr*); - } - } - - 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 * dest); - 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; - void const * type_info; //std::type_info * type_info; - 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; - }; - - class - msvc_cloned_exception: - clone_base - { - cpp_exception_type const * exception_type; - void * exception_object; - bool run_destructor; - - void - copy( void * source_object ) - { - BOOST_ASSERT(!exception_object); - exception_object = malloc(exception_type->type_info_table->info[0]->size); - if( exception_object ) - { - cpp_type_info const * type = exception_type->type_info_table->info[0]; - if( !(type->flags & class_is_simple_type) && type->copy_constructor.normal_copy_constructor ) - { - dummy_exception_type * dummy_exception_ptr = reinterpret_cast(exception_object); - if( type->flags & class_has_virtual_base ) - (dummy_exception_ptr->*(type->copy_constructor.copy_constructor_with_virtual_base))(source_object,exception_object); - else - (dummy_exception_ptr->*(type->copy_constructor.normal_copy_constructor))(source_object); - } - else - memmove(exception_object,source_object,type->size); - run_destructor=true; - } - } - - public: - - msvc_cloned_exception( void * source_object, cpp_exception_type const * exception_type_ ): - exception_type(exception_type_), - exception_object(0), - run_destructor(false) - { - copy(source_object); - } - - msvc_cloned_exception( msvc_cloned_exception const & other ): - exception_type(other.exception_type), - exception_object(0), - run_destructor(false) - { - copy(other.exception_object); - } - - ~msvc_cloned_exception() - { - if( exception_object ) - { - if( run_destructor ) - { - dummy_exception_type * dummy_exception_ptr=reinterpret_cast(exception_object); - (dummy_exception_ptr->*(exception_type->destructor))(); - } - free(exception_object); - } - } - - void - rethrow() - { - msvc_cloned_exception temp(*this); - - detail::win32::ulong_ptr args[detail::cpp_exception_parameter_count]; - args[0]=detail::cpp_exception_magic_flag; - args[1]=reinterpret_cast(temp.exception_object); - args[2]=reinterpret_cast(temp.exception_type); - - temp.run_destructor=false; - - detail::win32::RaiseException(detail::cpp_exception_code,detail::win32::exception_noncontinuable,detail::cpp_exception_parameter_count,args); - } - }; - } - - typedef boost::intrusive_ptr exception_ptr; - - namespace - exception_detail - { - extern "C" int * _errno(); - - bool - is_cpp_exception( win32::exception_record * 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( exception_ptr * ptr, void * info_ ) - { - win32::exception_pointers * info=reinterpret_cast(info_); - win32::exception_record * record=info->ExceptionRecord; - if( is_cpp_exception(record) ) - { - if( !record->ExceptionInformation[2] ) - { -#if _MSC_VER==1310 - unsigned const exception_info_offset=0x74; -#elif _MSC_VER==1400 - unsigned const exception_info_offset=0x80; -#endif - record = *reinterpret_cast(reinterpret_cast(_errno())+exception_info_offset); - } - if( is_cpp_exception(record) && record->ExceptionInformation[2] ) - *ptr = detail::heap_new(reinterpret_cast(record->ExceptionInformation[1]), - reinterpret_cast(record->ExceptionInformation[2])); - } - return EXCEPTION_EXECUTE_HANDLER; - } - - void - clone_current_exception( exception_ptr * res ) - { - __try - { - throw; - } - __except(exception_cloning_filter(res,GetExceptionInformation())) - { - } - } - } - - - inline - exception_ptr - current_exception() - { - exception_ptr res; - clone_current_exception(&res); - return res; - } - - inline - void - rethrow_exception(exception_ptr p) - { - if(p) - p->rethrow(); - else - throw "no exception stored"; - } - - template - exception_ptr - copy_exception(E e) - { - try - { - throw e; - } - catch( ... ) - { - return current_exception(); - } - } - } - -#endif -#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 2da9998..59660c7 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -11,7 +11,7 @@ project : requirements on /boost//exception -# BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR + BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR ; #to_string diff --git a/test/cloning_test.cpp b/test/cloning_test.cpp index 77abbe3..33602c9 100644 --- a/test/cloning_test.cpp +++ b/test/cloning_test.cpp @@ -146,6 +146,10 @@ test_std_exception() #endif } catch( + T & ) + { + } + catch( ... ) { BOOST_TEST(false); @@ -216,6 +220,10 @@ test_std_exception_what() #endif } catch( + T & ) + { + } + catch( ... ) { BOOST_TEST(false); @@ -385,6 +393,11 @@ main() BOOST_TEST(false); } catch( + derives_std_exception & ) + { + //Yay! Non-intrusive cloning supported! + } + catch( boost::unknown_exception & e ) { #ifndef BOOST_NO_RTTI @@ -434,6 +447,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)); @@ -495,6 +516,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/copy_exception_test.cpp b/test/copy_exception_test.cpp index 84974ce..a88e6d5 100644 --- a/test/copy_exception_test.cpp +++ b/test/copy_exception_test.cpp @@ -6,15 +6,37 @@ #include #include #include +#include #include typedef boost::error_info answer; +boost::detail::atomic_count exc_count(0); + struct err: virtual boost::exception, virtual std::exception { + err() + { + ++exc_count; + } + + err( err const & ) + { + ++exc_count; + } + + virtual + ~err() throw() + { + --exc_count; + } + + private: + + err & operator=( err const & ); }; class @@ -116,7 +138,9 @@ simple_test() int main() { + BOOST_TEST(++exc_count==1); simple_test(); thread_test(); + BOOST_TEST(!--exc_count); return boost::report_errors(); } 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);