diff --git a/src/clone_current_exception_non_intrusive.cpp b/src/clone_current_exception_non_intrusive.cpp index 1710cd7..7ebd7b5 100644 --- a/src/clone_current_exception_non_intrusive.cpp +++ b/src/clone_current_exception_non_intrusive.cpp @@ -10,18 +10,17 @@ #error This file requires exception handling to be enabled. #endif +#include #include -#if defined(BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR) && defined(_MSC_VER) && defined(_M_IX86) && !defined(_M_X64) +#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! +//Thanks to Martin Weiss for implementing 64-bit support! #include #include -#ifndef BOOST_NO_RTTI -#include -#endif #include #include @@ -32,8 +31,10 @@ namespace #if _MSC_VER==1310 int const exception_info_offset=0x74; -#elif (_MSC_VER==1400 || _MSC_VER==1500) +#elif ((_MSC_VER==1400 || _MSC_VER==1500) && !defined _M_X64) int const exception_info_offset=0x80; +#elif ((_MSC_VER==1400 || _MSC_VER==1500) && defined _M_X64) + int const exception_info_offset=0xE0; #else int const exception_info_offset=-1; #endif @@ -58,7 +59,11 @@ namespace unsigned const cpp_exception_code=0xE06D7363; unsigned const cpp_exception_magic_flag=0x19930520; +#ifdef _M_X64 + unsigned const cpp_exception_parameter_count=4; +#else unsigned const cpp_exception_parameter_count=3; +#endif struct dummy_exception_type @@ -72,10 +77,18 @@ namespace union cpp_copy_constructor { + void * address; normal_copy_constructor_ptr normal_copy_constructor; copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base; }; + union + cpp_destructor + { + void * address; + destructor_ptr destructor; + }; + enum cpp_type_flags { @@ -83,45 +96,46 @@ namespace class_has_virtual_base=4 }; + // ATTENTION: On x86 fields such as type_info and copy_constructor are really pointers + // but on 64bit these are 32bit offsets from HINSTANCE. Hints on the 64bit handling from + // http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx . struct cpp_type_info { unsigned flags; -#ifndef BOOST_NO_RTTI - void const * type_info; -#else - std::type_info * type_info; -#endif + int type_info; int this_offset; int vbase_descr; int vbase_offset; unsigned long size; - cpp_copy_constructor copy_constructor; + int copy_constructor; }; struct cpp_type_info_table { unsigned count; - const cpp_type_info * info[1]; + int info; }; struct cpp_exception_type { unsigned flags; - destructor_ptr destructor; - void(*custom_handler)(); - cpp_type_info_table const * type_info_table; + int destructor; + int custom_handler; + int type_info_table; }; struct exception_object_deleter { cpp_exception_type const & et_; + size_t image_base_; - exception_object_deleter( cpp_exception_type const & et ): - et_(et) + exception_object_deleter( cpp_exception_type const & et, size_t image_base ): + et_(et), + image_base_(image_base) { } @@ -129,45 +143,54 @@ namespace operator()( void * obj ) { BOOST_ASSERT(obj!=0); - dummy_exception_type * dummy_exception_ptr=reinterpret_cast(obj); - (dummy_exception_ptr->*(et_.destructor))(); + dummy_exception_type* dummy_exception_ptr = static_cast(obj); + if( et_.destructor ) + { + cpp_destructor destructor; + destructor.address = reinterpret_cast(et_.destructor + image_base_); + (dummy_exception_ptr->*(destructor.destructor))(); + } free(obj); } }; cpp_type_info const & - get_cpp_type_info( cpp_exception_type const & et ) + get_cpp_type_info( cpp_exception_type const & et, size_t image_base ) { - cpp_type_info const * ti = et.type_info_table->info[0]; + cpp_type_info_table * const typearray = reinterpret_cast(et.type_info_table + image_base); + cpp_type_info * const ti = reinterpret_cast(typearray->info + image_base); BOOST_ASSERT(ti!=0); return *ti; } void - copy_msvc_exception( void * dst, void * src, cpp_type_info const & ti ) + copy_msvc_exception( void * dst, void * src, cpp_type_info const & ti, size_t image_base ) { - if( !(ti.flags & class_is_simple_type) && ti.copy_constructor.normal_copy_constructor ) + cpp_copy_constructor copy_constructor; + copy_constructor.address = reinterpret_cast(ti.copy_constructor + image_base); + + if( !(ti.flags & class_is_simple_type) && copy_constructor.normal_copy_constructor ) { - dummy_exception_type * dummy_exception_ptr = reinterpret_cast(dst); + dummy_exception_type * dummy_exception_ptr = static_cast(dst); if( ti.flags & class_has_virtual_base ) - (dummy_exception_ptr->*(ti.copy_constructor.copy_constructor_with_virtual_base))(src,dst); + (dummy_exception_ptr->*(copy_constructor.copy_constructor_with_virtual_base))(src,dst); else - (dummy_exception_ptr->*(ti.copy_constructor.normal_copy_constructor))(src); + (dummy_exception_ptr->*(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 ) + clone_msvc_exception( void * src, cpp_exception_type const & et, size_t image_base ) { - assert(src!=0); - cpp_type_info const & ti=get_cpp_type_info(et); + BOOST_ASSERT(src!=0); + cpp_type_info const & ti=get_cpp_type_info(et,image_base); if( void * dst = malloc(ti.size) ) { try { - copy_msvc_exception(dst,src,ti); + copy_msvc_exception(dst,src,ti,image_base); } catch( ... ) @@ -175,7 +198,7 @@ namespace free(dst); throw; } - return boost::shared_ptr(dst,exception_object_deleter(et)); + return boost::shared_ptr(dst,exception_object_deleter(et,image_base)); } else throw std::bad_alloc(); @@ -189,13 +212,21 @@ namespace cloned_exception & operator=( cloned_exception const & ); cpp_exception_type const & et_; + size_t image_base_; boost::shared_ptr exc_; public: + cloned_exception( EXCEPTION_RECORD const * record ): + et_(*reinterpret_cast(record->ExceptionInformation[2])), + image_base_((cpp_exception_parameter_count==4) ? record->ExceptionInformation[3] : 0), + exc_(clone_msvc_exception(reinterpret_cast(record->ExceptionInformation[1]),et_,image_base_)) + { + } - cloned_exception( void * exc, cpp_exception_type const & et ): + cloned_exception( void * exc, cpp_exception_type const & et, size_t image_base ): et_(et), - exc_(clone_msvc_exception(exc,et_)) + image_base_(image_base), + exc_(clone_msvc_exception(exc,et_,image_base)) { } @@ -206,19 +237,22 @@ namespace boost::exception_detail::clone_base const * clone() const { - return new cloned_exception(exc_.get(),et_); + return new cloned_exception(exc_.get(),et_,image_base_); } void rethrow() const { - cpp_type_info const & ti=get_cpp_type_info(et_); + cpp_type_info const & ti=get_cpp_type_info(et_,image_base_); void * dst = _alloca(ti.size); - copy_msvc_exception(dst,exc_.get(),ti); + copy_msvc_exception(dst,exc_.get(),ti,image_base_); ULONG_PTR args[cpp_exception_parameter_count]; args[0]=cpp_exception_magic_flag; args[1]=reinterpret_cast(dst); args[2]=reinterpret_cast(&et_); + if (cpp_exception_parameter_count==4) + args[3]=image_base_; + RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args); } }; @@ -237,8 +271,7 @@ namespace { BOOST_ASSERT(exception_info_offset>=0); BOOST_ASSERT(info_!=0); - EXCEPTION_POINTERS * info=reinterpret_cast(info_); - EXCEPTION_RECORD * record=info->ExceptionRecord; + EXCEPTION_RECORD* record = static_cast(info_)->ExceptionRecord; if( is_cpp_exception(record) ) { if( !record->ExceptionInformation[2] ) @@ -246,9 +279,7 @@ namespace if( is_cpp_exception(record) && record->ExceptionInformation[2] ) try { - ptr = new cloned_exception( - reinterpret_cast(record->ExceptionInformation[1]), - *reinterpret_cast(record->ExceptionInformation[2])); + ptr = new cloned_exception(record); result = boost::exception_detail::clone_current_exception_result::success; } catch( @@ -301,8 +332,6 @@ boost //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 {