Non-intrusive exception_ptr support for msvc 7.1/8.0/9.0 (thanks Anthony Williams)

[SVN r65204]
This commit is contained in:
Emil Dotchevski
2010-09-03 02:03:15 +00:00
parent 5dbd4c8f32
commit 3b4cdfce47
7 changed files with 162 additions and 338 deletions

View File

@ -21,7 +21,8 @@ boost
{ {
int const success=0; int const success=0;
int const bad_alloc=1; int const bad_alloc=1;
int const not_supported=2; int const bad_exception=2;
int const not_supported=3;
} }
class clone_base; class clone_base;

View File

@ -70,31 +70,38 @@ boost
{ {
}; };
template <int Dummy> struct
bad_exception_:
boost::exception,
std::bad_exception
{
};
template <class Exception>
exception_ptr exception_ptr
get_bad_alloc() get_static_exception_object()
{ {
bad_alloc_ ba; Exception ba;
exception_detail::clone_impl<bad_alloc_> c(ba); exception_detail::clone_impl<Exception> c(ba);
c << c <<
throw_function(BOOST_CURRENT_FUNCTION) << throw_function(BOOST_CURRENT_FUNCTION) <<
throw_file(__FILE__) << throw_file(__FILE__) <<
throw_line(__LINE__); throw_line(__LINE__);
static exception_ptr ep(new exception_detail::clone_impl<bad_alloc_>(c)); static exception_ptr ep(new exception_detail::clone_impl<Exception>(c));
return ep; return ep;
} }
template <int Dummy> template <class Exception>
struct struct
exception_ptr_bad_alloc exception_ptr_static_exception_object
{ {
static exception_ptr const e; static exception_ptr const e;
}; };
template <int Dummy> template <class Exception>
exception_ptr const exception_ptr const
exception_ptr_bad_alloc<Dummy>:: exception_ptr_static_exception_object<Exception>::
e = get_bad_alloc<Dummy>(); e = get_static_exception_object<Exception>();
} }
class class
@ -259,7 +266,13 @@ boost
bad_alloc: bad_alloc:
{ {
BOOST_ASSERT(!e); BOOST_ASSERT(!e);
return exception_detail::exception_ptr_bad_alloc<42>::e; return exception_detail::exception_ptr_static_exception_object<bad_alloc_>::e;
}
case exception_detail::clone_current_exception_result::
bad_exception:
{
BOOST_ASSERT(!e);
return exception_detail::exception_ptr_static_exception_object<bad_exception_>::e;
} }
default: default:
BOOST_ASSERT(0); BOOST_ASSERT(0);
@ -346,7 +359,7 @@ boost
catch( catch(
std::bad_exception & e ) std::bad_exception & e )
{ {
return exception_detail::current_exception_std_exception(e); return exception_detail::exception_ptr_static_exception_object<exception_detail::bad_exception_>::e;
} }
catch( catch(
std::exception & e ) std::exception & e )
@ -380,25 +393,12 @@ boost
catch( catch(
std::bad_alloc & ) std::bad_alloc & )
{ {
ret=exception_detail::exception_ptr_bad_alloc<42>::e; ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_alloc_>::e;
} }
catch( catch(
... ) ... )
{ {
try ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_exception_>::e;
{
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);
}
} }
BOOST_ASSERT(ret); BOOST_ASSERT(ret);
return ret; return ret;

View File

