From patchwork Sat Nov 18 21:12:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1865559 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=tugraz.at header.i=@tugraz.at header.a=rsa-sha256 header.s=mailrelay header.b=qp3p+fyG; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SXmh71qWmz1yRg for ; Sun, 19 Nov 2023 08:12:55 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D2C073858C2D for ; Sat, 18 Nov 2023 21:12:52 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mailrelay.tugraz.at (mailrelay.tugraz.at [129.27.2.202]) by sourceware.org (Postfix) with ESMTPS id 680C63858D32 for ; Sat, 18 Nov 2023 21:12:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 680C63858D32 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=tugraz.at Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tugraz.at ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 680C63858D32 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=129.27.2.202 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700341961; cv=none; b=pUuyoLvSEO/D4GTzOY1ZlInDt4J6JCvx5op2hpj5Tzt+iPlIPiFX2ngMwqP+r6+DTC701jsORNW0SH+xrxfovUWkBk0qaf2iKvy1cowaxaym/uKzW3mROetG0puglnhiknxWaofejlRN2v8vFaePpADj66dzJFss6JShBnrblcg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700341961; c=relaxed/simple; bh=td2EfvD41TU0YA+MbHH20/j2vTJfZn/qUvqIDHQfw5A=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=rEQaambWfOe4VDmUvVBtx1A6SzOq7h3GXT/ajR7kKOjG9Rqw5zLsrLSwhTTSFTU3ODWNE8UZFkpBcDOkdwtNggWZTOh6+e9+lnzJEOTCpPLHWTAmV4antcAtT+9ZNTwcSfm/h/MdnO3MbtiTiQd7O0SXoV2jgX0EhA+WoTDNCXc= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-173-60.tugraz.at (vra-173-60.tugraz.at [129.27.173.60]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4SXmgh5JZ5z3wVZ; Sat, 18 Nov 2023 22:12:32 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700341952; bh=Vaw17kOC5vMtR4Z6d7SMWEFG43/OgT9M3PL/YV5c7xI=; h=Subject:From:To:Cc:Date:In-Reply-To:References; b=qp3p+fyG0Pn6p1Pf/DJfehAnttSz5ApZpeDehDpwgZp7OmbS+d8ZAyEqCzxy6MqFZ eM8DWzdy7KxovuRy5Y4ZbbNfSnwe2TukTiu7ZdGVAP1bGb9x9XhuhketKLSV7amqWk 4Bk0m+L7qI2Gk7tlt3nKXHnwUcJRKR+pDt/WfTqA= Message-ID: Subject: [PATCH 1/4] c: runtime checking for assigment of VM types 1/4 From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 18 Nov 2023 22:12:32 +0100 In-Reply-To: <45b668e3f0d58d6a5977397218a963bbde37ee83.camel@tugraz.at> References: <45b668e3f0d58d6a5977397218a963bbde37ee83.camel@tugraz.at> User-Agent: Evolution 3.46.4-2 MIME-Version: 1.0 X-TUG-Backscatter-control: G/VXY7/6zeyuAY/PU2/0qw X-Spam-Scanner: SpamAssassin 3.003001 X-Spam-Score-relay: -1.9 X-Scanned-By: MIMEDefang 2.74 on 129.27.10.117 X-Spam-Status: No, score=-10.5 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org 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. 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 | 15 ++ gcc/testsuite/gcc.dg/vla-bounds-1.c | 85 ++++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-1.c | 126 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-2.c | 126 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-3.c | 126 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-4.c | 133 ++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 56 +++++++ gcc/testsuite/gcc.dg/vla-bounds-init-1.c | 125 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-init-2.c | 125 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-init-3.c | 126 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-init-4.c | 125 +++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-nest-1.c | 39 +++++ gcc/testsuite/gcc.dg/vla-bounds-nest-2.c | 33 ++++ gcc/testsuite/gcc.dg/vla-bounds-ret-1.c | 132 ++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-ret-2.c | 133 ++++++++++++++++ 17 files changed, 1661 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 b10c6057cd1..29bc0956181 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -2280,6 +2280,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 1dbb4471a88..cb5887b6255 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -93,11 +93,13 @@ 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 tree lookup_field (tree, tree); static int convert_arguments (location_t, vec, tree, vec *, vec *, tree, @@ -106,6 +108,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); @@ -1058,6 +1063,38 @@ common_type (tree t1, tree t2) return c_common_type (t1, t2); } + +/* 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; @@ -1065,6 +1102,8 @@ struct comptypes_data { bool anon_field; const struct tagged_tu_seen_cache* cache; + + struct instrument_data **instr_vec; }; /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment @@ -1083,16 +1122,25 @@ comptypes (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; 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. */ @@ -1252,7 +1300,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 @@ -1288,7 +1347,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; @@ -1322,8 +1382,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 " @@ -1338,6 +1397,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'. */ @@ -1551,8 +1617,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; } @@ -3371,10 +3442,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) @@ -3384,6 +3456,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. @@ -6741,7 +6831,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 && error_mark_node != ret && 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 (void_node != instr_expr) + { + 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; @@ -6985,11 +7118,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; @@ -7400,7 +7533,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 1748afdbfe0..c94ca59086b 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10269,6 +10269,13 @@ void g (int n) @option{-Warray-parameter} option triggers warnings for similar problems involving ordinary array arguments. +@opindex Wvla-parameter-missing-check +@item -Wvla-parameter-missing-check +Warn when function calls can not be instrumented with the use of +@option{-fvla-bounds} to detect inconsistencies between the bounds of +VLA parameters at runtime. + + @opindex Wvolatile-register-var @opindex Wno-volatile-register-var @item -Wvolatile-register-var @@ -20052,6 +20059,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..7f71c1abbe5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-1.c @@ -0,0 +1,85 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +/* test return types */ + +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..40232925341 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +TRY( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + 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..f1f98704a1e --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +TRY( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + 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..0a811de5ffc --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +TRY( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + 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..3d8553c6426 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c @@ -0,0 +1,133 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int m, n; + +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } +static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; } +static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; } + + +int main() +{ + signal(SIGILL, handler); + + m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +TRY( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + 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..e4856017419 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c @@ -0,0 +1,56 @@ +/* { dg-do compile } */ +/* { dg-options "-fcheck-vla-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..9c9d959ee9e --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c @@ -0,0 +1,125 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +TRY( char (*qa)[v] = &a; ) // 3 != 4 + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + 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..8fb4ad8a3ea --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c @@ -0,0 +1,125 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +TRY( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + 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..83df5796942 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c @@ -0,0 +1,126 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +TRY( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + 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..81d252e3957 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c @@ -0,0 +1,125 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +int main() +{ + signal(SIGILL, handler); + + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +TRY( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + 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..30b0496107c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ +/* { dg-require-effective-target trampolines } */ + +#include +#include + +void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort() + +static char bb[4][4]; +static char (*g())[4][4] { return &bb; } + +int main() +{ + signal(SIGILL, handler); + + int n = 3; + char b[4]; + char (*f())[++n] { return &b; } + + if (4 != sizeof(*f())) + __builtin_abort(); + + TRY( char (*(*p)())[++n] = &f; ); + + if (5 != sizeof(*(*p)())) + __builtin_abort(); + + char (*(*q)())[++n][4]; + + if (6 * 4 != sizeof(*(*q)())) + __builtin_abort(); + + return 0; +} + 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..d871051225a --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c @@ -0,0 +1,33 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ +/* { dg-require-effective-target trampolines } */ + +#include +#include + +void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +static char bb[4][4]; +static char (*g())[4][4] { return &bb; } + +int main() +{ + signal(SIGILL, handler); + + int n = 3; + char b[4]; + char (*f())[++n] { return &b; } + + if (4 != sizeof(*f())) + __builtin_abort(); + + char (*(*p)())[++n] ERROR( = &f ); + +TRY( char (*(*q)())[++n][4] = &g; ); + + return 0; +} + 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..beb7dd414ed --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c @@ -0,0 +1,132 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +int m, n; + +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } +static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; } +static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; } + +int main() +{ + signal(SIGILL, handler); + + m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +TRY( z0(); ) // 5 != 3, 5, != 3 + +ERROR( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + 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..2df515e557f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c @@ -0,0 +1,133 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define ERROR(...) +#define TRY(...) __VA_ARGS__ __builtin_abort(); + +int n, m; + +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } +static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; } +static char (*z2(void))[5][5] { char (*p)[m][5] = 0; return p; } + + +int main() +{ + signal(SIGILL, handler); + + m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; +ERROR( char (*qa)[v] = &a; ) // 3 != 4 + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; +ERROR( char (*qb)[v] = &b; ) // 3 != 4 + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; +ERROR( char (*qc0)[v][u] = &c; ) // 3 != 4, 4 != 3 + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; +ERROR( char (*qc1)[v][3] = &c; ) // 3 != 4 + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; +ERROR( char (*qc2)[4][u] = &c; ) // 4 != 3 + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; +ERROR( char (*qc3)[][u] = &c; ) // 4 != 3 + + char d[u][v]; + char (*pd0)[4][3] = &d; +ERROR( char (*qd0)[3][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; +ERROR( char (*qd1)[v][4] = &d; ) // 3 != 4, 4 != 3 + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; +ERROR( char (*qd2)[3][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; +ERROR( char (*qd3)[v][u] = &d; ) // 3 != 4, 4 != 3 + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; +ERROR( char (*qe0)[4][4] = &e; ) // 4 != 3 + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; +ERROR( char (*qf)[3][3] = &f; ) // 3 != 4 + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; +ERROR( char (*(*qg)[v])[u] = &g; ) // 3 != 4, 4 != 3 + + /* assignment */ + + pa = &a; +ERROR( qa = &a; ) // 3 != 4 + + pb = &b; +ERROR( qb = &b; ) // 3 != 4 + + pc0 = &c; +ERROR( qc0 = &c; ) // 3 != 4, 4 != 3 + + pc1 = &c; +ERROR( qc1 = &c; ) // 3 != 4 + + pc2 = &c; +ERROR( qc2 = &c; ) // 4 != 3 + + pd0 = &d; +ERROR( qd0 = &d; ) // 3 != 4, 4 != 3 + + pd1 = &d; +ERROR( qd1 = &d; ) // 3 != 4, 4 != 3 + + pd2 = &d; +ERROR( qd2 = &d; ) // 3 != 4, 4 != 3 + + pd3 = &d; +ERROR( qd3 = &d; ) // 3 != 4, 4 != 3 + + pe0 = &e; +ERROR( qe0 = &e; ) // 4 != 3 + + pf = &f; +ERROR( qf = &f; ) // 3 != 4 + + /* return */ +ERROR( z0(); ) // 5 != 3, 5, != 3 + +TRY( z1(); ) // 4 != 3 + +ERROR( z2(); ) // 5 != 4 + +ERROR( char (*(*p)(void))[u][v] = &z0; ) // 4 != 5, 3 != 5 + + return 0; +} + From patchwork Sat Nov 18 21:13:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1865563 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=tugraz.at header.i=@tugraz.at header.a=rsa-sha256 header.s=mailrelay header.b=K9ojpSWR; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SXmhw4Kykz1yRg for ; Sun, 19 Nov 2023 08:13:36 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BB421385840C for ; Sat, 18 Nov 2023 21:13:33 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mailrelay.tugraz.at (mailrelay.tugraz.at [129.27.2.202]) by sourceware.org (Postfix) with ESMTPS id B98363858C60 for ; Sat, 18 Nov 2023 21:13:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B98363858C60 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=tugraz.at Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tugraz.at ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B98363858C60 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=129.27.2.202 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700342003; cv=none; b=P5HUTDGRVra0KU3aufhNgRcsHtDovTSQ1Bp0GKpOAHx7N573Mo1ma03V3eBk81hA4T+tbWw0VH7Ifssxy8eJ4tpL4z2I8rVpEbdJ9flMsHjOlt7L0SaHbaNw2iZpCrNMSJIzRUVzHM0X+bAWtyAP7muu9wMuNVgT+RaUlmb42I8= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700342003; c=relaxed/simple; bh=3MBbx9B5AcK76lhodtxmLi4PNBL9s7YY2Nmks2eEgJk=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=lI46OWsbdcVl1bQVW3qRj3Jc/eQl2oJbehYzyG5PhPYyFGIUDLwfOJGz1b6+9HJVN/fD1Cpg4kX7pbkuVyVbEjpiGWD69hFrVo1oyRJ4kpx4aZq8Oppgrq8cIHbT1AgteEZewL7gdYqrL7ZtzI7o56lPZ5hL/Ci7jLNITW1Io48= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-173-60.tugraz.at (vra-173-60.tugraz.at [129.27.173.60]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4SXmhJ14ztz3wdR; Sat, 18 Nov 2023 22:13:04 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700341984; bh=7T2SdvGmU7KwiTEegO5LzANHBgBx1jX5wQdcn4aD3Vc=; h=Subject:From:To:Cc:Date; b=K9ojpSWRMhk0uQMEVwJ3eSjzMHrTLxBqAdXhcvpzUOUr/e3hl9o+AKG05Pjt0c+X2 RvsmW70W3BAB4DDhHyfUNzT/bPxshAeXR7YVfT5DD4VDDZw009RGj/UoyN7JoLm29Q R327zbKTAad5mmqpuD3dn8eUhHJCm2GSWrrbRvVQ= Message-ID: <2ef9124eecefe8f39eab9557e5ce76f42e8d6c7c.camel@tugraz.at> Subject: [PATCH 2/4] c: runtime checking for assigment of VM types 2/4 From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 18 Nov 2023 22:13:03 +0100 User-Agent: Evolution 3.46.4-2 MIME-Version: 1.0 X-TUG-Backscatter-control: G/VXY7/6zeyuAY/PU2/0qw X-Spam-Scanner: SpamAssassin 3.003001 X-Spam-Score-relay: -1.9 X-Scanned-By: MIMEDefang 2.74 on 129.27.10.116 X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org 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 | 4 +- gcc/testsuite/gcc.dg/vla-bounds-func-10.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-11.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-12.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-13.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-14.c | 45 +++++++ gcc/testsuite/gcc.dg/vla-bounds-func-15.c | 45 +++++++ gcc/testsuite/gcc.dg/vla-bounds-func-16.c | 45 +++++++ gcc/testsuite/gcc.dg/vla-bounds-func-17.c | 45 +++++++ gcc/testsuite/gcc.dg/vla-bounds-func-18.c | 45 +++++++ gcc/testsuite/gcc.dg/vla-bounds-func-19.c | 45 +++++++ gcc/testsuite/gcc.dg/vla-bounds-func-2.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-20.c | 45 +++++++ gcc/testsuite/gcc.dg/vla-bounds-func-3.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-4.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-5.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-6.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-7.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-8.c | 99 ++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-9.c | 99 ++++++++++++++ 21 files changed, 1641 insertions(+), 17 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 --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index cb5887b6255..b65fc450940 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1067,19 +1067,13 @@ common_type (tree t1, tree t2) /* 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); @@ -3286,7 +3280,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. */ @@ -3446,7 +3441,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) @@ -3459,15 +3454,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 *values) { tree instr_expr = void_node; + tree args = NULL; + + /* Find the arguments for the function declaration / type. */ + if (function) + { + if (FUNCTION_DECL == TREE_CODE (function)) + { + 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 (ARRAY_TYPE == TREE_CODE (t1)); + gcc_assert (ARRAY_TYPE == TREE_CODE (t2)); + + tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (t1)); + tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (t2)); + + gcc_assert (as); + gcc_assert (bs); + + as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node); + bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node); + + if (function) + { + + if (INTEGER_CST == TREE_CODE (bs)) + goto cont; + + if (NOP_EXPR == TREE_CODE (bs) + && SAVE_EXPR == TREE_CODE (TREE_OPERAND (bs, 0))) + { + tree bs1 = TREE_OPERAND (bs, 0); + tree bs2 = TREE_OPERAND (bs1, 0); + + /* Another parameter of the current functions. */ + if (PARM_DECL == TREE_CODE (bs2) + && (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 (PARM_DECL == TREE_CODE (bs2) + && 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 (VAR_DECL == TREE_CODE (bs2)) + { + 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; @@ -3578,6 +3668,12 @@ convert_arguments (location_t loc, vec 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. */ @@ -3690,7 +3786,7 @@ convert_arguments (location_t loc, vec 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) { @@ -3745,7 +3841,7 @@ convert_arguments (location_t loc, vec 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) @@ -3757,6 +3853,31 @@ convert_arguments (location_t loc, vec 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); @@ -6850,7 +6971,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 (void_node != instr_expr) { 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 e4856017419..dd5f3e76b50 100644 --- a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fcheck-vla-bounds" } */ +/* { dg-options "-fvla-bounds" } */ // make sure we do not ICE on any of these @@ -51,6 +51,6 @@ 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..19942d2de95 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-10.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) if (0) { __VA_ARGS__ } + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..42859b0bd14 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-11.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +TRY( d0(&D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* "incompatible pointer type" */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..94334792b62 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-12.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* "incompatible pointer type" */ + // 3 != 4 + + d1(3, &C0); +TRY( d1(3, &D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..95c47e9587d --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-13.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* "incompatible pointer type" */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* "incompatible pointer type" */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +TRY( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..8ac1262e222 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-14.c @@ -0,0 +1,45 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +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]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; +ERROR( b1(4, &A0); ) // 4 != 3 +ERROR( b0(4, &A0); ) // 4 != 3 + +ERROR( b2(&A0, 4); ) // 4 != 3 + +ERROR( b3(&A0, 4); ) // 4 != 3 + + n = 4; +ERROR( b4(&A0); ) // 4 != 3 + +ERROR( b5(&A0); ) // 4 != 3 +} + + +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..ef59f6cad4b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-15.c @@ -0,0 +1,45 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +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]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; +TRY( b1(4, &A0); ) // 4 != 3 +ERROR( b0(4, &A0); ) // 4 != 3 + +ERROR( b2(&A0, 4); ) // 4 != 3 + +ERROR( b3(&A0, 4); ) // 4 != 3 + + n = 4; +ERROR( b4(&A0); ) // 4 != 3 + +ERROR( b5(&A0); ) // 4 != 3 +} + + +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-16.c b/gcc/testsuite/gcc.dg/vla-bounds-func-16.c new file mode 100644 index 00000000000..710871e6db1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-16.c @@ -0,0 +1,45 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +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]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; +ERROR( b1(4, &A0); ) // 4 != 3 +TRY( b0(4, &A0); ) // 4 != 3 + +ERROR( b2(&A0, 4); ) // 4 != 3 + +ERROR( b3(&A0, 4); ) // 4 != 3 + + n = 4; +ERROR( b4(&A0); ) // 4 != 3 + +ERROR( b5(&A0); ) // 4 != 3 +} + + +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-17.c b/gcc/testsuite/gcc.dg/vla-bounds-func-17.c new file mode 100644 index 00000000000..f2522030831 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-17.c @@ -0,0 +1,45 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +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]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; +ERROR( b1(4, &A0); ) // 4 != 3 +ERROR( b0(4, &A0); ) // 4 != 3 + +TRY( b2(&A0, 4); ) // 4 != 3 + +ERROR( b3(&A0, 4); ) // 4 != 3 + + n = 4; +ERROR( b4(&A0); ) // 4 != 3 + +ERROR( b5(&A0); ) // 4 != 3 +} + + +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-18.c b/gcc/testsuite/gcc.dg/vla-bounds-func-18.c new file mode 100644 index 00000000000..779dd370c8f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-18.c @@ -0,0 +1,45 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +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]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; +ERROR( b1(4, &A0); ) // 4 != 3 +ERROR( b0(4, &A0); ) // 4 != 3 + +ERROR( b2(&A0, 4); ) // 4 != 3 + +TRY( b3(&A0, 4); ) // 4 != 3 + + n = 4; +ERROR( b4(&A0); ) // 4 != 3 + +ERROR( b5(&A0); ) // 4 != 3 +} + + +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-19.c b/gcc/testsuite/gcc.dg/vla-bounds-func-19.c new file mode 100644 index 00000000000..7a129d2851f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-19.c @@ -0,0 +1,45 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +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]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; +ERROR( b1(4, &A0); ) // 4 != 3 +ERROR( b0(4, &A0); ) // 4 != 3 + +ERROR( b2(&A0, 4); ) // 4 != 3 + +ERROR( b3(&A0, 4); ) // 4 != 3 + + n = 4; +TRY( b4(&A0); ) // 4 != 3 + +ERROR( b5(&A0); ) // 4 != 3 +} + + +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-2.c b/gcc/testsuite/gcc.dg/vla-bounds-func-2.c new file mode 100644 index 00000000000..19942d2de95 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-2.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) if (0) { __VA_ARGS__ } + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..8532a2f3223 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-20.c @@ -0,0 +1,45 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +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]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; +ERROR( b1(4, &A0); ) // 4 != 3 +ERROR( b0(4, &A0); ) // 4 != 3 + +ERROR( b2(&A0, 4); ) // 4 != 3 + +ERROR( b3(&A0, 4); ) // 4 != 3 + + n = 4; +ERROR( b4(&A0); ) // 4 != 3 + +TRY( b5(&A0); ) // 4 != 3 +} + + +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-3.c b/gcc/testsuite/gcc.dg/vla-bounds-func-3.c new file mode 100644 index 00000000000..d21337f1de0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-3.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +TRY( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* "incompatible pointer type" */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* "incompatible pointer type" */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..14a0efae913 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-4.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +TRY( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* "incompatible pointer type" */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* "incompatible pointer type" */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..57f641695a0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-5.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) if (0) { __VA_ARGS__ } + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +TRY( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..88986a8bf23 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-6.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) if (0) { __VA_ARGS__ } + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +TRY( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..788d3243c58 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-7.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) if (0) { __VA_ARGS__ } + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +TRY( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..c0cbf85b647 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-8.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) if (0) { __VA_ARGS__ } + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +TRY( c0(&D2); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + 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..3e65106f053 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-9.c @@ -0,0 +1,99 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) if (0) { __VA_ARGS__ } + +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); + a0(&B0); /* { dg-warning "incompatible pointer type" } */ +ERROR( a0(&B1); ) // 4 != 3 + + b0(&A0); + b0(&A1); +ERROR( b0(&B0); ) // 4 != 3 + +ERROR( b0(&B1); ) // 4 != 3 + + b1(4, &A0); +ERROR( b1(4, &B0); ) // 4 != 3 + + 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); +ERROR( c0(&D0); ) // 4 != 4, 3 != 4 + +ERROR( c0(&D1); ) // 4 != 3, 3 != 4 + +ERROR( c0(&D2); ) // 4 != 3, 3 != 4 + +TRY( c0(&D3); ) // 4 != 3, 3 != 4 + + d0(&C0); +ERROR( d0(&D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + d1(3, &C0); +ERROR( d1(3, &D0); ) /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + + e0(&C0); + e0(&D0); /* { dg-warning "incompatible pointer type" } */ + e1(4, &C0); + e1(4, &D0); /* { dg-warning "incompatible pointer type" } */ + + f0(C0); +ERROR( f0(D0); ) // 3 != 4 + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 +} + From patchwork Sat Nov 18 21:13:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1865566 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=tugraz.at header.i=@tugraz.at header.a=rsa-sha256 header.s=mailrelay header.b=frEoX1oZ; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SXmjZ5FGZz1yRg for ; Sun, 19 Nov 2023 08:14:10 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id F00FE3858C20 for ; Sat, 18 Nov 2023 21:14:07 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mailrelay.tugraz.at (mailrelay.tugraz.at [129.27.2.202]) by sourceware.org (Postfix) with ESMTPS id 89B0C3858421 for ; Sat, 18 Nov 2023 21:13:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 89B0C3858421 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=tugraz.at Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tugraz.at ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 89B0C3858421 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=129.27.2.202 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700342037; cv=none; b=Y2wzucoP4feunERuqrAfkgnAEjRh/o+l+xWwtoDiJxmXOFofxc/m2ghBkDP2/l/n+WfHa/uafluIrU6FZYY24RISMIDuZ1+vaEJEYhW9grfDzrf5Ky8t+Z0g1HNGCyaUBtOfogsrNr1l6b2Zsx4slSTT6BZTmgUd0oz07e/Dmzc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700342037; c=relaxed/simple; bh=mdcW2Ar9xke+du3d6ps/+DhiCNs5TkR+jtl/kWzfnBw=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=GPHL1F67nHp7IdI+KdcJ8uTGnfvKAwBop5aPiTjs+zUZVEpqFAxeehhyDlV4MaQ9hbHxLEl7rlABW0LdyXakNFqyg8mW1Wh1DjPOA/iHDxNpjgy0vOxiAd5EDXxyiC8Vnw6ZkkEqY194IYdJB7CkivQ5NvKQU4dVCHWJnZ8KDlk= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-173-60.tugraz.at (vra-173-60.tugraz.at [129.27.173.60]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4SXmj45JLBz1LLyX; Sat, 18 Nov 2023 22:13:44 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 mailrelay.tugraz.at 4SXmj45JLBz1LLyX DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700342025; bh=Y+VmK9KpOL0zhGKpLt+TzqXq9+vurPIxW3bRFgc/5SY=; h=Subject:From:To:Cc:Date:From; b=frEoX1oZFzITiduCH1zRhprnSZtmSM+vw8qE3eoE+8Btl46Jkw9ND/w6ObUrSqL1n 0eU5l2MT2lju+l9GLEmPNhpBxCgAi8RIsTiqKjXPtK2dj2sGJMeCnr2505hTkhSuHu Mt52Ze/ALDQHbngENtbo9duGqiYTN/HzWmK5safg= Message-ID: <5af943163b8c49f75022e2bae151c18afd4b7c0c.camel@tugraz.at> Subject: [PATCH 3/4] c: runtime checking for assigment of VM types 3/4 From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 18 Nov 2023 22:13:44 +0100 User-Agent: Evolution 3.46.4-2 MIME-Version: 1.0 X-TUG-Backscatter-control: G/VXY7/6zeyuAY/PU2/0qw X-Spam-Scanner: SpamAssassin 3.003001 X-Spam-Score-relay: -1.9 X-Scanned-By: MIMEDefang 2.74 on 129.27.10.117 X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Support instrumentation of functions called via pointers. To do so, record the declaration with the parameter types, so that it can be retrieved later. gcc/c: c-decl.cc (get_parm_info): Record function declaration for arguments. c-typeck.cc (process_vm_constraints): Instrument functions called via pointers. gcc/testsuide/gcc.dg: * vla-bounds-func-1.c: Add warning. * vla-bounds-fnptr.c: New test. * vla-bounds-fnptr-1.c: New test. * vla-bounds-fnptr-2.c: New test. * vla-bounds-fnptr-3.c: New test. * vla-bounds-fnptr-4.c: New test. * vla-bounds-fnptr-5.c: New test. --- gcc/c/c-decl.cc | 4 ++ gcc/c/c-typeck.cc | 14 +++- gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c | 78 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c | 78 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c | 78 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c | 78 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c | 78 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-fnptr.c | 78 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 2 +- 9 files changed, 485 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr.c diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 64d3a941cb9..84a30f7476a 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -8549,6 +8549,10 @@ get_parm_info (bool ellipsis, tree expr) declared types. The back end may override this later. */ DECL_ARG_TYPE (decl) = type; types = tree_cons (0, type, types); + + /* Record the decl for use for VLA bounds checking. */ + if (flag_vla_bounds) + TREE_PURPOSE (types) = decl; } break; diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index b65fc450940..1200abc2f4a 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3472,9 +3472,19 @@ process_vm_constraints (location_t location, } else { - /* Functions called via pointers are not yet supported. */ - return void_node; + while (FUNCTION_TYPE != TREE_CODE (function)) + function = TREE_TYPE (function); + + args = TREE_PURPOSE (TYPE_ARG_TYPES (function)); + + if (!args) + { + /* FIXME: this can happen when forming composite types for the + conditional operator. */ + return void_node; + } } + gcc_assert (PARM_DECL == TREE_CODE (args)); } for (struct instrument_data* d = *instr_vec; d; d = d->next) diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c new file mode 100644 index 00000000000..b9af87f6338 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c @@ -0,0 +1,78 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +void foo1(void (*p)(int n, char (*a)[n])) +{ + char A0[3]; + (*p)(3, &A0); +TRY( (*p)(4, &A0); ) // 4 != 3 +} + +void b0(int n, char (*a)[n]) { } + + +int n; + +void foo2(void (*p)(int n, char (*a)[n])) +{ + n = 4; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo3(void (*p)(int n0, char (*a)[n])) +{ + n = 4; + char A0[3]; +ERROR( (*p)(3, &A0); ) // 4 != 3 +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo4(void (*p)(int n, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + + +void foo5(void (*p)(int n0, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); + (*p)(4, &A0); +} + + +void b1(int n0, char (*a)[n]) { } + + + +int main() +{ + signal(SIGILL, handler); + + foo1(&b0); + + foo2(&b1); + foo3(&b1); // we should diagnose mismatch and run-time discrepancies + + foo4(&b1); + foo5(&b1); // we should diagnose mismatch and run-time discrepancies +} + + + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c new file mode 100644 index 00000000000..4ec326af06c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c @@ -0,0 +1,78 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +void foo1(void (*p)(int n, char (*a)[n])) +{ + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void b0(int n, char (*a)[n]) { } + + +int n; + +void foo2(void (*p)(int n, char (*a)[n])) +{ + n = 4; + char A0[3]; + (*p)(3, &A0); +TRY( (*p)(4, &A0); ) // 4 != 3 +} + +void foo3(void (*p)(int n0, char (*a)[n])) +{ + n = 4; + char A0[3]; +ERROR( (*p)(3, &A0); ) // 4 != 3 +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo4(void (*p)(int n, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + + +void foo5(void (*p)(int n0, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); + (*p)(4, &A0); +} + + +void b1(int n0, char (*a)[n]) { } + + + +int main() +{ + signal(SIGILL, handler); + + foo1(&b0); + + foo2(&b1); + foo3(&b1); // we should diagnose mismatch and run-time discrepancies + + foo4(&b1); + foo5(&b1); // we should diagnose mismatch and run-time discrepancies +} + + + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c new file mode 100644 index 00000000000..9e28a8e4db7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c @@ -0,0 +1,78 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +void foo1(void (*p)(int n, char (*a)[n])) +{ + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void b0(int n, char (*a)[n]) { } + + +int n; + +void foo2(void (*p)(int n, char (*a)[n])) +{ + n = 4; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo3(void (*p)(int n0, char (*a)[n])) +{ + n = 4; + char A0[3]; +TRY( (*p)(3, &A0); ) // 4 != 3 +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo4(void (*p)(int n, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + + +void foo5(void (*p)(int n0, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); + (*p)(4, &A0); +} + + +void b1(int n0, char (*a)[n]) { } + + + +int main() +{ + signal(SIGILL, handler); + + foo1(&b0); + + foo2(&b1); + foo3(&b1); // we should diagnose mismatch and run-time discrepancies + + foo4(&b1); + foo5(&b1); // we should diagnose mismatch and run-time discrepancies +} + + + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c new file mode 100644 index 00000000000..7f70b53cc4c --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c @@ -0,0 +1,78 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +void foo1(void (*p)(int n, char (*a)[n])) +{ + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void b0(int n, char (*a)[n]) { } + + +int n; + +void foo2(void (*p)(int n, char (*a)[n])) +{ + n = 4; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo3(void (*p)(int n0, char (*a)[n])) +{ + n = 4; + char A0[3]; +ERROR( (*p)(3, &A0); ) // 4 != 3 +TRY( (*p)(4, &A0); ) // 4 != 3 +} + +void foo4(void (*p)(int n, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + + +void foo5(void (*p)(int n0, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); + (*p)(4, &A0); +} + + +void b1(int n0, char (*a)[n]) { } + + + +int main() +{ + signal(SIGILL, handler); + + foo1(&b0); + + foo2(&b1); + foo3(&b1); // we should diagnose mismatch and run-time discrepancies + + foo4(&b1); + foo5(&b1); // we should diagnose mismatch and run-time discrepancies +} + + + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c new file mode 100644 index 00000000000..012d32ff234 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c @@ -0,0 +1,78 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +void foo1(void (*p)(int n, char (*a)[n])) +{ + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void b0(int n, char (*a)[n]) { } + + +int n; + +void foo2(void (*p)(int n, char (*a)[n])) +{ + n = 4; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo3(void (*p)(int n0, char (*a)[n])) +{ + n = 4; + char A0[3]; +ERROR( (*p)(3, &A0); ) // 4 != 3 +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo4(void (*p)(int n, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); +TRY( (*p)(4, &A0); ) // 4 != 3 +} + + +void foo5(void (*p)(int n0, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); + (*p)(4, &A0); +} + + +void b1(int n0, char (*a)[n]) { } + + + +int main() +{ + signal(SIGILL, handler); + + foo1(&b0); + + foo2(&b1); + foo3(&b1); // we should diagnose mismatch and run-time discrepancies + + foo4(&b1); + foo5(&b1); // we should diagnose mismatch and run-time discrepancies +} + + + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr.c b/gcc/testsuite/gcc.dg/vla-bounds-fnptr.c new file mode 100644 index 00000000000..9d102673c94 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr.c @@ -0,0 +1,78 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +#define TRY(...) __VA_ARGS__ __builtin_abort(); +#define ERROR(...) + + + +void foo1(void (*p)(int n, char (*a)[n])) +{ + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void b0(int n, char (*a)[n]) { } + + +int n; + +void foo2(void (*p)(int n, char (*a)[n])) +{ + n = 4; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo3(void (*p)(int n0, char (*a)[n])) +{ + n = 4; + char A0[3]; +ERROR( (*p)(3, &A0); ) // 4 != 3 +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + +void foo4(void (*p)(int n, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); +ERROR( (*p)(4, &A0); ) // 4 != 3 +} + + +void foo5(void (*p)(int n0, char (*a)[n])) +{ + n = 3; + char A0[3]; + (*p)(3, &A0); + (*p)(4, &A0); +} + + +void b1(int n0, char (*a)[n]) { } + + + +int main() +{ + signal(SIGILL, handler); + + foo1(&b0); + + foo2(&b1); + foo3(&b1); // we should diagnose mismatch and run-time discrepancies + + foo4(&b1); + foo5(&b1); // we should diagnose mismatch and run-time discrepancies +} + + + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c index dd5f3e76b50..72dba39107b 100644 --- a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c @@ -31,7 +31,7 @@ void f(void) int u = 3; int v = 4; char a[u][v]; - (1 ? f1 : f2)(u, v, a); + (1 ? f1 : f2)(u, v, a); /* "Function call not instrumented." */ } /* size expression in parameter */ From patchwork Sat Nov 18 21:14:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1865567 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=tugraz.at header.i=@tugraz.at header.a=rsa-sha256 header.s=mailrelay header.b=GNQpsMxZ; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SXmk86cr0z1yRg for ; Sun, 19 Nov 2023 08:14:40 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2F15E385841F for ; Sat, 18 Nov 2023 21:14:38 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mailrelay.tugraz.at (mailrelay.tugraz.at [129.27.2.202]) by sourceware.org (Postfix) with ESMTPS id 2EF673858C74 for ; Sat, 18 Nov 2023 21:14:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2EF673858C74 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=tugraz.at Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tugraz.at ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 2EF673858C74 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=129.27.2.202 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700342061; cv=none; b=mPgqKWkTHytQJpiN8BmvXnMxL2csBJbUjndQu2bIuxCop2dKGzQylcwi9DxZQkXx4JJu9p50rynHT+h9WiDCvLZDwTSroBaBtInhj2ogMSEUlDj8U5PqTbAtT7i+n8Lb+eekEuzRtPkzihXnwkHMkeMDO+7uL40ImWaLZP9Z4nY= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1700342061; c=relaxed/simple; bh=IxIIEL/1GXisg0wH2wwzxpvCOR5TMYfn1ZW+DnwPJxM=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=FXz0/twM/pHTIn5giZ2Zx9QKHz4UbwxjlNfTB+kePGD6kucHl9OmCo8mQUQg59c2IUkXLArqfxdPnjHikCOYCL9LOdMdYwwr14vBe2MfN7zQ1KdKVu3eZkz541Havyn+szpTwGngGDRY0vUg2D4rzkTjNp0XmYkZjWU/PSZS11Q= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-173-60.tugraz.at (vra-173-60.tugraz.at [129.27.173.60]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4SXmjj5ZRjz1LLyX; Sat, 18 Nov 2023 22:14:17 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 mailrelay.tugraz.at 4SXmjj5ZRjz1LLyX DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1700342057; bh=G0IojL0fpC/kExPhm81rMe7jx6zKHbXhp4kPPCn6zw0=; h=Subject:From:To:Cc:Date:From; b=GNQpsMxZ2gkuaVg+dqgc3lY5wG51paLpcyzGt1pNfwQYuM1GJhzMWE90BZhGAHFH8 p53rmeSqKc7lLYznoI4rMwFMpBQWJkjy3jCX34k8D+xeSXTJ0omE4/jT0Xb9VZ3uPM 59bTDG7+efw3i60evfoRyFDzRNDMmvG9mGrigcZg= Message-ID: Subject: [PATCH 4/4] c: runtime checking for assigment of VM types 4/4 From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers Date: Sat, 18 Nov 2023 22:14:17 +0100 User-Agent: Evolution 3.46.4-2 MIME-Version: 1.0 X-TUG-Backscatter-control: G/VXY7/6zeyuAY/PU2/0qw X-Spam-Scanner: SpamAssassin 3.003001 X-Spam-Score-relay: -1.9 X-Scanned-By: MIMEDefang 2.74 on 129.27.10.117 X-Spam-Status: No, score=-11.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Add warning for the case when a function call can not be instrumened. gcc/c-family/: * c.opt (Wvla-parameter-missing-check): Add warning. gcc/c/: * c-typeck.cc (process_vm_constraints): Add warning. gcc/doc/: * invoke.texi (Wvla-parameter-missing-check): Document warning. (flag_vla_bounds): Update. gcc/testsuite/: * gcc.dg/vla-bounds-func-1.c: Add warning. --- gcc/c-family/c.opt | 5 +++++ gcc/c/c-typeck.cc | 4 ++++ gcc/doc/invoke.texi | 11 ++++++++--- gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 6 +++--- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 29bc0956181..bd45ba577bd 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1485,6 +1485,11 @@ Wvla-parameter C ObjC C++ ObjC++ Var(warn_vla_parameter) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall) Warn about mismatched declarations of VLA parameters. +Wvla-parameter-missing-check +C ObjC Var(warn_vla_parameter_check) Warning Init(0) +When using run-time checking of VLA bounds, warn about function calls which +could not be instrumented. + Wvolatile C++ ObjC++ Var(warn_volatile) Warning Warn about deprecated uses of volatile qualifier. diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 1200abc2f4a..a4fb0a6b527 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3481,6 +3481,8 @@ process_vm_constraints (location_t location, { /* FIXME: this can happen when forming composite types for the conditional operator. */ + warning_at (location, OPT_Wvla_parameter_missing_check, + "Function call not instrumented"); return void_node; } } @@ -3564,6 +3566,8 @@ process_vm_constraints (location_t location, 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.) */ + warning_at (location, OPT_Wvla_parameter_missing_check, + "Function call not instrumented"); return void_node; } cont: diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index c94ca59086b..6f4bbd43919 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10269,6 +10269,7 @@ void g (int n) @option{-Warray-parameter} option triggers warnings for similar problems involving ordinary array arguments. + @opindex Wvla-parameter-missing-check @item -Wvla-parameter-missing-check Warn when function calls can not be instrumented with the use of @@ -20063,9 +20064,13 @@ The @var{string} should be different for every file you compile. @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. - +and function calls involving variably-modified types that corresponding +size expressions evaluate to the same value. Note that for function +calls the visible declarations needs to have a size expression that +matches the size expression in the definition. A mismatch seen by the +the compiler is diagnosed by @option{-Wvla-parameter}). In same cases, +a function call can not be instrumented. This can be diagnosed by +@option{-Wvla-parameter-missing-check}. @opindex save-temps @item -save-temps diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c index 72dba39107b..205e5174185 100644 --- a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-fvla-bounds" } */ +/* { dg-options "-fvla-bounds -Wvla-parameter-missing-check" } */ // make sure we do not ICE on any of these @@ -31,7 +31,7 @@ void f(void) int u = 3; int v = 4; char a[u][v]; - (1 ? f1 : f2)(u, v, a); /* "Function call not instrumented." */ + (1 ? f1 : f2)(u, v, a); /* { dg-warning "Function call" "not instrumented." } */ } /* size expression in parameter */ @@ -51,6 +51,6 @@ int c(int u, char (*a)[u]) { } int d(void) { char a[3]; - c(3, &a); /* "Function call not instrumented." */ + c(3, &a); /* { dg-warning "Function call" "not instrumented." } */ }