exception.hpp 17 KB

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