Commit 39609077 by Richard Henderson Committed by Richard Henderson

re PR libstdc++/10606 (uncaught_exception() returns false too early)

        PR libstdc++/10606
gcc/cp/
        * except.c (do_get_exception_ptr): New.
        (expand_start_catch_block): Use it.
libstdc++/
        * config/linker-map.gnu (CXXABI_1.3.1): Add __cxa_get_exception_ptr.
        * libsupc++/eh_alloc.cc (__cxa_allocate_exception): Increment
        uncaughtExceptions here instead of ...
        * libsupc++/eh_throw.cc (__cxa_throw) ... here.
        (__cxa_rethrow): Increment uncaughtExceptions here instead of ...
        * libsupc++/eh_catch.cc (__cxa_end_catch): ... here.
        (__cxa_get_exception_ptr): New.
        * libsupc++/unwind-cxx.h (__cxa_get_exception_ptr): Declare.

From-SVN: r95262
parent 5ff489f1
2005-02-18 Richard Henderson <rth@redhat.com>
PR libstdc++/10606
* except.c (do_get_exception_ptr): New.
(expand_start_catch_block): Use it.
2005-02-19 Jakub Jelinek <jakub@redhat.com> 2005-02-19 Jakub Jelinek <jakub@redhat.com>
* decl.c (start_decl_1): Only check TYPE_NEEDS_CONSTRUCTING * decl.c (start_decl_1): Only check TYPE_NEEDS_CONSTRUCTING
......
...@@ -153,6 +153,26 @@ build_exc_ptr (void) ...@@ -153,6 +153,26 @@ build_exc_ptr (void)
return build0 (EXC_PTR_EXPR, ptr_type_node); return build0 (EXC_PTR_EXPR, ptr_type_node);
} }
/* Build up a call to __cxa_get_exception_ptr so that we can build a
copy constructor for the thrown object. */
static tree
do_get_exception_ptr (void)
{
tree fn;
fn = get_identifier ("__cxa_get_exception_ptr");
if (!get_global_value_if_present (fn, &fn))
{
/* Declare void* __cxa_get_exception_ptr (void *). */
tree tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
fn = push_library_fn (fn, build_function_type (ptr_type_node, tmp));
}
return build_function_call (fn, tree_cons (NULL_TREE, build_exc_ptr (),
NULL_TREE));
}
/* Build up a call to __cxa_begin_catch, to tell the runtime that the /* Build up a call to __cxa_begin_catch, to tell the runtime that the
exception has been handled. */ exception has been handled. */
...@@ -381,9 +401,8 @@ initialize_handler_parm (tree decl, tree exp) ...@@ -381,9 +401,8 @@ initialize_handler_parm (tree decl, tree exp)
tree tree
expand_start_catch_block (tree decl) expand_start_catch_block (tree decl)
{ {
tree exp = NULL_TREE; tree exp;
tree type; tree type;
bool is_java;
if (! doing_eh (1)) if (! doing_eh (1))
return NULL_TREE; return NULL_TREE;
...@@ -397,45 +416,50 @@ expand_start_catch_block (tree decl) ...@@ -397,45 +416,50 @@ expand_start_catch_block (tree decl)
else else
type = NULL_TREE; type = NULL_TREE;
is_java = false; if (decl && decl_is_java_type (type, 1))
if (decl) {
/* Java only passes object via pointer and doesn't require
adjusting. The java object is immediately before the
generic exception header. */
exp = build_exc_ptr ();
exp = build1 (NOP_EXPR, build_pointer_type (type), exp);
exp = build2 (MINUS_EXPR, TREE_TYPE (exp), exp,
TYPE_SIZE_UNIT (TREE_TYPE (exp)));
exp = build_indirect_ref (exp, NULL);
initialize_handler_parm (decl, exp);
return type;
}
/* Call __cxa_end_catch at the end of processing the exception. */
push_eh_cleanup (type);
/* If there's no decl at all, then all we need to do is make sure
to tell the runtime that we've begun handling the exception. */
if (decl == NULL)
finish_expr_stmt (do_begin_catch ());
/* If the C++ object needs constructing, we need to do that before
calling __cxa_begin_catch, so that std::uncaught_exception gets
the right value during the copy constructor. */
else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl)))
{ {
tree init; exp = do_get_exception_ptr ();
initialize_handler_parm (decl, exp);
finish_expr_stmt (do_begin_catch ());
}
if (decl_is_java_type (type, 1)) /* Otherwise the type uses a bitwise copy, and we don't have to worry
{ about the value of std::uncaught_exception and therefore can do the
/* Java only passes object via pointer and doesn't require copy with the return value of __cxa_end_catch instead. */
adjusting. The java object is immediately before the else
generic exception header. */ {
init = build_exc_ptr (); tree init = do_begin_catch ();
init = build1 (NOP_EXPR, build_pointer_type (type), init);
init = build2 (MINUS_EXPR, TREE_TYPE (init), init,
TYPE_SIZE_UNIT (TREE_TYPE (init)));
init = build_indirect_ref (init, NULL);
is_java = true;
}
else
{
/* C++ requires that we call __cxa_begin_catch to get the
pointer to the actual object. */
init = do_begin_catch ();
}
exp = create_temporary_var (ptr_type_node); exp = create_temporary_var (ptr_type_node);
DECL_REGISTER (exp) = 1; DECL_REGISTER (exp) = 1;
cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING); cp_finish_decl (exp, init, NULL_TREE, LOOKUP_ONLYCONVERTING);
finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init)); finish_expr_stmt (build_modify_expr (exp, INIT_EXPR, init));
initialize_handler_parm (decl, exp);
} }
else
finish_expr_stmt (do_begin_catch ());
/* C++ requires that we call __cxa_end_catch at the end of
processing the exception. */
if (! is_java)
push_eh_cleanup (type);
if (decl)
initialize_handler_parm (decl, exp);
return type; return type;
} }
......
// PR libstdc++/10606
// { dg-do run }
#include <exception>
#include <cstdlib>
struct Check {
int obj1, obj2;
bool state;
};
static Check const data[] = {
{ 0, 0, false }, // construct [0]
{ 1, 0, true }, // [1] = [0]
{ 0, 0, true }, // destruct [0]
{ 2, 1, true }, // [2] = [1]
{ 2, 2, true }, // destruct [2]
{ 3, 1, true }, // [3] = [1]
{ 3, 3, false }, // destruct [3]
{ 1, 1, false }, // destruct [1]
{ 9, 9, false } // end-of-data
};
static int pos = 0;
static void test(int obj1, int obj2, bool state)
{
if (obj1 != data[pos].obj1) abort ();
if (obj2 != data[pos].obj2) abort ();
if (state != data[pos].state) abort ();
pos++;
}
struct S {
int id;
S ();
S (const S &);
~S ();
};
static int next_id = 0;
S::S()
: id (next_id++)
{
test (id, id, std::uncaught_exception ());
}
S::S(const S &x)
: id (next_id++)
{
test (id, x.id, std::uncaught_exception ());
}
S::~S()
{
test (id, id, std::uncaught_exception ());
}
extern void foo (S *);
int main()
{
try
{
try
{
S s0;
throw s0; // s1 is the exception object
}
catch (S s2)
{
throw;
}
}
catch (S s3)
{
}
return 0;
}
2005-02-18 Richard Henderson <rth@redhat.com>
PR libstdc++/10606
* config/linker-map.gnu (CXXABI_1.3.1): Add __cxa_get_exception_ptr.
* libsupc++/eh_alloc.cc (__cxa_allocate_exception): Increment
uncaughtExceptions here instead of ...
* libsupc++/eh_throw.cc (__cxa_throw) ... here.
(__cxa_rethrow): Increment uncaughtExceptions here instead of ...
* libsupc++/eh_catch.cc (__cxa_end_catch): ... here.
(__cxa_get_exception_ptr): New.
* libsupc++/unwind-cxx.h (__cxa_get_exception_ptr): Declare.
2005-02-18 Matt Austern <austern@apple.com> 2005-02-18 Matt Austern <austern@apple.com>
* testsuite/tr1/6_containers/unordered/insert/array_syntax.cc: Fix * testsuite/tr1/6_containers/unordered/insert/array_syntax.cc: Fix
test case to use assignment instead of == test case to use assignment instead of ==
* testsuite/tr1/6_containers/unordered/insert/map_range.cc: New test. * testsuite/tr1/6_containers/unordered/insert/map_range.cc: New test.
......
...@@ -410,3 +410,9 @@ CXXABI_1.3 { ...@@ -410,3 +410,9 @@ CXXABI_1.3 {
local: local:
*; *;
}; };
CXXABI_1.3.1 {
__cxa_get_exception_ptr;
} CXXABI_1.3;
...@@ -147,6 +147,12 @@ __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw() ...@@ -147,6 +147,12 @@ __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw()
std::terminate (); std::terminate ();
} }
// We have an uncaught exception as soon as we allocate memory. This
// yields uncaught_exception() true during the copy-constructor that
// initializes the exception object. See Issue 475.
__cxa_eh_globals *globals = __cxa_get_globals ();
globals->uncaughtExceptions += 1;
memset (ret, 0, sizeof (__cxa_exception)); memset (ret, 0, sizeof (__cxa_exception));
return (void *)((char *)ret + sizeof (__cxa_exception)); return (void *)((char *)ret + sizeof (__cxa_exception));
......
...@@ -33,6 +33,15 @@ ...@@ -33,6 +33,15 @@
using namespace __cxxabiv1; using namespace __cxxabiv1;
extern "C" void *
__cxxabiv1::__cxa_get_exception_ptr(void *exc_obj_in) throw()
{
_Unwind_Exception *exceptionObject
= reinterpret_cast <_Unwind_Exception *>(exc_obj_in);
__cxa_exception *header = __get_exception_header_from_ue (exceptionObject);
return header->adjustedPtr;
}
extern "C" void * extern "C" void *
__cxxabiv1::__cxa_begin_catch (void *exc_obj_in) throw() __cxxabiv1::__cxa_begin_catch (void *exc_obj_in) throw()
...@@ -107,10 +116,7 @@ __cxxabiv1::__cxa_end_catch () ...@@ -107,10 +116,7 @@ __cxxabiv1::__cxa_end_catch ()
// This exception was rethrown. Decrement the (inverted) catch // This exception was rethrown. Decrement the (inverted) catch
// count and remove it from the chain when it reaches zero. // count and remove it from the chain when it reaches zero.
if (++count == 0) if (++count == 0)
{ globals->caughtExceptions = header->nextException;
globals->uncaughtExceptions += 1;
globals->caughtExceptions = header->nextException;
}
} }
else if (--count == 0) else if (--count == 0)
{ {
......
...@@ -66,9 +66,6 @@ __cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo, ...@@ -66,9 +66,6 @@ __cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo,
header->unwindHeader.exception_class = __gxx_exception_class; header->unwindHeader.exception_class = __gxx_exception_class;
header->unwindHeader.exception_cleanup = __gxx_exception_cleanup; header->unwindHeader.exception_cleanup = __gxx_exception_cleanup;
__cxa_eh_globals *globals = __cxa_get_globals ();
globals->uncaughtExceptions += 1;
#ifdef _GLIBCXX_SJLJ_EXCEPTIONS #ifdef _GLIBCXX_SJLJ_EXCEPTIONS
_Unwind_SjLj_RaiseException (&header->unwindHeader); _Unwind_SjLj_RaiseException (&header->unwindHeader);
#else #else
...@@ -86,6 +83,8 @@ __cxxabiv1::__cxa_rethrow () ...@@ -86,6 +83,8 @@ __cxxabiv1::__cxa_rethrow ()
__cxa_eh_globals *globals = __cxa_get_globals (); __cxa_eh_globals *globals = __cxa_get_globals ();
__cxa_exception *header = globals->caughtExceptions; __cxa_exception *header = globals->caughtExceptions;
globals->uncaughtExceptions += 1;
// Watch for luser rethrowing with no active exception. // Watch for luser rethrowing with no active exception.
if (header) if (header)
{ {
......
...@@ -107,6 +107,7 @@ extern "C" void __cxa_throw (void *thrown_exception, ...@@ -107,6 +107,7 @@ extern "C" void __cxa_throw (void *thrown_exception,
__attribute__((noreturn)); __attribute__((noreturn));
// Used to implement exception handlers. // Used to implement exception handlers.
extern "C" void *__cxa_get_exception_ptr (void *) throw();
extern "C" void *__cxa_begin_catch (void *) throw(); extern "C" void *__cxa_begin_catch (void *) throw();
extern "C" void __cxa_end_catch (); extern "C" void __cxa_end_catch ();
extern "C" void __cxa_rethrow () __attribute__((noreturn)); extern "C" void __cxa_rethrow () __attribute__((noreturn));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment