diff mbox series

[v3,2/4] c: runtime checking for assigment of VM types

Message ID 01b54c4cc3fb59856e4c0f3d490e7e911c0ed9ef.camel@tugraz.at
State New
Headers show
Series [v3,1/4] c: runtime checking for assigment of VM types | expand

Commit Message

Martin Uecker July 15, 2024, 7:20 a.m. UTC
Support instrumentation of function arguments for functions
called via a declaration. We can support only simple size
expressions without side effects, because the run-time
instrumentation is done before the call, but the expressions
are evaluated in the callee.

gcc/c:
 * c-typeck.cc (process_vm_constraints): Add support
 for instrumenting function arguments.
 (convert_arguments): Instrument function arguments.
 (convert_for_assigmnent): Adapt.

gcc/testsuide/gcc.dg:
 * vla-bounds-func-1.c: Update.
 * vla-bounds-func-2.c: New test.
 * vla-bounds-func-3.c: New test.
 * vla-bounds-func-4.c: New test.
 * vla-bounds-func-5.c: New test.
 * vla-bounds-func-6.c: New test.
 * vla-bounds-func-7.c: New test.
 * vla-bounds-func-8.c: New test.
 * vla-bounds-func-9.c: New test.
 * vla-bounds-func-10.c: New test.
 * vla-bounds-func-11.c: New test.
 * vla-bounds-func-12.c: New test.
 * vla-bounds-func-13.c: New test.
 * vla-bounds-func-14.c: New test.
 * vla-bounds-func-15.c: New test.
 * vla-bounds-func-16.c: New test.
 * vla-bounds-func-17.c: New test.
 * vla-bounds-func-18.c: New test.
 * vla-bounds-func-19.c: New test.
 * vla-bounds-func-20.c: New test.
---
 gcc/c/c-typeck.cc | 151 +++++++++++++++++++---
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 2 +-
 gcc/testsuite/gcc.dg/vla-bounds-func-10.c | 74 +++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-11.c | 28 ++++
 gcc/testsuite/gcc.dg/vla-bounds-func-12.c | 29 +++++
 gcc/testsuite/gcc.dg/vla-bounds-func-13.c | 37 ++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-14.c | 15 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-15.c | 20 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-16.c | 18 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-17.c | 18 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-18.c | 20 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-19.c | 21 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-2.c | 73 +++++++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-20.c | 22 ++++
 gcc/testsuite/gcc.dg/vla-bounds-func-3.c | 28 ++++
 gcc/testsuite/gcc.dg/vla-bounds-func-4.c | 37 ++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-5.c | 40 ++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-6.c | 36 ++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-7.c | 39 ++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-8.c | 38 ++++++
 gcc/testsuite/gcc.dg/vla-bounds-func-9.c | 39 ++++++
 21 files changed, 769 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-10.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-11.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-12.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-13.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-14.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-15.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-16.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-17.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-18.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-19.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-20.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-5.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-6.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-7.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-8.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-9.c
diff mbox series

Patch

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 59940a29b53..c0132a22e21 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1201,19 +1201,13 @@  comptypes_verify (tree type1, tree type2)
 /* Instrument assignment of variably modified types. */
 static tree
-c_instrument_vm_assign (location_t loc, tree a, tree b)
+c_instrument_vm_assign (location_t loc, tree a, tree b, tree as, tree bs)
 {
 gcc_assert (flag_vla_bounds);
 gcc_assert (TREE_CODE (a) == ARRAY_TYPE);
 gcc_assert (TREE_CODE (b) == ARRAY_TYPE);
- tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a));
- tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b));
-
- as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
- bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
-
 tree t = build2 (NE_EXPR, boolean_type_node, as, bs);
 tree tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
