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