exception_ptr.hpp 17 KB

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