// Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2008 Sebastian Redl #include #include #include #include "exception_ptr_gcc.hpp" struct foo { int a, b, c, d; foo() : a(1), b(2), c(3), d(4) { std::cerr << "Constructing foo @ " << this << "\n"; } foo(const foo &o) : a(a), b(b), c(c), d(d) { std::cerr << "Copying foo from " << &o << " to " << this << "\n"; } ~foo() { std::cerr << "Destroying foo @ " << this << "\n"; a = 0x10; b = 0x20; c = 0x30; d = 0x40; } }; void fn1() { std::cerr << "\n\n\nTest 1: Simple throw-catch-get-lose.\n" "The objective is not to crash and to not leak the exception.\n"; boost::exception_ptr p; try { throw foo(); } catch(...) { p = boost::current_exception(); } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } void fn2() { std::cerr << "\n\n\nTest 2: Simple rethrow-and-catch-again.\n" "The objective is not to crash and to not leak the exception.\n"; boost::exception_ptr p; try { throw foo(); } catch(...) { p = boost::current_exception(); } try { boost::rethrow_exception(p); } catch(...) { } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } void fn3_a() { boost::exception_ptr p; try { throw foo(); } catch(...) { p = boost::current_exception(); } boost::rethrow_exception(p); } void fn3() { std::cerr << "\n\n\nTest 3: Rethrow-and-lose-pointer.\n" "The objective is not to crash and to not leak the exception.\n"; try { fn3_a(); } catch(...) { } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } void fn4() { std::cerr << "\n\n\nTest 4: Get-twice.\n" "The objective is to produce the same pointer for both calls,\n" "not to leak it and not to double-free it.\n"; try { throw foo(); } catch(...) { boost::exception_ptr p1 = boost::current_exception(); boost::exception_ptr p2 = boost::current_exception(); if(p1 != p2) { std::cerr << "----------------------- Failed!!!\n"; } } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } void fn5() { std::cerr << "\n\n\nTest 5: Nested rethrow-and-catch-again.\n" "The objective is not to crash and to not leak the exception.\n"; boost::exception_ptr p; try { throw foo(); } catch(...) { p = boost::current_exception(); try { boost::rethrow_exception(p); } catch(...) { p = 0; p = boost::current_exception(); } } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } void fn6_a() { boost::exception_ptr p; try { throw foo(); } catch(...) { p = boost::current_exception(); } throw 0; } void fn6() { std::cerr << "\n\n\nTest 6: Catch-and-throw-other.\n" "This is known to leak. Check the exception address in test 7.\n"; try { fn6_a(); } catch(...) { } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } struct fn7_a { ~fn7_a() { boost::exception_ptr p; try { throw foo(); } catch(...) { p = boost::current_exception(); } } }; void fn7() { std::cerr << "\n\n\nTest 7: Get-and-lose in destructor.\n" "Don't leak. Check test 8.\n"; try { fn7_a x; (void)x; throw 0; } catch(...) { } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } void fn8() { std::cerr << "\n\n\nTest 8: Rethrow-other.\n" "This appears to work.\n"; try { throw 0; } catch(...) { boost::exception_ptr p; try { try { throw foo(); } catch(...) { p = boost::current_exception(); try { throw foo(); } catch(...) { boost::rethrow_exception(p); } } } catch(...) { if(boost::current_exception() != p) { std::cerr << "------------------------- Failed!!!\n"; } } // Check that the system isn't totally messed up. try { throw; } catch(...) { } } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } boost::exception_ptr fn9_a; void fn9_b() { try { throw foo(); } catch(...) { fn9_a = boost::current_exception(); } } void fn9() { std::cerr << "\n\n\nTest 9: Cross-thread.\n" "It's cross-thread rethrowing. Yeehaw!.\n"; boost::thread t(&fn9_b); t.join(); try { boost::rethrow_exception(fn9_a); } catch(...) { fn9_a = 0; } std::cerr << "++++++++++++++++++++++++ Completed.\n"; } int main() { std::cerr << std::hex; fn1(); fn2(); fn3(); fn4(); fn5(); fn6(); fn7(); fn8(); fn9(); }