Hi!

If the user provides his own __cxa_* prototypes and does so incorrectly
(or even worse declares them as variables etc.), we can get various ICEs.

The following patch adds some sanity checking, mainly that they are actually
functions and with a compatible return type and argument type(s).
For __cxa_throw it gives some freedom for the second and third arguments,
but apparently not enough for libitm where it causes
+FAIL: libitm.c++/throwdown.C (test for excess errors)

This is because cxxabi.h has:
  void
  __cxa_throw(void*, std::type_info*, void (_GLIBCXX_CDTOR_CALLABI *) (void *))
  __attribute__((__noreturn__));
and the patch checks that the second argument is a pointer (any kind) and
third parameter is a function pointer, but libitm.h has:
extern void _ITM_cxa_throw (void *obj, void *tinfo, void *dest);
and eh_cpp.cc has:
extern void __cxa_throw (void *, void *, void *) WEAK;
void 
_ITM_cxa_throw (void *obj, void *tinfo, void *dest)
{
  // This used to be instrumented, but does not need to be anymore.
  __cxa_throw (obj, tinfo, dest);
}
Shall we fix libitm to use void (*dest) (void *) instead of void *dest,
or shall I make the verify_library_fn handle both i == 1 and i == 2
the same?

Bootstrapped/regtested on x86_64-linux and i686-linux (with the above
mentioned FAIL), ok for trunk (and with what solution for libitm)?

2018-12-13  Jakub Jelinek  <ja...@redhat.com>

        PR c++/88482
        * except.c (verify_library_fn): New function.
        (declare_library_fn): Use it.
        (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.  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.

--- gcc/cp/except.c.jj  2018-12-07 00:23:15.008998854 +0100
+++ gcc/cp/except.c     2018-12-13 20:05:23.053122023 +0100
@@ -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 __cxa_throw last 2 arguments.  */
+         if (i == 1 && TREE_CODE (TREE_VALUE (targs)) != POINTER_TYPE)
+           goto bad;
+         if (i == 2
+             && (TREE_CODE (TREE_VALUE (targs)) != POINTER_TYPE
+                 || (TREE_CODE (TREE_TYPE (TREE_VALUE (targs)))
+                     != FUNCTION_TYPE)))
+           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
@@ -161,9 +204,16 @@ declare_library_fn (const char *name, tr
          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);
+         else if (!verify_library_fn (tm_fn, tm_name, rtype, ptype,
+                                      NULL_TREE, NULL_TREE))
+           tm_fn = error_mark_node;
+         if (tm_fn != error_mark_node)
+           record_tm_replacement (res, tm_fn);
        }
     }
+  else if (!verify_library_fn (res, name, rtype, ptype, NULL_TREE, NULL_TREE))
+    return error_mark_node;
+
   return res;
 }
 
@@ -236,7 +286,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 +451,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);
     }
 
@@ -625,10 +677,22 @@ build_throw (tree exp)
                  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);
+                 else if (!verify_library_fn (itm_fn, "_ITM_cxa_throw",
+                                              void_type_node, ptr_type_node,
+                                              ptr_type_node, cleanup_type))
+                   itm_fn = error_mark_node;
+                 if (itm_fn != error_mark_node)
+                   {
+                     apply_tm_attr (itm_fn,
+                                    get_identifier ("transaction_pure"));
+                     record_tm_replacement (throw_fn, itm_fn);
+                   }
                }
            }
+         else if (!verify_library_fn (throw_fn, "__cxa_throw", void_type_node,
+                                      ptr_type_node, ptr_type_node,
+                                      cleanup_type))
+           throw_fn = error_mark_node;
        }
 
       /* [except.throw]
@@ -658,6 +722,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);
@@ -766,8 +832,12 @@ build_throw (tree exp)
            /* Declare void __cxa_rethrow (void).  */
            rethrow_fn = push_throw_library_fn
              (name, build_function_type_list (void_type_node, NULL_TREE));
+         else if (!verify_library_fn (rethrow_fn, "__cxa_rethrow",
+                                      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"));
        }
 
--- gcc/testsuite/g++.dg/eh/builtin5.C.jj       2018-12-13 20:29:55.633235455 
+0100
+++ gcc/testsuite/g++.dg/eh/builtin5.C  2018-12-13 20:26:47.136297368 +0100
@@ -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;
+}
--- gcc/testsuite/g++.dg/eh/builtin6.C.jj       2018-12-13 20:29:58.528188430 
+0100
+++ gcc/testsuite/g++.dg/eh/builtin6.C  2018-12-13 20:35:13.441073600 +0100
@@ -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;
+}
--- gcc/testsuite/g++.dg/eh/builtin7.C.jj       2018-12-13 20:30:13.688942161 
+0100
+++ gcc/testsuite/g++.dg/eh/builtin7.C  2018-12-13 20:31:33.696642532 +0100
@@ -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;
+}
--- gcc/testsuite/g++.dg/eh/builtin8.C.jj       2018-12-13 20:31:43.635481087 
+0100
+++ gcc/testsuite/g++.dg/eh/builtin8.C  2018-12-13 20:32:09.484061207 +0100
@@ -0,0 +1,23 @@
+// PR c++/88482
+// { dg-do compile }
+
+#include <cxxabi.h>
+
+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;
+}
--- gcc/testsuite/g++.dg/eh/builtin9.C.jj       2018-12-13 20:32:20.079889087 
+0100
+++ gcc/testsuite/g++.dg/eh/builtin9.C  2018-12-13 20:34:34.043713014 +0100
@@ -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;
+}
--- gcc/testsuite/g++.dg/eh/builtin10.C.jj      2018-12-13 20:36:03.602259495 
+0100
+++ gcc/testsuite/g++.dg/eh/builtin10.C 2018-12-13 20:36:43.522611598 +0100
@@ -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;
+}
--- gcc/testsuite/g++.dg/eh/builtin11.C.jj      2018-12-13 20:36:59.407353793 
+0100
+++ gcc/testsuite/g++.dg/eh/builtin11.C 2018-12-13 20:37:49.222545303 +0100
@@ -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;
+}
--- gcc/testsuite/g++.dg/parse/crash55.C.jj     2010-01-22 18:47:18.000000000 
+0100
+++ gcc/testsuite/g++.dg/parse/crash55.C        2018-12-14 00:20:01.988703354 
+0100
@@ -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) { }
 }

        Jakub

Reply via email to