@ -12,6 +12,9 @@
#include <boost/exception/detail/clone_current_exception.hpp> #include <boost/exception/detail/clone_current_exception.hpp>
#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>
namespace namespace
@ -21,7 +24,7 @@ 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 #elif (_MSC_VER==1400 || _MSC_VER==1500)
int const exception_info_offset=0x80; int const exception_info_offset=0x80;
#else #else
int const exception_info_offset=-1; 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::*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)(); typedef void (dummy_exception_type::*destructor_ptr)();
union union
@ -76,7 +79,11 @@ namespace
cpp_type_info cpp_type_info
{ {
unsigned flags; 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 this_offset;
int vbase_descr; int vbase_descr;
int vbase_offset; int vbase_offset;
@ -103,47 +110,56 @@ namespace
struct struct
exception_object_deleter exception_object_deleter
{ {
cpp_exception_type const * exception_type_; cpp_exception_type const & et_;
bool run_destructor_;
exception_object_deleter( cpp_exception_type const * exception_type, bool run_destructor ): exception_object_deleter( cpp_exception_type const & et ):
exception_type_(exception_type), et_(et)
run_destructor_(run_destructor)
{ {
BOOST_ASSERT(exception_type_!=0);
} }
void void
operator()( void * exception_object ) operator()( void * obj )
{ {
BOOST_ASSERT(exception_object!=0); BOOST_ASSERT(obj!=0);
if( run_destructor_ ) dummy_exception_type * dummy_exception_ptr=reinterpret_cast<dummy_exception_type *>(obj);
{ (dummy_exception_ptr->*(et_.destructor))();
dummy_exception_type * dummy_exception_ptr=reinterpret_cast<dummy_exception_type *>(exception_object); free(obj);
(dummy_exception_ptr->*(exception_type_->destructor))();
}
free(exception_object);
} }
}; };
boost::shared_ptr<void> cpp_type_info const &
copy_msvc_exception( void * source_object, cpp_exception_type const * exception_type, bool run_destructor ) get_cpp_type_info( cpp_exception_type const & et )
{ {
void * exception_object = malloc(exception_type->type_info_table->info[0]->size); cpp_type_info const * ti = et.type_info_table->info[0];
if( !exception_object ) BOOST_ASSERT(ti!=0);
throw std::bad_alloc(); return *ti;
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 )
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<dummy_exception_type *>(exception_object); dummy_exception_type * dummy_exception_ptr = reinterpret_cast<dummy_exception_type *>(dst);
if( type->flags & class_has_virtual_base ) if( ti.flags & class_has_virtual_base )
(dummy_exception_ptr->*(type->copy_constructor.copy_constructor_with_virtual_base))(source_object,exception_object); (dummy_exception_ptr->*(ti.copy_constructor.copy_constructor_with_virtual_base))(src,dst);
else else
(dummy_exception_ptr->*(type->copy_constructor.normal_copy_constructor))(source_object); (dummy_exception_ptr->*(ti.copy_constructor.normal_copy_constructor))(src);
} }
else else
memmove(exception_object,source_object,type->size); memmove(dst,src,ti.size);
return boost::shared_ptr<void>(exception_object,exception_object_deleter(exception_type,run_destructor)); }
boost::shared_ptr<void>
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<void>(dst,exception_object_deleter(et));
} }
class class
@ -153,14 +169,14 @@ namespace
cloned_exception( cloned_exception const & ); cloned_exception( cloned_exception const & );
cloned_exception & operator=( cloned_exception const & ); cloned_exception & operator=( cloned_exception const & );
cpp_exception_type const * exception_type_; cpp_exception_type const & et_;
boost::shared_ptr<void> exception_object_; boost::shared_ptr<void> exc_;
public: public:
cloned_exception( void * source_object, cpp_exception_type const * exception_type ): cloned_exception( void * exc, cpp_exception_type const & et ):
exception_type_(exception_type), et_(et),
exception_object_(copy_msvc_exception(source_object,exception_type_,true)) exc_(clone_msvc_exception(exc,et_))
{ {
} }
@ -171,17 +187,19 @@ namespace
boost::exception_detail::clone_base const * boost::exception_detail::clone_base const *
clone() const clone() const
{ {
return new cloned_exception(exception_object_.get(),exception_type_); return new cloned_exception(exc_.get(),et_);
} }
void void
rethrow() const rethrow() const
{ {
boost::shared_ptr<void const> 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]; 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>(clone.get()); args[1]=reinterpret_cast<ULONG_PTR>(dst);
args[2]=reinterpret_cast<ULONG_PTR>(exception_type_); args[2]=reinterpret_cast<ULONG_PTR>(&et_);
RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args); RaiseException(cpp_exception_code,EXCEPTION_NONCONTINUABLE,cpp_exception_parameter_count,args);
} }
}; };
@ -198,6 +216,7 @@ namespace
unsigned long unsigned long
exception_cloning_filter( int & result, boost::exception_detail::clone_base const * & ptr, void * info_ ) exception_cloning_filter( int & result, boost::exception_detail::clone_base const * & ptr, void * info_ )
{ {
BOOST_ASSERT(exception_info_offset>=0);
BOOST_ASSERT(info_!=0); BOOST_ASSERT(info_!=0);
EXCEPTION_POINTERS * info=reinterpret_cast<EXCEPTION_POINTERS *>(info_); EXCEPTION_POINTERS * info=reinterpret_cast<EXCEPTION_POINTERS *>(info_);
EXCEPTION_RECORD * record=info->ExceptionRecord; EXCEPTION_RECORD * record=info->ExceptionRecord;
@ -210,7 +229,7 @@ namespace
{ {
ptr = new cloned_exception( ptr = new cloned_exception(
reinterpret_cast<void *>(record->ExceptionInformation[1]), reinterpret_cast<void *>(record->ExceptionInformation[1]),
reinterpret_cast<cpp_exception_type const *>(record->ExceptionInformation[2])); *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(
@ -221,7 +240,7 @@ namespace
catch( catch(
... ) ... )
{ {
BOOST_ASSERT(0); result = boost::exception_detail::clone_current_exception_result::bad_exception;
} }
} }
return EXCEPTION_EXECUTE_HANDLER; 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 <typeinfo>
#include "thread_heap_alloc.hpp"
#include <string.h>
#include "thread_primitives.hpp"
#include <excpt.h>
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<dummy_exception_type *>(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<dummy_exception_type *>(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<detail::win32::ulong_ptr>(temp.exception_object);
args[2]=reinterpret_cast<detail::win32::ulong_ptr>(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<detail::msvc_cloned_exception> 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<win32::exception_pointers *>(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<win32::exception_record * *>(reinterpret_cast<char *>(_errno())+exception_info_offset);
}
if( is_cpp_exception(record) && record->ExceptionInformation[2] )
*ptr = detail::heap_new<msvc_cloned_exception>(reinterpret_cast<void *>(record->ExceptionInformation[1]),
reinterpret_cast<cpp_exception_type const *>(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<class E>
exception_ptr
copy_exception(E e)
{
try
{
throw e;
}
catch( ... )
{
return current_exception();
}
}
}
#endif
#endif

View File

@ -11,7 +11,7 @@ project
: requirements : requirements
<exception-handling>on <exception-handling>on
<source>/boost//exception <source>/boost//exception
# <define>BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR <define>BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR
; ;
#to_string #to_string

View File

@ -146,6 +146,10 @@ test_std_exception()
#endif #endif
} }
catch( catch(
T & )
{
}
catch(
... ) ... )
{ {
BOOST_TEST(false); BOOST_TEST(false);
@ -216,6 +220,10 @@ test_std_exception_what()
#endif #endif
} }
catch( catch(
T & )
{
}
catch(
... ) ... )
{ {
BOOST_TEST(false); BOOST_TEST(false);
@ -385,6 +393,11 @@ main()
BOOST_TEST(false); BOOST_TEST(false);
} }
catch( catch(
derives_std_exception & )
{
//Yay! Non-intrusive cloning supported!
}
catch(
boost::unknown_exception & e ) boost::unknown_exception & e )
{ {
#ifndef BOOST_NO_RTTI #ifndef BOOST_NO_RTTI
@ -434,6 +447,14 @@ main()
BOOST_TEST(false); BOOST_TEST(false);
} }
catch( catch(
derives_std_boost_exception & x )
{
//Yay! Non-intrusive cloning supported!
BOOST_TEST(boost::get_error_info<my_info>(x));
if( int const * p=boost::get_error_info<my_info>(x) )
BOOST_TEST(*p==42);
}
catch(
boost::unknown_exception & x ) boost::unknown_exception & x )
{ {
BOOST_TEST(boost::get_error_info<my_info>(x)); BOOST_TEST(boost::get_error_info<my_info>(x));
@ -495,6 +516,14 @@ main()
BOOST_TEST(false); BOOST_TEST(false);
} }
catch( catch(
derives_boost_exception & x )
{
//Yay! Non-intrusive cloning supported!
BOOST_TEST(boost::get_error_info<my_info>(x));
if( int const * p=boost::get_error_info<my_info>(x) )
BOOST_TEST(*p==42);
}
catch(
boost::unknown_exception & x ) boost::unknown_exception & x )
{ {
BOOST_TEST(boost::get_error_info<my_info>(x)); BOOST_TEST(boost::get_error_info<my_info>(x));

View File

@ -6,15 +6,37 @@
#include <boost/exception_ptr.hpp> #include <boost/exception_ptr.hpp>
#include <boost/exception/get_error_info.hpp> #include <boost/exception/get_error_info.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
#include <boost/detail/atomic_count.hpp>
#include <boost/detail/lightweight_test.hpp> #include <boost/detail/lightweight_test.hpp>
typedef boost::error_info<struct tag_answer,int> answer; typedef boost::error_info<struct tag_answer,int> answer;
boost::detail::atomic_count exc_count(0);
struct struct
err: err:
virtual boost::exception, virtual boost::exception,
virtual std::exception virtual std::exception
{ {
err()
{
++exc_count;
}
err( err const & )
{
++exc_count;
}
virtual
~err() throw()
{
--exc_count;
}
private:
err & operator=( err const & );
}; };
class class
@ -116,7 +138,9 @@ simple_test()
int int
main() main()
{ {
BOOST_TEST(++exc_count==1);
simple_test(); simple_test();
thread_test(); thread_test();
BOOST_TEST(!--exc_count);
return boost::report_errors(); return boost::report_errors();
} }

View File

@ -62,6 +62,15 @@ main()
BOOST_TEST(false); BOOST_TEST(false);
} }
catch( catch(
boost::exception & x )
{
//Yay! Non-intrusive cloning supported!
if( int const * d=boost::get_error_info<test>(x) )
BOOST_TEST( 42==*d );
else
BOOST_TEST(false);
}
catch(
... ) ... )
{ {
BOOST_TEST(false); BOOST_TEST(false);
@ -101,6 +110,11 @@ main()
{ {
} }
catch( catch(
std::exception & )
{
//Yay! Non-intrusive cloning supported!
}
catch(
... ) ... )
{ {
BOOST_TEST(false); BOOST_TEST(false);
@ -114,6 +128,11 @@ main()
{ {
} }
catch( catch(
std::exception & )
{
//Yay! Non-intrusive cloning supported!
}
catch(
... ) ... )
{ {
BOOST_TEST(false); BOOST_TEST(false);