From patchwork Mon Jul 15 07:19:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1960445 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=UuwmOxv9; 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 4WMts53zWXz1xr4 for ; Mon, 15 Jul 2024 17:20:41 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id B64EB3864C6A for ; Mon, 15 Jul 2024 07:20:39 +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 8431C386481D for ; Mon, 15 Jul 2024 07:20:06 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 8431C386481D 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 8431C386481D 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=1721028012; cv=none; b=dEe4n4SCBQZCQdqGNIMiBqaGQDRpUJGMFj9qcKe6kOq59AA/Rk/+PrsU4Ujfqs4PtN/cnVfymKPu9QAdcxHRLtBzQP32j7Vp6ilmh4VwlXYEh9RUPxJIBDuuKOBKx9cqUaSAckRNxMDP0vgGp0dk/EvIuG9u6SSRsIFjjTrQ6Qo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721028012; c=relaxed/simple; bh=29wUW0RYE3YSsw6VW9UrFIdW9slIAMp5jhGmZFegoPs=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=BSkQnMJcR3pA83kkuKCYBTESnYiIjkl0d1pH3Y82wacmvfZMYVBqBkKDK07Iq4ZGRhGdeNuMKKXFEP5sCqRCcaho75ffj2hKxZ63g2NVl3LiPsUP77Rq6jma4qf1Ihgp8C4XM2ef1jHW4dTBFNaGsyJRqyuAh+S+tPKezu1b7bw= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-172-50.tugraz.at (vra-172-50.tugraz.at [129.27.172.50]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4WMtrH34Cpz1HNLp; Mon, 15 Jul 2024 09:19:59 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 mailrelay.tugraz.at 4WMtrH34Cpz1HNLp DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1721027999; bh=29wUW0RYE3YSsw6VW9UrFIdW9slIAMp5jhGmZFegoPs=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=UuwmOxv91HvIY3VNtv9HqkVJon/eP27Kd1tQBB4p/gd3AH5VEEjawXVpw+hImjYCJ N+RwC7yuKJrAHB5zfLo8YZN4ukJT7zqYpkOLBK4o6ZFBLzTqYxv9TpvLi1qoGxMj+V qDzmfmwqdG2Kh0sd1clWpgZDRjixDvWW39ZjxP2E= Message-ID: Subject: [PATCH v3 1/4] c: runtime checking for assigment of VM types From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers , Siddhesh Poyarekar , kees Cook , Marek Polacek Date: Mon, 15 Jul 2024 09:19:59 +0200 In-Reply-To: References: 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.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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 | 9 ++ gcc/testsuite/gcc.dg/vla-bounds-1.c | 74 +++++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-1.c | 32 ++++ gcc/testsuite/gcc.dg/vla-bounds-assign-2.c | 30 ++++ gcc/testsuite/gcc.dg/vla-bounds-assign-3.c | 43 ++++++ gcc/testsuite/gcc.dg/vla-bounds-assign-4.c | 26 ++++ gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 54 +++++++ gcc/testsuite/gcc.dg/vla-bounds-init-1.c | 26 ++++ gcc/testsuite/gcc.dg/vla-bounds-init-2.c | 25 +++ gcc/testsuite/gcc.dg/vla-bounds-init-3.c | 25 +++ gcc/testsuite/gcc.dg/vla-bounds-init-4.c | 27 ++++ gcc/testsuite/gcc.dg/vla-bounds-nest-1.c | 31 ++++ gcc/testsuite/gcc.dg/vla-bounds-nest-2.c | 26 ++++ gcc/testsuite/gcc.dg/vla-bounds-ret-1.c | 27 ++++ gcc/testsuite/gcc.dg/vla-bounds-ret-2.c | 28 ++++ 17 files changed, 639 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-2.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-3.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-4.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index a52682d835c..786cd4ce52a 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -2324,6 +2324,10 @@ fvisibility-ms-compat C++ ObjC++ Var(flag_visibility_ms_compat) Changes visibility to match Microsoft Visual Studio by default. +fvla-bounds +C Var(flag_vla_bounds) +Emit run-time consistency checks for variably-modified types. + fvtable-gc C++ ObjC++ WarnRemoved No longer supported. diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7e0f01ed22b..59940a29b53 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -97,11 +97,12 @@ static tree qualify_type (tree, tree); struct comptypes_data; static bool tagged_types_tu_compatible_p (const_tree, const_tree, struct comptypes_data *); -static bool comp_target_types (location_t, tree, tree); static bool function_types_compatible_p (const_tree, const_tree, struct comptypes_data *); static bool type_lists_compatible_p (const_tree, const_tree, struct comptypes_data *); +static bool comp_target_types_instr (location_t, tree, tree, + struct instrument_data **); static int convert_arguments (location_t, vec, tree, vec *, vec *, tree, tree); @@ -109,6 +110,9 @@ static tree pointer_diff (location_t, tree, tree, tree *); static tree convert_for_assignment (location_t, location_t, tree, tree, tree, enum impl_conv, bool, tree, tree, int, int = 0); +static tree convert_for_assignment_instrument (location_t, location_t, tree, tree, tree, + enum impl_conv, bool, tree, tree, int, int, + struct instrument_data **); static tree valid_compound_expr_initializer (tree, tree); static void push_string (const char *); static void push_member_name (tree); @@ -1193,6 +1197,39 @@ comptypes_verify (tree type1, tree type2) return true; } + +/* Instrument assignment of variably modified types. */ + +static tree +c_instrument_vm_assign (location_t loc, tree a, tree b) +{ + gcc_assert (flag_vla_bounds); + + gcc_assert (TREE_CODE (a) == ARRAY_TYPE); + gcc_assert (TREE_CODE (b) == ARRAY_TYPE); + + tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a)); + tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b)); + + as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node); + bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node); + + tree t = build2 (NE_EXPR, boolean_type_node, as, bs); + tree tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); + + return build3 (COND_EXPR, void_type_node, t, tt, void_node); +} + + + +struct instrument_data { + + tree t1; + tree t2; + struct instrument_data *next; +}; + + struct comptypes_data { bool enum_and_int_p; bool different_types_p; @@ -1202,6 +1239,8 @@ struct comptypes_data { bool equiv; const struct tagged_tu_seen_cache* cache; + + struct instrument_data **instr_vec; }; /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment @@ -1241,11 +1280,14 @@ comptypes_same_p (tree type1, tree type2) /* Like comptypes, but if it returns non-zero because enum and int are compatible, it sets *ENUM_AND_INT_P to true. */ -int -comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) +static int +comptypes_check_enum_int_instr (tree type1, tree type2, bool *enum_and_int_p, + struct instrument_data **instr_vec) { struct comptypes_data data = { }; + data.instr_vec = instr_vec; bool ret = comptypes_internal (type1, type2, &data); + *enum_and_int_p = data.enum_and_int_p; gcc_checking_assert (!ret || comptypes_verify (type1, type2)); @@ -1253,6 +1295,12 @@ comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) return ret ? (data.warning_needed ? 2 : 1) : 0; } +int +comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p) +{ + return comptypes_check_enum_int_instr (type1, type2, enum_and_int_p, NULL); +} + /* Like comptypes, but if it returns nonzero for different types, it sets *DIFFERENT_TYPES_P to true. */ @@ -1465,7 +1513,18 @@ comptypes_internal (const_tree type1, const_tree type2, if (d1_variable != d2_variable) data->different_types_p = true; if (d1_variable || d2_variable) - return true; + { + if (NULL != data->instr_vec) + { + struct instrument_data *id + = (struct instrument_data *)xmalloc (sizeof *id);; + id->t1 = TYPE_MAIN_VARIANT (t2); + id->t2 = TYPE_MAIN_VARIANT (t1); + id->next = *data->instr_vec; + *data->instr_vec = id; + } + return true; + } if (d1_zero && d2_zero) return true; if (d1_zero || d2_zero @@ -1501,7 +1560,8 @@ comptypes_internal (const_tree type1, const_tree type2, subset of the other. */ static bool -comp_target_types (location_t location, tree ttl, tree ttr) +comp_target_types_instr (location_t location, tree ttl, tree ttr, + struct instrument_data **instr_vec) { int val; int val_ped; @@ -1535,8 +1595,7 @@ comp_target_types (location_t location, tree ttl, tree ttr) ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC) : TYPE_MAIN_VARIANT (mvr)); - enum_and_int_p = false; - val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p); + val = comptypes_check_enum_int_instr (mvl, mvr, &enum_and_int_p, instr_vec); if (val == 1 && val_ped != 1) pedwarn_c11 (location, OPT_Wpedantic, "invalid use of pointers to arrays with different qualifiers " @@ -1551,6 +1610,13 @@ comp_target_types (location_t location, tree ttl, tree ttr) return val; } + +static int +comp_target_types (location_t location, tree ttl, tree ttr) +{ + return comp_target_types_instr (location, ttl, ttr, NULL); +} + /* Subroutines of `comptypes'. */ @@ -1815,8 +1881,13 @@ function_types_compatible_p (const_tree f1, const_tree f2, return val; } - /* Both types have argument lists: compare them and propagate results. */ + /* Both types have argument lists: compare them and propagate results. + Turn off instrumentation for bounds as these are all arrays of + unspecified size. */ + auto instr_vec_tmp = data->instr_vec; + data->instr_vec = NULL; val1 = type_lists_compatible_p (args1, args2, data); + data->instr_vec = instr_vec_tmp; return val1; } @@ -3857,10 +3928,11 @@ convert_argument (location_t ploc, tree function, tree fundecl, if (excess_precision) val = build1 (EXCESS_PRECISION_EXPR, valtype, val); - tree parmval = convert_for_assignment (ploc, ploc, type, - val, origtype, ic_argpass, - npc, fundecl, function, - parmnum + 1, warnopt); + tree parmval = convert_for_assignment_instrument (ploc, ploc, type, + val, origtype, ic_argpass, + npc, fundecl, function, + parmnum + 1, warnopt, + NULL); if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) && INTEGRAL_TYPE_P (type) @@ -3870,6 +3942,24 @@ convert_argument (location_t ploc, tree function, tree fundecl, return parmval; } + +/* Process all constraints for variably-modified types. */ + +static tree +process_vm_constraints (location_t location, + struct instrument_data **instr_vec) +{ + tree instr_expr = void_node; + + for (struct instrument_data* d = *instr_vec; d; d = d->next) + { + tree in = c_instrument_vm_assign (location, d->t1, d->t2); + instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, in, instr_expr); + } + return instr_expr; +} + + /* Convert the argument expressions in the vector VALUES to the types in the list TYPELIST. @@ -7313,7 +7403,50 @@ static tree convert_for_assignment (location_t location, location_t expr_loc, tree type, tree rhs, tree origtype, enum impl_conv errtype, bool null_pointer_constant, tree fundecl, - tree function, int parmnum, int warnopt /* = 0 */) + tree function, int parmnum, int warnopt) +{ + struct instrument_data *instr_first = NULL; + struct instrument_data **instr_vec = NULL; + + if (flag_vla_bounds && (ic_init_const != errtype)) + instr_vec = &instr_first; + + tree ret = convert_for_assignment_instrument (location, expr_loc, type, + rhs, origtype, errtype, + null_pointer_constant, fundecl, + function, parmnum, warnopt, + instr_vec); + if (instr_vec) + { + if (ret && ret != error_mark_node && instr_first != NULL) + { + /* We have to make sure that the rhs is evaluated first, + because we may use size expressions in it to check bounds. */ + tree instr_expr = process_vm_constraints (location, instr_vec); + if (instr_expr != void_node) + { + ret = save_expr (ret); + instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, ret, instr_expr); + ret = fold_build2 (COMPOUND_EXPR, TREE_TYPE (ret), instr_expr, ret); + } + } + while (instr_first) + { + struct instrument_data *next = instr_first->next; + free (instr_first); + instr_first = next; + } + instr_vec = NULL; + } + return ret; +} + +static tree +convert_for_assignment_instrument (location_t location, location_t expr_loc, tree type, + tree rhs, tree origtype, enum impl_conv errtype, + bool null_pointer_constant, tree fundecl, + tree function, int parmnum, int warnopt, + struct instrument_data **instr_vec) { enum tree_code codel = TREE_CODE (type); tree orig_rhs = rhs; @@ -7557,11 +7690,11 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, rhs = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (rhs)), rhs); SET_EXPR_LOCATION (rhs, location); - rhs = convert_for_assignment (location, expr_loc, - build_pointer_type (TREE_TYPE (type)), - rhs, origtype, errtype, - null_pointer_constant, fundecl, function, - parmnum, warnopt); + rhs = convert_for_assignment_instrument (location, expr_loc, + build_pointer_type (TREE_TYPE (type)), + rhs, origtype, errtype, + null_pointer_constant, fundecl, function, + parmnum, warnopt, instr_vec); if (rhs == error_mark_node) return error_mark_node; @@ -7955,7 +8088,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, Meanwhile, the lhs target must have all the qualifiers of the rhs. */ if ((VOID_TYPE_P (ttl) && !TYPE_ATOMIC (ttl)) || (VOID_TYPE_P (ttr) && !TYPE_ATOMIC (ttr)) - || (target_cmp = comp_target_types (location, type, rhstype)) + || (target_cmp = comp_target_types_instr (location, type, rhstype, instr_vec)) || is_opaque_pointer || ((c_common_unsigned_type (mvl) == c_common_unsigned_type (mvr)) diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 403ea9da1ab..8d6d68e4f27 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10698,6 +10698,7 @@ void g (int n) @option{-Warray-parameter} option triggers warnings for similar problems involving ordinary array arguments. + @opindex Wvolatile-register-var @opindex Wno-volatile-register-var @item -Wvolatile-register-var @@ -20831,6 +20832,14 @@ computing CRC32). The @var{string} should be different for every file you compile. +@opindex fvla-bounds +@item -fvla-bounds +This option is only available when compiling C code. If activated, +additional code is emitted that verifies at run time for assignments +involving variably-modified types that corresponding size expressions +evaluate to the same value. + + @opindex save-temps @item -save-temps Store the usual ``temporary'' intermediate files permanently; name them diff --git a/gcc/testsuite/gcc.dg/vla-bounds-1.c b/gcc/testsuite/gcc.dg/vla-bounds-1.c new file mode 100644 index 00000000000..093f5e7ba25 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-1.c @@ -0,0 +1,74 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +// test various valid initializations and assignments + +int main() +{ + int m = 4, n = 3; + + int u = 4; + int v = 3; + + /* initialization */ + + char a[4]; + char (*pa)[u] = &a; + char (*qa)[v]; + + char b[u]; + const char (*pb)[u] = &b; + char (*qb)[v]; + + char c[4][3]; + char (*pc0)[u][v] = &c; + char (*qc0)[v][u]; + + char (*pc1)[u][3] = &c; + char (*qc1)[v][3]; + + char (*pc2)[4][v] = &c; + char (*qc2)[4][u]; + + char (*pc3)[][v] = &c; + + char d[u][v]; + char (*pd0)[4][3] = &d; + char (*qd0)[3][4]; + + char (*pd1)[u][3] = &d; + char (*qd1)[v][4]; + + char (*pd2)[4][v] = &d; + char (*qd2)[3][u]; + + char (*pd3)[u][v] = &d; + char (*qd3)[v][u]; + + char e[4][v]; + char (*pe0)[4][3] = &e; + char (*qe0)[4][4]; + + char f[u][3]; + char (*pf)[4][3] = &f; + char (*qf)[3][3]; + + char (*g[u])[v]; + char (*(*pg)[u])[v] = &g; + + /* assignment */ + + pa = &a; + pb = &b; + pc0 = &c; + pc1 = &c; + pc2 = &c; + pd0 = &d; + pd1 = &d; + pd2 = &d; + pd3 = &d; + pe0 = &e; + pf = &f; + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c new file mode 100644 index 00000000000..ffef7e502dd --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-1.c @@ -0,0 +1,32 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test valid and invalid assignments involving pointers to arrays of + variable length. */ + +static void handler(int) { exit(0); } + +int main() +{ + signal(SIGILL, handler); + + int u = 4; + int v = 3; + + char a[4]; + char (*pa)[u]; + char (*qa)[v]; + + char b[u]; + const char (*pb)[u]; + + pa = &a; + pb = &b; + qa = &a; // 3 != 4 + abort(); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c new file mode 100644 index 00000000000..cc445dea459 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-2.c @@ -0,0 +1,30 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test valid and invalid assignment of a pointer to a 2D array to pointers + to 2D arrays of variable length. */ + +static void handler(int) { exit(0); } + +int main() +{ + signal(SIGILL, handler); + + int u = 4; + int v = 3; + + char c[4][3]; + char (*pc0)[u][v]; + char (*qc0)[v][u]; + char (*pc1)[u][3]; + char (*pc2)[4][v]; + + pc0 = &c; + pc1 = &c; + pc2 = &c; + qc0 = &c; // 3 != 4, 4 != 3 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c new file mode 100644 index 00000000000..068e9a57e65 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-3.c @@ -0,0 +1,43 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test valid and invalid assignment of a pointer to a 2D VLA to pointers + to 2D arrays of variable length. */ + +static void handler(int) { exit(0); } + +int main() +{ + signal(SIGILL, handler); + + int u = 4; + int v = 3; + + char d[u][v]; + char (*pd0)[4][3]; + char (*pd1)[u][3]; + char (*pd2)[4][v]; + char (*pd3)[u][v]; + + char e[4][v]; + char (*pe0)[4][3]; + + char f[u][3]; + char (*pf)[4][3]; + char (*qf)[3][3]; + + /* assignment */ + + pd0 = &d; + pd1 = &d; + pd2 = &d; + pd3 = &d; + pe0 = &e; + + pf = &f; + qf = &f; // 3 != 4 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c new file mode 100644 index 00000000000..b274e237eba --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-assign-4.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test assignment of pointer to function returning 2D array to pointer to + function returning a pointer to a variable length array. */ + +static void handler(int) { exit(0); } + +int m, n; +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } + +int main() +{ + signal(SIGILL, handler); + + m = 4, n = 3; + + int u = 4; + int v = 3; + + char (*(*p)(void))[u][v] = &z0; // 4 != 5, 3 != 5 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c new file mode 100644 index 00000000000..8256999fc50 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c @@ -0,0 +1,54 @@ +/* { dg-do compile } */ +/* { dg-options "-fvla-bounds" } */ + +// make sure we do not ICE on any of these + +const char* name = "hallo"; + +typedef void (*ht)(int n, int m, char x[n][m]); +void e(ht) { } + +int n, m; +static void f0(char a[n][m]) { } +static void f1(int u, int v, char a[u][v]) { } +static void f2(int u, int v, char a[u][v]) { } + +void f(void) +{ + int x = 1; + int (*m)[x] = 0; + m = ({ long* d2; (int (*)[d2[0]])(0); }); + + /* function pointer assignments */ + + void (*gp)(char x[4][3]) = f0; + void (*hp)(int n, int m, char x[n][m]) = f1; + ht hp2 = f1; + e(f1); + + /* composite type */ + + int u = 3; int v = 4; + char a[u][v]; + (1 ? f1 : f2)(u, v, a); +} + +/* size expression in parameter */ + +extern void a(long N, char (*a)[N]); + +static void b(void) +{ + a(1, ({ int d = 0; (char (*)[d])0; }) ); +} + +/* composite type */ + +int c(int u, char (*a)[u]); +int c(int u, char (*a)[u]) { } + +int d(void) +{ + char a[3]; + c(3, &a); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-1.c b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c new file mode 100644 index 00000000000..3e608ba0c34 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-1.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test valid and invalid initialization of pointers to arrays of + variable length. */ + +static void handler(int) { exit(0); } + +int main() +{ + signal(SIGILL, handler); + + int u = 4; + int v = 3; + + char b[u]; + const char (*pb)[u] = &b; + + char a[4]; + char (*pa)[u] = &a; + char (*qa)[v] = &a; // 3 != 4 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-2.c b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c new file mode 100644 index 00000000000..d26683e6c97 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-2.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test valid and invalid initialization of pointers to 2D arrays of + variable length with pointer to 2D regular array. */ + +static void handler(int) { exit(0); } + +int main() +{ + signal(SIGILL, handler); + + int u = 4; + int v = 3; + + char c[4][3]; + char (*pc1)[u][3] = &c; + char (*pc2)[4][v] = &c; + char (*pc0)[u][v] = &c; + char (*qc0)[v][u] = &c; // 3 != 4, 4 != 3 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-3.c b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c new file mode 100644 index 00000000000..7ab706af62e --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-3.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test valid and invalid initialization of pointers to 2D arrays of + variable length with incomplete first dimension. */ + +static void handler(int) { exit(0); } + +int main() +{ + signal(SIGILL, handler); + + int u = 4; + int v = 3; + + /* initialization */ + + char c[4][3]; + char (*pc3)[][v] = &c; + char (*qc3)[][u] = &c; // 4 != 3 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-init-4.c b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c new file mode 100644 index 00000000000..f20de91c156 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-init-4.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test valid and invalid initialization of pointers to 2D arrays of + variable length with pointer to 2D VLA. */ + +static void handler(int) { exit(0); } + +int main() +{ + signal(SIGILL, handler); + + int u = 4; + int v = 3; + + /* initialization */ + char d[u][v]; + char (*pd0)[4][3] = &d; + char (*pd1)[u][3] = &d; + char (*pd2)[4][v] = &d; + char (*pd3)[u][v] = &d; + char (*qd0)[3][4] = &d; // 3 != 4, 4 != 3 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c new file mode 100644 index 00000000000..7f33bc95e29 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-1.c @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ +/* { dg-require-effective-target trampolines } */ + +#include +#include + +/* Test valid and invalid assignment of a nested function mit variably + modified return type. */ + +void handler(int) { exit(0); } + +int main() +{ + signal(SIGILL, handler); + + int n = 3; + char b[4]; + char (*f())[++n] { return &b; } + + if (4 != sizeof(*f())) + abort(); + + char (*(*p)())[n++] = &f; + + if (4 != sizeof(*(*p)())) + abort(); + + char (*(*p2)())[++n] = &f; + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c new file mode 100644 index 00000000000..13f77d4e185 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-nest-2.c @@ -0,0 +1,26 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ +/* { dg-require-effective-target trampolines } */ + +#include +#include + +/* Test valid and invalid assignment of regular function pointer + return array to pointer to function with variably modified + return type. */ + +void handler(int) { exit(0); } + +static char bb[4][4]; +static char (*g())[4][4] { return &bb; } + +int main() +{ + signal(SIGILL, handler); + + int n = 4; + + char (*(*p)())[n][4] = &g; + char (*(*q)())[++n][4] = &g;; + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c new file mode 100644 index 00000000000..43919927ab8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-1.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test returning a pointer to a 2D variable length array in + a function returning a pointer to a regular 2D array. */ + +static void handler(int) { exit(0); } + +int m, n; + +static char (*z0(void))[5][5] { char (*p)[m][n] = 0; return p; } + +int main() +{ + signal(SIGILL, handler); + + m = 5, n = 5; + z0(); + + m = 4, n = 3; + z0(); // 5 != 3, 5, != 3 + abort(); +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c new file mode 100644 index 00000000000..af8475e9a5f --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-ret-2.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +/* Test returning a pointer to a 2D variable length array with + a fist constant dimension in a function returning a pointer + to a regular 2D array. */ + +static void handler(int) { exit(0); } + +int n, m; + +static char (*z1(void))[5][5] { char (*p)[5][n] = 0; return p; } + +int main() +{ + signal(SIGILL, handler); + + m = 5, n = 5; + z1(); + + m = 4, n = 3; + z1(); // 4 != 3 + abort(); +} + From patchwork Mon Jul 15 07:20:04 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1960448 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=W+QkoJqW; 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 4WMttQ57kfz20CW for ; Mon, 15 Jul 2024 17:21:50 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DD4BF3864825 for ; Mon, 15 Jul 2024 07:21:48 +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 0FDA8384CB95 for ; Mon, 15 Jul 2024 07:20:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 0FDA8384CB95 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 0FDA8384CB95 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=1721028018; cv=none; b=llPjW2EDebCSYIbEM45EZBFauGTwGlS06HHtJ54gjiA78SkmuAOtwMdDDYp26Wlpp7Zs4Nrj2DiRv2ILpCLKheTLlOFAKXPVb0+lepPDZ82KRu5+gItiQm7uFJ5kAmbJluQ1gvgTH+plMAcnaixRMJXg2ijPBp5ya3ow+t08EVQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721028018; c=relaxed/simple; bh=kE3/JV48KWNJbDecVdZl08LtQVgSma5LkWFpon+6drY=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=nP/wcSuGiJ5mIWKK3E5DGXvgwnuJgz2eW7we0oN/qOayalUhcmwfJfq75LW/GDILkF6S9/vuM+cicxAtlUw9KFTtXf7IJmudtlYFh+KwrCQVfuNlhe4qRqSPmK4/9aJuN2YjxWO3BWpwkr7kQwF+5BzrQ4r/bn8q70hXk6XKzRU= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-172-50.tugraz.at (vra-172-50.tugraz.at [129.27.172.50]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4WMtrQ15YGz3wcS; Mon, 15 Jul 2024 09:20:06 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1721028006; bh=kE3/JV48KWNJbDecVdZl08LtQVgSma5LkWFpon+6drY=; h=Subject:From:To:Cc:Date:In-Reply-To:References; b=W+QkoJqWrwPhdpmb1PE+qeoBnTWAHNpIa1S+1CTe7RzZAdnZIjv/BMtH4WQ656ydx yyBuI6sRopQhulT+D0ljSdhmZaa9hdwc3haYWQ5oY9bSVC30yzp14FfPbBEQ/8ct1i NRpJ/SLjF6GTj/9g6kxPj2OQa11pJ+jXPiuOmTAI= Message-ID: <01b54c4cc3fb59856e4c0f3d490e7e911c0ed9ef.camel@tugraz.at> Subject: [PATCH v3 2/4] c: runtime checking for assigment of VM types From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers , Siddhesh Poyarekar , kees Cook , Marek Polacek Date: Mon, 15 Jul 2024 09:20:04 +0200 In-Reply-To: References: 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.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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 | 2 +- gcc/testsuite/gcc.dg/vla-bounds-func-10.c | 74 +++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-11.c | 28 ++++ gcc/testsuite/gcc.dg/vla-bounds-func-12.c | 29 +++++ gcc/testsuite/gcc.dg/vla-bounds-func-13.c | 37 ++++++ gcc/testsuite/gcc.dg/vla-bounds-func-14.c | 15 +++ gcc/testsuite/gcc.dg/vla-bounds-func-15.c | 20 +++ gcc/testsuite/gcc.dg/vla-bounds-func-16.c | 18 +++ gcc/testsuite/gcc.dg/vla-bounds-func-17.c | 18 +++ gcc/testsuite/gcc.dg/vla-bounds-func-18.c | 20 +++ gcc/testsuite/gcc.dg/vla-bounds-func-19.c | 21 +++ gcc/testsuite/gcc.dg/vla-bounds-func-2.c | 73 +++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-20.c | 22 ++++ gcc/testsuite/gcc.dg/vla-bounds-func-3.c | 28 ++++ gcc/testsuite/gcc.dg/vla-bounds-func-4.c | 37 ++++++ gcc/testsuite/gcc.dg/vla-bounds-func-5.c | 40 ++++++ gcc/testsuite/gcc.dg/vla-bounds-func-6.c | 36 ++++++ gcc/testsuite/gcc.dg/vla-bounds-func-7.c | 39 ++++++ gcc/testsuite/gcc.dg/vla-bounds-func-8.c | 38 ++++++ gcc/testsuite/gcc.dg/vla-bounds-func-9.c | 39 ++++++ 21 files changed, 769 insertions(+), 16 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-10.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-11.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-12.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-13.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-14.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-15.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-16.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-17.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-18.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-19.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-2.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-20.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-3.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-4.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-5.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-6.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-7.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-8.c create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-9.c diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 59940a29b53..c0132a22e21 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -1201,19 +1201,13 @@ comptypes_verify (tree type1, tree type2) /* Instrument assignment of variably modified types. */ static tree -c_instrument_vm_assign (location_t loc, tree a, tree b) +c_instrument_vm_assign (location_t loc, tree a, tree b, tree as, tree bs) { gcc_assert (flag_vla_bounds); gcc_assert (TREE_CODE (a) == ARRAY_TYPE); gcc_assert (TREE_CODE (b) == ARRAY_TYPE); - tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a)); - tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b)); - - as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node); - bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node); - tree t = build2 (NE_EXPR, boolean_type_node, as, bs); tree tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); @@ -3772,7 +3766,8 @@ static tree convert_argument (location_t ploc, tree function, tree fundecl, tree type, tree origtype, tree val, tree valtype, bool npc, tree rname, int parmnum, int argnum, - bool excess_precision, int warnopt) + bool excess_precision, int warnopt, + struct instrument_data **instr_vec) { /* Formal parm type is specified by a function prototype. */ @@ -3932,7 +3927,7 @@ convert_argument (location_t ploc, tree function, tree fundecl, val, origtype, ic_argpass, npc, fundecl, function, parmnum + 1, warnopt, - NULL); + instr_vec); if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0) && INTEGRAL_TYPE_P (type) @@ -3945,15 +3940,110 @@ convert_argument (location_t ploc, tree function, tree fundecl, /* Process all constraints for variably-modified types. */ -static tree +tree process_vm_constraints (location_t location, - struct instrument_data **instr_vec) + struct instrument_data **instr_vec, + tree function, tree fundecl, vec *values) { tree instr_expr = void_node; + tree args = NULL; + + /* Find the arguments for the function declaration / type. */ + if (function) + { + if (TREE_CODE (function) == FUNCTION_DECL) + { + fundecl = function; + args = DECL_ARGUMENTS (fundecl); + } + else + { + /* Functions called via pointers are not yet supported. */ + return void_node; + } + } for (struct instrument_data* d = *instr_vec; d; d = d->next) { - tree in = c_instrument_vm_assign (location, d->t1, d->t2); + tree t1 = d->t1; + tree t2 = d->t2; + + gcc_assert (TREE_CODE (t1) == ARRAY_TYPE); + gcc_assert (TREE_CODE (t2) == ARRAY_TYPE); + + tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (t1)); + tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (t2)); + + if (!as || !bs) + continue; + + as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node); + bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node); + + if (function) + { + + if (TREE_CODE (bs) == INTEGER_CST) + goto cont; + + if (TREE_CODE (bs) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (bs, 0)) == SAVE_EXPR) + { + tree bs1 = TREE_OPERAND (bs, 0); + tree bs2 = TREE_OPERAND (bs1, 0); + + /* Another parameter of the current functions. */ + if (TREE_CODE (bs2) == PARM_DECL + && (DECL_CONTEXT (bs2) == fundecl + || DECL_CONTEXT (bs2) == NULL)) + { + tree arg = args; + int pos = 0; + while (arg) + { + if (arg == bs2) + { + bs = (*values)[pos]; + bs = save_expr (bs); + bs = build1 (NOP_EXPR, sizetype, bs); + break; + } + pos++; + arg = DECL_CHAIN (arg); + } + if (!arg) + goto giveup; + goto cont; + } + + /* A parameter of an enclosing function. */ + if (TREE_CODE (bs2) == PARM_DECL + && DECL_CONTEXT (bs2) != fundecl) + { + bs2 = unshare_expr (bs2); + bs1 = save_expr (bs2); + bs = build1 (NOP_EXPR, sizetype, bs1); + goto cont; + } + + /* A variable with enclosing scope. */ + if (TREE_CODE (bs2) == VAR_DECL) + { + bs2 = unshare_expr (bs2); + bs1 = save_expr (bs2); + bs = build1 (NOP_EXPR, sizetype, bs1); + goto cont; + } + } + giveup: + /* Give up. If we do not understand a size expression, we can + also not instrument any of the others because it may have + side effects affecting them. (We could restart and instrument + only the ones with integer constants.) */ + return void_node; + } +cont: + tree in = c_instrument_vm_assign (location, t1, t2, as, bs); instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, in, instr_expr); } return instr_expr; @@ -4064,6 +4154,12 @@ convert_arguments (location_t loc, vec arg_loc, tree typelist, } } + struct instrument_data *instr_first = NULL; + struct instrument_data **instr_vec = NULL; + + if (flag_vla_bounds) + instr_vec = &instr_first; + /* Scan the given expressions (VALUES) and types (TYPELIST), producing individual converted arguments. */ @@ -4176,7 +4272,7 @@ convert_arguments (location_t loc, vec arg_loc, tree typelist, tree origtype = (!origtypes) ? NULL_TREE : (*origtypes)[parmnum]; parmval = convert_argument (ploc, function, fundecl, type, origtype, val, valtype, npc, rname, parmnum, argnum, - excess_precision, 0); + excess_precision, 0, instr_vec); } else if (promote_float_arg) { @@ -4231,7 +4327,7 @@ convert_arguments (location_t loc, vec arg_loc, tree typelist, convert_argument (ploc, function, fundecl, builtin_type, origtype, val, valtype, npc, rname, parmnum, argnum, excess_precision, - OPT_Wbuiltin_declaration_mismatch); + OPT_Wbuiltin_declaration_mismatch, NULL); } if (typetail) @@ -4243,6 +4339,31 @@ convert_arguments (location_t loc, vec arg_loc, tree typelist, gcc_assert (parmnum == vec_safe_length (values)); + if (instr_vec) + { + if (0 < parmnum && instr_vec && instr_first != NULL) + { + tree instr_expr = process_vm_constraints (loc, instr_vec, function, fundecl, values); + /* We have to make sure that all parameters are evaluated first, + because we may use size expressions in it to check bounds. */ + if (void_node != instr_expr) + { + tree parmval = (*values)[0]; + parmval = save_expr (parmval); + instr_expr = fold_build2 (COMPOUND_EXPR, void_type_node, parmval, instr_expr); + parmval = fold_build2 (COMPOUND_EXPR, TREE_TYPE (parmval), instr_expr, parmval); + (*values)[0] = parmval; + } + } + while (instr_first) + { + struct instrument_data *next = instr_first->next; + free (instr_first); + instr_first = next; + } + instr_vec = NULL; + } + if (typetail != NULL_TREE && TREE_VALUE (typetail) != void_type_node) { error_at (loc, "too few arguments to function %qE", function); @@ -7422,7 +7543,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type, { /* We have to make sure that the rhs is evaluated first, because we may use size expressions in it to check bounds. */ - tree instr_expr = process_vm_constraints (location, instr_vec); + tree instr_expr = process_vm_constraints (location, instr_vec, NULL, NULL, NULL); if (instr_expr != void_node) { ret = save_expr (ret); diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c index 8256999fc50..378c6073688 100644 --- a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c @@ -50,5 +50,5 @@ int c(int u, char (*a)[u]) { } int d(void) { char a[3]; - c(3, &a); + c(3, &a); /* "Function call not instrumented." */ } diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-10.c b/gcc/testsuite/gcc.dg/vla-bounds-func-10.c new file mode 100644 index 00000000000..ad1b6e44923 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-10.c @@ -0,0 +1,74 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m, n; + +static void a0(char (*a)[4]) { } +static void b0(char (*a)[n]) { } +static void c0(char (*a)[n][m]) { } +static void d0(char (*a)[4][m]) { } +static void e0(char (*a)[n][3]) { } +static void f0(char a[n][m]) { } + +static void b1(int u, char (*a)[u]) { } +static void c1(int u, int v, char (*a)[u][v]) { } +static void d1(int v, char (*a)[4][v]) { } +static void e1(int u, char (*a)[u][3]) { } +static void f1(int u, int v, char a[u][v]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3, n = 4; + + int u = 4; + int v = 3; + + /* function arguments */ + + char A0[4]; + char A1[u]; + char B0[3]; + char B1[v]; + + a0(&A0); + a0(&A1); + + b0(&A0); + b0(&A1); + + b1(4, &A0); + + char C0[4][3]; + char C1[u][3]; + char C2[4][v]; + char C3[u][v]; + char D0[3][4]; + char D1[v][4]; + char D2[3][u]; + char D3[v][u]; + + c0(&C0); + c0(&C1); + c0(&C2); + c0(&C3); + + d0(&C0); + + d1(3, &C0); + + e0(&C0); + e1(4, &C0); + + f0(C0); + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-11.c b/gcc/testsuite/gcc.dg/vla-bounds-func-11.c new file mode 100644 index 00000000000..45095023d18 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-11.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-O2 -fvla-bounds -fpermissive" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m; + +static void d0(char (*a)[4][m]) { } +static void d1(int v, char (*a)[4][v]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3; + + char C0[4][3]; + char D0[3][4]; + + d1(3, &C0); + + d0(&C0); + d0(&D0); /* { dg-warning "incompatible pointer type" } */ + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-12.c b/gcc/testsuite/gcc.dg/vla-bounds-func-12.c new file mode 100644 index 00000000000..2c033761eac --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-12.c @@ -0,0 +1,29 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds -fpermissive" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m; + +static void d0(char (*a)[4][m]) { } +static void d1(int v, char (*a)[4][v]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3; + + char C0[4][3]; + char D0[3][4]; + + d0(&C0); + + d1(3, &C0); + d1(3, &D0); /* { dg-warning "incompatible pointer type" } */ + // 3 != 4 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-13.c b/gcc/testsuite/gcc.dg/vla-bounds-func-13.c new file mode 100644 index 00000000000..3919f320643 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-13.c @@ -0,0 +1,37 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds -fpermissive" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m, n; + +static void e0(char (*a)[n][3]) { } +static void f0(char a[n][m]) { } + +static void e1(int u, char (*a)[u][3]) { } +static void f1(int u, int v, char a[u][v]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3, n = 4; + + /* function arguments */ + + char C0[4][3]; + char D0[3][4]; + + e0(&C0); + e1(4, &C0); + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 + + f0(C0); + f0(D0); // 3 != 4 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-14.c b/gcc/testsuite/gcc.dg/vla-bounds-func-14.c new file mode 100644 index 00000000000..10678d10237 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-14.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-fvla-bounds" } */ + +void b0(int n, char (*a)[n]) { } +void b1(int m, char (*a)[m]); +void b2(int m; char (*a)[m], int m) { } +void b3(int m; char (*a)[m], int m); +int n; +void b4(char (*a)[n]) { } +void b5(char (*a)[n]); + +void b1(int n, char (*a)[n]) { } +void b3(int m; char (*a)[m], int m) { } +void b5(char (*a)[n]) { } + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-15.c b/gcc/testsuite/gcc.dg/vla-bounds-func-15.c new file mode 100644 index 00000000000..778a7c03219 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-15.c @@ -0,0 +1,20 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +void b1(int m, char (*a)[m]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; + b1(4, &A0); // 4 != 3 + abort(); +} + +void b1(int n, char (*a)[n]) { } diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-16.c b/gcc/testsuite/gcc.dg/vla-bounds-func-16.c new file mode 100644 index 00000000000..1da4d2632f2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-16.c @@ -0,0 +1,18 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +void b0(int n, char (*a)[n]) { } + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; + b0(4, &A0); // 4 != 3 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-17.c b/gcc/testsuite/gcc.dg/vla-bounds-func-17.c new file mode 100644 index 00000000000..2b52391ef59 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-17.c @@ -0,0 +1,18 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +void b2(int m; char (*a)[m], int m) { } + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; + b2(&A0, 4); // 4 != 3 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-18.c b/gcc/testsuite/gcc.dg/vla-bounds-func-18.c new file mode 100644 index 00000000000..61395c22e8a --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-18.c @@ -0,0 +1,20 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +void b3(int m; char (*a)[m], int m); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; + b3(&A0, 4); // 4 != 3 + abort(); +} + +void b3(int m; char (*a)[m], int m) { } diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-19.c b/gcc/testsuite/gcc.dg/vla-bounds-func-19.c new file mode 100644 index 00000000000..4b57580ac94 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-19.c @@ -0,0 +1,21 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int n; +void b4(char (*a)[n]) { } + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; + n = 4; + b4(&A0); // 4 != 3 + abort(); +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-2.c b/gcc/testsuite/gcc.dg/vla-bounds-func-2.c new file mode 100644 index 00000000000..f00c7e15774 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-2.c @@ -0,0 +1,73 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m, n; + +static void a0(char (*a)[4]) { } +static void b0(char (*a)[n]) { } +static void c0(char (*a)[n][m]) { } +static void d0(char (*a)[4][m]) { } +static void e0(char (*a)[n][3]) { } +static void f0(char a[n][m]) { } + +static void b1(int u, char (*a)[u]) { } +static void c1(int u, int v, char (*a)[u][v]) { } +static void d1(int v, char (*a)[4][v]) { } +static void e1(int u, char (*a)[u][3]) { } +static void f1(int u, int v, char a[u][v]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3, n = 4; + + int u = 4; + int v = 3; + + /* function arguments */ + + char A0[4]; + char A1[u]; + char B0[3]; + char B1[v]; + + a0(&A0); + a0(&A1); + + b0(&A0); + b0(&A1); + + b1(4, &A0); + + char C0[4][3]; + char C1[u][3]; + char C2[4][v]; + char C3[u][v]; + char D0[3][4]; + char D1[v][4]; + char D2[3][u]; + char D3[v][u]; + + c0(&C0); + c0(&C1); + c0(&C2); + c0(&C3); + + d0(&C0); + d1(3, &C0); + + e0(&C0); + e1(4, &C0); + + f0(C0); + + f1(4, 3, C0); + f1(4, 3, D0); // 3 != 4 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-20.c b/gcc/testsuite/gcc.dg/vla-bounds-func-20.c new file mode 100644 index 00000000000..c0c7a9c637b --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-20.c @@ -0,0 +1,22 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int n; +void b5(char (*a)[n]); + +int main() +{ + signal(SIGILL, handler); + + char A0[3]; + n = 4; + b5(&A0); // 4 != 3 + abort(); +} + +void b5(char (*a)[n]) { } diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-3.c b/gcc/testsuite/gcc.dg/vla-bounds-func-3.c new file mode 100644 index 00000000000..90e37d65365 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-3.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ +/* { dg-options "-O1 -fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +static void a0(char (*a)[4]) { } + +int main() +{ + signal(SIGILL, handler); + + int u = 4; + int v = 3; + + /* function arguments */ + + char A0[4]; + char A1[u]; + char B1[v]; + + a0(&A0); + a0(&A1); + a0(&B1); // 4 != 3 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-4.c b/gcc/testsuite/gcc.dg/vla-bounds-func-4.c new file mode 100644 index 00000000000..9b7173fee46 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-4.c @@ -0,0 +1,37 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds -fpermissive" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int n; + +static void a0(char (*a)[4]) { } +static void b0(char (*a)[n]) { } +static void b1(int u, char (*a)[u]) { } + +int main() +{ + signal(SIGILL, handler); + + n = 4; + + int u = 4; + + char A0[4]; + char A1[u]; + char B0[3]; + + a0(&A0); + a0(&A1); + + b1(4, &A0); + + b0(&A0); + b0(&A1); + b0(&B0); // 4 != 3 + + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-5.c b/gcc/testsuite/gcc.dg/vla-bounds-func-5.c new file mode 100644 index 00000000000..37ff64148ef --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-5.c @@ -0,0 +1,40 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int n; + +static void a0(char (*a)[4]) { } +static void b0(char (*a)[n]) { } +static void b1(int u, char (*a)[u]) { } + +int main() +{ + signal(SIGILL, handler); + + n = 4; + + int u = 4; + int v = 3; + + /* function arguments */ + + char A0[4]; + char A1[u]; + char B0[3]; + char B1[v]; + + a0(&A0); + a0(&A1); + + b0(&A0); + b0(&A1); + + b1(4, &A0); + b1(4, &B0); // 4 != 3 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-6.c b/gcc/testsuite/gcc.dg/vla-bounds-func-6.c new file mode 100644 index 00000000000..c678e6b450a --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-6.c @@ -0,0 +1,36 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m, n; + +static void c0(char (*a)[n][m]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3, n = 4; + + int u = 4; + int v = 3; + + /* function arguments */ + + char C0[4][3]; + char C1[u][3]; + char C2[4][v]; + char C3[u][v]; + char D0[3][4]; + + c0(&C0); + c0(&C1); + c0(&C2); + c0(&C3); + c0(&D0); // 4 != 4, 3 != 4 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-7.c b/gcc/testsuite/gcc.dg/vla-bounds-func-7.c new file mode 100644 index 00000000000..40a6252dbc7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-7.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m, n; + +static void c0(char (*a)[n][m]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3, n = 4; + + int u = 4; + int v = 3; + + /* function arguments */ + + char C0[4][3]; + char C1[u][3]; + char C2[4][v]; + char C3[u][v]; + char D0[3][4]; + char D1[v][4]; + + c0(&C0); + c0(&C1); + c0(&C2); + c0(&C3); + + c0(&D1); // 4 != 3, 3 != 4 + abort(); +} + diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-8.c b/gcc/testsuite/gcc.dg/vla-bounds-func-8.c new file mode 100644 index 00000000000..d89d7465fd5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-8.c @@ -0,0 +1,38 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m, n; + +static void c0(char (*a)[n][m]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3, n = 4; + + int u = 4; + int v = 3; + + /* function arguments */ + + char C0[4][3]; + char C1[u][3]; + char C2[4][v]; + char C3[u][v]; + char D0[3][4]; + char D1[v][4]; + char D2[3][u]; + + c0(&C0); + c0(&C1); + c0(&C2); + c0(&C3); + c0(&D2); // 4 != 3, 3 != 4 + abort(); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-9.c b/gcc/testsuite/gcc.dg/vla-bounds-func-9.c new file mode 100644 index 00000000000..2f71edb208a --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-9.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int m, n; + +static void c0(char (*a)[n][m]) { } + +int main() +{ + signal(SIGILL, handler); + + m = 3, n = 4; + + int u = 4; + int v = 3; + + /* function arguments */ + + char C0[4][3]; + char C1[u][3]; + char C2[4][v]; + char C3[u][v]; + char D0[3][4]; + char D1[v][4]; + char D2[3][u]; + char D3[v][u]; + + c0(&C0); + c0(&C1); + c0(&C2); + c0(&C3); + c0(&D3); // 4 != 3, 3 != 4 + abort(); +} From patchwork Mon Jul 15 07:20:15 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1960447 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=IIMDsn2A; 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 4WMttQ2vqRz1xr4 for ; Mon, 15 Jul 2024 17:21:50 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3BAF2384CB97 for ; Mon, 15 Jul 2024 07:21:48 +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 A291C386482E for ; Mon, 15 Jul 2024 07:20:22 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A291C386482E 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 A291C386482E 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=1721028025; cv=none; b=rtnc6a/y5DUQKi6JARZpfO/3CZXi3zpK9anDh6unFJIqUIR3I53fr1KqY/hvU3favz0Mc1nReVZnfX7q2rqsT1oY4fJaSvbiBgerV6rmdXclmWnoUr1jp5zU5l5ONtkoyjbUL2iyd/2OhjhScF6IX/up29xgM+58JA4tLc64gKo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721028025; c=relaxed/simple; bh=3zxvOJbTd4OyKQ7njWThH9IM62F8sxe8dZKHZyvXx2k=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=HVd0MbgrVYBDLwmkiu4aLcaQCWDExikbnMTg4NlxkdOOeM45yw2M4zcTb6Ll5KAEVYnItzLM8JByRKUUvLBwHK43kQeX8BlTLuYwnbXSFZ4/HAEuaxaTbRs9t4ACWSYHUBHSNwq1JbTdsfdbI55afn5u0+m9humv+XpeRksX/Co= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-172-50.tugraz.at (vra-172-50.tugraz.at [129.27.172.50]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4WMtrc1nTGz1HNLR; Mon, 15 Jul 2024 09:20:16 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 mailrelay.tugraz.at 4WMtrc1nTGz1HNLR DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1721028016; bh=3zxvOJbTd4OyKQ7njWThH9IM62F8sxe8dZKHZyvXx2k=; h=Subject:From:To:Cc:Date:In-Reply-To:References:From; b=IIMDsn2AO1oM1kJVj+Kx9uU61Bc1h48tEwXZodsHcJKZY/XUok4/RiZhHCnrZHkes Q2N77WnLswJYum5a7zlrt3f9VSJB6pMrfr0C82AvM0xmsMLDyZxVbCsI88xaBfsGsQ ZJ/OlmWZAkIk+xeVlPyZjuomf1mOBPI3luUpyjxc= Message-ID: <3cfb57e4cf401fce4a171fdf0a4ade0ac6c3a3e2.camel@tugraz.at> Subject: [PATCH v3 3/4] c: runtime checking for assigment of VM types From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers , Siddhesh Poyarekar , kees Cook , Marek Polacek Date: Mon, 15 Jul 2024 09:20:15 +0200 In-Reply-To: References: 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=-11.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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-1.c: New test. * vla-bounds-fnptr-2.c: New test. * vla-bounds-fnptr-3.c: New test. --- gcc/c/c-decl.cc | 4 ++++ gcc/c/c-typeck.cc | 14 ++++++++++-- gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c | 24 ++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c | 27 +++++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c | 25 +++++++++++++++++++++ gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 2 +- 6 files changed, 93 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 diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 97f1d346835..d328e3bd5ac 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -8628,6 +8628,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 c0132a22e21..6ffa0c24e0c 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3958,9 +3958,19 @@ process_vm_constraints (location_t location, } else { - /* Functions called via pointers are not yet supported. */ - return void_node; + while (TREE_CODE (function) != FUNCTION_TYPE) + 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 (TREE_CODE (args) == PARM_DECL); } 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..61ff0dff1db --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c @@ -0,0 +1,24 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +void foo1(void (*p)(int n, char (*a)[n])) +{ + char A0[3]; + (*p)(3, &A0); + (*p)(4, &A0); // 4 != 3 + abort(); +} + +void b0(int n, char (*a)[n]) { } + +int main() +{ + signal(SIGILL, handler); + + foo1(&b0); +} 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..0c01d4592ed --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c @@ -0,0 +1,27 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int n; + +void foo2(void (*p)(int n, char (*a)[n])) +{ + n = 4; + char A0[3]; + (*p)(3, &A0); + (*p)(4, &A0); + abort(); +} + +void b1(int n0, char (*a)[n]) { } + +int main() +{ + signal(SIGILL, handler); + + foo2(&b1); // we should diagnose mismatch +} 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..c239216cdfc --- /dev/null +++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c @@ -0,0 +1,25 @@ +/* { dg-do run } */ +/* { dg-options "-fvla-bounds" } */ + +#include +#include + +static void handler(int) { exit(0); } + +int n; + +void foo3(void (*p)(int n0, char (*a)[n])) +{ + n = 4; + char A0[3]; + (*p)(3, &A0); // 4 != 3 + abort(); +} + +void b1(int n0, char (*a)[n]) { } + +int main() +{ + signal(SIGILL, handler); + foo3(&b1); +} diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c index 378c6073688..36072a372a3 100644 --- a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c +++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c @@ -30,7 +30,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 */ -- 2.39.2 From patchwork Mon Jul 15 07:20:22 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Uecker X-Patchwork-Id: 1960446 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=PlI133S8; 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 4WMtsV3MZ2z1xr4 for ; Mon, 15 Jul 2024 17:21:02 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4EF22386583C for ; Mon, 15 Jul 2024 07:21:00 +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 D11CD3865C27 for ; Mon, 15 Jul 2024 07:20:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org D11CD3865C27 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 D11CD3865C27 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=1721028035; cv=none; b=emiP3Up36PfDMvNrNzxh5U49uv8JkShAdWvBYiP7fhls4jkPDOdT4Q0TbFAvVY417KvFI3obfibbKPXtVQ77XKOPgQfZ4gKpgsCu7b0KIpmO56j8zsoykcRvs52Jz0LrGXuqeVcxoyt8bkjFhHzdROK0BKUMmfJDE/DMLeOqU/Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721028035; c=relaxed/simple; bh=V6Sj1sfOdgxf3fn0r27t7LRa84Xr8C0YsEdkRfYSrLw=; h=DKIM-Signature:Message-ID:Subject:From:To:Date:MIME-Version; b=VRjEMaukf4OGUEvMXuSJnIjVPmxGnqAEedf9NPAOT8fa5x8uxG/1Vx0+lWVG1dojfDqpr9VLG73yHq3iKRfaO65UjrI1MN71bWuGY4qFjcR2c/2K5oGXoz2Uq39z+uUErnA8C4KcCycQiX91oSomMSGrR+bI6dA3wOEdOGOYuOM= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from vra-172-50.tugraz.at (vra-172-50.tugraz.at [129.27.172.50]) by mailrelay.tugraz.at (Postfix) with ESMTPSA id 4WMtrl0KCTz3wPx; Mon, 15 Jul 2024 09:20:22 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tugraz.at; s=mailrelay; t=1721028023; bh=V6Sj1sfOdgxf3fn0r27t7LRa84Xr8C0YsEdkRfYSrLw=; h=Subject:From:To:Cc:Date:In-Reply-To:References; b=PlI133S8te0Ni1hiyyDWNZJEV/u3ldZn1DHj4rGnsfVfvLPnS3AtT/zxlOoctKl4D bgVIHdCJpOZhrtMbW3YyDZ4SRefMoYX0BWu6Svf7QiZIFzlthkKc8YW8noQMll544v K19OhMRkqPrRwmYXBRAsFx3ukh/7xdHFuSlOh6rM= Message-ID: Subject: [PATCH v3 4/4] c: runtime checking for assigment of VM types From: Martin Uecker To: gcc-patches@gcc.gnu.org Cc: Joseph Myers , Siddhesh Poyarekar , kees Cook , Marek Polacek Date: Mon, 15 Jul 2024 09:20:22 +0200 In-Reply-To: References: 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=-11.3 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP 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 instrumented and add documentation for instrumentation of function calls. 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 | 17 ++++++++++++++--- gcc/testsuite/gcc.dg/vla-bounds-func-1.c | 6 +++--- 4 files changed, 26 insertions(+), 6 deletions(-) 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 */ @@ -50,5 +50,5 @@ 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." } */ } diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 786cd4ce52a..7070ff767bf 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -1542,6 +1542,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 6ffa0c24e0c..3f380761efd 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -3967,6 +3967,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; } } @@ -4050,6 +4052,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 8d6d68e4f27..510d29735a7 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10699,6 +10699,13 @@ void g (int n) 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 @@ -20836,9 +20843,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 36072a372a3..b7a994a80b7 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 @@ -30,7 +30,7 @@ void f(void) int u = 3; int v = 4;