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