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