exception_ptr.hpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. //Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc.
  2. //Copyright (c) 2019 Dario Menendez, Banco Santander
  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. #ifndef BOOST_EXCEPTION_618474C2DE1511DEB74A388C56D89593
  6. #define BOOST_EXCEPTION_618474C2DE1511DEB74A388C56D89593
  7. #include <boost/config.hpp>
  8. #ifdef BOOST_NO_EXCEPTIONS
  9. #error This header requires exception handling to be enabled.
  10. #endif
  11. #include <boost/exception/exception.hpp>
  12. #include <boost/exception/info.hpp>
  13. #include <boost/exception/diagnostic_information.hpp>
  14. #include <boost/exception/detail/clone_current_exception.hpp>
  15. #include <boost/exception/detail/type_info.hpp>
  16. #ifndef BOOST_NO_RTTI
  17. #include <boost/core/demangle.hpp>
  18. #endif
  19. #include <boost/shared_ptr.hpp>
  20. #include <stdexcept>
  21. #include <new>
  22. #include <ios>
  23. #include <stdlib.h>
  24. #ifndef BOOST_EXCEPTION_ENABLE_WARNINGS
  25. #if __GNUC__*100+__GNUC_MINOR__>301
  26. #pragma GCC system_header
  27. #endif
  28. #ifdef __clang__
  29. #pragma clang system_header
  30. #endif
  31. #ifdef _MSC_VER
  32. #pragma warning(push,1)
  33. #endif
  34. #endif
  35. namespace
  36. boost
  37. {
  38. class exception_ptr;
  39. BOOST_NORETURN void rethrow_exception( exception_ptr const & );
  40. exception_ptr current_exception();
  41. class
  42. exception_ptr
  43. {
  44. typedef boost::shared_ptr<exception_detail::clone_base const> impl;
  45. impl ptr_;
  46. friend void rethrow_exception( exception_ptr const & );
  47. typedef exception_detail::clone_base const * (impl::*unspecified_bool_type)() const;
  48. public:
  49. exception_ptr()
  50. {
  51. }
  52. explicit
  53. exception_ptr( impl const & ptr ):
  54. ptr_(ptr)
  55. {
  56. }
  57. bool
  58. operator==( exception_ptr const & other ) const
  59. {
  60. return ptr_==other.ptr_;
  61. }
  62. bool
  63. operator!=( exception_ptr const & other ) const
  64. {
  65. return ptr_!=other.ptr_;
  66. }
  67. operator unspecified_bool_type() const
  68. {
  69. return ptr_?&impl::get:0;
  70. }
  71. };
  72. template <class T>
  73. inline
  74. exception_ptr
  75. copy_exception( T const & e )
  76. {
  77. try
  78. {
  79. throw enable_current_exception(e);
  80. }
  81. catch(
  82. ... )
  83. {
  84. return current_exception();
  85. }
  86. }
  87. #ifndef BOOST_NO_RTTI
  88. typedef error_info<struct tag_original_exception_type,std::type_info const *> original_exception_type;
  89. inline
  90. std::string
  91. to_string( original_exception_type const & x )
  92. {
  93. return core::demangle(x.value()->name());
  94. }
  95. #endif
  96. namespace
  97. exception_detail
  98. {
  99. struct
  100. bad_alloc_:
  101. boost::exception,
  102. std::bad_alloc
  103. {
  104. ~bad_alloc_() BOOST_NOEXCEPT_OR_NOTHROW { }
  105. };
  106. struct
  107. bad_exception_:
  108. boost::exception,
  109. std::bad_exception
  110. {
  111. ~bad_exception_() BOOST_NOEXCEPT_OR_NOTHROW { }
  112. };
  113. template <class Exception>
  114. exception_ptr
  115. get_static_exception_object()
  116. {
  117. Exception ba;
  118. exception_detail::clone_impl<Exception> c(ba);
  119. #ifndef BOOST_EXCEPTION_DISABLE
  120. c <<
  121. throw_function(BOOST_CURRENT_FUNCTION) <<
  122. throw_file(__FILE__) <<
  123. throw_line(__LINE__);
  124. #endif
  125. static exception_ptr ep(shared_ptr<exception_detail::clone_base const>(new exception_detail::clone_impl<Exception>(c)));
  126. return ep;
  127. }
  128. template <class Exception>
  129. struct
  130. exception_ptr_static_exception_object
  131. {
  132. static exception_ptr const e;
  133. };
  134. template <class Exception>
  135. exception_ptr const
  136. exception_ptr_static_exception_object<Exception>::
  137. e = get_static_exception_object<Exception>();
  138. }
  139. #if defined(__GNUC__)
  140. # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
  141. # pragma GCC visibility push (default)
  142. # endif
  143. #endif
  144. class
  145. unknown_exception:
  146. public boost::exception,
  147. public std::exception
  148. {
  149. public:
  150. unknown_exception()
  151. {
  152. }
  153. explicit
  154. unknown_exception( std::exception const & e )
  155. {
  156. add_original_type(e);
  157. }
  158. explicit
  159. unknown_exception( boost::exception const & e ):
  160. boost::exception(e)
  161. {
  162. add_original_type(e);
  163. }
  164. ~unknown_exception() BOOST_NOEXCEPT_OR_NOTHROW
  165. {
  166. }
  167. private:
  168. template <class E>
  169. void
  170. add_original_type( E const & e )
  171. {
  172. #ifndef BOOST_NO_RTTI
  173. (*this) << original_exception_type(&typeid(e));
  174. #endif
  175. }
  176. };
  177. #if defined(__GNUC__)
  178. # if (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
  179. # pragma GCC visibility pop
  180. # endif
  181. #endif
  182. namespace
  183. exception_detail
  184. {
  185. template <class T>
  186. class
  187. current_exception_std_exception_wrapper:
  188. public T,
  189. public boost::exception
  190. {
  191. public:
  192. explicit
  193. current_exception_std_exception_wrapper( T const & e1 ):
  194. T(e1)
  195. {
  196. add_original_type(e1);
  197. }
  198. current_exception_std_exception_wrapper( T const & e1, boost::exception const & e2 ):
  199. T(e1),
  200. boost::exception(e2)
  201. {
  202. add_original_type(e1);
  203. }
  204. ~current_exception_std_exception_wrapper() BOOST_NOEXCEPT_OR_NOTHROW
  205. {
  206. }
  207. private:
  208. template <class E>
  209. void
  210. add_original_type( E const & e )
  211. {
  212. #ifndef BOOST_NO_RTTI
  213. (*this) << original_exception_type(&typeid(e));
  214. #endif
  215. }
  216. };
  217. #ifdef BOOST_NO_RTTI
  218. template <class T>
  219. boost::exception const *
  220. get_boost_exception( T const * )
  221. {
  222. try
  223. {
  224. throw;
  225. }
  226. catch(
  227. boost::exception & x )
  228. {
  229. return &x;
  230. }
  231. catch(...)
  232. {
  233. return 0;
  234. }
  235. }
  236. #else
  237. template <class T>
  238. boost::exception const *
  239. get_boost_exception( T const * x )
  240. {
  241. return dynamic_cast<boost::exception const *>(x);
  242. }
  243. #endif
  244. template <class T>
  245. inline
  246. exception_ptr
  247. current_exception_std_exception( T const & e1 )
  248. {
  249. if( boost::exception const * e2 = get_boost_exception(&e1) )
  250. return boost::copy_exception(current_exception_std_exception_wrapper<T>(e1,*e2));
  251. else
  252. return boost::copy_exception(current_exception_std_exception_wrapper<T>(e1));
  253. }
  254. inline
  255. exception_ptr
  256. current_exception_unknown_exception()
  257. {
  258. return boost::copy_exception(unknown_exception());
  259. }
  260. inline
  261. exception_ptr
  262. current_exception_unknown_boost_exception( boost::exception const & e )
  263. {
  264. return boost::copy_exception(unknown_exception(e));
  265. }
  266. inline
  267. exception_ptr
  268. current_exception_unknown_std_exception( std::exception const & e )
  269. {
  270. if( boost::exception const * be = get_boost_exception(&e) )
  271. return current_exception_unknown_boost_exception(*be);
  272. else
  273. return boost::copy_exception(unknown_exception(e));
  274. }
  275. #ifndef BOOST_NO_CXX11_HDR_EXCEPTION
  276. struct
  277. std_exception_ptr_wrapper
  278. {
  279. std::exception_ptr p;
  280. explicit std_exception_ptr_wrapper( std::exception_ptr const & ptr ) BOOST_NOEXCEPT:
  281. p(ptr)
  282. {
  283. }
  284. #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
  285. explicit std_exception_ptr_wrapper( std::exception_ptr && ptr ) BOOST_NOEXCEPT:
  286. p(static_cast<std::exception_ptr &&>(ptr))
  287. {
  288. }
  289. #endif
  290. };
  291. #endif
  292. inline
  293. exception_ptr
  294. current_exception_impl()
  295. {
  296. exception_detail::clone_base const * e=0;
  297. switch(
  298. exception_detail::clone_current_exception(e) )
  299. {
  300. case exception_detail::clone_current_exception_result::
  301. success:
  302. {
  303. BOOST_ASSERT(e!=0);
  304. return exception_ptr(shared_ptr<exception_detail::clone_base const>(e));
  305. }
  306. case exception_detail::clone_current_exception_result::
  307. bad_alloc:
  308. {
  309. BOOST_ASSERT(!e);
  310. return exception_detail::exception_ptr_static_exception_object<bad_alloc_>::e;
  311. }
  312. case exception_detail::clone_current_exception_result::
  313. bad_exception:
  314. {
  315. BOOST_ASSERT(!e);
  316. return exception_detail::exception_ptr_static_exception_object<bad_exception_>::e;
  317. }
  318. default:
  319. BOOST_ASSERT(0);
  320. case exception_detail::clone_current_exception_result::
  321. not_supported:
  322. {
  323. BOOST_ASSERT(!e);
  324. try
  325. {
  326. throw;
  327. }
  328. catch(
  329. exception_detail::clone_base & e )
  330. {
  331. return exception_ptr(shared_ptr<exception_detail::clone_base const>(e.clone()));
  332. }
  333. catch(
  334. std::domain_error & e )
  335. {
  336. return exception_detail::current_exception_std_exception(e);
  337. }
  338. catch(
  339. std::invalid_argument & e )
  340. {
  341. return exception_detail::current_exception_std_exception(e);
  342. }
  343. catch(
  344. std::length_error & e )
  345. {
  346. return exception_detail::current_exception_std_exception(e);
  347. }
  348. catch(
  349. std::out_of_range & e )
  350. {
  351. return exception_detail::current_exception_std_exception(e);
  352. }
  353. catch(
  354. std::logic_error & e )
  355. {
  356. return exception_detail::current_exception_std_exception(e);
  357. }
  358. catch(
  359. std::range_error & e )
  360. {
  361. return exception_detail::current_exception_std_exception(e);
  362. }
  363. catch(
  364. std::overflow_error & e )
  365. {
  366. return exception_detail::current_exception_std_exception(e);
  367. }
  368. catch(
  369. std::underflow_error & e )
  370. {
  371. return exception_detail::current_exception_std_exception(e);
  372. }
  373. catch(
  374. std::ios_base::failure & e )
  375. {
  376. return exception_detail::current_exception_std_exception(e);
  377. }
  378. catch(
  379. std::runtime_error & e )
  380. {
  381. return exception_detail::current_exception_std_exception(e);
  382. }
  383. catch(
  384. std::bad_alloc & e )
  385. {
  386. return exception_detail::current_exception_std_exception(e);
  387. }
  388. #ifndef BOOST_NO_TYPEID
  389. catch(
  390. std::bad_cast & e )
  391. {
  392. return exception_detail::current_exception_std_exception(e);
  393. }
  394. catch(
  395. std::bad_typeid & e )
  396. {
  397. return exception_detail::current_exception_std_exception(e);
  398. }
  399. #endif
  400. catch(
  401. std::bad_exception & e )
  402. {
  403. return exception_detail::current_exception_std_exception(e);
  404. }
  405. #ifdef BOOST_NO_CXX11_HDR_EXCEPTION
  406. // this case can be handled losslesly with std::current_exception() (see below)
  407. catch(
  408. std::exception & e )
  409. {
  410. return exception_detail::current_exception_unknown_std_exception(e);
  411. }
  412. #endif
  413. catch(
  414. boost::exception & e )
  415. {
  416. return exception_detail::current_exception_unknown_boost_exception(e);
  417. }
  418. catch(
  419. ... )
  420. {
  421. #ifndef BOOST_NO_CXX11_HDR_EXCEPTION
  422. try
  423. {
  424. // wrap the std::exception_ptr in a clone-enabled Boost.Exception object
  425. exception_detail::clone_base const & base =
  426. boost::enable_current_exception(std_exception_ptr_wrapper(std::current_exception()));
  427. return exception_ptr(shared_ptr<exception_detail::clone_base const>(base.clone()));
  428. }
  429. catch(
  430. ...)
  431. {
  432. return exception_detail::current_exception_unknown_exception();
  433. }
  434. #else
  435. return exception_detail::current_exception_unknown_exception();
  436. #endif
  437. }
  438. }
  439. }
  440. }
  441. }
  442. inline
  443. exception_ptr
  444. current_exception()
  445. {
  446. exception_ptr ret;
  447. try
  448. {
  449. ret=exception_detail::current_exception_impl();
  450. }
  451. catch(
  452. std::bad_alloc & )
  453. {
  454. ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_alloc_>::e;
  455. }
  456. catch(
  457. ... )
  458. {
  459. ret=exception_detail::exception_ptr_static_exception_object<exception_detail::bad_exception_>::e;
  460. }
  461. BOOST_ASSERT(ret);
  462. return ret;
  463. }
  464. BOOST_NORETURN
  465. inline
  466. void
  467. rethrow_exception( exception_ptr const & p )
  468. {
  469. BOOST_ASSERT(p);
  470. #ifndef BOOST_NO_CXX11_HDR_EXCEPTION
  471. try
  472. {
  473. p.ptr_->rethrow();
  474. }
  475. catch(
  476. exception_detail::std_exception_ptr_wrapper const & wrp)
  477. {
  478. // if an std::exception_ptr was wrapped above then rethrow it
  479. std::rethrow_exception(wrp.p);
  480. }
  481. #else
  482. p.ptr_->rethrow();
  483. #endif
  484. BOOST_ASSERT(0);
  485. #if defined(UNDER_CE)
  486. // some CE platforms don't define ::abort()
  487. exit(-1);
  488. #else
  489. abort();
  490. #endif
  491. }
  492. inline
  493. std::string
  494. diagnostic_information( exception_ptr const & p, bool verbose=true )
  495. {
  496. if( p )
  497. try
  498. {
  499. rethrow_exception(p);
  500. }
  501. catch(
  502. ... )
  503. {
  504. return current_exception_diagnostic_information(verbose);
  505. }
  506. return "<empty>";
  507. }
  508. inline
  509. std::string
  510. to_string( exception_ptr const & p )
  511. {
  512. std::string s='\n'+diagnostic_information(p);
  513. std::string padding(" ");
  514. std::string r;
  515. bool f=false;
  516. for( std::string::const_iterator i=s.begin(),e=s.end(); i!=e; ++i )
  517. {
  518. if( f )
  519. r+=padding;
  520. char c=*i;
  521. r+=c;
  522. f=(c=='\n');
  523. }
  524. return r;
  525. }
  526. }
  527. #if defined(_MSC_VER) && !defined(BOOST_EXCEPTION_ENABLE_WARNINGS)
  528. #pragma warning(pop)
  529. #endif
  530. #endif