forked from boostorg/exception
64-bit support in clone_current_exception_non_intrusive.cpp, thanks Martin Weiss
This commit is contained in:
@ -10,18 +10,17 @@
|
|||||||
#error This file requires exception handling to be enabled.
|
#error This file requires exception handling to be enabled.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
#include <boost/exception/detail/clone_current_exception.hpp>
|
#include <boost/exception/detail/clone_current_exception.hpp>
|
||||||
|
|
||||||
#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.
|
//Non-intrusive cloning support implemented below, only for MSVC versions mentioned above.
|
||||||
//Thanks Anthony Williams!
|
//Thanks Anthony Williams!
|
||||||
|
//Thanks to Martin Weiss for implementing 64-bit support!
|
||||||
|
|
||||||
#include <boost/exception/exception.hpp>
|
#include <boost/exception/exception.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
#ifndef BOOST_NO_RTTI
|
|
||||||
#include <typeinfo>
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
|
|
||||||
@ -32,8 +31,10 @@ namespace
|
|||||||
|
|
||||||
#if _MSC_VER==1310
|
#if _MSC_VER==1310
|
||||||
int const exception_info_offset=0x74;
|
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;
|
int const exception_info_offset=0x80;
|
||||||
|
#elif ((_MSC_VER==1400 || _MSC_VER==1500) && defined _M_X64)
|
||||||
|
int const exception_info_offset=0xE0;
|
||||||
#else
|
#else
|
||||||
int const exception_info_offset=-1;
|
int const exception_info_offset=-1;
|
||||||
#endif
|
#endif
|
||||||
@ -58,7 +59,11 @@ namespace
|
|||||||
|
|
||||||
unsigned const cpp_exception_code=0xE06D7363;
|
unsigned const cpp_exception_code=0xE06D7363;
|
||||||
unsigned const cpp_exception_magic_flag=0x19930520;
|
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;
|
unsigned const cpp_exception_parameter_count=3;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct
|
struct
|
||||||
dummy_exception_type
|
dummy_exception_type
|
||||||
@ -72,10 +77,18 @@ namespace
|
|||||||
union
|
union
|
||||||
cpp_copy_constructor
|
cpp_copy_constructor
|
||||||
{
|
{
|
||||||
|
void * address;
|
||||||
normal_copy_constructor_ptr normal_copy_constructor;
|
normal_copy_constructor_ptr normal_copy_constructor;
|
||||||
copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base;
|
copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
cpp_destructor
|
||||||
|
{
|
||||||
|
void * address;
|
||||||
|
destructor_ptr destructor;
|
||||||
|
};
|
||||||
|
|
||||||
enum
|
enum
|
||||||
cpp_type_flags
|
cpp_type_flags
|
||||||
{
|
{
|
||||||
@ -83,45 +96,46 @@ namespace
|
|||||||
class_has_virtual_base=4
|
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
|
struct
|
||||||
cpp_type_info
|
cpp_type_info
|
||||||
{
|
{
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
#ifndef BOOST_NO_RTTI
|
int type_info;
|
||||||
void const * type_info;
|
|
||||||
#else
|
|
||||||
std::type_info * type_info;
|
|
||||||
#endif
|
|
||||||
int this_offset;
|
int this_offset;
|
||||||
int vbase_descr;
|
int vbase_descr;
|
||||||
int vbase_offset;
|
int vbase_offset;
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
cpp_copy_constructor copy_constructor;
|
int copy_constructor;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct
|
struct
|
||||||
cpp_type_info_table
|
cpp_type_info_table
|
||||||
{
|
{
|
||||||
unsigned count;
|
unsigned count;
|
||||||
const cpp_type_info * info[1];
|
int info;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct
|
struct
|
||||||
cpp_exception_type
|
cpp_exception_type
|
||||||
{
|
{
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
destructor_ptr destructor;
|
int destructor;
|
||||||
void(*custom_handler)();
|
int custom_handler;
|
||||||
cpp_type_info_table const * type_info_table;
|
int type_info_table;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct
|
struct
|
||||||
exception_object_deleter
|
exception_object_deleter
|
||||||
{
|
{
|
||||||
cpp_exception_type const & et_;
|
cpp_exception_type const & et_;
|
||||||
|
size_t image_base_;
|
||||||
|
|
||||||
exception_object_deleter( cpp_exception_type const & et ):
|
exception_object_deleter( cpp_exception_type const & et, size_t image_base ):
|
||||||
et_(et)
|
et_(et),
|
||||||
|
image_base_(image_base)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,45 +143,54 @@ namespace
|
|||||||
operator()( void * obj )
|
operator()( void * obj )
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(obj!=0);
|
BOOST_ASSERT(obj!=0);
|
||||||
dummy_exception_type * dummy_exception_ptr=reinterpret_cast<dummy_exception_type *>(obj);
|
dummy_exception_type* dummy_exception_ptr = static_cast<dummy_exception_type *>(obj);
|
||||||
(dummy_exception_ptr->*(et_.destructor))();
|
if( et_.destructor )
|
||||||
|
{
|
||||||
|
cpp_destructor destructor;
|
||||||
|
destructor.address = reinterpret_cast<void *>(et_.destructor + image_base_);
|
||||||
|
(dummy_exception_ptr->*(destructor.destructor))();
|
||||||
|
}
|
||||||
free(obj);
|
free(obj);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
cpp_type_info const &
|
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<cpp_type_info_table * const>(et.type_info_table + image_base);
|
||||||
|
cpp_type_info * const ti = reinterpret_cast<cpp_type_info * const>(typearray->info + image_base);
|
||||||
BOOST_ASSERT(ti!=0);
|
BOOST_ASSERT(ti!=0);
|
||||||
return *ti;
|
return *ti;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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<void *>(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<dummy_exception_type *>(dst);
|
dummy_exception_type * dummy_exception_ptr = static_cast<dummy_exception_type *>(dst);
|
||||||
if( ti.flags & class_has_virtual_base )
|
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
|
else
|
||||||
(dummy_exception_ptr->*(ti.copy_constructor.normal_copy_constructor))(src);
|
(dummy_exception_ptr->*(copy_constructor.normal_copy_constructor))(src);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
memmove(dst,src,ti.size);
|
memmove(dst,src,ti.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::shared_ptr<void>
|
boost::shared_ptr<void>
|
||||||
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);
|
BOOST_ASSERT(src!=0);
|
||||||
cpp_type_info const & ti=get_cpp_type_info(et);
|
cpp_type_info const & ti=get_cpp_type_info(et,image_base);
|
||||||
if( void * dst = malloc(ti.size) )
|
if( void * dst = malloc(ti.size) )
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
copy_msvc_exception(dst,src,ti);
|
copy_msvc_exception(dst,src,ti,image_base);
|
||||||
}
|
}
|
||||||
catch(
|
catch(
|
||||||
... )
|
... )
|
||||||
@ -175,7 +198,7 @@ namespace
|
|||||||
free(dst);
|
free(dst);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
return boost::shared_ptr<void>(dst,exception_object_deleter(et));
|
return boost::shared_ptr<void>(dst,exception_object_deleter(et,image_base));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
@ -189,13 +212,21 @@ namespace
|
|||||||
cloned_exception & operator=( cloned_exception const & );
|
cloned_exception & operator=( cloned_exception const & );
|
||||||
|
|
||||||
cpp_exception_type const & et_;
|
cpp_exception_type const & et_;
|
||||||
|
size_t image_base_;
|
||||||
boost::shared_ptr<void> exc_;
|
boost::shared_ptr<void> exc_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
cloned_exception( EXCEPTION_RECORD const * record ):
|
||||||
|
et_(*reinterpret_cast<cpp_exception_type const *>(record->ExceptionInformation[2])),
|
||||||
|
image_base_((cpp_exception_parameter_count==4) ? record->ExceptionInformation[3] : 0),
|
||||||
|
exc_(clone_msvc_exception(reinterpret_cast<void *>(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),
|
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 *
|
boost::exception_detail::clone_base const *
|
||||||
clone() const
|
clone() const
|
||||||
{
|
{
|
||||||
return new cloned_exception(exc_.get(),et_);
|
return new cloned_exception(exc_.get(),et_,image_base_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rethrow() const
|
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);
|
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];
|
ULONG_PTR args[cpp_exception_parameter_count];
|
||||||
args[0]=cpp_exception_magic_flag;
|
args[0]=cpp_exception_magic_flag;
|
||||||
args[1]=reinterpret_cast<ULONG_PTR>(dst);
|
args[1]=reinterpret_cast<ULONG_PTR>(dst);
|
||||||
args[2]=reinterpret_cast<ULONG_PTR>(&et_);
|
args[2]=reinterpret_cast<ULONG_PTR>(&et_);
|
||||||
|
if (cpp_exception_parameter_count==4)
|
||||||
|
args[3]=image_base_;
|
||||||
|
|
||||||
RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args);
|
RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -237,8 +271,7 @@ namespace
|
|||||||
{
|
{
|
||||||
BOOST_ASSERT(exception_info_offset>=0);
|
BOOST_ASSERT(exception_info_offset>=0);
|
||||||
BOOST_ASSERT(info_!=0);
|
BOOST_ASSERT(info_!=0);
|
||||||
EXCEPTION_POINTERS * info=reinterpret_cast<EXCEPTION_POINTERS *>(info_);
|
EXCEPTION_RECORD* record = static_cast<EXCEPTION_POINTERS *>(info_)->ExceptionRecord;
|
||||||
EXCEPTION_RECORD * record=info->ExceptionRecord;
|
|
||||||
if( is_cpp_exception(record) )
|
if( is_cpp_exception(record) )
|
||||||
{
|
{
|
||||||
if( !record->ExceptionInformation[2] )
|
if( !record->ExceptionInformation[2] )
|
||||||
@ -246,9 +279,7 @@ namespace
|
|||||||
if( is_cpp_exception(record) && record->ExceptionInformation[2] )
|
if( is_cpp_exception(record) && record->ExceptionInformation[2] )
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ptr = new cloned_exception(
|
ptr = new cloned_exception(record);
|
||||||
reinterpret_cast<void *>(record->ExceptionInformation[1]),
|
|
||||||
*reinterpret_cast<cpp_exception_type const *>(record->ExceptionInformation[2]));
|
|
||||||
result = boost::exception_detail::clone_current_exception_result::success;
|
result = boost::exception_detail::clone_current_exception_result::success;
|
||||||
}
|
}
|
||||||
catch(
|
catch(
|
||||||
@ -301,8 +332,6 @@ boost
|
|||||||
//On all other compilers, return clone_current_exception_result::not_supported.
|
//On all other compilers, return clone_current_exception_result::not_supported.
|
||||||
//On such platforms, only the intrusive enable_current_exception() cloning will work.
|
//On such platforms, only the intrusive enable_current_exception() cloning will work.
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
boost
|
boost
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user