Return-Path: Delivered-To: apmail-incubator-stdcxx-commits-archive@www.apache.org Received: (qmail 4528 invoked from network); 22 May 2006 22:56:35 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 22 May 2006 22:56:35 -0000 Received: (qmail 8576 invoked by uid 500); 22 May 2006 22:56:35 -0000 Delivered-To: apmail-incubator-stdcxx-commits-archive@incubator.apache.org Received: (qmail 8562 invoked by uid 500); 22 May 2006 22:56:35 -0000 Mailing-List: contact stdcxx-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: stdcxx-dev@incubator.apache.org Delivered-To: mailing list stdcxx-commits@incubator.apache.org Received: (qmail 8550 invoked by uid 99); 22 May 2006 22:56:34 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 22 May 2006 15:56:34 -0700 X-ASF-Spam-Status: No, hits=0.6 required=10.0 tests=NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 22 May 2006 15:56:33 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 439871A9846; Mon, 22 May 2006 15:56:13 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r408779 - /incubator/stdcxx/trunk/tests/support/18.exception.cpp Date: Mon, 22 May 2006 22:56:12 -0000 To: stdcxx-commits@incubator.apache.org From: sebor@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060522225613.439871A9846@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: sebor Date: Mon May 22 15:56:12 2006 New Revision: 408779 URL: http://svn.apache.org/viewvc?rev=408779&view=rev Log: 2006-05-22 Martin Sebor STDCXX-4 * 18.exception.cpp: Converted to new test driver. Added: incubator/stdcxx/trunk/tests/support/18.exception.cpp (with props) Added: incubator/stdcxx/trunk/tests/support/18.exception.cpp URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/tests/support/18.exception.cpp?rev=408779&view=auto ============================================================================== --- incubator/stdcxx/trunk/tests/support/18.exception.cpp (added) +++ incubator/stdcxx/trunk/tests/support/18.exception.cpp Mon May 22 15:56:12 2006 @@ -0,0 +1,1030 @@ +/*************************************************************************** + * + * exception.cpp - test exercising [lib.support.exception] + * + * $Id$ + * + *************************************************************************** + * + * Copyright 2006 The Apache Software Foundation or its licensors, + * as applicable. + * + * Copyright 2001-2006 Rogue Wave Software. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + **************************************************************************/ + +#ifdef __SUNPRO_CC + // working around a SunPro/SunOS 5.8 bug (PR #26255) +# include +#endif // __SUNPRO_CC + +#include // for bad_exception, exception +#include // for ios_base::failure +#include // for bad_alloc +#include // for exception classes +#include // for bad_cast, bad_typeid + +#include // for jmp_buf, longjmp(), setjmp() +#include // for signal(), SIGABRT +#include // for sprintf() +#include // for strcmp(), strlen() + +#include // for _RWSTD_ERROR_XXX constants + + +#ifndef _RWSTD_NO_SETRLIMIT +# include // for setrlimit() +#endif // _RWSTD_NO_SETRLIMIT + +#include + +/**************************************************************************/ + +// check header synopsis +void test_synopsis () +{ + // verify that classes are declared + std::exception *pex = (std::exception*)0; + + // verify that bad_exception publicly derives from exception + pex = (std::bad_exception*)0; + _RWSTD_UNUSED (pex); + + // check handler types + void (*phandler)() = (std::unexpected_handler)0; + phandler = (std::terminate_handler)0; + + // check unexpected and terminate + phandler = &std::unexpected; + phandler = &std::terminate; + _RWSTD_UNUSED (phandler); + + // check set_{unexpected,terminate} + std::unexpected_handler (*pset)(std::unexpected_handler) _PTR_THROWS (()); + + pset = &std::set_unexpected; + pset = &std::set_terminate; + _RWSTD_UNUSED (pset); + + // check uncaught_exception() + // see http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#70 + // for exception specification details + bool (*pue)() _PTR_THROWS (()) = &std::uncaught_exception; + _RWSTD_UNUSED (pue); +} + +/**************************************************************************/ + + +// defined at global scope rather than as locals +// to work around an MSVC 6.0 bug (see PR #26305) +static bool dtor_virtual = false; +static bool what_virtual = false; + +// check the signatures of class exception and bad_exception members +void test_signatures () +{ +// verify that a member function is accessible and has the appropriate +// signature, including return type and exception specification +#define MEMFUN(result, T, name, arg_list) do { \ + result (T::*pf) arg_list _PTR_THROWS (()) = &T::name; \ + _RWSTD_UNUSED (pf); \ + } while (0) + + rw_info (0, 0, __LINE__, "std::exception member function signatures"); + + // verify 18.6.1 [lib.exception] + + // verify that a public default and copy ctors exist + std::exception e1; + std::exception e2 (e1); + + MEMFUN (std::exception&, std::exception, operator=, + (const std::exception&)); + MEMFUN (const char*, std::exception, what, () const); + + struct test_exception_virtuals: std::exception { + + ~test_exception_virtuals () _THROWS (()) { + dtor_virtual = true; + } + const char* what () const _THROWS (()) { + what_virtual = true; + + // working around an MSVC 6.0 bug (PR #26330) + typedef std::exception Base; + return Base::what (); + } + }; + + std::exception *pe = new test_exception_virtuals; + + // verify that destructor and what() are virtual + pe->what (); + rw_assert (what_virtual, 0, __LINE__, + "std::exception::what() not virtual"); + + delete pe; + rw_assert (dtor_virtual, 0, __LINE__, + "std::exception::~exception() not virtual"); + + + rw_info (0, 0, __LINE__, "std::bad_exception member function signatures"); + + // verify 18.6.2.1 [lib.bad.exception] + // verify that a public default and copy ctors exist + std::bad_exception be1; + std::bad_exception be2 (be1); + + MEMFUN (std::bad_exception&, std::bad_exception, operator=, + (const std::bad_exception&)); + MEMFUN (const char*, std::bad_exception, what, () const); + + dtor_virtual = false; + what_virtual = false; + + struct test_bad_exception_virtuals: std::bad_exception { + + ~test_bad_exception_virtuals () _THROWS (()) { + dtor_virtual = true; + } + const char* what () const _THROWS (()) { + what_virtual = true; + + // working around an MSVC 6.0 bug (PR #26330) + typedef std::bad_exception Base; + return Base::what (); + } + }; + + pe = new test_bad_exception_virtuals; + + // verify that destructor and what() are virtual + pe->what (); + rw_assert (what_virtual, 0, __LINE__, + "std::bad_exception::what() not virtual"); + + delete pe; + rw_assert (dtor_virtual, 0, __LINE__, + "std::bad_exception::~bad_exception() not virtual"); +} + +/**************************************************************************/ + +// test globals (to make the accessible in signal and other handlers) +std::unexpected_handler puh; // previous unexpected_handler +std::terminate_handler pth; // previous terminate_handler +int expect_abort; // SIGABRT expected if 1 +int expect_terminate; // terminate expected if 1 +int expect_unexpected; // unexpected expected if 1 +int expect_throw_proc; // throw_proc expected if 1 +std::jmp_buf env; + +/**************************************************************************/ + +// called in response to abort() (called from std::terminate()) +extern "C" { + +static void +SIGABRT_handler (int signo) +{ + rw_assert (1 == expect_abort && SIGABRT == signo, 0, __LINE__, + "SIGABRT unexpected"); + + // reestablish handler + std::signal (SIGABRT, SIGABRT_handler); + + expect_abort = -1; + + std::longjmp (env, 1); +} + +} // extern "C" + +/**************************************************************************/ + +static void +test_terminate_handler () +{ + rw_assert (1 == expect_terminate, 0, __LINE__, + "std::terminate() unexpected"); + + expect_terminate = -1; + + // establish a handler for SIGABRT (raised from abort()) + std::signal (SIGABRT, SIGABRT_handler); + + // invoke default terminate handler + pth (); + + // shouldn't be reached + rw_assert (false, 0, __LINE__, + "std::terminate() not called or returned"); + + std::longjmp (env, -1); +} + +/**************************************************************************/ + +static void +test_unexpected_handler () +{ + rw_assert (1 == expect_unexpected, 0, __LINE__, + "std::unexpected() unexpected"); + + expect_unexpected = -1; + + // establish a handler for SIGABRT (raised from abort()) + std::signal (SIGABRT, SIGABRT_handler); + + expect_abort = 1; + expect_terminate = 1; + + // throw an exception outside of any try block + // useless conditional used to prevent warnings + if (expect_abort) + throw 1; + + // shouldn't be reached + rw_assert (false, 0, __LINE__, + "std::terminate() not called or returned"); + + std::longjmp (env, -1); +} + +/**************************************************************************/ + +// test the effects of 18.6 +static void +test_effects () +{ + // verify 18.6.1, p8: whhat() returns an implementation-defined NTBS + std::exception e1; + const char *what = e1.what (); + rw_assert (what && 1 <= 1 + std::strlen (what), 0, __LINE__, + "std::exception::what() != 0"); + + std::exception e2 (e1); + what = e2.what (); + rw_assert (what && 1 <= 1 + std::strlen (what), 0, __LINE__, + "std::exception::what() != 0"); + + // verify 18.6.2.1, p5: what() returns an implementation-defined NTBS + std::bad_exception e3; + what = e3.what (); + rw_assert (what && 1 <= 1 + std::strlen (what), 0, __LINE__, + "std::bad_exception::what() != 0"); + + std::exception e4 (e3); + what = e4.what (); + rw_assert (what && 1 <= 1 + std::strlen (what), 0, __LINE__, + "std::bad_exception::what()"); + +#if !defined (_RWSTD_NO_EXCEPTIONS) \ + && !defined (_RWSTD_NO_EXCEPTION_SPECIFICATION) + + struct S { + static void foo () throw (double) { + throw 1; + } + }; + + rw_info (0, 0, __LINE__, "std::set_unexpected()"); + rw_info (0, 0, __LINE__, "std::set_terminate()"); + + // determine the address of the default + // handlers and replace them with our own + puh = std::set_unexpected (test_unexpected_handler); + pth = std::set_terminate (test_terminate_handler); + + // invoke a function that throws an exception + // that is not in its exception specification + expect_unexpected = 1; + + try { + S::foo (); + } + catch (...) { + rw_assert (0, 0, __LINE__, "incompatible exception propagated"); + } + + std::longjmp (env, -1); + +#else + + // prevent failures due to functionality not implemented in compiler + expect_abort = -1; + expect_terminate = -1; + expect_unexpected = -1; + +#endif // _RWSTD_NO_EXCEPTIONS && ... +} + +/**************************************************************************/ + +struct UncaughtExceptionCheck { + bool *presult_; + + ~UncaughtExceptionCheck () { + *presult_ = std::uncaught_exception (); + } +}; + +static void +test_uncaught_exception () +{ + rw_info (0, 0, __LINE__, "std::uncaught_exception()"); + + bool expect; + bool uncaught = std::uncaught_exception (); + +#if !defined (_RWSTD_NO_STD_UNCAUGHT_EXCEPTION) \ + || !defined (_RWSTD_NO_GLOBAL_UNCAUGHT_EXCEPTION) + + expect = false; + +#else + +# ifndef _RWSTD_NO_EXCEPTIONS + + expect = true; + +# else // if defined (_RWSTD_NO_EXCEPTIONS) + + expect = false; + +# endif // _RWSTD_NO_EXCEPTIONS) + +#endif + + rw_assert (uncaught == expect, 0, __LINE__, + "std::uncaught_exception() == %d, got %d", expect, uncaught); + +#ifndef _RWSTD_NO_EXCEPTIONS + + expect = true; + + try { + UncaughtExceptionCheck chk; + + chk.presult_ = &uncaught; + + throw 0; + } + catch (...) { + } + +#else // if defined (_RWSTD_NO_EXCEPTIONS) + + expect = false; + + { + UncaughtExceptionCheck chk; + + chk.presult_ = &uncaught; + } + +#endif // _RWSTD_NO_EXCEPTIONS + + rw_assert (uncaught == expect, 0, __LINE__, + "std::uncaught_exception() == %d, got %d", expect, uncaught); +} + +/**************************************************************************/ + +// original throw proc +void (*const pthrow_proc_save)(int, char*) = _RW::__rw_throw_proc; + +// replaces the original throw proc +static void +test_throw_proc (int id, char *s) +{ + rw_assert (id == expect_throw_proc, 0, __LINE__, + "throw_proc expected %d, got %d (\"%s\")", + expect_throw_proc, id, s); + + // do not delete[] s if returning to the lib + // must delete only if rethrowing or jumping from here + _RWSTD_UNUSED (s); + + // signal that we were successfully called and with what value + expect_throw_proc = -id; +} + +/**************************************************************************/ + +// exercise __rw::__rw_throw() and __rw::__rw_throw_proc() +static void +test_rwthrow () +{ +#ifndef _RWSTD_NO_EXCEPTIONS + + rw_info (0, 0, __LINE__, "__rw::__rw_throw()"); + + // exception format strings + static const char* strings[] = { _RWSTD_ERROR_STRINGS }; + + // exception id's: strings [i + 1] corresponds to expect [i] + static const int expect[] = { + _RWSTD_ERROR_FIRST + 1, // _RWSTD_ERROR_EXCEPTION + _RWSTD_ERROR_FIRST + 2, // _RWSTD_ERROR_BAD_EXCEPTION + _RWSTD_ERROR_FIRST + 3, // _RWSTD_ERROR_BAD_ALLOC + _RWSTD_ERROR_FIRST + 4, // _RWSTD_ERROR_BAD_CAST + _RWSTD_ERROR_LOGIC_ERROR, + _RWSTD_ERROR_DOMAIN_ERROR, + _RWSTD_ERROR_INVALID_ARGUMENT, + _RWSTD_ERROR_LENGTH_ERROR, + _RWSTD_ERROR_OUT_OF_RANGE, + _RWSTD_ERROR_RUNTIME_ERROR, + _RWSTD_ERROR_RANGE_ERROR, + _RWSTD_ERROR_OVERFLOW_ERROR, + _RWSTD_ERROR_UNDERFLOW_ERROR, + + _RWSTD_ERROR_FAILBIT_SET, + _RWSTD_ERROR_BADBIT_SET, + _RWSTD_ERROR_EOFBIT_SET, + _RWSTD_ERROR_IOSTATE_BIT_SET + }; + + const char* const ex_names[] = { + "std::exception", + "std::bad_exception", + "std::bad_alloc", + "std::bad_cast", + "std::logic_error", + "std::domain_error", + "std::invalid_argument", + "std::length_error", + "std::out_of_range", + "std::runtime_error", + "std::range_error", + "std::overflow_error", + "std::underflow_error", + + "std::ios_base::failbit_set", + "std::ios_base::badbit_set", + "std::ios_base::eofbit_set", + "std::ios_base::failure" + }; + + const char empty[] = ""; + + // raise each exception by its id, check that + // an exception object of the correct type is thrown + for (unsigned i = 0; i != sizeof expect / sizeof *expect; ++i) { + + rw_info (0, 0, __LINE__, "%s", ex_names [i]); + + int caught = -1; + + // set up a new throw proc (prevent exceptions) + _RW::__rw_throw_proc = test_throw_proc; + + // no exception should be thrown at this point + expect_throw_proc = expect [i]; + + const char format[] = _RWSTD_FILE_LINE; + const char func[] = "void test_rwthrow (Test&)"; + + _RW::__rw_throw (expect [i], format, func, empty, empty, empty); + + rw_assert (expect [i] == -expect_throw_proc, 0, __LINE__, + "%d. throw_proc (%d, ...) not called", i, expect [i]); + + try { + // reestablish original throw proc + _RW::__rw_throw_proc = pthrow_proc_save; + + // expect an exception + _RW::__rw_throw (expect [i], format, func, empty, empty, empty); + + rw_assert (false, 0, __LINE__, + "%d. __rw::__rw_throw(%d, ...) returned", + i, expect [i]); + } + catch (std::domain_error &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "domain_error::what() != 0"); + caught = _RWSTD_ERROR_DOMAIN_ERROR; + } + catch (std::invalid_argument &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "invalid_argument::what() != 0"); + caught = _RWSTD_ERROR_INVALID_ARGUMENT; + } + catch (std::length_error &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "length_error::what() != 0"); + caught = _RWSTD_ERROR_LENGTH_ERROR; + } + catch (std::out_of_range &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "out_of_range::what() != 0"); + caught = _RWSTD_ERROR_OUT_OF_RANGE; + } + catch (std::range_error &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "range_error::what() != 0"); + caught = _RWSTD_ERROR_RANGE_ERROR; + } + catch (std::overflow_error &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "overflow_error::what() != 0"); + caught = _RWSTD_ERROR_OVERFLOW_ERROR; + } + catch (std::underflow_error &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "underflow_error::what() != 0"); + caught = _RWSTD_ERROR_UNDERFLOW_ERROR; + } + catch (std::logic_error &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "logic_error::what() != 0"); + caught = _RWSTD_ERROR_LOGIC_ERROR; + } + catch (std::runtime_error &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "runtime_error::what() != 0"); + caught = _RWSTD_ERROR_RUNTIME_ERROR; + } + catch (std::bad_alloc &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "bad_alloc::what() != 0"); + caught = _RWSTD_ERROR_FIRST + 3; // _RWSTD_BAD_ALLOC + } + catch (std::bad_exception &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "bad_exception::what() != 0"); + caught = _RWSTD_ERROR_FIRST + 2; // _RWSTD_ERROR_BAD_EXCEPTION + } + catch (std::bad_cast &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "bad_cast::what() != 0"); + caught = _RWSTD_ERROR_FIRST + 4; // _RWSTD_ERROR_BAD_CAST; + } + +#ifdef _RWSTD_ERROR_BAD_TYPEID + + catch (std::bad_typeid &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "bad_typeid::what() != 0"); + caught = _RWSTD_ERROR_BAD_TYPEID; + } + +#endif // _RWSTD_ERROR_BAD_TYPEID; + +#ifndef _RWSTD_NO_EXT_FAILURE + + catch (std::ios_base::failbit_set &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "ios_base::failbit_set::what() != 0"); + caught = _RWSTD_ERROR_FAILBIT_SET; + } + catch (std::ios_base::badbit_set &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "ios_base::badbit_set::what() != 0"); + caught = _RWSTD_ERROR_BADBIT_SET; + } + catch (std::ios_base::eofbit_set &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "ios_base::eofbit_set::what() != 0"); + caught = _RWSTD_ERROR_EOFBIT_SET; + } + +#endif // _RWSTD_NO_EXT_FAILURE + + catch (std::ios_base::failure &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "ios_base::failure::what() != 0"); + caught = _RWSTD_ERROR_IOSTATE_BIT_SET; + } + catch (std::exception &ex) { + rw_assert (!!ex.what (), 0, __LINE__, + "exception::what() != 0"); + caught = _RWSTD_ERROR_FIRST + 1; // _RWSTD_ERROR_EXCEPTION + } + catch (...) { + caught = -1; + } + + rw_assert (expect [i] == caught, 0, __LINE__, + "%d. expected %d, caught %d", i, expect [i], caught); + } + + + // reestablish original throw proc + _RW::__rw_throw_proc = pthrow_proc_save; + + char str [1024]; + char result [2 * sizeof str]; + + rw_info (0, 0, __LINE__, + "exercising throwing standard exception objects " + "constructed with string arguments up to %zu " + "characters long (not including context info)", + sizeof str); + + // exercise the ability or __rw_throw() to correctly format + // strings of arbitrary length, also verify that format string + // macros are used to format the what() strings as expected + for (unsigned j = 0; j != sizeof str - 1; ++j) { + + // exclude exception, bad_alloc, bad_cast, and bad_exception + // they are typically generated by the compiler and their + // what() strings are implementation-specific + unsigned en = j % ((sizeof expect / sizeof *expect) - 5); + + // null-terminate str + str [j] = '\0'; + + std::sprintf (result, strings [en + 5], __FILE__, str, + empty, empty, empty); + + try { + // expect an exception + _RW::__rw_throw (expect [en + 4], __FILE__, str, + empty, empty, empty); + + rw_assert (false, 0, __LINE__, + "%d. __rw::__rw_throw (%d, ...) returned", + j, expect [en + 4]); + } + catch (std::exception &e) { + rw_assert (e.what () && 0 == std::strcmp (e.what (), result), + 0, __LINE__, + "%u. \"%s\" != \"%s\" [%u]", + j, e.what (), result, en + 3); + } + + // append a decimal digit + str [j] = '0' + j % 10; + } + +#endif // _RWSTD_NO_EXCEPTIONS +} + +/**************************************************************************/ + +static void +throwing_unexpected_handler () +{ + // throw an exception that can't otherwise be possibly thrown + // to induce std::bad_exception to be rethrown by the langauage + // runtime library + + struct PrivateStruct { }; + + // prevent assertions from the installed SIGABRT handler + // and terminate_handler in case they are invoked as a + // result of throwing the exception below + expect_terminate = 1; + expect_abort = 1; + + throw PrivateStruct (); +} + +/**************************************************************************/ + +enum RuntimeExceptionId { + E_bad_alloc, E_bad_cast, E_bad_exception, E_bad_typeid, E_error +}; + +// induce the language runtime into throwing an exception +// returns e if exception cannot bee thrown +static RuntimeExceptionId +induce_exception (RuntimeExceptionId reid, const char *name) +{ + const char *why = 0; + + switch (reid) { + + case E_bad_alloc: { //////////////////////////////////////////// + +#ifndef _RWSTD_NO_NEW_THROWS + +# ifndef _RWSTD_NO_SETRLIMIT + +# if !defined (__HP_aCC) + + // work around an HP aCC 5.xx (IPF) bug (PR #29014) + + // retrieve the current resource limits + struct rlimit rl = { 0, 0 }; + if (getrlimit (RLIMIT_DATA, &rl)) + return E_error; + + // set the soft limit, leave hard limit unchanged + rl.rlim_cur = 0; + if (setrlimit (RLIMIT_DATA, &rl)) + return E_error; + + try { + +# endif // __HP_aCC +# endif // _RWSTD_NO_SETRLIMIT + + // try to allocate a huge amount of memory to induce bad_alloc + ::operator new (~0UL - 4096UL); + +# ifndef _RWSTD_NO_SETRLIMIT +# if !defined (__HP_aCC) + + } + catch (...) { + + // reset the soft limit back to the value of the hard limit + rl.rlim_cur = rl.rlim_max; + setrlimit (RLIMIT_DATA, &rl); + + // rethrow bad_alloc + throw; + } + +# endif // __HP_aCC + + return E_error; + +# endif // _RWSTD_NO_SETRLIMIT + +#else // if defined (_RWSTD_NO_NEW_THROWS) + + why = "_RWSTD_NO_NEW_THROWS is #defined"; + + break; // unable to induce bad_alloc + +#endif // NO_NEW_THROWS + + } + + case E_bad_cast: { ///////////////////////////////////////////// + +#ifndef _RWSTD_NO_DYNAMIC_CAST + + struct A { virtual ~A () { } }; + struct B: A { } b; + struct C: A { }; + + A &a = b; + + // induce bad_cast + dynamic_cast(a); + + return E_error; + +#else // if defined (_RWSTD_NO_DYNAMIC_CAST) + + why = "_RWSTD_NO_DYNAMIC_CAST is #defined"; + + break; // unable to induce bad_cast + +#endif // _RWSTD_NO_DYNAMIC_CAST + } + + case E_bad_exception: { //////////////////////////////////////// + +#ifndef _RWSTD_NO_EXCEPTION_SPECIFICATION + + std::set_unexpected (throwing_unexpected_handler); + + struct S { + // induce bad_exception + S () throw (std::bad_exception) { throw 0; } + } s; + + _RWSTD_UNUSED (s); + return E_error; + +#else // if defined (_RWSTD_NO_EXCEPTION_SPECIFICATION) + + why = "_RWSTD_NO_EXCEPTION_SPECIFICATION is #defined"; + + break; // unable to induce bad_exception + +#endif // _RWSTD_NO_EXCEPTION_SPECIFICATION + + } + + case E_bad_typeid: { /////////////////////////////////////////// + +#if !defined (_RWSTD_NO_GLOBAL_BAD_TYPEID) \ + || !defined (_RWSTD_NO_STD_BAD_TYPEID) + + struct S { virtual ~S () { } } *s = 0; + + // induce bad_typeid + typeid (*s); + + return E_error; + +#else // if _RWSTD_NO_GLOBAL_BAD_TYPEID && _RWSTD_NO_STD_BAD_TYPEID + + why = "both _RWSTD_NO_GLOBAL_BAD_TYPEID and _RWSTD_NO_STD_BAD_TYPEID " + "are #defined"; + + break; // unable to induce bad_typeid + +#endif // NO_BAD_TYPEID + + } + + default: + break; + } + + rw_warn (0, 0, __LINE__, "unable to induce std::%s: %s\n", name, why); + + return reid; +} + +/**************************************************************************/ + +static const RuntimeExceptionId +rt_exceptions[] = { + E_bad_alloc, E_bad_cast, E_bad_exception, E_bad_typeid, + E_error +}; + +static const char* const +rt_exception_names[] = { + "bad_alloc", "bad_cast", "bad_exception", "bad_typeid" +}; + +static int +opt_no_rt_exception [E_error]; + + +static void +test_runtime () +{ +#ifndef _RWSTD_NO_EXCEPTIONS + + rw_info (0, 0, __LINE__, "runtime support for exceptions"); + + + // using static to avoid gcc 3.x warning: variable + // might be clobbered by `longjmp' or `vfork' + + for (static unsigned i = 0; E_error != rt_exceptions [i]; ++i) { + + const RuntimeExceptionId ex_id = rt_exceptions [i]; + const char* const ex_name = rt_exception_names [i]; + + rw_info (0, 0, __LINE__, "std::%s", ex_name); + + if (0 == rw_note (0 == opt_no_rt_exception [i], + 0, __LINE__, + "std::%s test disabled", ex_name)) + continue; + + static int ex0; + static int ex1; + + ex0 = ex1 = 0; + + try { + try { + // jump back here if the induced exception causes + // a call to terminate() and/or raises SIGABRT + if (0 == setjmp (env)) { + + // try to induce the standard exception + if (ex_id == induce_exception (ex_id, ex_name)) { + ex0 = -1; + ex1 = -1; + } + } + else { + rw_assert (false, 0, __LINE__, + "inducing std::%s caused a call " + "to std::terminate()", ex_name); + // prevent additional assertions + ex0 = -1; + } + } + catch (std::exception&) { + // so far so good, rethrow and try to catch again + ex0 = 0; + throw; + } + catch (...) { + // failure to catch a standard exception using std::exception + // most likely indication of class exception having been + // defined in a different namespace by the C++ Standard + // library than by the language support library (compiler + // runtime) + ex0 = -2; + throw; + } + } + catch (std::bad_alloc&) { ex1 = E_bad_alloc; } + catch (std::bad_cast&) { ex1 = E_bad_cast; } + catch (std::bad_exception&) { ex1 = E_bad_exception; } + catch (std::bad_typeid&) { ex1 = E_bad_typeid; } + catch (...) { ex1 = -2; } + + rw_assert (-1 == ex0 || 0 == ex0, 0, __LINE__, + "std::%s thrown, std::exception not caught", + ex_name); + + rw_assert (-1 == ex1 || rt_exceptions [i] == ex1, 0, __LINE__, + "std::%s thrown, unknown exception caught", + ex_name); + } + +#endif // _RWSTD_NO_EXCEPTIONS +} + +/**************************************************************************/ + +static int opt_no_synopsis; // for --no-synopis +static int opt_no_signatures; // for --no-signatures +static int opt_no_uncaught; // for --no-uncaught_exception +static int opt_no_effects; // for --no-effects +static int opt_no_rw_throw; // for --no-rw_throw +static int opt_no_runtime; // for --no-runtime + +static int +run_test (int, char**) +{ + // check header synopsis + rw_info (0, 0, __LINE__, "header synopsis"); + + test_synopsis (); + + // check the signatures of class exception and bad_exception members + test_signatures (); + + // exercise std::uncaught_exception() before running any other tests + // since some of them might affect the correct behavior of the function + // (if they violate such constraints as returning from a call to + // std::terminate()) + test_uncaught_exception (); + + if (0 == setjmp (env)) { + // test the effects of 18.6 + test_effects (); + } + + // verify that test worked as expected (each handler sets + // its own expect_xxx variable to -1 after it's been called) + rw_error (-1 == expect_abort, 0, __LINE__, + "abort() was called unexpectedly"); + + rw_error (-1 == expect_terminate, 0, __LINE__, + "terminate() was called unexpectedly"); + + rw_error (-1 == expect_unexpected, 0, __LINE__, + "unexpected() was called unexpectedly"); + + // exercise __rw::__rw_throw() and __rw::__rw_throw_proc() + test_rwthrow (); + + // exercise the cooperation between the C++ standard library and + // the runtime support library when throwing standard exceptions + test_runtime (); + + return 0; +} + +/**************************************************************************/ + +int main (int argc, char *argv[]) +{ + return rw_test (argc, argv, __FILE__, + "lib.support.exception", + 0 /* no comment */, + run_test, + "|-no-synopis# " + "|-no-signatures# " + "|-no-uncaught_exception# " + "|-no-effects# " + "|-no-rw_throw# " + "|-no-runtime# " + "|-no-bad_alloc# " + "|-no-bad_cast# " + "|-bad_exception# " + "|-bad_typeid#", + &opt_no_synopsis, + &opt_no_signatures, + &opt_no_uncaught, + &opt_no_effects, + &opt_no_rw_throw, + &opt_no_runtime, + opt_no_rt_exception + E_bad_alloc, + opt_no_rt_exception + E_bad_cast, + opt_no_rt_exception + E_bad_exception, + opt_no_rt_exception + E_bad_typeid, + 0 /* sentinel */); +} Propchange: incubator/stdcxx/trunk/tests/support/18.exception.cpp ------------------------------------------------------------------------------ svn:eol-style = native Propchange: incubator/stdcxx/trunk/tests/support/18.exception.cpp ------------------------------------------------------------------------------ svn:keywords = Id