@@ -3772,7 +3766,8 @@  static tree
 convert_argument (location_t ploc, tree function, tree fundecl,
 tree type, tree origtype, tree val, tree valtype,
 bool npc, tree rname, int parmnum, int argnum,
- bool excess_precision, int warnopt)
+ bool excess_precision, int warnopt,
+ struct instrument_data **instr_vec)
 {
 /* Formal parm type is specified by a function prototype. */
@@ -3932,7 +3927,7 @@  convert_argument (location_t ploc, tree function, tree fundecl,
 val, origtype, ic_argpass,
 npc, fundecl, function,
 parmnum + 1, warnopt,
- NULL);
+ instr_vec);
 if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
 && INTEGRAL_TYPE_P (type)
@@ -3945,15 +3940,110 @@  convert_argument (location_t ploc, tree function, tree fundecl,
 /* Process all constraints for variably-modified types. */
-static tree
+tree
 process_vm_constraints (location_t location,
- struct instrument_data **instr_vec)
+ struct instrument_data **instr_vec,
+ tree function, tree fundecl, vec<tree, va_gc> *values)
 {
 tree instr_expr = void_node;
+ tree args = NULL;
+
+ /* Find the arguments for the function declaration / type. */
+ if (function)
+ {
+ if (TREE_CODE (function) == FUNCTION_DECL)
+ {
+ fundecl = function;
+ args = DECL_ARGUMENTS (fundecl);
+ }
+ else
+ {
+ /* Functions called via pointers are not yet supported. */
+ return void_node;
+ }
+ }
 for (struct instrument_data* d = *instr_vec; d; d = d->next)
 {
- tree in = c_instrument_vm_assign (location, d->t1, d->t2);
+ tree t1 = d->t1;
+ tree t2 = d->t2;
+
+ gcc_assert (TREE_CODE (t1) == ARRAY_TYPE);
+ gcc_assert (TREE_CODE (t2) == ARRAY_TYPE);
+
+ tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (t1));
+ tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (t2));
+
+ if (!as || !bs)
+ continue;
+
+ as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
+ bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
+
+ if (function)
+ {
+
+ if (TREE_CODE (bs) == INTEGER_CST)
+ goto cont;
+
+ if (TREE_CODE (bs) == NOP_EXPR
+ && TREE_CODE (TREE_OPERAND (bs, 0)) == SAVE_EXPR)
+ {
+ tree bs1 = TREE_OPERAND (bs, 0);
+ tree bs2 = TREE_OPERAND (bs1, 0);
+
+ /* Another parameter of the current functions. */
+ if (TREE_CODE (bs2) == PARM_DECL
+ && (DECL_CONTEXT (bs2) == fundecl
+ || DECL_CONTEXT (bs2) == NULL))
+ {
+ tree arg = args;
+ int pos = 0;
+ while (arg)
+ {
+ if (arg == bs2)
+ {
+ bs = (*values)[pos];
+ bs = save_expr (bs);
+ bs = build1 (NOP_EXPR, sizetype, bs);
+ break;
+ }
+ pos++;
+ arg = DECL_CHAIN (arg);
+ }
+ if (!arg)
+ goto giveup;
+ goto cont;
+ }
+
+ /* A parameter of an enclosing function. */
+ if (TREE_CODE (bs2) == PARM_DECL
+ && DECL_CONTEXT (bs2) != fundecl)
+ {
+ bs2 = unshare_expr (bs2);
+ bs1 = save_expr (bs2);
+ bs = build1 (NOP_EXPR, sizetype, bs1);
+ goto cont;
+ }
+
+ /* A variable with enclosing scope. */
+ if (TREE_CODE (bs2) == VAR_DECL)
+ {
+ bs2 = unshare_expr (bs2);
+ bs1 = save_expr (bs2);
+ bs = build1 (NOP_EXPR, sizetype, bs1);
+ goto cont;
+ }
+ }
+ giveup:
+ /* Give up. If we do not understand a size expression, we can
+ also not instrument any of the others because it may have
+ side effects affecting them. (We could restart and instrument
+ only the ones with integer constants.) */
+ return void_node;
+ }
+cont:
+ tree in = c_instrument_vm_assign (location, t1, t2, as, bs);
 instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, in, instr_expr);
 }
 return instr_expr;
@@ -4064,6 +4154,12 @@  convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
 }
 }
