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/config.hpp>
14 #include <boost/exception/detail/clone_current_exception.hpp>
16 #if defined(BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR) && defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
18 //Non-intrusive cloning support implemented below, only for MSVC versions mentioned above.
19 //Thanks Anthony Williams!
20 //Thanks to Martin Weiss for implementing 64-bit support!
22 #include <boost/exception/exception.hpp>
23 #include <boost/shared_ptr.hpp>
29 unsigned const exception_maximum_parameters
=15;
30 unsigned const exception_noncontinuable
=1;
33 int const exception_info_offset
=0x74;
34 #elif ((_MSC_VER==1400 || _MSC_VER==1500) && !defined _M_X64)
35 int const exception_info_offset
=0x80;
36 #elif ((_MSC_VER==1400 || _MSC_VER==1500) && defined _M_X64)
37 int const exception_info_offset
=0xE0;
39 int const exception_info_offset
=-1;
45 unsigned long ExceptionCode
;
46 unsigned long ExceptionFlags
;
47 exception_record
* ExceptionRecord
;
48 void * ExceptionAddress
;
49 unsigned long NumberParameters
;
50 ULONG_PTR ExceptionInformation
[exception_maximum_parameters
];
56 exception_record
* ExceptionRecord
;
60 unsigned const cpp_exception_code
=0xE06D7363;
61 unsigned const cpp_exception_magic_flag
=0x19930520;
63 unsigned const cpp_exception_parameter_count
=4;
65 unsigned const cpp_exception_parameter_count
=3;
73 typedef int(dummy_exception_type::*normal_copy_constructor_ptr
)(void * src
);
74 typedef int(dummy_exception_type::*copy_constructor_with_virtual_base_ptr
)(void * src
,void * dst
);
75 typedef void (dummy_exception_type::*destructor_ptr
)();
81 normal_copy_constructor_ptr normal_copy_constructor
;
82 copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base
;
89 destructor_ptr destructor
;
95 class_is_simple_type
=1,
96 class_has_virtual_base
=4
99 // ATTENTION: On x86 fields such as type_info and copy_constructor are really pointers
100 // but on 64bit these are 32bit offsets from HINSTANCE. Hints on the 64bit handling from
101 // http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx .
111 int copy_constructor
;
131 exception_object_deleter
133 cpp_exception_type
const & et_
;
136 exception_object_deleter( cpp_exception_type
const & et
, size_t image_base
):
138 image_base_(image_base
)
143 operator()( void * obj
)
145 BOOST_ASSERT(obj
!=0);
146 dummy_exception_type
* dummy_exception_ptr
= static_cast<dummy_exception_type
*>(obj
);
149 cpp_destructor destructor
;
150 destructor
.address
= reinterpret_cast<void *>(et_
.destructor
+ image_base_
);
151 (dummy_exception_ptr
->*(destructor
.destructor
))();
157 cpp_type_info
const &
158 get_cpp_type_info( cpp_exception_type
const & et
, size_t image_base
)
160 cpp_type_info_table
* const typearray
= reinterpret_cast<cpp_type_info_table
* const>(et
.type_info_table
+ image_base
);
161 cpp_type_info
* const ti
= reinterpret_cast<cpp_type_info
* const>(typearray
->info
+ image_base
);
167 copy_msvc_exception( void * dst
, void * src
, cpp_type_info
const & ti
, size_t image_base
)
169 cpp_copy_constructor copy_constructor
;
170 copy_constructor
.address
= reinterpret_cast<void *>(ti
.copy_constructor
+ image_base
);
172 if( !(ti
.flags
& class_is_simple_type
) && copy_constructor
.normal_copy_constructor
)
174 dummy_exception_type
* dummy_exception_ptr
= static_cast<dummy_exception_type
*>(dst
);
175 if( ti
.flags
& class_has_virtual_base
)
176 (dummy_exception_ptr
->*(copy_constructor
.copy_constructor_with_virtual_base
))(src
,dst
);
178 (dummy_exception_ptr
->*(copy_constructor
.normal_copy_constructor
))(src
);
181 memmove(dst
,src
,ti
.size
);
184 boost::shared_ptr
<void>
185 clone_msvc_exception( void * src
, cpp_exception_type
const & et
, size_t image_base
)
187 BOOST_ASSERT(src
!=0);
188 cpp_type_info
const & ti
=get_cpp_type_info(et
,image_base
);
189 if( void * dst
= malloc(ti
.size
) )
193 copy_msvc_exception(dst
,src
,ti
,image_base
);
201 return boost::shared_ptr
<void>(dst
,exception_object_deleter(et
,image_base
));
204 throw std::bad_alloc();
209 public boost::exception_detail::clone_base
211 cloned_exception( cloned_exception
const & );
212 cloned_exception
& operator=( cloned_exception
const & );
214 cpp_exception_type
const & et_
;
216 boost::shared_ptr
<void> exc_
;
219 cloned_exception( EXCEPTION_RECORD
const * record
):
220 et_(*reinterpret_cast<cpp_exception_type
const *>(record
->ExceptionInformation
[2])),
221 image_base_((cpp_exception_parameter_count
==4) ? record
->ExceptionInformation
[3] : 0),
222 exc_(clone_msvc_exception(reinterpret_cast<void *>(record
->ExceptionInformation
[1]),et_
,image_base_
))
226 cloned_exception( void * exc
, cpp_exception_type
const & et
, size_t image_base
):
228 image_base_(image_base
),
229 exc_(clone_msvc_exception(exc
,et_
,image_base
))
233 ~cloned_exception() throw()
237 boost::exception_detail::clone_base
const *
240 return new cloned_exception(exc_
.get(),et_
,image_base_
);
246 cpp_type_info
const & ti
=get_cpp_type_info(et_
,image_base_
);
247 void * dst
= _alloca(ti
.size
);
248 copy_msvc_exception(dst
,exc_
.get(),ti
,image_base_
);
249 ULONG_PTR args
[cpp_exception_parameter_count
];
250 args
[0]=cpp_exception_magic_flag
;
251 args
[1]=reinterpret_cast<ULONG_PTR
>(dst
);
252 args
[2]=reinterpret_cast<ULONG_PTR
>(&et_
);
253 if (cpp_exception_parameter_count
==4)
256 RaiseException(cpp_exception_code
,EXCEPTION_NONCONTINUABLE
,cpp_exception_parameter_count
,args
);
261 is_cpp_exception( EXCEPTION_RECORD
const * record
)
264 (record
->ExceptionCode
==cpp_exception_code
) &&
265 (record
->NumberParameters
==cpp_exception_parameter_count
) &&
266 (record
->ExceptionInformation
[0]==cpp_exception_magic_flag
);
270 exception_cloning_filter( int & result
, boost::exception_detail::clone_base
const * & ptr
, void * info_
)
272 BOOST_ASSERT(exception_info_offset
>=0);
273 BOOST_ASSERT(info_
!=0);
274 EXCEPTION_RECORD
* record
= static_cast<EXCEPTION_POINTERS
*>(info_
)->ExceptionRecord
;
275 if( is_cpp_exception(record
) )
277 if( !record
->ExceptionInformation
[2] )
278 record
= *reinterpret_cast<EXCEPTION_RECORD
* *>(reinterpret_cast<char *>(_errno())+exception_info_offset
);
279 if( is_cpp_exception(record
) && record
->ExceptionInformation
[2] )
282 ptr
= new cloned_exception(record
);
283 result
= boost::exception_detail::clone_current_exception_result::success
;
288 result
= boost::exception_detail::clone_current_exception_result::bad_alloc
;
293 result
= boost::exception_detail::clone_current_exception_result::bad_exception
;
296 return EXCEPTION_EXECUTE_HANDLER
;
307 clone_current_exception_non_intrusive( clone_base
const * & cloned
)
309 BOOST_ASSERT(!cloned
);
310 int result
= clone_current_exception_result::not_supported
;
311 if( exception_info_offset
>=0 )
313 clone_base
const * ptr
=0;
318 __except(exception_cloning_filter(result
,ptr
,GetExceptionInformation()))
321 if( result
==clone_current_exception_result::success
)
324 BOOST_ASSERT(result
!=clone_current_exception_result::success
|| cloned
);
332 //On all other compilers, return clone_current_exception_result::not_supported.
333 //On such platforms, only the intrusive enable_current_exception() cloning will work.
342 clone_current_exception_non_intrusive( clone_base
const * & )
344 return clone_current_exception_result::not_supported
;