Am Donnerstag, dem 18.07.2024 um 18:32 +0000 schrieb Qing Zhao: > Hi, Martin, > > I briefly reviewed these 4 patches this week. > > Overall, I think that this is a nice new security feature to be added into > gcc.
Thank you! (not only for security! it currently helps me with my numerics) > > At the same time, I have the following questions about the patches: > > 1. Does the name of the option mismatch the description of the option? > > -fvla-bounds > Emit run-time consistency checks for variably-modified types. > > Is “variably-modified type” equal to “via” (variable length array)? > > I see all other current options -Wvla-parameter, -Wvla, etc, the “vla”s all > are > for "variable length array" in the description. > > So, a little confused with the “variable-modified type” you used in the > documentation for > “vla”. > > I see that in GCC source code, the concept of “variable-modified type” > includes “via”. > but seems not limited to “vla”. Variably modified types are types that are a VLA or are derived from a VLA somehow, e.g. a pointer to a VLA. So I would say both terms are correct in this context because we check all bounds in a variably modified type but each bound belongs to an embedded VLA type. But anyway, I agree that the description would better if it would not refer to variably modified types. I also wonder about the name of the option too. Maybe there is a better name? > > 2. I feel that the documentation of the option need some simple examples to > show > the new feature’s capabilities to help users to use it. > > Currently. The doc of the option: > > +@item -fvla-bounds > > +This option is only available when compiling C code. If activated, > > +additional code is emitted that verifies at run time for assignments > > +involving variably-modified types that corresponding size expressions > > +evaluate to the same value. > > Providing multiple simple examples below will be helpful. Yes. > > 3. From my understanding, with -fvla-bounds, when there is any bound > mismatch > during runtime, the program will trap, but without any information on why such > trap happens. > > Is this correct? > > If so, I think that this might need to be documented to inform user the > current behavior, > then the users will have an accurate expectation on what might happen with > this > option. That makes sense. > > Later some error message might need to be issued at the same time when the > trap happens. > > > On Jul 15, 2024, at 03:19, Martin Uecker <uec...@tugraz.at> wrote: > > > > > > When checking compatibility of types during assignment, collect > > all pairs of types where the outermost bound needs to match at > > run-time. This list is then processed to add runtime checks for > > each bound. > > > > gcc/c-family: > > * c-opt (fvla-bounds): New flag. > > > > gcc/c: > > * c-typeck.cc (struct instrument_data): New structure. > > (comp_target_types_instr convert_for_assignment_instrument): New > > interfaces for existing functions. > > (struct comptypes_data): Add instrumentation. > > (comptypes_check_enum_int_intr): New interface. > > (comptypes_check_enum_int): Old interface (calls new). > > (comptypes_internal): Collect VLA types needed for UBSan. > > (comp_target_types_instr): New interface. > > (comp_target_types): Old interface (calls new). > > (function_types_compatible_p): No instrumentation for function > > arguments. > > (process_vm_constraints): New function. > > (convert_argument): Adapt. > > (convert_for_assignment_instrument): New interface. > > (convert_for_assignment): Instrument assignments. > > (c_instrument_vm_assign): Helper function. > > (process_vm_constraints): Helper function. > > “process_vm_constraints” repeated twice in the above. > > > thanks. Thank you! Martin > > Qing > > > > gcc/doc/: > > * invoke.texi (fvla-bounds): Document new flag. > > > > gcc/testsuite: > > * gcc.dg/vla-bounds-1.c: New test. > > * gcc.dg/vla-bounds-assign-1.c: New test. > > * gcc.dg/vla-bounds-assign-2.c: New test. > > * gcc.dg/vla-bounds-assign-3.c: New test. > > * gcc.dg/vla-bounds-assign-4.c: New test. > > * gcc.dg/vla-bounds-func-1.c: New test. > > * gcc.dg/vla-bounds-init-1.c: New test. > > * gcc.dg/vla-bounds-init-2.c: New test. > > * gcc.dg/vla-bounds-init-3.c: New test. > > * gcc.dg/vla-bounds-init-4.c: New test. > > * gcc.dg/vla-bounds-nest-1.c: New test. > > * gcc.dg/vla-bounds-nest-2.c: New test. > > * gcc.dg/vla-bounds-ret-1.c: New test. > > * gcc.dg/vla-bounds-ret-2.c: New test. > > --- > > gcc/c-family/c.opt | 4 + > > gcc/c/c-typeck.cc | 171 ++++++++++++++++++--- > > gcc/doc/invoke.texi | 9 ++ > > gcc/testsuite/gcc.dg/vla-bounds-1.c | 74 +++++++++ > > gcc/testsuite/gcc.dg/vla-bounds-assign-1.c | 32 ++++ > > gcc/testsuite/gcc.dg/vla-bounds-assign-2.c | 30 ++++ > > gcc/testsuite/gcc.dg/vla-bounds-assign-3.c | 43 ++++++ > > gcc/testsuite/gcc.dg/vla-bounds-assign-4.c | 26 ++++ > > gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 54 +++++++ > > gcc/testsuite/gcc.dg/vla-bounds-init-1.c | 26 ++++ > > gcc/testsuite/gcc.dg/vla-bounds-init-2.c | 25 +++ > > gcc/testsuite/gcc.dg/vla-bounds-init-3.c | 25 +++ > > gcc/testsuite/gcc.dg/vla-bounds-init-4.c | 27 ++++ > > gcc/testsuite/gcc.dg/vla-bounds-nest-1.c | 31 ++++ > > gcc/testsuite/gcc.dg/vla-bounds-nest-2.c | 26 ++++ > > gcc/testsuite/gcc.dg/vla-bounds-ret-1.c | 27 ++++ > > gcc/testsuite/gcc.dg/vla-bounds-ret-2.c | 28 ++++ > > 17 files changed, 639 insertions(+), 19 deletions(-) > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-1.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-1.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-1.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-2.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-3.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-4.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c > > create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c > > > > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt > > index a52682d835c..786cd4ce52a 100644 > > --- a/gcc/c-family/c.opt > > +++ b/gcc/c-family/c.opt > > @@ -2324,6 +2324,10 @@ fvisibility-ms-compat > > C++ ObjC++ Var(flag_visibility_ms_compat) > > Changes visibility to match Microsoft Visual Studio by default. > > +fvla-bounds > > +C Var(flag_vla_bounds) > > +Emit run-time consistency checks for variably-modified types. > > + > > fvtable-gc > > C++ ObjC++ WarnRemoved > > No longer supported. > > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc > > index 7e0f01ed22b..59940a29b53 100644 > > --- a/gcc/c/c-typeck.cc > > +++ b/gcc/c/c-typeck.cc > > @@ -97,11 +97,12 @@ static tree qualify_type (tree, tree); > > struct comptypes_data; > > static bool tagged_types_tu_compatible_p (const_tree, const_tree, > > struct comptypes_data *); > > -static bool comp_target_types (location_t, tree, tree); > > static bool function_types_compatible_p (const_tree, const_tree, > > struct comptypes_data *); > > static bool type_lists_compatible_p (const_tree, const_tree, > > struct comptypes_data *); > > +static bool comp_target_types_instr (location_t, tree, tree, > > + struct instrument_data **); > > static int convert_arguments (location_t, vec<location_t>, tree, > > vec<tree, va_gc> *, vec<tree, va_gc> *, tree, > > tree); > > @@ -109,6 +110,9 @@ static tree pointer_diff (location_t, tree, tree, tree > > *); > > static tree convert_for_assignment (location_t, location_t, tree, tree, > > tree, > > enum impl_conv, bool, tree, tree, int, > > int = 0); > > +static tree convert_for_assignment_instrument (location_t, location_t, > > tree, tree, tree, > > + enum impl_conv, bool, tree, tree, int, int, > > + struct instrument_data **); > > static tree valid_compound_expr_initializer (tree, tree); > > static void push_string (const char *); > > static void push_member_name (tree); > > @@ -1193,6 +1197,39 @@ comptypes_verify (tree type1, tree type2) > > return true; > > } > > + > > +/* Instrument assignment of variably modified types. */ > > + > > +static tree > > +c_instrument_vm_assign (location_t loc, tree a, tree b) > > +{ > > + 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); > > + > > + return build3 (COND_EXPR, void_type_node, t, tt, void_node); > > +} > > + > > + > > + > > +struct instrument_data { > > + > > + tree t1; > > + tree t2; > > + struct instrument_data *next; > > +}; > > + > > + > > struct comptypes_data { > > bool enum_and_int_p; > > bool different_types_p; > > @@ -1202,6 +1239,8 @@ struct comptypes_data { > > bool equiv; > > const struct tagged_tu_seen_cache* cache; > > + > > + struct instrument_data **instr_vec; > > }; > > /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment > > @@ -1241,11 +1280,14 @@ comptypes_same_p (tree type1, tree type2) > > /* Like comptypes, but if it returns non-zero because enum and int are > > compatible, it sets *ENUM_AND_INT_P to true. */ > > -int > > -comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) > > +static int > > +comptypes_check_enum_int_instr (tree type1, tree type2, bool > > *enum_and_int_p, > > + struct instrument_data **instr_vec) > > { > > struct comptypes_data data = { }; > > + data.instr_vec = instr_vec; > > bool ret = comptypes_internal (type1, type2, &data); > > + > > *enum_and_int_p = data.enum_and_int_p; > > gcc_checking_assert (!ret || comptypes_verify (type1, type2)); > > @@ -1253,6 +1295,12 @@ comptypes_check_enum_int (tree type1, tree type2, > > bool *enum_and_int_p) > > return ret ? (data.warning_needed ? 2 : 1) : 0; > > } > > +int > > +comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) > > +{ > > + return comptypes_check_enum_int_instr (type1, type2, enum_and_int_p, > > NULL); > > +} > > + > > /* Like comptypes, but if it returns nonzero for different types, it > > sets *DIFFERENT_TYPES_P to true. */ > > @@ -1465,7 +1513,18 @@ comptypes_internal (const_tree type1, const_tree > > type2, > > if (d1_variable != d2_variable) > > data->different_types_p = true; > > if (d1_variable || d2_variable) > > - return true; > > + { > > + if (NULL != data->instr_vec) > > + { > > + struct instrument_data *id > > + = (struct instrument_data *)xmalloc (sizeof *id);; > > + id->t1 = TYPE_MAIN_VARIANT (t2); > > + id->t2 = TYPE_MAIN_VARIANT (t1); > > + id->next = *data->instr_vec; > > + *data->instr_vec = id; > > + } > > + return true; > > + } > > if (d1_zero && d2_zero) > > return true; > > if (d1_zero || d2_zero > > @@ -1501,7 +1560,8 @@ comptypes_internal (const_tree type1, const_tree > > type2, > > subset of the other. */ > > static bool > > -comp_target_types (location_t location, tree ttl, tree ttr) > > +comp_target_types_instr (location_t location, tree ttl, tree ttr, > > + struct instrument_data **instr_vec) > > { > > int val; > > int val_ped; > > @@ -1535,8 +1595,7 @@ comp_target_types (location_t location, tree ttl, > > tree ttr) > > ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC) > > : TYPE_MAIN_VARIANT (mvr)); > > - enum_and_int_p = false; > > - val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); > > + val = comptypes_check_enum_int_instr (mvl, mvr, &enum_and_int_p, > > instr_vec); > > if (val == 1 && val_ped != 1) > > pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays > > with different qualifiers " > > @@ -1551,6 +1610,13 @@ comp_target_types (location_t location, tree ttl, > > tree ttr) > > return val; > > } > > + > > +static int > > +comp_target_types (location_t location, tree ttl, tree ttr) > > +{ > > + return comp_target_types_instr (location, ttl, ttr, NULL); > > +} > > + > > > > /* Subroutines of `comptypes'. */ > > @@ -1815,8 +1881,13 @@ function_types_compatible_p (const_tree f1, > > const_tree f2, > > return val; > > } > > - /* Both types have argument lists: compare them and propagate results. */ > > + /* Both types have argument lists: compare them and propagate results. > > + Turn off instrumentation for bounds as these are all arrays of > > + unspecified size. */ > > + auto instr_vec_tmp = data->instr_vec; > > + data->instr_vec = NULL; > > val1 = type_lists_compatible_p (args1, args2, data); > > + data->instr_vec = instr_vec_tmp; > > return val1; > > } > > @@ -3857,10 +3928,11 @@ convert_argument (location_t ploc, tree function, > > tree fundecl, > > if (excess_precision) > > val = build1 (EXCESS_PRECISION_EXPR, valtype, val); > > - tree parmval = convert_for_assignment (ploc, ploc, type, > > - val, origtype, ic_argpass, > > - npc, fundecl, function, > > - parmnum + 1, warnopt); > > + tree parmval = convert_for_assignment_instrument (ploc, ploc, type, > > + val, origtype, ic_argpass, > > + npc, fundecl, function, > > + parmnum + 1, warnopt, > > + NULL); > > if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) > > && INTEGRAL_TYPE_P (type) > > @@ -3870,6 +3942,24 @@ convert_argument (location_t ploc, tree function, > > tree fundecl, > > return parmval; > > } > > + > > +/* Process all constraints for variably-modified types. */ > > + > > +static tree > > +process_vm_constraints (location_t location, > > + struct instrument_data **instr_vec) > > +{ > > + tree instr_expr = void_node; > > + > > + for (struct instrument_data* d = *instr_vec; d; d = d->next) > > + { > > + tree in = c_instrument_vm_assign (location, d->t1, d->t2); > > + instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, in, instr_expr); > > + } > > + return instr_expr; > > +} > > + > > + > > /* Convert the argument expressions in the vector VALUES > > to the types in the list TYPELIST. > > @@ -7313,7 +7403,50 @@ static tree > > convert_for_assignment (location_t location, location_t expr_loc, tree type, > > tree rhs, tree origtype, enum impl_conv errtype, > > bool null_pointer_constant, tree fundecl, > > - tree function, int parmnum, int warnopt /* = 0 */) > > + tree function, int parmnum, int warnopt) > > +{ > > + struct instrument_data *instr_first = NULL; > > + struct instrument_data **instr_vec = NULL; > > + > > + if (flag_vla_bounds && (ic_init_const != errtype)) > > + instr_vec = &instr_first; > > + > > + tree ret = convert_for_assignment_instrument (location, expr_loc, type, > > + rhs, origtype, errtype, > > + null_pointer_constant, fundecl, > > + function, parmnum, warnopt, > > + instr_vec); > > + if (instr_vec) > > + { > > + if (ret && ret != error_mark_node && instr_first != NULL) > > + { > > + /* 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); > > + if (instr_expr != void_node) > > + { > > + ret = save_expr (ret); > > + instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, ret, instr_expr); > > + ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), instr_expr, ret); > > + } > > + } > > + while (instr_first) > > + { > > + struct instrument_data *next = instr_first->next; > > + free (instr_first); > > + instr_first = next; > > + } > > + instr_vec = NULL; > > + } > > + return ret; > > +} > > + > > +static tree > > +convert_for_assignment_instrument (location_t location, location_t > > expr_loc, tree type, > > + tree rhs, tree origtype, enum impl_conv errtype, > > + bool null_pointer_constant, tree fundecl, > > + tree function, int parmnum, int warnopt, > > + struct instrument_data **instr_vec) > > { > > enum tree_code codel = TREE_CODE (type); > > tree orig_rhs = rhs; > > @@ -7557,11 +7690,11 @@ convert_for_assignment (location_t location, > > location_t expr_loc, tree type, > > rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs); > > SET_EXPR_LOCATION (rhs, location); > > - rhs = convert_for_assignment (location, expr_loc, > > - build_pointer_type (TREE_TYPE (type)), > > - rhs, origtype, errtype, > > - null_pointer_constant, fundecl, function, > > - parmnum, warnopt); > > + rhs = convert_for_assignment_instrument (location, expr_loc, > > + build_pointer_type (TREE_TYPE (type)), > > + rhs, origtype, errtype, > > + null_pointer_constant, fundecl, function, > > + parmnum, warnopt, instr_vec); > > if (rhs == error_mark_node) > > return error_mark_node; > > @@ -7955,7 +8088,7 @@ convert_for_assignment (location_t location, > > location_t expr_loc, tree type, > > Meanwhile, the lhs target must have all the qualifiers of the rhs. */ > > if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl)) > > > > (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr)) > > - || (target_cmp = comp_target_types (location, type, rhstype)) > > + || (target_cmp = comp_target_types_instr (location, type, rhstype, > > instr_vec)) > > > > is_opaque_pointer > > > > ((c_common_unsigned_type (mvl) > > == c_common_unsigned_type (mvr)) > > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi > > index 403ea9da1ab..8d6d68e4f27 100644 > > --- a/gcc/doc/invoke.texi > > +++ b/gcc/doc/invoke.texi > > @@ -10698,6 +10698,7 @@ void g (int n) > > @option{-Warray-parameter} option triggers warnings for similar problems > > involving ordinary array arguments. > > + > > @opindex Wvolatile-register-var > > @opindex Wno-volatile-register-var > > @item -Wvolatile-register-var > > @@ -20831,6 +20832,14 @@ computing CRC32). > > The @var{string} should be different for every file you compile. > > +@opindex fvla-bounds > > +@item -fvla-bounds > > +This option is only available when compiling C code. If activated, > > +additional code is emitted that verifies at run time for assignments > > +involving variably-modified types that corresponding size expressions > > +evaluate to the same value. > > + > > + > > @opindex save-temps > > @item -save-temps > > Store the usual ``temporary'' intermediate files permanently; name them > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-1.c > > b/gcc/testsuite/gcc.dg/vla-bounds-1.c > > new file mode 100644 > > index 00000000000..093f5e7ba25 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-1.c > > @@ -0,0 +1,74 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +// test various valid initializations and assignments > > + > > +int main() > > +{ > > + int m = 4, n = 3; > > + > > + int u = 4; > > + int v = 3; > > + > > + /* initialization */ > > + > > + char a[4]; > > + char (*pa)[u] = &a; > > + char (*qa)[v]; > > + > > + char b[u]; > > + const char (*pb)[u] = &b; > > + char (*qb)[v]; > > + > > + char c[4][3]; > > + char (*pc0)[u][v] = &c; > > + char (*qc0)[v][u]; > > + > > + char (*pc1)[u][3] = &c; > > + char (*qc1)[v][3]; > > + > > + char (*pc2)[4][v] = &c; > > + char (*qc2)[4][u]; > > + > > + char (*pc3)[][v] = &c; > > + > > + char d[u][v]; > > + char (*pd0)[4][3] = &d; > > + char (*qd0)[3][4]; > > + > > + char (*pd1)[u][3] = &d; > > + char (*qd1)[v][4]; > > + > > + char (*pd2)[4][v] = &d; > > + char (*qd2)[3][u]; > > + > > + char (*pd3)[u][v] = &d; > > + char (*qd3)[v][u]; > > + > > + char e[4][v]; > > + char (*pe0)[4][3] = &e; > > + char (*qe0)[4][4]; > > + > > + char f[u][3]; > > + char (*pf)[4][3] = &f; > > + char (*qf)[3][3]; > > + > > + char (*g[u])[v]; > > + char (*(*pg)[u])[v] = &g; > > + > > + /* assignment */ > > + > > + pa = &a; > > + pb = &b; > > + pc0 = &c; > > + pc1 = &c; > > + pc2 = &c; > > + pd0 = &d; > > + pd1 = &d; > > + pd2 = &d; > > + pd3 = &d; > > + pe0 = &e; > > + pf = &f; > > + > > + return 0; > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c > > b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c > > new file mode 100644 > > index 00000000000..ffef7e502dd > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c > > @@ -0,0 +1,32 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid assignments involving pointers to arrays of > > + variable length. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int u = 4; > > + int v = 3; > > + > > + char a[4]; > > + char (*pa)[u]; > > + char (*qa)[v]; > > + > > + char b[u]; > > + const char (*pb)[u]; > > + > > + pa = &a; > > + pb = &b; > > + qa = &a; // 3 != 4 > > + abort(); > > + > > + return 0; > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c > > b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c > > new file mode 100644 > > index 00000000000..cc445dea459 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c > > @@ -0,0 +1,30 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid assignment of a pointer to a 2D array to pointers > > + to 2D arrays of variable length. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int u = 4; > > + int v = 3; > > + > > + char c[4][3]; > > + char (*pc0)[u][v]; > > + char (*qc0)[v][u]; > > + char (*pc1)[u][3]; > > + char (*pc2)[4][v]; > > + > > + pc0 = &c; > > + pc1 = &c; > > + pc2 = &c; > > + qc0 = &c; // 3 != 4, 4 != 3 > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c > > b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c > > new file mode 100644 > > index 00000000000..068e9a57e65 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c > > @@ -0,0 +1,43 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid assignment of a pointer to a 2D VLA to pointers > > + to 2D arrays of variable length. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int u = 4; > > + int v = 3; > > + > > + char d[u][v]; > > + char (*pd0)[4][3]; > > + char (*pd1)[u][3]; > > + char (*pd2)[4][v]; > > + char (*pd3)[u][v]; > > + > > + char e[4][v]; > > + char (*pe0)[4][3]; > > + > > + char f[u][3]; > > + char (*pf)[4][3]; > > + char (*qf)[3][3]; > > + > > + /* assignment */ > > + > > + pd0 = &d; > > + pd1 = &d; > > + pd2 = &d; > > + pd3 = &d; > > + pe0 = &e; > > + > > + pf = &f; > > + qf = &f; // 3 != 4 > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c > > b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c > > new file mode 100644 > > index 00000000000..b274e237eba > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c > > @@ -0,0 +1,26 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test assignment of pointer to function returning 2D array to pointer to > > + function returning a pointer to a variable length array. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int m, n; > > +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + m = 4, n = 3; > > + > > + int u = 4; > > + int v = 3; > > + > > + char (*(*p)(void))[u][v] = &z0; // 4 != 5, 3 != 5 > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c > > b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c > > new file mode 100644 > > index 00000000000..8256999fc50 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c > > @@ -0,0 +1,54 @@ > > +/* { dg-do compile } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +// make sure we do not ICE on any of these > > + > > +const char* name = "hallo"; > > + > > +typedef void (*ht)(int n, int m, char x[n][m]); > > +void e(ht) { } > > + > > +int n, m; > > +static void f0(char a[n][m]) { } > > +static void f1(int u, int v, char a[u][v]) { } > > +static void f2(int u, int v, char a[u][v]) { } > > + > > +void f(void) > > +{ > > + int x = 1; > > + int (*m)[x] = 0; > > + m = ({ long* d2; (int (*)[d2[0]])(0); }); > > + > > + /* function pointer assignments */ > > + > > + void (*gp)(char x[4][3]) = f0; > > + void (*hp)(int n, int m, char x[n][m]) = f1; > > + ht hp2 = f1; > > + e(f1); > > + > > + /* composite type */ > > + > > + int u = 3; int v = 4; > > + char a[u][v]; > > + (1 ? f1 : f2)(u, v, a); > > +} > > + > > +/* size expression in parameter */ > > + > > +extern void a(long N, char (*a)[N]); > > + > > +static void b(void) > > +{ > > + a(1, ({ int d = 0; (char (*)[d])0; }) ); > > +} > > + > > +/* composite type */ > > + > > +int c(int u, char (*a)[u]); > > +int c(int u, char (*a)[u]) { } > > + > > +int d(void) > > +{ > > + char a[3]; > > + c(3, &a); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-1.c > > b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c > > new file mode 100644 > > index 00000000000..3e608ba0c34 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c > > @@ -0,0 +1,26 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid initialization of pointers to arrays of > > + variable length. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int u = 4; > > + int v = 3; > > + > > + char b[u]; > > + const char (*pb)[u] = &b; > > + > > + char a[4]; > > + char (*pa)[u] = &a; > > + char (*qa)[v] = &a; // 3 != 4 > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-2.c > > b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c > > new file mode 100644 > > index 00000000000..d26683e6c97 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c > > @@ -0,0 +1,25 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid initialization of pointers to 2D arrays of > > + variable length with pointer to 2D regular array. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int u = 4; > > + int v = 3; > > + > > + char c[4][3]; > > + char (*pc1)[u][3] = &c; > > + char (*pc2)[4][v] = &c; > > + char (*pc0)[u][v] = &c; > > + char (*qc0)[v][u] = &c; // 3 != 4, 4 != 3 > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-3.c > > b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c > > new file mode 100644 > > index 00000000000..7ab706af62e > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c > > @@ -0,0 +1,25 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid initialization of pointers to 2D arrays of > > + variable length with incomplete first dimension. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int u = 4; > > + int v = 3; > > + > > + /* initialization */ > > + > > + char c[4][3]; > > + char (*pc3)[][v] = &c; > > + char (*qc3)[][u] = &c; // 4 != 3 > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-4.c > > b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c > > new file mode 100644 > > index 00000000000..f20de91c156 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c > > @@ -0,0 +1,27 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid initialization of pointers to 2D arrays of > > + variable length with pointer to 2D VLA. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int u = 4; > > + int v = 3; > > + > > + /* initialization */ > > + char d[u][v]; > > + char (*pd0)[4][3] = &d; > > + char (*pd1)[u][3] = &d; > > + char (*pd2)[4][v] = &d; > > + char (*pd3)[u][v] = &d; > > + char (*qd0)[3][4] = &d; // 3 != 4, 4 != 3 > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c > > b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c > > new file mode 100644 > > index 00000000000..7f33bc95e29 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c > > @@ -0,0 +1,31 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > +/* { dg-require-effective-target trampolines } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid assignment of a nested function mit variably > > + modified return type. */ > > + > > +void handler(int) { exit(0); } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int n = 3; > > + char b[4]; > > + char (*f())[++n] { return &b; } > > + > > + if (4 != sizeof(*f())) > > + abort(); > > + > > + char (*(*p)())[n++] = &f; > > + > > + if (4 != sizeof(*(*p)())) > > + abort(); > > + > > + char (*(*p2)())[++n] = &f; > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c > > b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c > > new file mode 100644 > > index 00000000000..13f77d4e185 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c > > @@ -0,0 +1,26 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > +/* { dg-require-effective-target trampolines } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test valid and invalid assignment of regular function pointer > > + return array to pointer to function with variably modified > > + return type. */ > > + > > +void handler(int) { exit(0); } > > + > > +static char bb[4][4]; > > +static char (*g())[4][4] { return &bb; } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + int n = 4; > > + > > + char (*(*p)())[n][4] = &g; > > + char (*(*q)())[++n][4] = &g;; > > + abort(); > > +} > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c > > b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c > > new file mode 100644 > > index 00000000000..43919927ab8 > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c > > @@ -0,0 +1,27 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test returning a pointer to a 2D variable length array in > > + a function returning a pointer to a regular 2D array. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int m, n; > > + > > +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + m = 5, n = 5; > > + z0(); > > + > > + m = 4, n = 3; > > + z0(); // 5 != 3, 5, != 3 > > + abort(); > > +} > > + > > diff --git a/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c > > b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c > > new file mode 100644 > > index 00000000000..af8475e9a5f > > --- /dev/null > > +++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c > > @@ -0,0 +1,28 @@ > > +/* { dg-do run } */ > > +/* { dg-options "-fvla-bounds" } */ > > + > > +#include <signal.h> > > +#include <stdlib.h> > > + > > +/* Test returning a pointer to a 2D variable length array with > > + a fist constant dimension in a function returning a pointer > > + to a regular 2D array. */ > > + > > +static void handler(int) { exit(0); } > > + > > +int n, m; > > + > > +static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; } > > + > > +int main() > > +{ > > + signal(SIGILL, handler); > > + > > + m = 5, n = 5; > > + z1(); > > + > > + m = 4, n = 3; > > + z1(); // 4 != 3 > > + abort(); > > +} > > + > > -- > > 2.39.2 > > > > > > >