+ struct instrument_data *instr_first = NULL;
+ struct instrument_data **instr_vec = NULL;
+
+ if (flag_vla_bounds)
+ instr_vec = &instr_first;
+
 /* Scan the given expressions (VALUES) and types (TYPELIST), producing
 individual converted arguments. */
@@ -4176,7 +4272,7 @@  convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
 tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum];
 parmval = convert_argument (ploc, function, fundecl, type, origtype,
 val, valtype, npc, rname, parmnum, argnum,
- excess_precision, 0);
+ excess_precision, 0, instr_vec);
 }
 else if (promote_float_arg)
 {
@@ -4231,7 +4327,7 @@  convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
 convert_argument (ploc, function, fundecl, builtin_type, origtype,
 val, valtype, npc, rname, parmnum, argnum,
 excess_precision,
- OPT_Wbuiltin_declaration_mismatch);
+ OPT_Wbuiltin_declaration_mismatch, NULL);
 }
 if (typetail)
@@ -4243,6 +4339,31 @@  convert_arguments (location_t loc, vec<location_t> arg_loc, tree typelist,
 gcc_assert (parmnum == vec_safe_length (values));
+ if (instr_vec)
+ {
+ if (0 < parmnum && instr_vec && instr_first != NULL)
+ {
+ tree instr_expr = process_vm_constraints (loc, instr_vec, function, fundecl, values);
+ /* We have to make sure that all parameters are evaluated first,
+ because we may use size expressions in it to check bounds. */
+ if (void_node != instr_expr)
+ {
+ tree parmval = (*values)[0];
+ parmval = save_expr (parmval);
+ instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, parmval, instr_expr);
+ parmval = fold_build2 (COMPOUND_EXPR, TREE_TYPE (parmval), instr_expr, parmval);
+ (*values)[0] = parmval;
+ }
+ }
+ while (instr_first)
+ {
+ struct instrument_data *next = instr_first->next;
+ free (instr_first);
+ instr_first = next;
+ }
+ instr_vec = NULL;
+ }
+
 if (typetail != NULL_TREE && TREE_VALUE (typetail) != void_type_node)
 {
 error_at (loc, "too few arguments to function %qE", function);
@@ -7422,7 +7543,7 @@  convert_for_assignment (location_t location, location_t expr_loc, tree type,
 {
 /* We have to make sure that the rhs is evaluated first,
 because we may use size expressions in it to check bounds. */
- tree instr_expr = process_vm_constraints (location, instr_vec);
+ tree instr_expr = process_vm_constraints (location, instr_vec, NULL, NULL, NULL);
 if (instr_expr != void_node)
 {
 ret = save_expr (ret);
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
index 8256999fc50..378c6073688 100644
--- a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
@@ -50,5 +50,5 @@  int c(int u, char (*a)[u]) { }
 int d(void)
 {
 char a[3];
- c(3, &a);
+ c(3, &a); /* "Function call not instrumented." */
 }
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-10.c b/gcc/testsuite/gcc.dg/vla-bounds-func-10.c
new file mode 100644
index 00000000000..ad1b6e44923
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-10.c
@@ -0,0 +1,74 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m, n;
+
+static void a0(char (*a)[4]) { }
+static void b0(char (*a)[n]) { }
+static void c0(char (*a)[n][m]) { }
+static void d0(char (*a)[4][m]) { }
+static void e0(char (*a)[n][3]) { }
+static void f0(char a[n][m]) { }
+
+static void b1(int u, char (*a)[u]) { }
+static void c1(int u, int v, char (*a)[u][v]) { }
+static void d1(int v, char (*a)[4][v]) { }
+static void e1(int u, char (*a)[u][3]) { }
+static void f1(int u, int v, char a[u][v]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3, n = 4;
+
+ int u = 4;
+ int v = 3;
+
+ /* function arguments */
+
+ char A0[4];
+ char A1[u];
+ char B0[3];
+ char B1[v];
+
+ a0(&A0);
+ a0(&A1);
+
+ b0(&A0);
+ b0(&A1);
+
+ b1(4, &A0);
+
+ char C0[4][3];
+ char C1[u][3];
+ char C2[4][v];
+ char C3[u][v];
+ char D0[3][4];
+ char D1[v][4];
+ char D2[3][u];
+ char D3[v][u];
+
+ c0(&C0);
+ c0(&C1);
+ c0(&C2);
+ c0(&C3);
+ 
+ d0(&C0);
+
+ d1(3, &C0);
+
+ e0(&C0);
+ e1(4, &C0);
+
+ f0(C0);
+
+ f1(4, 3, C0);
+ f1(4, 3, D0); // 3 != 4
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-11.c b/gcc/testsuite/gcc.dg/vla-bounds-func-11.c
new file mode 100644
index 00000000000..45095023d18
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-11.c
@@ -0,0 +1,28 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2 -fvla-bounds -fpermissive" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m;
+
+static void d0(char (*a)[4][m]) { }
+static void d1(int v, char (*a)[4][v]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3;
+
+ char C0[4][3];
+ char D0[3][4];
+
+ d1(3, &C0);
+
+ d0(&C0);
+ d0(&D0); /* { dg-warning "incompatible pointer type" } */
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-12.c b/gcc/testsuite/gcc.dg/vla-bounds-func-12.c
new file mode 100644
index 00000000000..2c033761eac
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-12.c
@@ -0,0 +1,29 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds -fpermissive" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m;
+
+static void d0(char (*a)[4][m]) { }
+static void d1(int v, char (*a)[4][v]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3;
+
+ char C0[4][3];
+ char D0[3][4];
+
+ d0(&C0);
+
+ d1(3, &C0);
+ d1(3, &D0); /* { dg-warning "incompatible pointer type" } */
+ // 3 != 4
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-13.c b/gcc/testsuite/gcc.dg/vla-bounds-func-13.c
new file mode 100644
index 00000000000..3919f320643
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-13.c
@@ -0,0 +1,37 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds -fpermissive" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m, n;
+
+static void e0(char (*a)[n][3]) { }
+static void f0(char a[n][m]) { }
+
+static void e1(int u, char (*a)[u][3]) { }
+static void f1(int u, int v, char a[u][v]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3, n = 4;
+
+ /* function arguments */
+
+ char C0[4][3];
+ char D0[3][4];
+
+ e0(&C0);
+ e1(4, &C0);
+
+ f1(4, 3, C0);
+ f1(4, 3, D0); // 3 != 4
+
+ f0(C0);
+ f0(D0); // 3 != 4
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-14.c b/gcc/testsuite/gcc.dg/vla-bounds-func-14.c
new file mode 100644
index 00000000000..10678d10237
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-14.c
@@ -0,0 +1,15 @@ 
+/* { dg-do compile } */
+/* { dg-options "-fvla-bounds" } */
+
+void b0(int n, char (*a)[n]) { }
+void b1(int m, char (*a)[m]);
+void b2(int m; char (*a)[m], int m) { }
+void b3(int m; char (*a)[m], int m);
+int n;
+void b4(char (*a)[n]) { }
+void b5(char (*a)[n]);
+
+void b1(int n, char (*a)[n]) { }
+void b3(int m; char (*a)[m], int m) { }
+void b5(char (*a)[n]) { }
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-15.c b/gcc/testsuite/gcc.dg/vla-bounds-func-15.c
new file mode 100644
index 00000000000..778a7c03219
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-15.c
@@ -0,0 +1,20 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+void b1(int m, char (*a)[m]);
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ char A0[3];
+ b1(4, &A0); // 4 != 3
+ abort();
+}
+
+void b1(int n, char (*a)[n]) { }
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-16.c b/gcc/testsuite/gcc.dg/vla-bounds-func-16.c
new file mode 100644
index 00000000000..1da4d2632f2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-16.c
@@ -0,0 +1,18 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+void b0(int n, char (*a)[n]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ char A0[3];
+ b0(4, &A0); // 4 != 3
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-17.c b/gcc/testsuite/gcc.dg/vla-bounds-func-17.c
new file mode 100644
index 00000000000..2b52391ef59
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-17.c
@@ -0,0 +1,18 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+void b2(int m; char (*a)[m], int m) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ char A0[3];
+ b2(&A0, 4); // 4 != 3
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-18.c b/gcc/testsuite/gcc.dg/vla-bounds-func-18.c
new file mode 100644
index 00000000000..61395c22e8a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-18.c
@@ -0,0 +1,20 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+void b3(int m; char (*a)[m], int m);
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ char A0[3];
+ b3(&A0, 4); // 4 != 3
+ abort();
+}
+
+void b3(int m; char (*a)[m], int m) { }
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-19.c b/gcc/testsuite/gcc.dg/vla-bounds-func-19.c
new file mode 100644
index 00000000000..4b57580ac94
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-19.c
@@ -0,0 +1,21 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int n;
+void b4(char (*a)[n]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ char A0[3];
+ n = 4;
+ b4(&A0); // 4 != 3
+ abort();
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-2.c b/gcc/testsuite/gcc.dg/vla-bounds-func-2.c
new file mode 100644
index 00000000000..f00c7e15774
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-2.c
@@ -0,0 +1,73 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m, n;
+
+static void a0(char (*a)[4]) { }
+static void b0(char (*a)[n]) { }
+static void c0(char (*a)[n][m]) { }
+static void d0(char (*a)[4][m]) { }
+static void e0(char (*a)[n][3]) { }
+static void f0(char a[n][m]) { }
+
+static void b1(int u, char (*a)[u]) { }
+static void c1(int u, int v, char (*a)[u][v]) { }
+static void d1(int v, char (*a)[4][v]) { }
+static void e1(int u, char (*a)[u][3]) { }
+static void f1(int u, int v, char a[u][v]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3, n = 4;
+
+ int u = 4;
+ int v = 3;
+
+ /* function arguments */
+
+ char A0[4];
+ char A1[u];
+ char B0[3];
+ char B1[v];
+
+ a0(&A0);
+ a0(&A1);
+
+ b0(&A0);
+ b0(&A1);
+
+ b1(4, &A0);
+
+ char C0[4][3];
+ char C1[u][3];
+ char C2[4][v];
+ char C3[u][v];
+ char D0[3][4];
+ char D1[v][4];
+ char D2[3][u];
+ char D3[v][u];
+
+ c0(&C0);
+ c0(&C1);
+ c0(&C2);
+ c0(&C3);
+ 
+ d0(&C0);
+ d1(3, &C0);
+
+ e0(&C0);
+ e1(4, &C0);
+
+ f0(C0);
+
+ f1(4, 3, C0);
+ f1(4, 3, D0); // 3 != 4
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-20.c b/gcc/testsuite/gcc.dg/vla-bounds-func-20.c
new file mode 100644
index 00000000000..c0c7a9c637b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-20.c
@@ -0,0 +1,22 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int n;
+void b5(char (*a)[n]);
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ char A0[3];
+ n = 4;
+ b5(&A0); // 4 != 3
+ abort();
+}
+
+void b5(char (*a)[n]) { }
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-3.c b/gcc/testsuite/gcc.dg/vla-bounds-func-3.c
new file mode 100644
index 00000000000..90e37d65365
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-3.c
@@ -0,0 +1,28 @@ 
+/* { dg-do run } */
+/* { dg-options "-O1 -fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+static void a0(char (*a)[4]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ int u = 4;
+ int v = 3;
+
+ /* function arguments */
+
+ char A0[4];
+ char A1[u];
+ char B1[v];
+
+ a0(&A0);
+ a0(&A1);
+ a0(&B1); // 4 != 3
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-4.c b/gcc/testsuite/gcc.dg/vla-bounds-func-4.c
new file mode 100644
index 00000000000..9b7173fee46
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-4.c
@@ -0,0 +1,37 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds -fpermissive" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int n;
+
+static void a0(char (*a)[4]) { }
+static void b0(char (*a)[n]) { }
+static void b1(int u, char (*a)[u]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ n = 4;
+
+ int u = 4;
+
+ char A0[4];
+ char A1[u];
+ char B0[3];
+
+ a0(&A0);
+ a0(&A1);
+
+ b1(4, &A0);
+
+ b0(&A0);
+ b0(&A1);
+ b0(&B0); // 4 != 3
+
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-5.c b/gcc/testsuite/gcc.dg/vla-bounds-func-5.c
new file mode 100644
index 00000000000..37ff64148ef
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-5.c
@@ -0,0 +1,40 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int n;
+
+static void a0(char (*a)[4]) { }
+static void b0(char (*a)[n]) { }
+static void b1(int u, char (*a)[u]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ n = 4;
+
+ int u = 4;
+ int v = 3;
+
+ /* function arguments */
+
+ char A0[4];
+ char A1[u];
+ char B0[3];
+ char B1[v];
+
+ a0(&A0);
+ a0(&A1);
+
+ b0(&A0);
+ b0(&A1);
+
+ b1(4, &A0);
+ b1(4, &B0); // 4 != 3
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-6.c b/gcc/testsuite/gcc.dg/vla-bounds-func-6.c
new file mode 100644
index 00000000000..c678e6b450a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-6.c
@@ -0,0 +1,36 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m, n;
+
+static void c0(char (*a)[n][m]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3, n = 4;
+
+ int u = 4;
+ int v = 3;
+
+ /* function arguments */
+
+ char C0[4][3];
+ char C1[u][3];
+ char C2[4][v];
+ char C3[u][v];
+ char D0[3][4];
+
+ c0(&C0);
+ c0(&C1);
+ c0(&C2);
+ c0(&C3);
+ c0(&D0); // 4 != 4, 3 != 4
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-7.c b/gcc/testsuite/gcc.dg/vla-bounds-func-7.c
new file mode 100644
index 00000000000..40a6252dbc7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-7.c
@@ -0,0 +1,39 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m, n;
+
+static void c0(char (*a)[n][m]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3, n = 4;
+
+ int u = 4;
+ int v = 3;
+
+ /* function arguments */
+
+ char C0[4][3];
+ char C1[u][3];
+ char C2[4][v];
+ char C3[u][v];
+ char D0[3][4];
+ char D1[v][4];
+
+ c0(&C0);
+ c0(&C1);
+ c0(&C2);
+ c0(&C3);
+
+ c0(&D1); // 4 != 3, 3 != 4
+ abort();
+}
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-8.c b/gcc/testsuite/gcc.dg/vla-bounds-func-8.c
new file mode 100644
index 00000000000..d89d7465fd5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-8.c
@@ -0,0 +1,38 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m, n;
+
+static void c0(char (*a)[n][m]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3, n = 4;
+
+ int u = 4;
+ int v = 3;
+
+ /* function arguments */
+
+ char C0[4][3];
+ char C1[u][3];
+ char C2[4][v];
+ char C3[u][v];
+ char D0[3][4];
+ char D1[v][4];
+ char D2[3][u];
+
+ c0(&C0);
+ c0(&C1);
+ c0(&C2);
+ c0(&C3);
+ c0(&D2); // 4 != 3, 3 != 4
+ abort();
+}
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-9.c b/gcc/testsuite/gcc.dg/vla-bounds-func-9.c
new file mode 100644
index 00000000000..2f71edb208a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-9.c
@@ -0,0 +1,39 @@ 
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include <signal.h>
+#include <stdlib.h>
+
+static void handler(int) { exit(0); }
+
+int m, n;
+
+static void c0(char (*a)[n][m]) { }
+
+int main()
+{
+ signal(SIGILL, handler);
+
+ m = 3, n = 4;
+
+ int u = 4;
+ int v = 3;
+
+ /* function arguments */
+
+ char C0[4][3];
+ char C1[u][3];
+ char C2[4][v];
+ char C3[u][v];
+ char D0[3][4];
+ char D1[v][4];
+ char D2[3][u];
+ char D3[v][u];
+
+ c0(&C0);
+ c0(&C1);
+ c0(&C2);
+ c0(&C3);
+ c0(&D3); // 4 != 3, 3 != 4
+ abort();
+}