This adds guards to genmatch generated code before accessing call
expression or stmt arguments that might be out of bounds when
the user provided bogus prototypes for what we consider builtins.

Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.

Richard.

2020-02-05  Richard Biener  <rguent...@suse.de>

        PR middle-end/90648
        * genmatch.c (dt_node::gen_kids_1): Emit number of argument
        checks before matching calls.

        * gcc.dg/pr90648.c: New testcase.
---
 gcc/genmatch.c                 | 22 ++++++++++++++--------
 gcc/testsuite/gcc.dg/pr90648.c |  8 ++++++++
 2 files changed, 22 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr90648.c

diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index d174d4144fd..0a8cba62e0c 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -3060,10 +3060,15 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, 
int depth,
            {
              expr *e = as_a <expr *>(fns[i]->op);
              fprintf_indent (f, indent, "case %s:\n", e->operation->id);
-             fprintf_indent (f, indent, "  {\n");
-             fns[i]->gen (f, indent + 4, true, depth);
-             fprintf_indent (f, indent, "    break;\n");
-             fprintf_indent (f, indent, "  }\n");
+             /* We need to be defensive against bogus prototypes allowing
+                calls with not enough arguments.  */
+             fprintf_indent (f, indent,
+                             "  if (gimple_call_num_args (_c%d) == %d)\n"
+                             "    {\n", depth, e->ops.length ());
+             fns[i]->gen (f, indent + 6, true, depth);
+             fprintf_indent (f, indent,
+                             "    }\n"
+                             "  break;\n");
            }
 
          fprintf_indent (f, indent, "default:;\n");
@@ -3125,10 +3130,11 @@ dt_node::gen_kids_1 (FILE *f, int indent, bool gimple, 
int depth,
          gcc_assert (e->operation->kind == id_base::FN);
 
          fprintf_indent (f, indent, "case %s:\n", e->operation->id);
-         fprintf_indent (f, indent, "  {\n");
-         generic_fns[j]->gen (f, indent + 4, false, depth);
-         fprintf_indent (f, indent, "    break;\n");
-         fprintf_indent (f, indent, "  }\n");
+         fprintf_indent (f, indent, "  if (call_expr_nargs (%s) == %d)\n"
+                                    "    {\n", kid_opname, e->ops.length ());
+         generic_fns[j]->gen (f, indent + 6, false, depth);
+         fprintf_indent (f, indent, "    }\n"
+                                    "  break;\n");
        }
       fprintf_indent (f, indent, "default:;\n");
 
diff --git a/gcc/testsuite/gcc.dg/pr90648.c b/gcc/testsuite/gcc.dg/pr90648.c
new file mode 100644
index 00000000000..bf1fa989478
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr90648.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O" } */
+
+extern double copysign ();
+double foo (double x)
+{
+  return x * copysign (); /* { dg-warning "too few arguments" } */
+}
-- 
2.16.4

Reply via email to