]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/exception/src/clone_current_exception_non_intrusive.cpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / exception / src / clone_current_exception_non_intrusive.cpp
1 //Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
2
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)
5
6 //This MSVC-specific cpp file implements non-intrusive cloning of exception objects.
7 //Based on an exception_ptr implementation by Anthony Williams.
8
9 #ifdef BOOST_NO_EXCEPTIONS
10 #error This file requires exception handling to be enabled.
11 #endif
12
13 #include <boost/exception/detail/clone_current_exception.hpp>
14
15 #if defined(BOOST_ENABLE_NON_INTRUSIVE_EXCEPTION_PTR) && defined(_MSC_VER) && defined(_M_IX86) && !defined(_M_X64)
16
17 //Non-intrusive cloning support implemented below, only for MSVC versions mentioned above.
18 //Thanks Anthony Williams!
19
20 #include <boost/exception/exception.hpp>
21 #include <boost/shared_ptr.hpp>
22 #ifndef BOOST_NO_RTTI
23 #include <typeinfo>
24 #endif
25 #include <windows.h>
26 #include <malloc.h>
27
28 namespace
29 {
30 unsigned const exception_maximum_parameters=15;
31 unsigned const exception_noncontinuable=1;
32
33 #if _MSC_VER==1310
34 int const exception_info_offset=0x74;
35 #elif (_MSC_VER==1400 || _MSC_VER==1500)
36 int const exception_info_offset=0x80;
37 #else
38 int const exception_info_offset=-1;
39 #endif
40
41 struct
42 exception_record
43 {
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];
50 };
51
52 struct
53 exception_pointers
54 {
55 exception_record * ExceptionRecord;
56 void * ContextRecord;
57 };
58
59 unsigned const cpp_exception_code=0xE06D7363;
60 unsigned const cpp_exception_magic_flag=0x19930520;
61 unsigned const cpp_exception_parameter_count=3;
62
63 struct
64 dummy_exception_type
65 {
66 };
67
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)();
71
72 union
73 cpp_copy_constructor
74 {
75 normal_copy_constructor_ptr normal_copy_constructor;
76 copy_constructor_with_virtual_base_ptr copy_constructor_with_virtual_base;
77 };
78
79 enum
80 cpp_type_flags
81 {
82 class_is_simple_type=1,
83 class_has_virtual_base=4
84 };
85
86 struct
87 cpp_type_info
88 {
89 unsigned flags;
90 #ifndef BOOST_NO_RTTI
91 void const * type_info;
92 #else
93 std::type_info * type_info;
94 #endif
95 int this_offset;
96 int vbase_descr;
97 int vbase_offset;
98 unsigned long size;
99 cpp_copy_constructor copy_constructor;
100 };
101
102 struct
103 cpp_type_info_table
104 {
105 unsigned count;
106 const cpp_type_info * info[1];
107 };
108
109 struct
110 cpp_exception_type
111 {
112 unsigned flags;
113 destructor_ptr destructor;
114 void(*custom_handler)();
115 cpp_type_info_table const * type_info_table;
116 };
117
118 struct
119 exception_object_deleter
120 {
121 cpp_exception_type const & et_;
122
123 exception_object_deleter( cpp_exception_type const & et ):
124 et_(et)
125 {
126 }
127
128 void
129 operator()( void * obj )
130 {
131 BOOST_ASSERT(obj!=0);
132 dummy_exception_type * dummy_exception_ptr=reinterpret_cast<dummy_exception_type *>(obj);
133 (dummy_exception_ptr->*(et_.destructor))();
134 free(obj);
135 }
136 };
137
138 cpp_type_info const &
139 get_cpp_type_info( cpp_exception_type const & et )
140 {
141 cpp_type_info const * ti = et.type_info_table->info[0];
142 BOOST_ASSERT(ti!=0);
143 return *ti;
144 }
145
146 void
147 copy_msvc_exception( void * dst, void * src, cpp_type_info const & ti )
148 {
149 if( !(ti.flags & class_is_simple_type) && ti.copy_constructor.normal_copy_constructor )
150 {
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);
154 else
155 (dummy_exception_ptr->*(ti.copy_constructor.normal_copy_constructor))(src);
156 }
157 else
158 memmove(dst,src,ti.size);
159 }
160
161 boost::shared_ptr<void>
162 clone_msvc_exception( void * src, cpp_exception_type const & et )
163 {
164 assert(src!=0);
165 cpp_type_info const & ti=get_cpp_type_info(et);
166 if( void * dst = malloc(ti.size) )
167 {
168 try
169 {
170 copy_msvc_exception(dst,src,ti);
171 }
172 catch(
173 ... )
174 {
175 free(dst);
176 throw;
177 }
178 return boost::shared_ptr<void>(dst,exception_object_deleter(et));
179 }
180 else
181 throw std::bad_alloc();
182 }
183
184 class
185 cloned_exception:
186 public boost::exception_detail::clone_base
187 {
188 cloned_exception( cloned_exception const & );
189 cloned_exception & operator=( cloned_exception const & );
190
191 cpp_exception_type const & et_;
192 boost::shared_ptr<void> exc_;
193
194 public:
195
196 cloned_exception( void * exc, cpp_exception_type const & et ):
197 et_(et),
198 exc_(clone_msvc_exception(exc,et_))
199 {
200 }
201
202 ~cloned_exception() throw()
203 {
204 }
205
206 boost::exception_detail::clone_base const *
207 clone() const
208 {
209 return new cloned_exception(exc_.get(),et_);
210 }
211
212 void
213 rethrow() const
214 {
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);
223 }
224 };
225
226 bool
227 is_cpp_exception( EXCEPTION_RECORD const * record )
228 {
229 return record &&
230 (record->ExceptionCode==cpp_exception_code) &&
231 (record->NumberParameters==cpp_exception_parameter_count) &&
232 (record->ExceptionInformation[0]==cpp_exception_magic_flag);
233 }
234
235 unsigned long
236 exception_cloning_filter( int & result, boost::exception_detail::clone_base const * & ptr, void * info_ )
237 {
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) )
243 {
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] )
247 try
248 {
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;
253 }
254 catch(
255 std::bad_alloc & )
256 {
257 result = boost::exception_detail::clone_current_exception_result::bad_alloc;
258 }
259 catch(
260 ... )
261 {
262 result = boost::exception_detail::clone_current_exception_result::bad_exception;
263 }
264 }
265 return EXCEPTION_EXECUTE_HANDLER;
266 }
267 }
268
269 namespace
270 boost
271 {
272 namespace
273 exception_detail
274 {
275 int
276 clone_current_exception_non_intrusive( clone_base const * & cloned )
277 {
278 BOOST_ASSERT(!cloned);
279 int result = clone_current_exception_result::not_supported;
280 if( exception_info_offset>=0 )
281 {
282 clone_base const * ptr=0;
283 __try
284 {
285 throw;
286 }
287 __except(exception_cloning_filter(result,ptr,GetExceptionInformation()))
288 {
289 }
290 if( result==clone_current_exception_result::success )
291 cloned=ptr;
292 }
293 BOOST_ASSERT(result!=clone_current_exception_result::success || cloned);
294 return result;
295 }
296 }
297 }
298
299 #else
300
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.
303
304 #include <boost/config.hpp>
305
306 namespace
307 boost
308 {
309 namespace
310 exception_detail
311 {
312 int
313 clone_current_exception_non_intrusive( clone_base const * & )
314 {
315 return clone_current_exception_result::not_supported;
316 }
317 }
318 }
319
320 #endif