1 //Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
3 //Distributed under the Boost Software License, Version 1.0. (See accompanying
4 //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //This MSVC-specific cpp file implements non-intrusive cloning of exception objects.
7 //Based on an exception_ptr implementation by Anthony Williams.
9 #ifdef BOOST_NO_EXCEPTIONS
10 #error This file requires exception handling to be enabled.
13 #include <boost/exception/detail/clone_current_exception.hpp>
15 #if defined(BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR) && defined(_MSC_VER) && defined(_M_IX86) && !defined(_M_X64)
17 //Non-intrusive cloning support implemented below, only for MSVC versions mentioned above.
18 //Thanks Anthony Williams!
20 #include <boost/exception/exception.hpp>
21 #include <boost/shared_ptr.hpp>
30 unsigned const exception_maximum_parameters
=15;
31 unsigned const exception_noncontinuable
=1;
34 int const exception_info_offset
=0x74;
35 #elif (_MSC_VER==1400 || _MSC_VER==1500)
36 int const exception_info_offset
=0x80;
38 int const exception_info_offset
=-1;
44 unsigned long ExceptionCode
;
45 unsigned long ExceptionFlags
;
46 exception_record
* ExceptionRecord
;
47 void * ExceptionAddress
;
48 unsigned long NumberParameters
;
49 ULONG_PTR ExceptionInformation
[exception_maximum_parameters
];
55 exception_record
* ExceptionRecord
;
59 unsigned const cpp_exception_code
=0xE06D7363;
60 unsigned const cpp_exception_magic_flag
=0x19930520;
61 unsigned const cpp_exception_parameter_count
=3;
68 typedef int(dummy_exception_type::*normal_copy_constructor_ptr
)(void * src
);
69 typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr
)(void * src
,void * dst
);
70 typedef void (dummy_exception_type::*destructor_ptr
)();
75 normal_copy_constructor_ptr normal_copy_constructor
;
76 copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base
;
82 class_is_simple_type
=1,
83 class_has_virtual_base
=4
91 void const * type_info
;
93 std::type_info
* type_info
;
99 cpp_copy_constructor copy_constructor
;
106 const cpp_type_info
* info
[1];
113 destructor_ptr destructor
;
114 void(*custom_handler
)();
115 cpp_type_info_table
const * type_info_table
;
119 exception_object_deleter
121 cpp_exception_type
const & et_
;
123 exception_object_deleter( cpp_exception_type
const & et
):
129 operator()( void * obj
)
131 BOOST_ASSERT(obj
!=0);
132 dummy_exception_type
* dummy_exception_ptr
=reinterpret_cast<dummy_exception_type
*>(obj
);
133 (dummy_exception_ptr
->*(et_
.destructor
))();
138 cpp_type_info
const &
139 get_cpp_type_info( cpp_exception_type
const & et
)
141 cpp_type_info
const * ti
= et
.type_info_table
->info
[0];
147 copy_msvc_exception( void * dst
, void * src
, cpp_type_info
const & ti
)
149 if( !(ti
.flags
& class_is_simple_type
) && ti
.copy_constructor
.normal_copy_constructor
)
151 dummy_exception_type
* dummy_exception_ptr
= reinterpret_cast<dummy_exception_type
*>(dst
);
152 if( ti
.flags
& class_has_virtual_base
)
153 (dummy_exception_ptr
->*(ti
.copy_constructor
.copy_constructor_with_virtual_base
))(src
,dst
);
155 (dummy_exception_ptr
->*(ti
.copy_constructor
.normal_copy_constructor
))(src
);
158 memmove(dst
,src
,ti
.size
);
161 boost::shared_ptr
<void>
162 clone_msvc_exception( void * src
, cpp_exception_type
const & et
)
165 cpp_type_info
const & ti
=get_cpp_type_info(et
);
166 if( void * dst
= malloc(ti
.size
) )
170 copy_msvc_exception(dst
,src
,ti
);
178 return boost::shared_ptr
<void>(dst
,exception_object_deleter(et
));
181 throw std::bad_alloc();
186 public boost::exception_detail::clone_base
188 cloned_exception( cloned_exception
const & );
189 cloned_exception
& operator=( cloned_exception
const & );
191 cpp_exception_type
const & et_
;
192 boost::shared_ptr
<void> exc_
;
196 cloned_exception( void * exc
, cpp_exception_type
const & et
):
198 exc_(clone_msvc_exception(exc
,et_
))
202 ~cloned_exception() throw()
206 boost::exception_detail::clone_base
const *
209 return new cloned_exception(exc_
.get(),et_
);
215 cpp_type_info
const & ti
=get_cpp_type_info(et_
);
216 void * dst
= _alloca(ti
.size
);
217 copy_msvc_exception(dst
,exc_
.get(),ti
);
218 ULONG_PTR args
[cpp_exception_parameter_count
];
219 args
[0]=cpp_exception_magic_flag
;
220 args
[1]=reinterpret_cast<ULONG_PTR
>(dst
);
221 args
[2]=reinterpret_cast<ULONG_PTR
>(&et_
);
222 RaiseException(cpp_exception_code
,EXCEPTION_NONCONTINUABLE
,cpp_exception_parameter_count
,args
);
227 is_cpp_exception( EXCEPTION_RECORD
const * record
)
230 (record
->ExceptionCode
==cpp_exception_code
) &&
231 (record
->NumberParameters
==cpp_exception_parameter_count
) &&
232 (record
->ExceptionInformation
[0]==cpp_exception_magic_flag
);
236 exception_cloning_filter( int & result
, boost::exception_detail::clone_base
const * & ptr
, void * info_
)
238 BOOST_ASSERT(exception_info_offset
>=0);
239 BOOST_ASSERT(info_
!=0);
240 EXCEPTION_POINTERS
* info
=reinterpret_cast<EXCEPTION_POINTERS
*>(info_
);
241 EXCEPTION_RECORD
* record
=info
->ExceptionRecord
;
242 if( is_cpp_exception(record
) )
244 if( !record
->ExceptionInformation
[2] )
245 record
= *reinterpret_cast<EXCEPTION_RECORD
* *>(reinterpret_cast<char *>(_errno())+exception_info_offset
);
246 if( is_cpp_exception(record
) && record
->ExceptionInformation
[2] )
249 ptr
= new cloned_exception(
250 reinterpret_cast<void *>(record
->ExceptionInformation
[1]),
251 *reinterpret_cast<cpp_exception_type
const *>(record
->ExceptionInformation
[2]));
252 result
= boost::exception_detail::clone_current_exception_result::success
;
257 result
= boost::exception_detail::clone_current_exception_result::bad_alloc
;
262 result
= boost::exception_detail::clone_current_exception_result::bad_exception
;
265 return EXCEPTION_EXECUTE_HANDLER
;
276 clone_current_exception_non_intrusive( clone_base
const * & cloned
)
278 BOOST_ASSERT(!cloned
);
279 int result
= clone_current_exception_result::not_supported
;
280 if( exception_info_offset
>=0 )
282 clone_base
const * ptr
=0;
287 __except(exception_cloning_filter(result
,ptr
,GetExceptionInformation()))
290 if( result
==clone_current_exception_result::success
)
293 BOOST_ASSERT(result
!=clone_current_exception_result::success
|| cloned
);
301 //On all other compilers, return clone_current_exception_result::not_supported.
302 //On such platforms, only the intrusive enable_current_exception() cloning will work.
304 #include <boost/config.hpp>
313 clone_current_exception_non_intrusive( clone_base
const * & )
315 return clone_current_exception_result::not_supported
;