From: Jakub Jelinek Date: Sat, 15 Dec 2018 23:51:31 +0000 (+0100) Subject: re PR c++/88482 (ICE when wrongly declaring __cxa_allocate_exception) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=784417d1f808ea70f013a90aeede3b20e6013e39;p=gcc.git re PR c++/88482 (ICE when wrongly declaring __cxa_allocate_exception) PR c++/88482 * except.c (verify_library_fn): New function. (declare_library_fn): Use it. Initialize TM even if the non-TM library function has been user declared. (do_end_catch): Don't set TREE_NOTHROW on error_mark_node. (expand_start_catch_block): Don't call initialize_handler_parm for error_mark_node. (build_throw): Use verify_library_fn. Initialize TM even if the non-TM library function has been user declared. Don't crash if any library fn is error_mark_node. * g++.dg/eh/builtin5.C: New test. * g++.dg/eh/builtin6.C: New test. * g++.dg/eh/builtin7.C: New test. * g++.dg/eh/builtin8.C: New test. * g++.dg/eh/builtin9.C: New test. * g++.dg/eh/builtin10.C: New test. * g++.dg/eh/builtin11.C: New test. * g++.dg/parse/crash55.C: Adjust expected diagnostics. * eh_cpp.cc (__cxa_throw): Change DEST argument type from void * to void (*) (void *). (_ITM_cxa_throw): Likewise. * libitm.h (_ITM_cxa_throw): Likewise. * libitm.texi (_ITM_cxa_throw): Likewise. From-SVN: r267179 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9b8dae3c504..d12173e69e9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +2018-12-16 Jakub Jelinek + + PR c++/88482 + * except.c (verify_library_fn): New function. + (declare_library_fn): Use it. Initialize TM even if the non-TM + library function has been user declared. + (do_end_catch): Don't set TREE_NOTHROW on error_mark_node. + (expand_start_catch_block): Don't call initialize_handler_parm + for error_mark_node. + (build_throw): Use verify_library_fn. Initialize TM even if the + non-TM library function has been user declared. Don't crash if + any library fn is error_mark_node. + 2018-12-14 Jason Merrill * pt.c (tsubst_expr) [DECL_EXPR]: Ignore class-scope bindings when diff --git a/gcc/cp/except.c b/gcc/cp/except.c index ab1bd8267ff..b04eb0c5332 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -132,6 +132,49 @@ build_exc_ptr (void) 1, integer_zero_node); } +/* Check that user declared function FN is a function and has return + type RTYPE and argument types ARG{1,2,3}TYPE. */ + +static bool +verify_library_fn (tree fn, const char *name, tree rtype, + tree arg1type, tree arg2type, tree arg3type) +{ + if (TREE_CODE (fn) != FUNCTION_DECL + || TREE_CODE (TREE_TYPE (fn)) != FUNCTION_TYPE) + { + bad: + error_at (DECL_SOURCE_LOCATION (fn), "%qs declared incorrectly", name); + return false; + } + tree fntype = TREE_TYPE (fn); + if (!same_type_p (TREE_TYPE (fntype), rtype)) + goto bad; + tree targs = TYPE_ARG_TYPES (fntype); + tree args[3] = { arg1type, arg2type, arg3type }; + for (int i = 0; i < 3 && args[i]; i++) + { + if (targs == NULL_TREE) + goto bad; + if (!same_type_p (TREE_VALUE (targs), args[i])) + { + if (i == 0) + goto bad; + /* Be less strict for second and following arguments, __cxa_throw + needs to be more permissive. */ + if (TYPE_PTROBV_P (TREE_VALUE (targs)) && TYPE_PTROBV_P (args[i])) + /* Both object pointers. */; + else if (TYPE_PTRFN_P (TREE_VALUE (targs)) && TYPE_PTRFN_P (args[i])) + /* Both function pointers. */; + else + goto bad; + } + targs = TREE_CHAIN (targs); + } + if (targs != void_list_node) + goto bad; + return true; +} + /* Find or declare a function NAME, returning RTYPE, taking a single parameter PTYPE, with an empty exception specification. ECF are the library fn flags. If TM_ECF is non-zero, also find or create a @@ -148,21 +191,39 @@ declare_library_fn (const char *name, tree rtype, tree ptype, { tree ident = get_identifier (name); tree res = get_global_binding (ident); + tree fntype = NULL_TREE; + tree except = NULL_TREE; if (!res) { - tree type = build_function_type_list (rtype, ptype, NULL_TREE); - tree except = ecf & ECF_NOTHROW ? empty_except_spec : NULL_TREE; - res = push_library_fn (ident, type, except, ecf); - if (tm_ecf && flag_tm) + fntype = build_function_type_list (rtype, ptype, NULL_TREE); + if (ecf & ECF_NOTHROW) + except = empty_except_spec; + res = push_library_fn (ident, fntype, except, ecf); + } + else if (!verify_library_fn (res, name, rtype, ptype, NULL_TREE, NULL_TREE)) + return error_mark_node; + + if (tm_ecf && flag_tm) + { + char *tm_name = concat ("_ITM_", name + 2, NULL_TREE); + tree tm_ident = get_identifier (tm_name); + tree tm_fn = get_global_binding (tm_ident); + if (!tm_fn) { - char *tm_name = concat ("_ITM_", name + 2, NULL_TREE); - tree tm_ident = get_identifier (tm_name); - free (tm_name); - tree tm_fn = get_global_binding (tm_ident); - if (!tm_fn) - tm_fn = push_library_fn (tm_ident, type, except, ecf | tm_ecf); - record_tm_replacement (res, tm_fn); + if (!fntype) + { + fntype = build_function_type_list (rtype, ptype, NULL_TREE); + if (ecf & ECF_NOTHROW) + except = empty_except_spec; + } + tm_fn = push_library_fn (tm_ident, fntype, except, ecf | tm_ecf); } + else if (!verify_library_fn (tm_fn, tm_name, rtype, ptype, + NULL_TREE, NULL_TREE)) + tm_fn = error_mark_node; + free (tm_name); + if (tm_fn != error_mark_node) + record_tm_replacement (res, tm_fn); } return res; } @@ -236,7 +297,8 @@ do_end_catch (tree type) tree cleanup = cp_build_function_call_vec (end_catch_fn, NULL, tf_warning_or_error); - TREE_NOTHROW (cleanup) = dtor_nothrow (type); + if (cleanup != error_mark_node) + TREE_NOTHROW (cleanup) = dtor_nothrow (type); return cleanup; } @@ -400,7 +462,8 @@ expand_start_catch_block (tree decl) && TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))) { exp = do_get_exception_ptr (); - initialize_handler_parm (decl, exp); + if (exp != error_mark_node) + initialize_handler_parm (decl, exp); finish_expr_stmt (init); } @@ -608,23 +671,44 @@ build_throw (tree exp) if (!throw_fn) { - tree name = get_identifier ("__cxa_throw"); - throw_fn = get_global_binding (name); + const char *name = "__cxa_throw"; + tree ident = get_identifier (name); + tree fntype = NULL_TREE; + throw_fn = get_global_binding (ident); if (!throw_fn) { /* Declare void __cxa_throw (void*, void*, void (*)(void*)). */ /* ??? Second argument is supposed to be "std::type_info*". */ - tmp = build_function_type_list (void_type_node, - ptr_type_node, ptr_type_node, - cleanup_type, NULL_TREE); - throw_fn = push_throw_library_fn (name, tmp); + fntype = build_function_type_list (void_type_node, + ptr_type_node, ptr_type_node, + cleanup_type, NULL_TREE); + throw_fn = push_throw_library_fn (ident, fntype); + } + else if (!verify_library_fn (throw_fn, name, void_type_node, + ptr_type_node, ptr_type_node, + cleanup_type)) + throw_fn = error_mark_node; - if (flag_tm) + if (flag_tm && throw_fn != error_mark_node) + { + const char *itm_name = "_ITM_cxa_throw"; + tree itm_ident = get_identifier (itm_name); + tree itm_fn = get_global_binding (itm_ident); + if (!itm_fn) + { + if (!fntype) + fntype + = build_function_type_list (void_type_node, + ptr_type_node, ptr_type_node, + cleanup_type, NULL_TREE); + itm_fn = push_throw_library_fn (itm_ident, fntype); + } + else if (!verify_library_fn (itm_fn, itm_name, void_type_node, + ptr_type_node, ptr_type_node, + cleanup_type)) + itm_fn = error_mark_node; + if (itm_fn != error_mark_node) { - tree itm_name = get_identifier ("_ITM_cxa_throw"); - tree itm_fn = get_global_binding (itm_name); - if (!itm_fn) - itm_fn = push_throw_library_fn (itm_name, tmp); apply_tm_attr (itm_fn, get_identifier ("transaction_pure")); record_tm_replacement (throw_fn, itm_fn); } @@ -658,6 +742,8 @@ build_throw (tree exp) /* Allocate the space for the exception. */ allocate_expr = do_allocate_exception (temp_type); + if (allocate_expr == error_mark_node) + return error_mark_node; allocate_expr = get_target_expr (allocate_expr); ptr = TARGET_EXPR_SLOT (allocate_expr); TARGET_EXPR_CLEANUP (allocate_expr) = do_free_exception (ptr); @@ -760,14 +846,21 @@ build_throw (tree exp) /* Rethrow current exception. */ if (!rethrow_fn) { - tree name = get_identifier ("__cxa_rethrow"); - rethrow_fn = get_global_binding (name); + const char *name = "__cxa_rethrow"; + tree ident = get_identifier (name); + rethrow_fn = get_global_binding (ident); if (!rethrow_fn) - /* Declare void __cxa_rethrow (void). */ - rethrow_fn = push_throw_library_fn - (name, build_function_type_list (void_type_node, NULL_TREE)); + { + /* Declare void __cxa_rethrow (void). */ + tree fntype + = build_function_type_list (void_type_node, NULL_TREE); + rethrow_fn = push_throw_library_fn (ident, fntype); + } + else if (!verify_library_fn (rethrow_fn, name, void_type_node, + NULL_TREE, NULL_TREE, NULL_TREE)) + rethrow_fn = error_mark_node; - if (flag_tm) + if (flag_tm && rethrow_fn != error_mark_node) apply_tm_attr (rethrow_fn, get_identifier ("transaction_pure")); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d97f9d094a8..7977fdaadde 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2018-12-16 Jakub Jelinek + + PR c++/88482 + * g++.dg/eh/builtin5.C: New test. + * g++.dg/eh/builtin6.C: New test. + * g++.dg/eh/builtin7.C: New test. + * g++.dg/eh/builtin8.C: New test. + * g++.dg/eh/builtin9.C: New test. + * g++.dg/eh/builtin10.C: New test. + * g++.dg/eh/builtin11.C: New test. + * g++.dg/parse/crash55.C: Adjust expected diagnostics. + 2019-12-15 Steven G. Kargl PR fortran/88138 diff --git a/gcc/testsuite/g++.dg/eh/builtin10.C b/gcc/testsuite/g++.dg/eh/builtin10.C new file mode 100644 index 00000000000..8c48e3de6d3 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/builtin10.C @@ -0,0 +1,29 @@ +// PR c++/88482 +// { dg-do compile } + +extern "C" void __cxa_throw (void *, void *, void (*) (void *)); +extern "C" float __cxa_get_exception_ptr (void *); // { dg-error "declared incorrectly" } +extern "C" void *__cxa_begin_catch (void *); +extern "C" void __cxa_end_catch (); +extern "C" void __cxa_rethrow (); +extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__); +extern "C" int __cxa_free_exception (void *); // { dg-error "declared incorrectly" } + +struct S { S (); S (const S &); ~S (); }; + +int +foo (int x) +{ + if (x > 27) + throw 19; + try + { + if (x > 15) + throw S (); + } + catch (S s) + { + throw; + } + return x + 3; +} diff --git a/gcc/testsuite/g++.dg/eh/builtin11.C b/gcc/testsuite/g++.dg/eh/builtin11.C new file mode 100644 index 00000000000..fb1d4f38ab3 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/builtin11.C @@ -0,0 +1,29 @@ +// PR c++/88482 +// { dg-do compile } + +extern "C" void __cxa_throw (float, void *, void (*) (void *)); // { dg-error "declared incorrectly" } +extern "C" void *__cxa_get_exception_ptr (void *); +extern "C" void *__cxa_begin_catch (int); // { dg-error "declared incorrectly" } +extern "C" void __cxa_end_catch (long long); // { dg-error "declared incorrectly" } +extern "C" void __cxa_rethrow (int); // { dg-error "declared incorrectly" } +extern "C" void *__cxa_allocate_exception (void *); // { dg-error "declared incorrectly" } +extern "C" void __cxa_free_exception (void *); + +struct S { S (); S (const S &); ~S (); }; + +int +foo (int x) +{ + if (x > 27) + throw 19; + try + { + if (x > 15) + throw S (); + } + catch (S s) + { + throw; + } + return x + 3; +} diff --git a/gcc/testsuite/g++.dg/eh/builtin5.C b/gcc/testsuite/g++.dg/eh/builtin5.C new file mode 100644 index 00000000000..eec6f2509a5 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/builtin5.C @@ -0,0 +1,29 @@ +// PR c++/88482 +// { dg-do compile } + +extern "C" void __cxa_throw (void *, void *, void (*) (void *)); +extern "C" void *__cxa_get_exception_ptr (void *); +extern "C" void *__cxa_begin_catch (void *); +extern "C" void __cxa_end_catch (); +extern "C" void __cxa_rethrow (); +extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__); +extern "C" void __cxa_free_exception (void *); + +struct S { S (); S (const S &); ~S (); }; + +int +foo (int x) +{ + if (x > 27) + throw 19; + try + { + if (x > 15) + throw S (); + } + catch (S s) + { + throw; + } + return x + 3; +} diff --git a/gcc/testsuite/g++.dg/eh/builtin6.C b/gcc/testsuite/g++.dg/eh/builtin6.C new file mode 100644 index 00000000000..a70b406cf84 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/builtin6.C @@ -0,0 +1,29 @@ +// PR c++/88482 +// { dg-do compile } + +float __cxa_throw; // { dg-error "declared incorrectly" } +extern "C" void *__cxa_get_exception_ptr (void *); +float __cxa_begin_catch; // { dg-error "declared incorrectly" } +float __cxa_end_catch; // { dg-error "declared incorrectly" } +float __cxa_rethrow; // { dg-error "declared incorrectly" } +float __cxa_allocate_exception; // { dg-error "declared incorrectly" } +extern "C" void __cxa_free_exception (void *); + +struct S { S (); S (const S &); ~S (); }; + +int +foo (int x) +{ + if (x > 27) + throw 19; + try + { + if (x > 15) + throw S (); + } + catch (S s) + { + throw; + } + return x + 3; +} diff --git a/gcc/testsuite/g++.dg/eh/builtin7.C b/gcc/testsuite/g++.dg/eh/builtin7.C new file mode 100644 index 00000000000..ad9c7f6802d --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/builtin7.C @@ -0,0 +1,29 @@ +// PR c++/88482 +// { dg-do compile } + +extern "C" void __cxa_throw (void *, void *, void (*) (void *)); +int __cxa_get_exception_ptr; // { dg-error "declared incorrectly" } +extern "C" void *__cxa_begin_catch (void *); +extern "C" void __cxa_end_catch (); +extern "C" void __cxa_rethrow (); +extern "C" void *__cxa_allocate_exception (__SIZE_TYPE__); +int __cxa_free_exception; // { dg-error "declared incorrectly" } + +struct S { S (); S (const S &); ~S (); }; + +int +foo (int x) +{ + if (x > 27) + throw 19; + try + { + if (x > 15) + throw S (); + } + catch (S s) + { + throw; + } + return x + 3; +} diff --git a/gcc/testsuite/g++.dg/eh/builtin8.C b/gcc/testsuite/g++.dg/eh/builtin8.C new file mode 100644 index 00000000000..19c32ae7c8b --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/builtin8.C @@ -0,0 +1,23 @@ +// PR c++/88482 +// { dg-do compile } + +#include + +struct S { S (); S (const S &); ~S (); }; + +int +foo (int x) +{ + if (x > 27) + throw 19; + try + { + if (x > 15) + throw S (); + } + catch (S s) + { + throw; + } + return x + 3; +} diff --git a/gcc/testsuite/g++.dg/eh/builtin9.C b/gcc/testsuite/g++.dg/eh/builtin9.C new file mode 100644 index 00000000000..acd1a5e7dd6 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/builtin9.C @@ -0,0 +1,29 @@ +// PR c++/88482 +// { dg-do compile } + +extern "C" int __cxa_throw (void *, void *, void (*) (void *)); // { dg-error "declared incorrectly" } +extern "C" void *__cxa_get_exception_ptr (void *); +extern "C" double __cxa_begin_catch (void *); // { dg-error "declared incorrectly" } +extern "C" long *__cxa_end_catch (); // { dg-error "declared incorrectly" } +extern "C" char __cxa_rethrow (); // { dg-error "declared incorrectly" } +extern "C" void __cxa_allocate_exception (__SIZE_TYPE__); // { dg-error "declared incorrectly" } +extern "C" void __cxa_free_exception (void *); + +struct S { S (); S (const S &); ~S (); }; + +int +foo (int x) +{ + if (x > 27) + throw 19; + try + { + if (x > 15) + throw S (); + } + catch (S s) + { + throw; + } + return x + 3; +} diff --git a/gcc/testsuite/g++.dg/parse/crash55.C b/gcc/testsuite/g++.dg/parse/crash55.C index 7676d49bcd9..23ce203b3b5 100644 --- a/gcc/testsuite/g++.dg/parse/crash55.C +++ b/gcc/testsuite/g++.dg/parse/crash55.C @@ -1,8 +1,8 @@ // PR c++/42038 -extern int __cxa_begin_catch; +extern int __cxa_begin_catch; // { dg-error "declared incorrectly" } void f(void) { - try { } catch (int) { } // { dg-error "cannot be used" } + try { } catch (int) { } } diff --git a/libitm/ChangeLog b/libitm/ChangeLog index bda0985b803..5ca36bb31b6 100644 --- a/libitm/ChangeLog +++ b/libitm/ChangeLog @@ -1,3 +1,12 @@ +2018-12-16 Jakub Jelinek + + PR c++/88482 + * eh_cpp.cc (__cxa_throw): Change DEST argument type from + void * to void (*) (void *). + (_ITM_cxa_throw): Likewise. + * libitm.h (_ITM_cxa_throw): Likewise. + * libitm.texi (_ITM_cxa_throw): Likewise. + 2018-12-13 Peter Bergner * config/powerpc/target.h (htm_available): Add support for diff --git a/libitm/eh_cpp.cc b/libitm/eh_cpp.cc index 7a6c37679b8..55b0c4e74fb 100644 --- a/libitm/eh_cpp.cc +++ b/libitm/eh_cpp.cc @@ -89,7 +89,7 @@ struct __cxa_eh_globals extern void *__cxa_allocate_exception (size_t) WEAK; extern void __cxa_free_exception (void *) WEAK; -extern void __cxa_throw (void *, void *, void *) WEAK; +extern void __cxa_throw (void *, void *, void (*) (void *)) WEAK; extern void *__cxa_begin_catch (void *) WEAK; extern void __cxa_end_catch (void) WEAK; extern void __cxa_tm_cleanup (void *, void *, unsigned int) WEAK; @@ -98,7 +98,7 @@ extern __cxa_eh_globals *__cxa_get_globals (void) WEAK; #if !defined (HAVE_ELF_STYLE_WEAKREF) void *__cxa_allocate_exception (size_t) { return NULL; } void __cxa_free_exception (void *) { return; } -void __cxa_throw (void *, void *, void *) { return; } +void __cxa_throw (void *, void *, void (*) (void *)) { return; } void *__cxa_begin_catch (void *) { return NULL; } void __cxa_end_catch (void) { return; } void __cxa_tm_cleanup (void *, void *, unsigned int) { return; } @@ -136,7 +136,7 @@ _ITM_cxa_free_exception (void *exc_ptr) } void -_ITM_cxa_throw (void *obj, void *tinfo, void *dest) +_ITM_cxa_throw (void *obj, void *tinfo, void (*dest) (void *)) { // This used to be instrumented, but does not need to be anymore. __cxa_throw (obj, tinfo, dest); diff --git a/libitm/libitm.h b/libitm/libitm.h index daf342ea56f..dd9b5de585f 100644 --- a/libitm/libitm.h +++ b/libitm/libitm.h @@ -284,7 +284,7 @@ extern void _ITM_deregisterTMCloneTable (void *); extern void *_ITM_cxa_allocate_exception (size_t); extern void _ITM_cxa_free_exception (void *exc_ptr); -extern void _ITM_cxa_throw (void *obj, void *tinfo, void *dest); +extern void _ITM_cxa_throw (void *obj, void *tinfo, void (*dest) (void *)); extern void *_ITM_cxa_begin_catch (void *exc_ptr); extern void _ITM_cxa_end_catch (void); extern void _ITM_commitTransactionEH(void *exc_ptr) ITM_REGPARM; diff --git a/libitm/libitm.texi b/libitm/libitm.texi index 7a91348947f..d0b7b07e90b 100644 --- a/libitm/libitm.texi +++ b/libitm/libitm.texi @@ -269,7 +269,7 @@ transactions. void _ITM_commitTransactionEH(void *exc_ptr) ITM_REGPARM; void *_ITM_cxa_allocate_exception (size_t); void _ITM_cxa_free_exception (void *exc_ptr); -void _ITM_cxa_throw (void *obj, void *tinfo, void *dest); +void _ITM_cxa_throw (void *obj, void *tinfo, void (*dest) (void *)); void *_ITM_cxa_begin_catch (void *exc_ptr); void _ITM_cxa_end_catch (void); @end example