1
2 #ifndef BOOST_CONTRACT_DETAIL_INLINED_EXCEPTION_HPP_
3 #define BOOST_CONTRACT_DETAIL_INLINED_EXCEPTION_HPP_
4
5 // Copyright (C) 2008-2018 Lorenzo Caminiti
6 // Distributed under the Boost Software License, Version 1.0 (see accompanying
7 // file LICENSE_1_0.txt or a copy at http://www.boost.org/LICENSE_1_0.txt).
8 // See: http://www.boost.org/doc/libs/release/libs/contract/doc/html/index.html
9
10 // IMPORTANT: Do NOT use config macros BOOST_CONTRACT_... in this file so lib
11 // .cpp does not need recompiling if config changes (recompile only user code).
12
13 #include <boost/contract/core/exception.hpp>
14 #include <boost/contract/detail/static_local_var.hpp>
15 #include <boost/contract/detail/declspec.hpp>
16 #include <boost/thread/lock_guard.hpp>
17 #include <boost/thread/mutex.hpp>
18 #include <boost/exception/diagnostic_information.hpp>
19 #include <boost/config.hpp>
20 #include <string>
21 #include <sstream>
22 #include <iostream>
23 #include <exception>
24
25 namespace boost { namespace contract {
26
27 BOOST_CONTRACT_DETAIL_DECLINLINE
~exception()28 exception::~exception() BOOST_NOEXCEPT_OR_NOTHROW {}
29
30 BOOST_CONTRACT_DETAIL_DECLINLINE
bad_virtual_result_cast(char const * from_type_name,char const * to_type_name)31 bad_virtual_result_cast::bad_virtual_result_cast(char const* from_type_name,
32 char const* to_type_name) {
33 std::ostringstream text;
34 text
35 << "incompatible contracted virtual function result type "
36 << "conversion from '" << from_type_name << "' to '"
37 << to_type_name << "'"
38 ;
39 what_ = text.str();
40 }
41
42 BOOST_CONTRACT_DETAIL_DECLINLINE
~bad_virtual_result_cast()43 bad_virtual_result_cast::~bad_virtual_result_cast() BOOST_NOEXCEPT_OR_NOTHROW {}
44
45 BOOST_CONTRACT_DETAIL_DECLINLINE
what() const46 char const* bad_virtual_result_cast::what() const BOOST_NOEXCEPT_OR_NOTHROW {
47 return what_.c_str();
48 }
49
50 BOOST_CONTRACT_DETAIL_DECLINLINE
assertion_failure(char const * const file,unsigned long const line,char const * const code)51 assertion_failure::assertion_failure(char const* const file,
52 unsigned long const line, char const* const code) :
53 file_(file), line_(line), code_(code)
54 { init(); }
55
56 BOOST_CONTRACT_DETAIL_DECLINLINE
assertion_failure(char const * const code)57 assertion_failure::assertion_failure(char const* const code) :
58 file_(""), line_(0), code_(code)
59 { init(); }
60
61 BOOST_CONTRACT_DETAIL_DECLINLINE
~assertion_failure()62 assertion_failure::~assertion_failure() BOOST_NOEXCEPT_OR_NOTHROW {}
63
64 BOOST_CONTRACT_DETAIL_DECLINLINE
what() const65 char const* assertion_failure::what() const BOOST_NOEXCEPT_OR_NOTHROW {
66 return what_.c_str();
67 }
68
69 BOOST_CONTRACT_DETAIL_DECLINLINE
file() const70 char const* assertion_failure::file() const { return file_; }
71
72 BOOST_CONTRACT_DETAIL_DECLINLINE
line() const73 unsigned long assertion_failure::line() const { return line_; }
74
75 BOOST_CONTRACT_DETAIL_DECLINLINE
code() const76 char const* assertion_failure::code() const { return code_; }
77
78 BOOST_CONTRACT_DETAIL_DECLINLINE
init()79 void assertion_failure::init() {
80 std::ostringstream text;
81 text << "assertion";
82 if(std::string(code_) != "") text << " \"" << code_ << "\"";
83 text << " failed";
84 if(std::string(file_) != "") {
85 text << ": file \"" << file_ << "\"";
86 if(line_ != 0) text << ", line " << line_;
87 }
88 what_ = text.str();
89 }
90
91 namespace exception_ {
92 enum failure_key {
93 check_failure_key,
94 pre_failure_key,
95 post_failure_key,
96 except_failure_key,
97 old_failure_key,
98 entry_inv_failure_key,
99 exit_inv_failure_key
100 };
101
102 template<failure_key Key>
default_handler()103 void default_handler() {
104 std::string k = "";
105 switch(Key) {
106 case check_failure_key: k = "check "; break;
107 case pre_failure_key: k = "precondition "; break;
108 case post_failure_key: k = "postcondition "; break;
109 case except_failure_key: k = "except "; break;
110 case old_failure_key: k = "old copy "; break;
111 case entry_inv_failure_key: k = "entry invariant "; break;
112 case exit_inv_failure_key: k = "exit invariant "; break;
113 // No default (so compiler warning/error on missing enum case).
114 }
115 try { throw; }
116 catch(boost::contract::assertion_failure const& error) {
117 // what = "assertion '...' failed: ...".
118 std::cerr << k << error.what() << std::endl;
119 } catch(...) { // old_failure_key prints this, not above.
120 std::cerr << k << "threw following exception:" << std::endl
121 << boost::current_exception_diagnostic_information();
122 }
123 std::terminate(); // Default handlers log and call terminate.
124 }
125
126 template<failure_key Key>
default_from_handler(from)127 void default_from_handler(from) { default_handler<Key>(); }
128
129 // Check failure.
130
131 struct check_failure_mutex_tag;
132 typedef boost::contract::detail::static_local_var<check_failure_mutex_tag,
133 boost::mutex> check_failure_mutex;
134
135 struct check_failure_handler_tag;
136 typedef boost::contract::detail::static_local_var_init<
137 check_failure_handler_tag,
138 failure_handler,
139 void (*)(),
140 &default_handler<check_failure_key>
141 > check_failure_handler;
142
143 BOOST_CONTRACT_DETAIL_DECLINLINE
set_check_failure_unlocked(failure_handler const & f)144 failure_handler const& set_check_failure_unlocked(failure_handler const& f)
145 BOOST_NOEXCEPT_OR_NOTHROW {
146 check_failure_handler::ref() = f;
147 return f;
148 }
149
150 BOOST_CONTRACT_DETAIL_DECLINLINE
set_check_failure_locked(failure_handler const & f)151 failure_handler const& set_check_failure_locked(failure_handler const& f)
152 BOOST_NOEXCEPT_OR_NOTHROW {
153 boost::lock_guard<boost::mutex> lock(check_failure_mutex::ref());
154 return set_check_failure_unlocked(f);
155 }
156
157 BOOST_CONTRACT_DETAIL_DECLINLINE
get_check_failure_unlocked()158 failure_handler get_check_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW {
159 return check_failure_handler::ref();
160 }
161
162 BOOST_CONTRACT_DETAIL_DECLINLINE
get_check_failure_locked()163 failure_handler get_check_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW {
164 boost::lock_guard<boost::mutex> lock(check_failure_mutex::ref());
165 return get_check_failure_unlocked();
166 }
167
168 BOOST_CONTRACT_DETAIL_DECLINLINE
check_failure_unlocked()169 void check_failure_unlocked() /* can throw */ {
170 check_failure_handler::ref()();
171 }
172
173 BOOST_CONTRACT_DETAIL_DECLINLINE
check_failure_locked()174 void check_failure_locked() /* can throw */ {
175 boost::lock_guard<boost::mutex> lock(check_failure_mutex::ref());
176 check_failure_unlocked();
177 }
178
179 // Precondition failure.
180
181 struct pre_failure_mutex_tag;
182 typedef boost::contract::detail::static_local_var<pre_failure_mutex_tag,
183 boost::mutex> pre_failure_mutex;
184
185 struct pre_failure_handler_tag;
186 typedef boost::contract::detail::static_local_var_init<
187 pre_failure_handler_tag,
188 from_failure_handler,
189 void (*)(from),
190 &default_from_handler<pre_failure_key>
191 > pre_failure_handler;
192
193 BOOST_CONTRACT_DETAIL_DECLINLINE
set_pre_failure_unlocked(from_failure_handler const & f)194 from_failure_handler const& set_pre_failure_unlocked(from_failure_handler
195 const& f) BOOST_NOEXCEPT_OR_NOTHROW {
196 pre_failure_handler::ref() = f;
197 return f;
198 }
199
200 BOOST_CONTRACT_DETAIL_DECLINLINE
set_pre_failure_locked(from_failure_handler const & f)201 from_failure_handler const& set_pre_failure_locked(from_failure_handler
202 const& f) BOOST_NOEXCEPT_OR_NOTHROW {
203 boost::lock_guard<boost::mutex> lock(pre_failure_mutex::ref());
204 return set_pre_failure_unlocked(f);
205 }
206
207 BOOST_CONTRACT_DETAIL_DECLINLINE
get_pre_failure_unlocked()208 from_failure_handler get_pre_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW {
209 return pre_failure_handler::ref();
210 }
211
212 BOOST_CONTRACT_DETAIL_DECLINLINE
get_pre_failure_locked()213 from_failure_handler get_pre_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW {
214 boost::lock_guard<boost::mutex> lock(pre_failure_mutex::ref());
215 return get_pre_failure_unlocked();
216 }
217
218 BOOST_CONTRACT_DETAIL_DECLINLINE
pre_failure_unlocked(from where)219 void pre_failure_unlocked(from where) /* can throw */ {
220 pre_failure_handler::ref()(where);
221 }
222
223 BOOST_CONTRACT_DETAIL_DECLINLINE
pre_failure_locked(from where)224 void pre_failure_locked(from where) /* can throw */ {
225 boost::lock_guard<boost::mutex> lock(pre_failure_mutex::ref());
226 pre_failure_unlocked(where);
227 }
228
229 // Postcondition failure.
230
231 struct post_failure_mutex_tag;
232 typedef boost::contract::detail::static_local_var<post_failure_mutex_tag,
233 boost::mutex> post_failure_mutex;
234
235 struct post_failure_handler_tag;
236 typedef boost::contract::detail::static_local_var_init<
237 post_failure_handler_tag,
238 from_failure_handler,
239 void (*)(from),
240 &default_from_handler<post_failure_key>
241 > post_failure_handler;
242
243 BOOST_CONTRACT_DETAIL_DECLINLINE
set_post_failure_unlocked(from_failure_handler const & f)244 from_failure_handler const& set_post_failure_unlocked(from_failure_handler
245 const& f) BOOST_NOEXCEPT_OR_NOTHROW {
246 post_failure_handler::ref() = f;
247 return f;
248 }
249
250 BOOST_CONTRACT_DETAIL_DECLINLINE
set_post_failure_locked(from_failure_handler const & f)251 from_failure_handler const& set_post_failure_locked(from_failure_handler
252 const& f) BOOST_NOEXCEPT_OR_NOTHROW {
253 boost::lock_guard<boost::mutex> lock(post_failure_mutex::ref());
254 return set_post_failure_unlocked(f);
255 }
256
257 BOOST_CONTRACT_DETAIL_DECLINLINE
get_post_failure_unlocked()258 from_failure_handler get_post_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW {
259 return post_failure_handler::ref();
260 }
261
262 BOOST_CONTRACT_DETAIL_DECLINLINE
get_post_failure_locked()263 from_failure_handler get_post_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW {
264 boost::lock_guard<boost::mutex> lock(post_failure_mutex::ref());
265 return get_post_failure_unlocked();
266 }
267
268 BOOST_CONTRACT_DETAIL_DECLINLINE
post_failure_unlocked(from where)269 void post_failure_unlocked(from where) /* can throw */ {
270 post_failure_handler::ref()(where);
271 }
272
273 BOOST_CONTRACT_DETAIL_DECLINLINE
post_failure_locked(from where)274 void post_failure_locked(from where) /* can throw */ {
275 boost::lock_guard<boost::mutex> lock(post_failure_mutex::ref());
276 post_failure_unlocked(where);
277 }
278
279 // Except failure.
280
281 struct except_failure_mutex_tag;
282 typedef boost::contract::detail::static_local_var<except_failure_mutex_tag,
283 boost::mutex> except_failure_mutex;
284
285 struct except_failure_handler_tag;
286 typedef boost::contract::detail::static_local_var_init<
287 except_failure_handler_tag,
288 from_failure_handler,
289 void (*)(from),
290 &default_from_handler<except_failure_key>
291 > except_failure_handler;
292
293 BOOST_CONTRACT_DETAIL_DECLINLINE
set_except_failure_unlocked(from_failure_handler const & f)294 from_failure_handler const& set_except_failure_unlocked(from_failure_handler
295 const& f) BOOST_NOEXCEPT_OR_NOTHROW {
296 except_failure_handler::ref() = f;
297 return f;
298 }
299
300 BOOST_CONTRACT_DETAIL_DECLINLINE
set_except_failure_locked(from_failure_handler const & f)301 from_failure_handler const& set_except_failure_locked(from_failure_handler
302 const& f) BOOST_NOEXCEPT_OR_NOTHROW {
303 boost::lock_guard<boost::mutex> lock(except_failure_mutex::ref());
304 return set_except_failure_unlocked(f);
305 }
306
307 BOOST_CONTRACT_DETAIL_DECLINLINE
get_except_failure_unlocked()308 from_failure_handler get_except_failure_unlocked()
309 BOOST_NOEXCEPT_OR_NOTHROW {
310 return except_failure_handler::ref();
311 }
312
313 BOOST_CONTRACT_DETAIL_DECLINLINE
get_except_failure_locked()314 from_failure_handler get_except_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW {
315 boost::lock_guard<boost::mutex> lock(except_failure_mutex::ref());
316 return get_except_failure_unlocked();
317 }
318
319 BOOST_CONTRACT_DETAIL_DECLINLINE
except_failure_unlocked(from where)320 void except_failure_unlocked(from where) /* can throw */ {
321 except_failure_handler::ref()(where);
322 }
323
324 BOOST_CONTRACT_DETAIL_DECLINLINE
except_failure_locked(from where)325 void except_failure_locked(from where) /* can throw */ {
326 boost::lock_guard<boost::mutex> lock(except_failure_mutex::ref());
327 except_failure_unlocked(where);
328 }
329
330 // Old-copy failure.
331
332 struct old_failure_mutex_tag;
333 typedef boost::contract::detail::static_local_var<old_failure_mutex_tag,
334 boost::mutex> old_failure_mutex;
335
336 struct old_failure_handler_tag;
337 typedef boost::contract::detail::static_local_var_init<
338 old_failure_handler_tag,
339 from_failure_handler,
340 void (*)(from),
341 &default_from_handler<old_failure_key>
342 > old_failure_handler;
343
344 BOOST_CONTRACT_DETAIL_DECLINLINE
set_old_failure_unlocked(from_failure_handler const & f)345 from_failure_handler const& set_old_failure_unlocked(from_failure_handler
346 const& f) BOOST_NOEXCEPT_OR_NOTHROW {
347 old_failure_handler::ref() = f;
348 return f;
349 }
350
351 BOOST_CONTRACT_DETAIL_DECLINLINE
set_old_failure_locked(from_failure_handler const & f)352 from_failure_handler const& set_old_failure_locked(from_failure_handler
353 const& f) BOOST_NOEXCEPT_OR_NOTHROW {
354 boost::lock_guard<boost::mutex> lock(old_failure_mutex::ref());
355 return set_old_failure_unlocked(f);
356 }
357
358 BOOST_CONTRACT_DETAIL_DECLINLINE
get_old_failure_unlocked()359 from_failure_handler get_old_failure_unlocked() BOOST_NOEXCEPT_OR_NOTHROW {
360 return old_failure_handler::ref();
361 }
362
363 BOOST_CONTRACT_DETAIL_DECLINLINE
get_old_failure_locked()364 from_failure_handler get_old_failure_locked() BOOST_NOEXCEPT_OR_NOTHROW {
365 boost::lock_guard<boost::mutex> lock(old_failure_mutex::ref());
366 return get_old_failure_unlocked();
367 }
368
369 BOOST_CONTRACT_DETAIL_DECLINLINE
old_failure_unlocked(from where)370 void old_failure_unlocked(from where) /* can throw */ {
371 old_failure_handler::ref()(where);
372 }
373
374 BOOST_CONTRACT_DETAIL_DECLINLINE
old_failure_locked(from where)375 void old_failure_locked(from where) /* can throw */ {
376 boost::lock_guard<boost::mutex> lock(old_failure_mutex::ref());
377 old_failure_unlocked(where);
378 }
379
380 // Entry invariant failure.
381
382 struct entry_inv_failure_mutex_tag;
383 typedef boost::contract::detail::static_local_var<
384 entry_inv_failure_mutex_tag, boost::mutex> entry_inv_failure_mutex;
385
386 struct entry_inv_failure_handler_tag;
387 typedef boost::contract::detail::static_local_var_init<
388 entry_inv_failure_handler_tag,
389 from_failure_handler,
390 void (*)(from),
391 &default_from_handler<entry_inv_failure_key>
392 > entry_inv_failure_handler;
393
394 BOOST_CONTRACT_DETAIL_DECLINLINE
set_entry_inv_failure_unlocked(from_failure_handler const & f)395 from_failure_handler const& set_entry_inv_failure_unlocked(
396 from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW {
397 entry_inv_failure_handler::ref() = f;
398 return f;
399 }
400
401 BOOST_CONTRACT_DETAIL_DECLINLINE
set_entry_inv_failure_locked(from_failure_handler const & f)402 from_failure_handler const& set_entry_inv_failure_locked(
403 from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW {
404 boost::lock_guard<boost::mutex> lock(entry_inv_failure_mutex::ref());
405 return set_entry_inv_failure_unlocked(f);
406 }
407
408 BOOST_CONTRACT_DETAIL_DECLINLINE
get_entry_inv_failure_unlocked()409 from_failure_handler get_entry_inv_failure_unlocked()
410 BOOST_NOEXCEPT_OR_NOTHROW {
411 return entry_inv_failure_handler::ref();
412 }
413
414 BOOST_CONTRACT_DETAIL_DECLINLINE
get_entry_inv_failure_locked()415 from_failure_handler get_entry_inv_failure_locked()
416 BOOST_NOEXCEPT_OR_NOTHROW {
417 boost::lock_guard<boost::mutex> lock(entry_inv_failure_mutex::ref());
418 return get_entry_inv_failure_unlocked();
419 }
420
421 BOOST_CONTRACT_DETAIL_DECLINLINE
entry_inv_failure_unlocked(from where)422 void entry_inv_failure_unlocked(from where) /* can throw */ {
423 entry_inv_failure_handler::ref()(where);
424 }
425
426 BOOST_CONTRACT_DETAIL_DECLINLINE
entry_inv_failure_locked(from where)427 void entry_inv_failure_locked(from where) /* can throw */ {
428 boost::lock_guard<boost::mutex> lock(entry_inv_failure_mutex::ref());
429 entry_inv_failure_unlocked(where);
430 }
431
432 // Exit invariant failure.
433
434 struct exit_inv_failure_mutex_tag;
435 typedef boost::contract::detail::static_local_var<
436 exit_inv_failure_mutex_tag, boost::mutex> exit_inv_failure_mutex;
437
438 struct exit_inv_failure_handler_tag;
439 typedef boost::contract::detail::static_local_var_init<
440 exit_inv_failure_handler_tag,
441 from_failure_handler,
442 void (*)(from),
443 &default_from_handler<exit_inv_failure_key>
444 > exit_inv_failure_handler;
445
446 BOOST_CONTRACT_DETAIL_DECLINLINE
set_exit_inv_failure_unlocked(from_failure_handler const & f)447 from_failure_handler const& set_exit_inv_failure_unlocked(
448 from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW {
449 exit_inv_failure_handler::ref() = f;
450 return f;
451 }
452
453 BOOST_CONTRACT_DETAIL_DECLINLINE
set_exit_inv_failure_locked(from_failure_handler const & f)454 from_failure_handler const& set_exit_inv_failure_locked(
455 from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW {
456 boost::lock_guard<boost::mutex> lock(exit_inv_failure_mutex::ref());
457 return set_exit_inv_failure_unlocked(f);
458 }
459
460 BOOST_CONTRACT_DETAIL_DECLINLINE
get_exit_inv_failure_unlocked()461 from_failure_handler get_exit_inv_failure_unlocked()
462 BOOST_NOEXCEPT_OR_NOTHROW {
463 return exit_inv_failure_handler::ref();
464 }
465
466 BOOST_CONTRACT_DETAIL_DECLINLINE
get_exit_inv_failure_locked()467 from_failure_handler get_exit_inv_failure_locked()
468 BOOST_NOEXCEPT_OR_NOTHROW {
469 boost::lock_guard<boost::mutex> lock(exit_inv_failure_mutex::ref());
470 return get_exit_inv_failure_unlocked();
471 }
472
473 BOOST_CONTRACT_DETAIL_DECLINLINE
exit_inv_failure_unlocked(from where)474 void exit_inv_failure_unlocked(from where) /* can throw */ {
475 exit_inv_failure_handler::ref()(where);
476 }
477
478 BOOST_CONTRACT_DETAIL_DECLINLINE
exit_inv_failure_locked(from where)479 void exit_inv_failure_locked(from where) /* can throw */ {
480 boost::lock_guard<boost::mutex> lock(exit_inv_failure_mutex::ref());
481 exit_inv_failure_unlocked(where);
482 }
483 }
484
485 from_failure_handler const& set_entry_invariant_failure(
486 from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW;
487
488 from_failure_handler const& set_exit_invariant_failure(
489 from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW;
490
491 BOOST_CONTRACT_DETAIL_DECLINLINE
set_invariant_failure(from_failure_handler const & f)492 from_failure_handler const& set_invariant_failure(
493 from_failure_handler const& f) BOOST_NOEXCEPT_OR_NOTHROW {
494 set_entry_invariant_failure(f);
495 set_exit_invariant_failure(f);
496 return f;
497 }
498
499 } } // namespace
500
501 #endif // #include guard
502
503