From patchwork Fri Nov 26 05:28:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 48169 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C46B93857C56 for ; Fri, 26 Nov 2021 05:29:57 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from donkey.elm.relay.mailchannels.net (donkey.elm.relay.mailchannels.net [23.83.212.49]) by sourceware.org (Postfix) with ESMTPS id 14A8C3858424 for ; Fri, 26 Nov 2021 05:29:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 14A8C3858424 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 812DBE0775; Fri, 26 Nov 2021 05:29:09 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 7D021E0722; Fri, 26 Nov 2021 05:29:08 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.116.149.62 (trex/6.4.3); Fri, 26 Nov 2021 05:29:09 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Lyrical-Cure: 246ed4d02eba2020_1637904549209_3827728342 X-MC-Loop-Signature: 1637904549209:1984115649 X-MC-Ingress-Time: 1637904549208 Received: from rhbox.intra.reserved-bit.com (unknown [1.186.223.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4J0jwL6q25z3Z; Thu, 25 Nov 2021 21:29:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1637904548; bh=SV3PKqeLoiBDNiV5sdZ4fey22vQ=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=mT7AveQznWq83XjHZv+fnRSXrtovE0uuJbHROmfAGGAypzJYx199O/Vx+MDeTgjfS 4p4jsRc5HiWW6hl1km49J2egDYTp5kuLGHxzE9p9HsNHWAyyC/jV10/I6bnyXzoCfw v4dJy4/hiQS4RgyQR4r1euH9arlAL/yqBFXXmqdQ= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v3 1/8] tree-object-size: Replace magic numbers with enums Date: Fri, 26 Nov 2021 10:58:44 +0530 Message-Id: <20211126052851.2176408-2-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211126052851.2176408-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211126052851.2176408-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.2 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" A simple cleanup to allow inserting dynamic size code more easily. gcc/ChangeLog: * tree-object-size.c: New enum. (object_sizes, computed, addr_object_size, compute_builtin_object_size, expr_object_size, call_object_size, merge_object_sizes, plus_stmt_object_size, collect_object_sizes_for, init_object_sizes, fini_object_sizes, object_sizes_execute): Replace magic numbers with enums. Signed-off-by: Siddhesh Poyarekar --- Changes from v2: - Incorporated review suggestions. gcc/tree-object-size.c | 59 ++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 4334e05ef70..5e93bb74f92 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -45,6 +45,13 @@ struct object_size_info unsigned int *stack, *tos; }; +enum +{ + OST_SUBOBJECT = 1, + OST_MINIMUM = 2, + OST_END = 4, +}; + static tree compute_object_offset (const_tree, const_tree); static bool addr_object_size (struct object_size_info *, const_tree, int, unsigned HOST_WIDE_INT *); @@ -67,10 +74,10 @@ static void check_for_plus_in_loops_1 (struct object_size_info *, tree, the subobject (innermost array or field with address taken). object_sizes[2] is lower bound for number of bytes till the end of the object and object_sizes[3] lower bound for subobject. */ -static vec object_sizes[4]; +static vec object_sizes[OST_END]; /* Bitmaps what object sizes have been computed already. */ -static bitmap computed[4]; +static bitmap computed[OST_END]; /* Maximum value of offset we consider to be addition. */ static unsigned HOST_WIDE_INT offset_limit; @@ -227,11 +234,11 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, { unsigned HOST_WIDE_INT sz; - if (!osi || (object_size_type & 1) != 0 + if (!osi || (object_size_type & OST_SUBOBJECT) != 0 || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME) { compute_builtin_object_size (TREE_OPERAND (pt_var, 0), - object_size_type & ~1, &sz); + object_size_type & ~OST_SUBOBJECT, &sz); } else { @@ -266,7 +273,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, } else if (DECL_P (pt_var)) { - pt_var_size = decl_init_size (pt_var, object_size_type & 2); + pt_var_size = decl_init_size (pt_var, object_size_type & OST_MINIMUM); if (!pt_var_size) return false; } @@ -287,7 +294,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, { tree var; - if (object_size_type & 1) + if (object_size_type & OST_SUBOBJECT) { var = TREE_OPERAND (ptr, 0); @@ -528,7 +535,7 @@ bool compute_builtin_object_size (tree ptr, int object_size_type, unsigned HOST_WIDE_INT *psize) { - gcc_assert (object_size_type >= 0 && object_size_type <= 3); + gcc_assert (object_size_type >= 0 && object_size_type < OST_END); /* Set to unknown and overwrite just before returning if the size could be determined. */ @@ -546,7 +553,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, if (computed[object_size_type] == NULL) { - if (optimize || object_size_type & 1) + if (optimize || object_size_type & OST_SUBOBJECT) return false; /* When not optimizing, rather than failing, make a small effort @@ -586,8 +593,8 @@ compute_builtin_object_size (tree ptr, int object_size_type, if (dump_file) { fprintf (dump_file, "Computing %s %sobject size for ", - (object_size_type & 2) ? "minimum" : "maximum", - (object_size_type & 1) ? "sub" : ""); + (object_size_type & OST_MINIMUM) ? "minimum" : "maximum", + (object_size_type & OST_SUBOBJECT) ? "sub" : ""); print_generic_expr (dump_file, ptr, dump_flags); fprintf (dump_file, ":\n"); } @@ -620,7 +627,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, terminate, it could take a long time. If a pointer is increasing this way, we need to assume 0 object size. E.g. p = &buf[0]; while (cond) p = p + 4; */ - if (object_size_type & 2) + if (object_size_type & OST_MINIMUM) { osi.depths = XCNEWVEC (unsigned int, num_ssa_names); osi.stack = XNEWVEC (unsigned int, num_ssa_names); @@ -679,8 +686,9 @@ compute_builtin_object_size (tree ptr, int object_size_type, fprintf (dump_file, ": %s %sobject size " HOST_WIDE_INT_PRINT_UNSIGNED "\n", - (object_size_type & 2) ? "minimum" : "maximum", - (object_size_type & 1) ? "sub" : "", + ((object_size_type & OST_MINIMUM) ? "minimum" + : "maximum"), + (object_size_type & OST_SUBOBJECT) ? "sub" : "", object_sizes[object_size_type][i]); } } @@ -718,7 +726,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) else bytes = unknown (object_size_type); - if ((object_size_type & 2) == 0) + if ((object_size_type & OST_MINIMUM) == 0) { if (object_sizes[object_size_type][varno] < bytes) object_sizes[object_size_type][varno] = bytes; @@ -748,7 +756,7 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) bytes = alloc_object_size (call, object_size_type); - if ((object_size_type & 2) == 0) + if ((object_size_type & OST_MINIMUM) == 0) { if (object_sizes[object_size_type][varno] < bytes) object_sizes[object_size_type][varno] = bytes; @@ -804,7 +812,7 @@ merge_object_sizes (struct object_size_info *osi, tree dest, tree orig, orig_bytes = (offset > orig_bytes) ? HOST_WIDE_INT_0U : orig_bytes - offset; - if ((object_size_type & 2) == 0) + if ((object_size_type & OST_MINIMUM) == 0) { if (object_sizes[object_size_type][varno] < orig_bytes) { @@ -882,7 +890,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) else bytes = unknown (object_size_type); - if ((object_size_type & 2) == 0) + if ((object_size_type & OST_MINIMUM) == 0) { if (object_sizes[object_size_type][varno] < bytes) object_sizes[object_size_type][varno] = bytes; @@ -968,7 +976,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) if (bitmap_set_bit (osi->visited, varno)) { object_sizes[object_size_type][varno] - = (object_size_type & 2) ? -1 : 0; + = (object_size_type & OST_MINIMUM) ? -1 : 0; } else { @@ -1238,7 +1246,7 @@ init_object_sizes (void) if (computed[0]) return; - for (object_size_type = 0; object_size_type <= 3; object_size_type++) + for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { object_sizes[object_size_type].safe_grow (num_ssa_names, true); computed[object_size_type] = BITMAP_ALLOC (NULL); @@ -1255,7 +1263,7 @@ fini_object_sizes (void) { int object_size_type; - for (object_size_type = 0; object_size_type <= 3; object_size_type++) + for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { object_sizes[object_size_type].release (); BITMAP_FREE (computed[object_size_type]); @@ -1302,7 +1310,7 @@ object_sizes_execute (function *fun, bool insert_min_max_p) { unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost); tree ptr = gimple_call_arg (call, 0); - if ((object_size_type == 1 || object_size_type == 3) + if ((object_size_type & OST_SUBOBJECT) && (TREE_CODE (ptr) == ADDR_EXPR || TREE_CODE (ptr) == SSA_NAME)) { @@ -1315,7 +1323,8 @@ object_sizes_execute (function *fun, bool insert_min_max_p) tree tem = make_ssa_name (type); gimple_call_set_lhs (call, tem); enum tree_code code - = object_size_type == 1 ? MIN_EXPR : MAX_EXPR; + = (object_size_type & OST_MINIMUM + ? MAX_EXPR : MIN_EXPR); tree cst = build_int_cstu (type, bytes); gimple *g = gimple_build_assign (lhs, code, tem, cst); @@ -1336,11 +1345,11 @@ object_sizes_execute (function *fun, bool insert_min_max_p) { unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost); - if (object_size_type < 2) + if (object_size_type & OST_MINIMUM) + result = build_zero_cst (size_type_node); + else if (object_size_type < OST_END) result = fold_convert (size_type_node, integer_minus_one_node); - else if (object_size_type < 4) - result = build_zero_cst (size_type_node); } if (!result) From patchwork Fri Nov 26 05:28:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 48170 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E356F3857C59 for ; Fri, 26 Nov 2021 05:30:33 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from fennec.ash.relay.mailchannels.net (fennec.ash.relay.mailchannels.net [23.83.222.58]) by sourceware.org (Postfix) with ESMTPS id 2EF583857C51 for ; Fri, 26 Nov 2021 05:29:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 2EF583857C51 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 6F582200F92; Fri, 26 Nov 2021 05:29:11 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id D0A53200FAE; Fri, 26 Nov 2021 05:29:10 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.124.138.98 (trex/6.4.3); Fri, 26 Nov 2021 05:29:11 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Gusty-Abortive: 3bb2f4f654a2e8c6_1637904551230_364836392 X-MC-Loop-Signature: 1637904551230:3974795379 X-MC-Ingress-Time: 1637904551230 Received: from rhbox.intra.reserved-bit.com (unknown [1.186.223.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4J0jwP23Dgz3C; Thu, 25 Nov 2021 21:29:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1637904550; bh=9xIM7aAUjGd65ipf3iXJcizp8Bk=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=OaV3sUykha3KRvdwYk2sPoihYri6zR8KkyvO1HmG8FcD30F1ABkhKWnYZiSf8dIdJ 2tXpPCXom2JH/JhcalIrz6ViYTI+mcocTj+VzXmaHTyMmmbT4dQObtGF8Ys00pmtls M6edGB5OkOEwy/htPt6RcGuN2OXUDuDyjR5dvZO4= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v3 2/8] tree-object-size: Abstract object_sizes array Date: Fri, 26 Nov 2021 10:58:45 +0530 Message-Id: <20211126052851.2176408-3-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211126052851.2176408-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211126052851.2176408-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Put all accesses to object_sizes behind functions so that we can add dynamic capability more easily. gcc/ChangeLog: * tree-object-size.c (object_sizes_grow, object_sizes_release, object_sizes_unknown_p, object_sizes_get, object_size_set_force, object_sizes_set): New functions. (addr_object_size, compute_builtin_object_size, expr_object_size, call_object_size, unknown_object_size, merge_object_sizes, plus_stmt_object_size, cond_expr_object_size, collect_object_sizes_for, check_for_plus_in_loops_1, init_object_sizes, fini_object_sizes): Adjust. Signed-off-by: Siddhesh Poyarekar --- Changes from v2: - Incorporated review suggestions. gcc/tree-object-size.c | 177 +++++++++++++++++++++++------------------ 1 file changed, 98 insertions(+), 79 deletions(-) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 5e93bb74f92..3780437ff91 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -88,6 +88,71 @@ unknown (int object_size_type) return ((unsigned HOST_WIDE_INT) -((object_size_type >> 1) ^ 1)); } +/* Grow object_sizes[OBJECT_SIZE_TYPE] to num_ssa_names. */ + +static inline void +object_sizes_grow (int object_size_type) +{ + if (num_ssa_names > object_sizes[object_size_type].length ()) + object_sizes[object_size_type].safe_grow (num_ssa_names, true); +} + +/* Release object_sizes[OBJECT_SIZE_TYPE]. */ + +static inline void +object_sizes_release (int object_size_type) +{ + object_sizes[object_size_type].release (); +} + +/* Return true if object_sizes[OBJECT_SIZE_TYPE][VARNO] is unknown. */ + +static inline bool +object_sizes_unknown_p (int object_size_type, unsigned varno) +{ + return (object_sizes[object_size_type][varno] + == unknown (object_size_type)); +} + +/* Return size for VARNO corresponding to OSI. */ + +static inline unsigned HOST_WIDE_INT +object_sizes_get (struct object_size_info *osi, unsigned varno) +{ + return object_sizes[osi->object_size_type][varno]; +} + +/* Set size for VARNO corresponding to OSI to VAL. */ + +static inline bool +object_sizes_set_force (struct object_size_info *osi, unsigned varno, + unsigned HOST_WIDE_INT val) +{ + object_sizes[osi->object_size_type][varno] = val; + return true; +} + +/* Set size for VARNO corresponding to OSI to VAL if it is the new minimum or + maximum. */ + +static inline bool +object_sizes_set (struct object_size_info *osi, unsigned varno, + unsigned HOST_WIDE_INT val) +{ + int object_size_type = osi->object_size_type; + if ((object_size_type & OST_MINIMUM) == 0) + { + if (object_sizes[object_size_type][varno] < val) + return object_sizes_set_force (osi, varno, val); + } + else + { + if (object_sizes[object_size_type][varno] > val) + return object_sizes_set_force (osi, varno, val); + } + return false; +} + /* Initialize OFFSET_LIMIT variable. */ static void init_offset_limit (void) @@ -247,7 +312,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, collect_object_sizes_for (osi, var); if (bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (var))) - sz = object_sizes[object_size_type][SSA_NAME_VERSION (var)]; + sz = object_sizes_get (osi, SSA_NAME_VERSION (var)); else sz = unknown (object_size_type); } @@ -582,14 +647,14 @@ compute_builtin_object_size (tree ptr, int object_size_type, return false; } + struct object_size_info osi; + osi.object_size_type = object_size_type; if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr))) { - struct object_size_info osi; bitmap_iterator bi; unsigned int i; - if (num_ssa_names > object_sizes[object_size_type].length ()) - object_sizes[object_size_type].safe_grow (num_ssa_names, true); + object_sizes_grow (object_size_type); if (dump_file) { fprintf (dump_file, "Computing %s %sobject size for ", @@ -601,7 +666,6 @@ compute_builtin_object_size (tree ptr, int object_size_type, osi.visited = BITMAP_ALLOC (NULL); osi.reexamine = BITMAP_ALLOC (NULL); - osi.object_size_type = object_size_type; osi.depths = NULL; osi.stack = NULL; osi.tos = NULL; @@ -678,8 +742,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, if (dump_file) { EXECUTE_IF_SET_IN_BITMAP (osi.visited, 0, i, bi) - if (object_sizes[object_size_type][i] - != unknown (object_size_type)) + if (!object_sizes_unknown_p (object_size_type, i)) { print_generic_expr (dump_file, ssa_name (i), dump_flags); @@ -689,7 +752,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, ((object_size_type & OST_MINIMUM) ? "minimum" : "maximum"), (object_size_type & OST_SUBOBJECT) ? "sub" : "", - object_sizes[object_size_type][i]); + object_sizes_get (&osi, i)); } } @@ -697,7 +760,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, BITMAP_FREE (osi.visited); } - *psize = object_sizes[object_size_type][SSA_NAME_VERSION (ptr)]; + *psize = object_sizes_get (&osi, SSA_NAME_VERSION (ptr)); return *psize != unknown (object_size_type); } @@ -710,8 +773,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) unsigned int varno = SSA_NAME_VERSION (ptr); unsigned HOST_WIDE_INT bytes; - gcc_assert (object_sizes[object_size_type][varno] - != unknown (object_size_type)); + gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_assert (osi->pass == 0); if (TREE_CODE (value) == WITH_SIZE_EXPR) @@ -726,16 +788,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) else bytes = unknown (object_size_type); - if ((object_size_type & OST_MINIMUM) == 0) - { - if (object_sizes[object_size_type][varno] < bytes) - object_sizes[object_size_type][varno] = bytes; - } - else - { - if (object_sizes[object_size_type][varno] > bytes) - object_sizes[object_size_type][varno] = bytes; - } + object_sizes_set (osi, varno, bytes); } @@ -750,22 +803,12 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) gcc_assert (is_gimple_call (call)); - gcc_assert (object_sizes[object_size_type][varno] - != unknown (object_size_type)); + gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_assert (osi->pass == 0); bytes = alloc_object_size (call, object_size_type); - if ((object_size_type & OST_MINIMUM) == 0) - { - if (object_sizes[object_size_type][varno] < bytes) - object_sizes[object_size_type][varno] = bytes; - } - else - { - if (object_sizes[object_size_type][varno] > bytes) - object_sizes[object_size_type][varno] = bytes; - } + object_sizes_set (osi, varno, bytes); } @@ -776,12 +819,11 @@ unknown_object_size (struct object_size_info *osi, tree ptr) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (ptr); - unsigned HOST_WIDE_INT bytes = unknown (object_size_type); - gcc_checking_assert (object_sizes[object_size_type][varno] != bytes); + gcc_checking_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_checking_assert (osi->pass == 0); - object_sizes[object_size_type][varno] = bytes; + object_sizes_set (osi, varno, unknown (object_size_type)); } @@ -796,38 +838,24 @@ merge_object_sizes (struct object_size_info *osi, tree dest, tree orig, unsigned int varno = SSA_NAME_VERSION (dest); unsigned HOST_WIDE_INT orig_bytes; - if (object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) return false; if (offset >= offset_limit) { - object_sizes[object_size_type][varno] = unknown (object_size_type); + object_sizes_set (osi, varno, unknown (object_size_type)); return false; } if (osi->pass == 0) collect_object_sizes_for (osi, orig); - orig_bytes = object_sizes[object_size_type][SSA_NAME_VERSION (orig)]; + orig_bytes = object_sizes_get (osi, SSA_NAME_VERSION (orig)); if (orig_bytes != unknown (object_size_type)) orig_bytes = (offset > orig_bytes) ? HOST_WIDE_INT_0U : orig_bytes - offset; - if ((object_size_type & OST_MINIMUM) == 0) - { - if (object_sizes[object_size_type][varno] < orig_bytes) - { - object_sizes[object_size_type][varno] = orig_bytes; - osi->changed = true; - } - } - else - { - if (object_sizes[object_size_type][varno] > orig_bytes) - { - object_sizes[object_size_type][varno] = orig_bytes; - osi->changed = true; - } - } + osi->changed = object_sizes_set (osi, varno, orig_bytes); + return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig)); } @@ -859,7 +887,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) else gcc_unreachable (); - if (object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) return false; /* Handle PTR + OFFSET here. */ @@ -890,16 +918,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) else bytes = unknown (object_size_type); - if ((object_size_type & OST_MINIMUM) == 0) - { - if (object_sizes[object_size_type][varno] < bytes) - object_sizes[object_size_type][varno] = bytes; - } - else - { - if (object_sizes[object_size_type][varno] > bytes) - object_sizes[object_size_type][varno] = bytes; - } + object_sizes_set (osi, varno, bytes); return false; } @@ -918,7 +937,7 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) gcc_assert (gimple_assign_rhs_code (stmt) == COND_EXPR); - if (object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) return false; then_ = gimple_assign_rhs2 (stmt); @@ -929,7 +948,7 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) else expr_object_size (osi, var, then_); - if (object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) return reexamine; if (TREE_CODE (else_) == SSA_NAME) @@ -975,8 +994,10 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { if (bitmap_set_bit (osi->visited, varno)) { - object_sizes[object_size_type][varno] - = (object_size_type & OST_MINIMUM) ? -1 : 0; + /* Initialize to 0 for maximum size and M1U for minimum size so that + it gets immediately overridden. */ + object_sizes_set_force (osi, varno, + unknown (object_size_type ^ OST_MINIMUM)); } else { @@ -1047,7 +1068,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) case GIMPLE_ASM: /* Pointers defined by __asm__ statements can point anywhere. */ - object_sizes[object_size_type][varno] = unknown (object_size_type); + object_sizes_set (osi, varno, unknown (object_size_type)); break; case GIMPLE_NOP: @@ -1056,7 +1077,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) expr_object_size (osi, var, SSA_NAME_VAR (var)); else /* Uninitialized SSA names point nowhere. */ - object_sizes[object_size_type][varno] = unknown (object_size_type); + object_sizes_set (osi, varno, unknown (object_size_type)); break; case GIMPLE_PHI: @@ -1067,8 +1088,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { tree rhs = gimple_phi_arg (stmt, i)->def; - if (object_sizes[object_size_type][varno] - == unknown (object_size_type)) + if (object_sizes_unknown_p (object_size_type, varno)) break; if (TREE_CODE (rhs) == SSA_NAME) @@ -1083,8 +1103,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) gcc_unreachable (); } - if (! reexamine - || object_sizes[object_size_type][varno] == unknown (object_size_type)) + if (! reexamine || object_sizes_unknown_p (object_size_type, varno)) { bitmap_set_bit (computed[object_size_type], varno); bitmap_clear_bit (osi->reexamine, varno); @@ -1124,7 +1143,7 @@ check_for_plus_in_loops_1 (struct object_size_info *osi, tree var, --sp; bitmap_clear_bit (osi->reexamine, *sp); bitmap_set_bit (computed[osi->object_size_type], *sp); - object_sizes[osi->object_size_type][*sp] = 0; + object_sizes_set_force (osi, *sp, 0); if (*sp == varno) break; } @@ -1248,7 +1267,7 @@ init_object_sizes (void) for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { - object_sizes[object_size_type].safe_grow (num_ssa_names, true); + object_sizes_grow (object_size_type); computed[object_size_type] = BITMAP_ALLOC (NULL); } @@ -1265,7 +1284,7 @@ fini_object_sizes (void) for (object_size_type = 0; object_size_type < OST_END; object_size_type++) { - object_sizes[object_size_type].release (); + object_sizes_release (object_size_type); BITMAP_FREE (computed[object_size_type]); } } From patchwork Fri Nov 26 05:28:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 48171 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 970FA3858037 for ; Fri, 26 Nov 2021 05:31:04 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from dog.birch.relay.mailchannels.net (dog.birch.relay.mailchannels.net [23.83.209.48]) by sourceware.org (Postfix) with ESMTPS id 4853E3857C4B for ; Fri, 26 Nov 2021 05:29:17 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 4853E3857C4B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 8F57A661240; Fri, 26 Nov 2021 05:29:15 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 3C1AF6609E5; Fri, 26 Nov 2021 05:29:13 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.99.149.17 (trex/6.4.3); Fri, 26 Nov 2021 05:29:15 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Continue-Skirt: 03109e7471769dc0_1637904555372_3322960649 X-MC-Loop-Signature: 1637904555372:2399730136 X-MC-Ingress-Time: 1637904555371 Received: from rhbox.intra.reserved-bit.com (unknown [1.186.223.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4J0jwR2JXHz3Z; Thu, 25 Nov 2021 21:29:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1637904553; bh=trYh0W5tYYINv50UWehTInNvSbs=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=L1YG1Ory/XH9v+E0cMUq72PYtK6tYU8RGw0aHKkwByBQzO6fQLfFeOLjTdytMzIXq 0YdcD5kd13VPWT0lKxLl3o9peZfm9H/HbwijU66Q9uqyVTEfLosUZiXcHEl2C1xVNX pDWe0sMSzuYg5+7F8kzu0smolkDtxIhjMQJU3ulE= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v3 3/8] tree-object-size: Save sizes as trees and support negative offsets Date: Fri, 26 Nov 2021 10:58:46 +0530 Message-Id: <20211126052851.2176408-4-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211126052851.2176408-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211126052851.2176408-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Transform tree-object-size to operate on tree objects instead of host wide integers. This makes it easier to extend to dynamic expressions for object sizes. The compute_builtin_object_size interface also now returns a tree expression instead of HOST_WIDE_INT, so callers have been adjusted to account for that. The trees in object_sizes are each a TREE_VEC with the first element being the bytes from the pointer to the end of the object and the second, the size of the whole object. This allows analysis of negative offsets, which can now be allowed to the extent of the object bounds. Tests have been added to verify that it actually works. gcc/ChangeLog: * tree-object-size.h (compute_builtin_object_size): Return tree instead of HOST_WIDE_INT. * builtins.c (fold_builtin_object_size): Adjust. * gimple-fold.c (gimple_fold_builtin_strncat): Likewise. * ubsan.c (instrument_object_size): Likewise. * tree-object-size.c (object_sizes): Change type to vec. (initval): New function. (unknown): Use it. (size_unknown_p, size_initval, size_unknown): New functions. (object_sizes_unknown_p): Use it. (object_sizes_get): Return tree. (object_sizes_initialize): Rename from object_sizes_set_force and set VAL parameter type as tree. Add new parameter WHOLEVAL. (object_sizes_set): Set VAL parameter type as tree and adjust implementation. Add new parameter WHOLEVAL. (size_for_offset): New function. (decl_init_size): Adjust comment. (addr_object_size): Change PSIZE parameter to tree and adjust implementation. Add new parameter PWHOLESIZE. (alloc_object_size): Return tree. (compute_builtin_object_size): Return tree in PSIZE. (expr_object_size, call_object_size, unknown_object_size): Adjust for object_sizes_set change. (merge_object_sizes): Drop OFFSET parameter and adjust implementation for tree change. (plus_stmt_object_size): Call collect_object_sizes_for directly instead of merge_object_size and call size_for_offset to get net size. (cond_expr_object_size, collect_object_sizes_for, object_sizes_execute): Adjust for change of type from HOST_WIDE_INT to tree. (check_for_plus_in_loops_1): Likewise and skip non-positive offsets. gcc/testsuite/ChangeLog: * gcc.dg/builtin-object-size-1.c (test9): New test. (main): Call it. * gcc.dg/builtin-object-size-2.c (test8): New test. (main): Call it. * gcc.dg/builtin-object-size-3.c (test9): New test. (main): Call it. * gcc.dg/builtin-object-size-4.c (test8): New test. (main): Call it. * gcc.dg/builtin-object-size-5.c (test5, test6, test7): New tests. Signed-off-by: Siddhesh Poyarekar --- Changes from v2: - Incorporated review suggestions. - Added support for negative offsets. gcc/builtins.c | 10 +- gcc/gimple-fold.c | 11 +- gcc/testsuite/gcc.dg/builtin-object-size-1.c | 30 ++ gcc/testsuite/gcc.dg/builtin-object-size-2.c | 30 ++ gcc/testsuite/gcc.dg/builtin-object-size-3.c | 31 ++ gcc/testsuite/gcc.dg/builtin-object-size-4.c | 30 ++ gcc/testsuite/gcc.dg/builtin-object-size-5.c | 25 ++ gcc/tree-object-size.c | 388 ++++++++++++------- gcc/tree-object-size.h | 2 +- gcc/ubsan.c | 5 +- 10 files changed, 403 insertions(+), 159 deletions(-) diff --git a/gcc/builtins.c b/gcc/builtins.c index 384864bfb3a..50e66692775 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -10226,7 +10226,7 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode) static tree fold_builtin_object_size (tree ptr, tree ost) { - unsigned HOST_WIDE_INT bytes; + tree bytes; int object_size_type; if (!validate_arg (ptr, POINTER_TYPE) @@ -10251,8 +10251,8 @@ fold_builtin_object_size (tree ptr, tree ost) if (TREE_CODE (ptr) == ADDR_EXPR) { compute_builtin_object_size (ptr, object_size_type, &bytes); - if (wi::fits_to_tree_p (bytes, size_type_node)) - return build_int_cstu (size_type_node, bytes); + if (int_fits_type_p (bytes, size_type_node)) + return fold_convert (size_type_node, bytes); } else if (TREE_CODE (ptr) == SSA_NAME) { @@ -10260,8 +10260,8 @@ fold_builtin_object_size (tree ptr, tree ost) later. Maybe subsequent passes will help determining it. */ if (compute_builtin_object_size (ptr, object_size_type, &bytes) - && wi::fits_to_tree_p (bytes, size_type_node)) - return build_int_cstu (size_type_node, bytes); + && int_fits_type_p (bytes, size_type_node)) + return fold_convert (size_type_node, bytes); } return NULL_TREE; diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 73f090bb14c..b5cfb502633 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -2492,17 +2492,16 @@ gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi) if (!src_len || known_lower (stmt, len, src_len, true)) return false; - unsigned HOST_WIDE_INT dstsize; - bool found_dstsize = compute_builtin_object_size (dst, 1, &dstsize); - /* Warn on constant LEN. */ if (TREE_CODE (len) == INTEGER_CST) { bool nowarn = warning_suppressed_p (stmt, OPT_Wstringop_overflow_); + tree dstsize; - if (!nowarn && found_dstsize) + if (!nowarn && compute_builtin_object_size (dst, 1, &dstsize) + && TREE_CODE (dstsize) == INTEGER_CST) { - int cmpdst = compare_tree_int (len, dstsize); + int cmpdst = tree_int_cst_compare (len, dstsize); if (cmpdst >= 0) { @@ -2518,7 +2517,7 @@ gimple_fold_builtin_strncat (gimple_stmt_iterator *gsi) ? G_("%qD specified bound %E equals " "destination size") : G_("%qD specified bound %E exceeds " - "destination size %wu"), + "destination size %E"), fndecl, len, dstsize); if (nowarn) suppress_warning (stmt, OPT_Wstringop_overflow_); diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 8cdae49a6b1..0154f4e9695 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -424,6 +424,35 @@ test8 (void) abort (); } +void +__attribute__ ((noinline)) +test9 (unsigned cond) +{ + char *buf2 = malloc (10); + char *p; + + if (cond) + p = &buf2[8]; + else + p = &buf2[4]; + + if (__builtin_object_size (&p[-4], 0) != 10) + abort (); + + for (unsigned i = cond; i > 0; i--) + p--; + + if (__builtin_object_size (p, 0) != 10) + abort (); + + p = &y.c[8]; + for (unsigned i = cond; i > 0; i--) + p--; + + if (__builtin_object_size (p, 0) != sizeof (y)) + abort (); +} + int main (void) { @@ -437,5 +466,6 @@ main (void) test6 (4); test7 (); test8 (); + test9 (1); exit (0); } diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index ad2dd296a9a..5cf29291aff 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -382,6 +382,35 @@ test7 (void) abort (); } +void +__attribute__ ((noinline)) +test8 (unsigned cond) +{ + char *buf2 = malloc (10); + char *p; + + if (cond) + p = &buf2[8]; + else + p = &buf2[4]; + + if (__builtin_object_size (&p[-4], 1) != 10) + abort (); + + for (unsigned i = cond; i > 0; i--) + p--; + + if (__builtin_object_size (p, 1) != 10) + abort (); + + p = &y.c[8]; + for (unsigned i = cond; i > 0; i--) + p--; + + if (__builtin_object_size (p, 1) != sizeof (y.c)) + abort (); +} + int main (void) { @@ -394,5 +423,6 @@ main (void) test5 (4); test6 (); test7 (); + test8 (1); exit (0); } diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index d5ca5047ee9..3a692c4e3d2 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -430,6 +430,36 @@ test8 (void) abort (); } +void +__attribute__ ((noinline)) +test9 (unsigned cond) +{ + char *buf2 = malloc (10); + char *p; + + if (cond) + p = &buf2[8]; + else + p = &buf2[4]; + + if (__builtin_object_size (&p[-4], 2) != 6) + abort (); + + for (unsigned i = cond; i > 0; i--) + p--; + + if (__builtin_object_size (p, 2) != 2) + abort (); + + p = &y.c[8]; + for (unsigned i = cond; i > 0; i--) + p--; + + if (__builtin_object_size (p, 2) + != sizeof (y) - __builtin_offsetof (struct A, c) - 8) + abort (); +} + int main (void) { @@ -443,5 +473,6 @@ main (void) test6 (4); test7 (); test8 (); + test9 (1); exit (0); } diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index 9f159e36a0f..87381620cc9 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -395,6 +395,35 @@ test7 (void) abort (); } +void +__attribute__ ((noinline)) +test8 (unsigned cond) +{ + char *buf2 = malloc (10); + char *p; + + if (cond) + p = &buf2[8]; + else + p = &buf2[4]; + + if (__builtin_object_size (&p[-4], 3) != 6) + abort (); + + for (unsigned i = cond; i > 0; i--) + p--; + + if (__builtin_object_size (p, 3) != 2) + abort (); + + p = &y.c[8]; + for (unsigned i = cond; i > 0; i--) + p--; + + if (__builtin_object_size (p, 3) != sizeof (y.c) - 8) + abort (); +} + int main (void) { @@ -407,5 +436,6 @@ main (void) test5 (4); test6 (); test7 (); + test8 (1); exit (0); } diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-object-size-5.c index 7c274cdfd42..8e63d9c7a5e 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-5.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-5.c @@ -53,4 +53,29 @@ test4 (size_t x) abort (); } +void +test5 (void) +{ + char *p = &buf[0x90000004]; + if (__builtin_object_size (p + 2, 0) != 0) + abort (); +} + +void +test6 (void) +{ + char *p = &buf[-4]; + if (__builtin_object_size (p + 2, 0) != 0) + abort (); +} + +void +test7 (void) +{ + char *buf2 = __builtin_malloc (8); + char *p = &buf2[0x90000004]; + if (__builtin_object_size (p + 2, 0) != 0) + abort (); +} + /* { dg-final { scan-assembler-not "abort" } } */ diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 3780437ff91..1a1e3d56126 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -54,13 +54,12 @@ enum static tree compute_object_offset (const_tree, const_tree); static bool addr_object_size (struct object_size_info *, - const_tree, int, unsigned HOST_WIDE_INT *); -static unsigned HOST_WIDE_INT alloc_object_size (const gcall *, int); + const_tree, int, tree *, tree *t = NULL); +static tree alloc_object_size (const gcall *, int); static tree pass_through_call (const gcall *); static void collect_object_sizes_for (struct object_size_info *, tree); static void expr_object_size (struct object_size_info *, tree, tree); -static bool merge_object_sizes (struct object_size_info *, tree, tree, - unsigned HOST_WIDE_INT); +static bool merge_object_sizes (struct object_size_info *, tree, tree); static bool plus_stmt_object_size (struct object_size_info *, tree, gimple *); static bool cond_expr_object_size (struct object_size_info *, tree, gimple *); static void init_offset_limit (void); @@ -68,13 +67,17 @@ static void check_for_plus_in_loops (struct object_size_info *, tree); static void check_for_plus_in_loops_1 (struct object_size_info *, tree, unsigned int); -/* object_sizes[0] is upper bound for number of bytes till the end of - the object. - object_sizes[1] is upper bound for number of bytes till the end of - the subobject (innermost array or field with address taken). - object_sizes[2] is lower bound for number of bytes till the end of - the object and object_sizes[3] lower bound for subobject. */ -static vec object_sizes[OST_END]; +/* Each tree in the object_sizes vector is a TREE_VEC. The first element is an + estimate of the number of bytes till the end of the object and the second + element is an estimate of the the whole size of the object. + + object_sizes[0] is upper bound for the object size and number of bytes till + the end of the object. + object_sizes[1] is upper bound for the object size and number of bytes till + the end of the subobject (innermost array or field with address taken). + object_sizes[2] is lower bound for the object size and number of bytes till + the end of the object and object_sizes[3] lower bound for subobject. */ +static vec object_sizes[OST_END]; /* Bitmaps what object sizes have been computed already. */ static bitmap computed[OST_END]; @@ -82,10 +85,46 @@ static bitmap computed[OST_END]; /* Maximum value of offset we consider to be addition. */ static unsigned HOST_WIDE_INT offset_limit; +/* Initial value of object sizes; zero for maximum and SIZE_MAX for minimum + object size. */ + +static inline unsigned HOST_WIDE_INT +initval (int object_size_type) +{ + return (object_size_type & OST_MINIMUM) ? HOST_WIDE_INT_M1U : 0; +} + +/* Unknown object size value; it's the opposite of initval. */ + static inline unsigned HOST_WIDE_INT unknown (int object_size_type) { - return ((unsigned HOST_WIDE_INT) -((object_size_type >> 1) ^ 1)); + return ~initval (object_size_type); +} + +/* Return true if VAL is represents an unknown size for OBJECT_SIZE_TYPE. */ + +static inline bool +size_unknown_p (tree val, int object_size_type) +{ + return (tree_fits_uhwi_p (val) + && tree_to_uhwi (val) == unknown (object_size_type)); +} + +/* Return a tree with initial value for OBJECT_SIZE_TYPE. */ + +static inline tree +size_initval (int object_size_type) +{ + return size_int (initval (object_size_type)); +} + +/* Return a tree with unknown value for OBJECT_SIZE_TYPE. */ + +static inline tree +size_unknown (int object_size_type) +{ + return size_int (unknown (object_size_type)); } /* Grow object_sizes[OBJECT_SIZE_TYPE] to num_ssa_names. */ @@ -110,47 +149,56 @@ object_sizes_release (int object_size_type) static inline bool object_sizes_unknown_p (int object_size_type, unsigned varno) { - return (object_sizes[object_size_type][varno] - == unknown (object_size_type)); + return size_unknown_p (object_sizes[object_size_type][varno], + object_size_type); } -/* Return size for VARNO corresponding to OSI. */ +/* Return size for VARNO corresponding to OSI. If WHOLE is true, return the + whole object size. */ -static inline unsigned HOST_WIDE_INT -object_sizes_get (struct object_size_info *osi, unsigned varno) +static inline tree +object_sizes_get (struct object_size_info *osi, unsigned varno, + bool whole = false) { - return object_sizes[osi->object_size_type][varno]; + return TREE_VEC_ELT (object_sizes[osi->object_size_type][varno], whole); } /* Set size for VARNO corresponding to OSI to VAL. */ -static inline bool -object_sizes_set_force (struct object_size_info *osi, unsigned varno, - unsigned HOST_WIDE_INT val) +static inline void +object_sizes_initialize (struct object_size_info *osi, unsigned varno, + tree val, tree wholeval) { - object_sizes[osi->object_size_type][varno] = val; - return true; + int object_size_type = osi->object_size_type; + + tree res = make_tree_vec (2); + TREE_VEC_ELT (res, 0) = val; + TREE_VEC_ELT (res, 1) = wholeval; + + object_sizes[object_size_type][varno] = res; } /* Set size for VARNO corresponding to OSI to VAL if it is the new minimum or maximum. */ static inline bool -object_sizes_set (struct object_size_info *osi, unsigned varno, - unsigned HOST_WIDE_INT val) +object_sizes_set (struct object_size_info *osi, unsigned varno, tree val, + tree wholeval) { int object_size_type = osi->object_size_type; - if ((object_size_type & OST_MINIMUM) == 0) - { - if (object_sizes[object_size_type][varno] < val) - return object_sizes_set_force (osi, varno, val); - } - else - { - if (object_sizes[object_size_type][varno] > val) - return object_sizes_set_force (osi, varno, val); - } - return false; + tree size = object_sizes[object_size_type][varno]; + + tree oldval = TREE_VEC_ELT (size, 0); + tree old_wholeval = TREE_VEC_ELT (size, 1); + + enum tree_code code = object_size_type & OST_MINIMUM ? MIN_EXPR : MAX_EXPR; + + val = size_binop (code, val, oldval); + wholeval = size_binop (code, wholeval, old_wholeval); + + TREE_VEC_ELT (size, 0) = val; + TREE_VEC_ELT (size, 1) = wholeval; + return tree_int_cst_compare (oldval, val) != 0; } /* Initialize OFFSET_LIMIT variable. */ @@ -164,6 +212,48 @@ init_offset_limit (void) offset_limit /= 2; } +/* Bytes at end of the object with SZ from offset OFFSET. If WHOLESIZE is not + NULL_TREE, use it to get the net offset of the pointer, which should always + be positive and hence, be within OFFSET_LIMIT for valid offsets. */ + +static tree +size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) +{ + gcc_checking_assert (TREE_CODE (offset) == INTEGER_CST); + gcc_checking_assert (TREE_CODE (sz) == INTEGER_CST); + gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype)); + + /* For negative offsets, if we have a distinct WHOLESIZE, use it to get a net + offset from the whole object. */ + if (wholesize && tree_int_cst_compare (sz, wholesize)) + { + gcc_checking_assert (TREE_CODE (wholesize) == INTEGER_CST); + gcc_checking_assert (types_compatible_p (TREE_TYPE (wholesize), + sizetype)); + + /* Restructure SZ - OFFSET as + WHOLESIZE - (WHOLESIZE + OFFSET - SZ) so that the offset part, i.e. + WHOLESIZE + OFFSET - SZ is only allowed to be positive. */ + tree tmp = size_binop (MAX_EXPR, wholesize, sz); + offset = fold_build2 (PLUS_EXPR, sizetype, tmp, offset); + offset = fold_build2 (MINUS_EXPR, sizetype, offset, sz); + sz = tmp; + } + + /* Safe to convert now, since a valid net offset should be non-negative. */ + if (!types_compatible_p (TREE_TYPE (offset), sizetype)) + fold_convert (sizetype, offset); + + if (integer_zerop (offset)) + return sz; + + /* Negative or too large offset even after adjustment, cannot be within + bounds of an object. */ + if (compare_tree_int (offset, offset_limit) > 0) + return size_zero_node; + + return size_binop (MINUS_EXPR, size_binop (MAX_EXPR, sz, offset), offset); +} /* Compute offset of EXPR within VAR. Return error_mark_node if unknown. */ @@ -274,19 +364,22 @@ decl_init_size (tree decl, bool min) /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR. OBJECT_SIZE_TYPE is the second argument from __builtin_object_size. - If unknown, return unknown (object_size_type). */ + If unknown, return size_unknown (object_size_type). */ static bool addr_object_size (struct object_size_info *osi, const_tree ptr, - int object_size_type, unsigned HOST_WIDE_INT *psize) + int object_size_type, tree *psize, tree *pwholesize) { - tree pt_var, pt_var_size = NULL_TREE, var_size, bytes; + tree pt_var, pt_var_size = NULL_TREE, pt_var_wholesize = NULL_TREE; + tree var_size, bytes, wholebytes; gcc_assert (TREE_CODE (ptr) == ADDR_EXPR); /* Set to unknown and overwrite just before returning if the size could be determined. */ - *psize = unknown (object_size_type); + *psize = size_unknown (object_size_type); + if (pwholesize) + *pwholesize = size_unknown (object_size_type); pt_var = TREE_OPERAND (ptr, 0); while (handled_component_p (pt_var)) @@ -297,13 +390,14 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, if (TREE_CODE (pt_var) == MEM_REF) { - unsigned HOST_WIDE_INT sz; + tree sz, wholesize; if (!osi || (object_size_type & OST_SUBOBJECT) != 0 || TREE_CODE (TREE_OPERAND (pt_var, 0)) != SSA_NAME) { compute_builtin_object_size (TREE_OPERAND (pt_var, 0), object_size_type & ~OST_SUBOBJECT, &sz); + wholesize = sz; } else { @@ -312,46 +406,47 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, collect_object_sizes_for (osi, var); if (bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (var))) - sz = object_sizes_get (osi, SSA_NAME_VERSION (var)); + { + sz = object_sizes_get (osi, SSA_NAME_VERSION (var)); + wholesize = object_sizes_get (osi, SSA_NAME_VERSION (var), true); + } else - sz = unknown (object_size_type); + sz = wholesize = size_unknown (object_size_type); } - if (sz != unknown (object_size_type)) + if (!size_unknown_p (sz, object_size_type)) { - offset_int mem_offset; - if (mem_ref_offset (pt_var).is_constant (&mem_offset)) - { - offset_int dsz = wi::sub (sz, mem_offset); - if (wi::neg_p (dsz)) - sz = 0; - else if (wi::fits_uhwi_p (dsz)) - sz = dsz.to_uhwi (); - else - sz = unknown (object_size_type); - } + tree offset = TREE_OPERAND (pt_var, 1); + if (TREE_CODE (offset) != INTEGER_CST + || TREE_CODE (sz) != INTEGER_CST) + sz = wholesize = size_unknown (object_size_type); else - sz = unknown (object_size_type); + sz = size_for_offset (sz, offset, wholesize); } - if (sz != unknown (object_size_type) && sz < offset_limit) - pt_var_size = size_int (sz); + if (!size_unknown_p (sz, object_size_type) + && TREE_CODE (sz) == INTEGER_CST + && compare_tree_int (sz, offset_limit) < 0) + { + pt_var_size = sz; + pt_var_wholesize = wholesize; + } } else if (DECL_P (pt_var)) { - pt_var_size = decl_init_size (pt_var, object_size_type & OST_MINIMUM); + pt_var_size = pt_var_wholesize + = decl_init_size (pt_var, object_size_type & OST_MINIMUM); if (!pt_var_size) return false; } else if (TREE_CODE (pt_var) == STRING_CST) - pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var)); + pt_var_size = pt_var_wholesize = TYPE_SIZE_UNIT (TREE_TYPE (pt_var)); else return false; if (pt_var_size) { /* Validate the size determined above. */ - if (!tree_fits_uhwi_p (pt_var_size) - || tree_to_uhwi (pt_var_size) >= offset_limit) + if (compare_tree_int (pt_var_size, offset_limit) >= 0) return false; } @@ -496,28 +591,35 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, bytes = size_binop (MIN_EXPR, bytes, bytes2); } } + + wholebytes + = object_size_type & OST_SUBOBJECT ? var_size : pt_var_wholesize; } else if (!pt_var_size) return false; else - bytes = pt_var_size; - - if (tree_fits_uhwi_p (bytes)) { - *psize = tree_to_uhwi (bytes); - return true; + bytes = pt_var_size; + wholebytes = pt_var_wholesize; } - return false; + if (TREE_CODE (bytes) != INTEGER_CST + || TREE_CODE (wholebytes) != INTEGER_CST) + return false; + + *psize = bytes; + if (pwholesize) + *pwholesize = wholebytes; + return true; } /* Compute __builtin_object_size for CALL, which is a GIMPLE_CALL. Handles calls to functions declared with attribute alloc_size. OBJECT_SIZE_TYPE is the second argument from __builtin_object_size. - If unknown, return unknown (object_size_type). */ + If unknown, return size_unknown (object_size_type). */ -static unsigned HOST_WIDE_INT +static tree alloc_object_size (const gcall *call, int object_size_type) { gcc_assert (is_gimple_call (call)); @@ -529,7 +631,7 @@ alloc_object_size (const gcall *call, int object_size_type) calltype = gimple_call_fntype (call); if (!calltype) - return unknown (object_size_type); + return size_unknown (object_size_type); /* Set to positions of alloc_size arguments. */ int arg1 = -1, arg2 = -1; @@ -549,7 +651,7 @@ alloc_object_size (const gcall *call, int object_size_type) || (arg2 >= 0 && (arg2 >= (int)gimple_call_num_args (call) || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST))) - return unknown (object_size_type); + return size_unknown (object_size_type); tree bytes = NULL_TREE; if (arg2 >= 0) @@ -559,10 +661,7 @@ alloc_object_size (const gcall *call, int object_size_type) else if (arg1 >= 0) bytes = fold_convert (sizetype, gimple_call_arg (call, arg1)); - if (bytes && tree_fits_uhwi_p (bytes)) - return tree_to_uhwi (bytes); - - return unknown (object_size_type); + return bytes; } @@ -598,13 +697,13 @@ pass_through_call (const gcall *call) bool compute_builtin_object_size (tree ptr, int object_size_type, - unsigned HOST_WIDE_INT *psize) + tree *psize) { gcc_assert (object_size_type >= 0 && object_size_type < OST_END); /* Set to unknown and overwrite just before returning if the size could be determined. */ - *psize = unknown (object_size_type); + *psize = size_unknown (object_size_type); if (! offset_limit) init_offset_limit (); @@ -638,8 +737,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, psize)) { /* Return zero when the offset is out of bounds. */ - unsigned HOST_WIDE_INT off = tree_to_shwi (offset); - *psize = off < *psize ? *psize - off : 0; + *psize = size_for_offset (*psize, offset); return true; } } @@ -747,12 +845,13 @@ compute_builtin_object_size (tree ptr, int object_size_type, print_generic_expr (dump_file, ssa_name (i), dump_flags); fprintf (dump_file, - ": %s %sobject size " - HOST_WIDE_INT_PRINT_UNSIGNED "\n", + ": %s %sobject size ", ((object_size_type & OST_MINIMUM) ? "minimum" : "maximum"), - (object_size_type & OST_SUBOBJECT) ? "sub" : "", - object_sizes_get (&osi, i)); + (object_size_type & OST_SUBOBJECT) ? "sub" : ""); + print_generic_expr (dump_file, object_sizes_get (&osi, i), + dump_flags); + fprintf (dump_file, "\n"); } } @@ -761,7 +860,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, } *psize = object_sizes_get (&osi, SSA_NAME_VERSION (ptr)); - return *psize != unknown (object_size_type); + return !size_unknown_p (*psize, object_size_type); } /* Compute object_sizes for PTR, defined to VALUE, which is not an SSA_NAME. */ @@ -771,7 +870,7 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (ptr); - unsigned HOST_WIDE_INT bytes; + tree bytes, wholesize; gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_assert (osi->pass == 0); @@ -784,11 +883,11 @@ expr_object_size (struct object_size_info *osi, tree ptr, tree value) || !POINTER_TYPE_P (TREE_TYPE (value))); if (TREE_CODE (value) == ADDR_EXPR) - addr_object_size (osi, value, object_size_type, &bytes); + addr_object_size (osi, value, object_size_type, &bytes, &wholesize); else - bytes = unknown (object_size_type); + bytes = wholesize = size_unknown (object_size_type); - object_sizes_set (osi, varno, bytes); + object_sizes_set (osi, varno, bytes, wholesize); } @@ -799,16 +898,14 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (ptr); - unsigned HOST_WIDE_INT bytes; gcc_assert (is_gimple_call (call)); gcc_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_assert (osi->pass == 0); + tree bytes = alloc_object_size (call, object_size_type); - bytes = alloc_object_size (call, object_size_type); - - object_sizes_set (osi, varno, bytes); + object_sizes_set (osi, varno, bytes, bytes); } @@ -822,8 +919,9 @@ unknown_object_size (struct object_size_info *osi, tree ptr) gcc_checking_assert (!object_sizes_unknown_p (object_size_type, varno)); gcc_checking_assert (osi->pass == 0); + tree bytes = size_unknown (object_size_type); - object_sizes_set (osi, varno, unknown (object_size_type)); + object_sizes_set (osi, varno, bytes, bytes); } @@ -831,30 +929,22 @@ unknown_object_size (struct object_size_info *osi, tree ptr) the object size might need reexamination later. */ static bool -merge_object_sizes (struct object_size_info *osi, tree dest, tree orig, - unsigned HOST_WIDE_INT offset) +merge_object_sizes (struct object_size_info *osi, tree dest, tree orig) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (dest); - unsigned HOST_WIDE_INT orig_bytes; + tree orig_bytes, wholesize; if (object_sizes_unknown_p (object_size_type, varno)) return false; - if (offset >= offset_limit) - { - object_sizes_set (osi, varno, unknown (object_size_type)); - return false; - } if (osi->pass == 0) collect_object_sizes_for (osi, orig); orig_bytes = object_sizes_get (osi, SSA_NAME_VERSION (orig)); - if (orig_bytes != unknown (object_size_type)) - orig_bytes = (offset > orig_bytes) - ? HOST_WIDE_INT_0U : orig_bytes - offset; + wholesize = object_sizes_get (osi, SSA_NAME_VERSION (orig), true); - osi->changed = object_sizes_set (osi, varno, orig_bytes); + osi->changed = object_sizes_set (osi, varno, orig_bytes, wholesize); return bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (orig)); } @@ -869,8 +959,9 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) { int object_size_type = osi->object_size_type; unsigned int varno = SSA_NAME_VERSION (var); - unsigned HOST_WIDE_INT bytes; + tree bytes, wholesize; tree op0, op1; + bool reexamine = false; if (gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR) { @@ -895,31 +986,37 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) && (TREE_CODE (op0) == SSA_NAME || TREE_CODE (op0) == ADDR_EXPR)) { - if (! tree_fits_uhwi_p (op1)) - bytes = unknown (object_size_type); - else if (TREE_CODE (op0) == SSA_NAME) - return merge_object_sizes (osi, var, op0, tree_to_uhwi (op1)); + if (TREE_CODE (op0) == SSA_NAME) + { + if (osi->pass == 0) + collect_object_sizes_for (osi, op0); + + bytes = object_sizes_get (osi, SSA_NAME_VERSION (op0)); + wholesize = object_sizes_get (osi, SSA_NAME_VERSION (op0), true); + reexamine = bitmap_bit_p (osi->reexamine, SSA_NAME_VERSION (op0)); + } else { - unsigned HOST_WIDE_INT off = tree_to_uhwi (op1); - - /* op0 will be ADDR_EXPR here. */ - addr_object_size (osi, op0, object_size_type, &bytes); - if (bytes == unknown (object_size_type)) - ; - else if (off > offset_limit) - bytes = unknown (object_size_type); - else if (off > bytes) - bytes = 0; - else - bytes -= off; + /* op0 will be ADDR_EXPR here. We should never come here during + reexamination. */ + gcc_checking_assert (osi->pass == 0); + addr_object_size (osi, op0, object_size_type, &bytes, &wholesize); } + + /* In the first pass, do not compute size for offset if either the + maximum size is unknown or the minimum size is not initialized yet; + the latter indicates a dependency loop and will be resolved in + subsequent passes. We attempt to compute offset for 0 minimum size + too because a negative offset could be within bounds of WHOLESIZE, + giving a non-zero result for VAR. */ + if (osi->pass != 0 || !size_unknown_p (bytes, 0)) + bytes = size_for_offset (bytes, op1, wholesize); } else - bytes = unknown (object_size_type); + bytes = wholesize = size_unknown (object_size_type); - object_sizes_set (osi, varno, bytes); - return false; + osi->changed = object_sizes_set (osi, varno, bytes, wholesize); + return reexamine; } @@ -944,7 +1041,7 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) else_ = gimple_assign_rhs3 (stmt); if (TREE_CODE (then_) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, then_, 0); + reexamine |= merge_object_sizes (osi, var, then_); else expr_object_size (osi, var, then_); @@ -952,7 +1049,7 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) return reexamine; if (TREE_CODE (else_) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, else_, 0); + reexamine |= merge_object_sizes (osi, var, else_); else expr_object_size (osi, var, else_); @@ -969,11 +1066,11 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) object size is object size of the first operand minus the constant. If the constant is bigger than the number of remaining bytes until the end of the object, object size is 0, but if it is instead a pointer - subtraction, object size is unknown (object_size_type). + subtraction, object size is size_unknown (object_size_type). To differentiate addition from subtraction, ADDR_EXPR returns - unknown (object_size_type) for all objects bigger than half of the address - space, and constants less than half of the address space are considered - addition, while bigger constants subtraction. + size_unknown (object_size_type) for all objects bigger than half of the + address space, and constants less than half of the address space are + considered addition, while bigger constants subtraction. For a memcpy like GIMPLE_CALL that always returns one of its arguments, the object size is object size of that argument. Otherwise, object size is the maximum of object sizes of variables @@ -996,8 +1093,9 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { /* Initialize to 0 for maximum size and M1U for minimum size so that it gets immediately overridden. */ - object_sizes_set_force (osi, varno, - unknown (object_size_type ^ OST_MINIMUM)); + object_sizes_initialize (osi, varno, + size_initval (object_size_type), + size_initval (object_size_type)); } else { @@ -1040,7 +1138,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { if (TREE_CODE (rhs) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (rhs))) - reexamine = merge_object_sizes (osi, var, rhs, 0); + reexamine = merge_object_sizes (osi, var, rhs); else expr_object_size (osi, var, rhs); } @@ -1057,7 +1155,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { if (TREE_CODE (arg) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (arg))) - reexamine = merge_object_sizes (osi, var, arg, 0); + reexamine = merge_object_sizes (osi, var, arg); else expr_object_size (osi, var, arg); } @@ -1068,7 +1166,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) case GIMPLE_ASM: /* Pointers defined by __asm__ statements can point anywhere. */ - object_sizes_set (osi, varno, unknown (object_size_type)); + unknown_object_size (osi, var); break; case GIMPLE_NOP: @@ -1077,7 +1175,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) expr_object_size (osi, var, SSA_NAME_VAR (var)); else /* Uninitialized SSA names point nowhere. */ - object_sizes_set (osi, varno, unknown (object_size_type)); + unknown_object_size (osi, var); break; case GIMPLE_PHI: @@ -1092,7 +1190,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) break; if (TREE_CODE (rhs) == SSA_NAME) - reexamine |= merge_object_sizes (osi, var, rhs, 0); + reexamine |= merge_object_sizes (osi, var, rhs); else if (osi->pass == 0) expr_object_size (osi, var, rhs); } @@ -1143,7 +1241,8 @@ check_for_plus_in_loops_1 (struct object_size_info *osi, tree var, --sp; bitmap_clear_bit (osi->reexamine, *sp); bitmap_set_bit (computed[osi->object_size_type], *sp); - object_sizes_set_force (osi, *sp, 0); + object_sizes_set (osi, *sp, size_zero_node, + object_sizes_get (osi, *sp, true)); if (*sp == varno) break; } @@ -1243,7 +1342,8 @@ check_for_plus_in_loops (struct object_size_info *osi, tree var) gcc_assert (TREE_CODE (cst) == INTEGER_CST); - if (integer_zerop (cst)) + /* Skip non-positive offsets. */ + if (integer_zerop (cst) || compare_tree_int (cst, offset_limit) > 0) return; osi->depths[SSA_NAME_VERSION (basevar)] = 1; @@ -1334,17 +1434,17 @@ object_sizes_execute (function *fun, bool insert_min_max_p) || TREE_CODE (ptr) == SSA_NAME)) { tree type = TREE_TYPE (lhs); - unsigned HOST_WIDE_INT bytes; + tree bytes; if (compute_builtin_object_size (ptr, object_size_type, &bytes) - && wi::fits_to_tree_p (bytes, type)) + && int_fits_type_p (bytes, type)) { tree tem = make_ssa_name (type); gimple_call_set_lhs (call, tem); enum tree_code code = (object_size_type & OST_MINIMUM ? MAX_EXPR : MIN_EXPR); - tree cst = build_int_cstu (type, bytes); + tree cst = fold_convert (type, bytes); gimple *g = gimple_build_assign (lhs, code, tem, cst); gsi_insert_after (&i, g, GSI_NEW_STMT); diff --git a/gcc/tree-object-size.h b/gcc/tree-object-size.h index ef18aea50db..b2d6a58324c 100644 --- a/gcc/tree-object-size.h +++ b/gcc/tree-object-size.h @@ -22,7 +22,7 @@ along with GCC; see the file COPYING3. If not see extern void init_object_sizes (void); extern void fini_object_sizes (void); -extern bool compute_builtin_object_size (tree, int, unsigned HOST_WIDE_INT *); +extern bool compute_builtin_object_size (tree, int, tree *); extern tree decl_init_size (tree, bool); #endif // GCC_TREE_OBJECT_SIZE_H diff --git a/gcc/ubsan.c b/gcc/ubsan.c index ba9adf0ad96..364cf174bf0 100644 --- a/gcc/ubsan.c +++ b/gcc/ubsan.c @@ -2160,9 +2160,8 @@ instrument_object_size (gimple_stmt_iterator *gsi, tree t, bool is_lhs) if (decl_p) base_addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (base)), base); - unsigned HOST_WIDE_INT size; - if (compute_builtin_object_size (base_addr, 0, &size)) - sizet = build_int_cst (sizetype, size); + if (compute_builtin_object_size (base_addr, 0, &sizet)) + ; else if (optimize) { if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION) From patchwork Fri Nov 26 05:28:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 48172 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id F20573858036 for ; Fri, 26 Nov 2021 05:31:40 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from beige.elm.relay.mailchannels.net (beige.elm.relay.mailchannels.net [23.83.212.16]) by sourceware.org (Postfix) with ESMTPS id 0E8603857C5B for ; Fri, 26 Nov 2021 05:29:18 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 0E8603857C5B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 818A73410CF; Fri, 26 Nov 2021 05:29:17 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 2431634123E; Fri, 26 Nov 2021 05:29:16 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.111.70.137 (trex/6.4.3); Fri, 26 Nov 2021 05:29:17 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Thread-Stretch: 5e484a9d4f0466ff_1637904557248_3040913036 X-MC-Loop-Signature: 1637904557248:4234907581 X-MC-Ingress-Time: 1637904557248 Received: from rhbox.intra.reserved-bit.com (unknown [1.186.223.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4J0jwV0D4mz1QQ; Thu, 25 Nov 2021 21:29:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1637904555; bh=L5pPTAz08N1iluwenmlJG1pVpbc=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=nXvXWw4D7O5wUAoDyxe7lE006gp9LIfvdAeaELfYMDAEane3zKlGsQoQ9d1HqbSxV qoTP+dXEbYKPLEWA4D+jr0inRmnyTz1ZVqzK6C2twc7uBJqzoAgfYkFHKgoxkWVFXO 4sO5DFImDiFYEKQxjJ/YodtStafUPOYJhW/Q52d4= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v3 4/8] __builtin_dynamic_object_size: Recognize builtin Date: Fri, 26 Nov 2021 10:58:47 +0530 Message-Id: <20211126052851.2176408-5-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211126052851.2176408-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211126052851.2176408-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3028.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP, UNWANTED_LANGUAGE_BODY autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Recognize the __builtin_dynamic_object_size builtin and add paths in the object size path to deal with it, but treat it like __builtin_object_size for now. Also add tests to provide the same testing coverage for the new builtin name. gcc/ChangeLog: * builtins.def (BUILT_IN_DYNAMIC_OBJECT_SIZE): New builtin. * tree-object-size.h: Move object size type bits enum from tree-object-size.c and add new value OST_DYNAMIC. * builtins.c (expand_builtin, fold_builtin_2): Handle it. (fold_builtin_object_size): Handle new builtin and adjust for change to compute_builtin_object_size. * tree-object-size.c: Include builtins.h. (compute_builtin_object_size): Adjust. (early_object_sizes_execute_one, dynamic_object_sizes_execute_one): New functions. (object_sizes_execute): Rename insert_min_max_p argument to early. Handle BUILT_IN_DYNAMIC_OBJECT_SIZE and call the new functions. doc/extend.texi (__builtin_dynamic_object_size): Document new builtin. gcc/testsuite/ChangeLog: * g++.dg/ext/builtin-dynamic-object-size1.C: New test. * g++.dg/ext/builtin-dynamic-object-size2.C: Likewise. * gcc.dg/builtin-dynamic-alloc-size.c: Likewise. * gcc.dg/builtin-dynamic-object-size-1.c: Likewise. * gcc.dg/builtin-dynamic-object-size-10.c: Likewise. * gcc.dg/builtin-dynamic-object-size-11.c: Likewise. * gcc.dg/builtin-dynamic-object-size-12.c: Likewise. * gcc.dg/builtin-dynamic-object-size-13.c: Likewise. * gcc.dg/builtin-dynamic-object-size-14.c: Likewise. * gcc.dg/builtin-dynamic-object-size-15.c: Likewise. * gcc.dg/builtin-dynamic-object-size-16.c: Likewise. * gcc.dg/builtin-dynamic-object-size-17.c: Likewise. * gcc.dg/builtin-dynamic-object-size-18.c: Likewise. * gcc.dg/builtin-dynamic-object-size-19.c: Likewise. * gcc.dg/builtin-dynamic-object-size-2.c: Likewise. * gcc.dg/builtin-dynamic-object-size-3.c: Likewise. * gcc.dg/builtin-dynamic-object-size-4.c: Likewise. * gcc.dg/builtin-dynamic-object-size-5.c: Likewise. * gcc.dg/builtin-dynamic-object-size-6.c: Likewise. * gcc.dg/builtin-dynamic-object-size-7.c: Likewise. * gcc.dg/builtin-dynamic-object-size-8.c: Likewise. * gcc.dg/builtin-dynamic-object-size-9.c: Likewise. * gcc.dg/builtin-object-size-16.c: Adjust to allow inclusion from builtin-dynamic-object-size-16.c. * gcc.dg/builtin-object-size-17.c: Likewise. Signed-off-by: Siddhesh Poyarekar --- Changes from v2: - Incorporated review suggestions. gcc/builtins.c | 11 +- gcc/builtins.def | 1 + gcc/doc/extend.texi | 13 ++ .../g++.dg/ext/builtin-dynamic-object-size1.C | 5 + .../g++.dg/ext/builtin-dynamic-object-size2.C | 5 + .../gcc.dg/builtin-dynamic-alloc-size.c | 7 + .../gcc.dg/builtin-dynamic-object-size-1.c | 6 + .../gcc.dg/builtin-dynamic-object-size-10.c | 9 ++ .../gcc.dg/builtin-dynamic-object-size-11.c | 7 + .../gcc.dg/builtin-dynamic-object-size-12.c | 5 + .../gcc.dg/builtin-dynamic-object-size-13.c | 5 + .../gcc.dg/builtin-dynamic-object-size-14.c | 5 + .../gcc.dg/builtin-dynamic-object-size-15.c | 5 + .../gcc.dg/builtin-dynamic-object-size-16.c | 6 + .../gcc.dg/builtin-dynamic-object-size-17.c | 7 + .../gcc.dg/builtin-dynamic-object-size-18.c | 8 + .../gcc.dg/builtin-dynamic-object-size-19.c | 104 ++++++++++++ .../gcc.dg/builtin-dynamic-object-size-2.c | 6 + .../gcc.dg/builtin-dynamic-object-size-3.c | 6 + .../gcc.dg/builtin-dynamic-object-size-4.c | 6 + .../gcc.dg/builtin-dynamic-object-size-5.c | 7 + .../gcc.dg/builtin-dynamic-object-size-6.c | 5 + .../gcc.dg/builtin-dynamic-object-size-7.c | 5 + .../gcc.dg/builtin-dynamic-object-size-8.c | 5 + .../gcc.dg/builtin-dynamic-object-size-9.c | 5 + gcc/testsuite/gcc.dg/builtin-object-size-16.c | 2 + gcc/testsuite/gcc.dg/builtin-object-size-17.c | 2 + gcc/tree-object-size.c | 152 +++++++++++++----- gcc/tree-object-size.h | 10 ++ 29 files changed, 378 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size1.C create mode 100644 gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size2.C create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-alloc-size.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-11.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-12.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-13.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-14.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-15.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-16.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-17.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-18.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-19.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-6.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-7.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-8.c create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-9.c diff --git a/gcc/builtins.c b/gcc/builtins.c index 50e66692775..573f7e9b9df 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -178,7 +178,7 @@ static rtx expand_builtin_memory_chk (tree, rtx, machine_mode, enum built_in_function); static void maybe_emit_chk_warning (tree, enum built_in_function); static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function); -static tree fold_builtin_object_size (tree, tree); +static tree fold_builtin_object_size (tree, tree, enum built_in_function); unsigned HOST_WIDE_INT target_newline; unsigned HOST_WIDE_INT target_percent; @@ -7880,6 +7880,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, return const0_rtx; case BUILT_IN_OBJECT_SIZE: + case BUILT_IN_DYNAMIC_OBJECT_SIZE: return expand_builtin_object_size (exp); case BUILT_IN_MEMCPY_CHK: @@ -9286,7 +9287,8 @@ fold_builtin_2 (location_t loc, tree expr, tree fndecl, tree arg0, tree arg1) break; case BUILT_IN_OBJECT_SIZE: - return fold_builtin_object_size (arg0, arg1); + case BUILT_IN_DYNAMIC_OBJECT_SIZE: + return fold_builtin_object_size (arg0, arg1, fcode); case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE: return fold_builtin_atomic_always_lock_free (arg0, arg1); @@ -10224,7 +10226,7 @@ maybe_emit_sprintf_chk_warning (tree exp, enum built_in_function fcode) if possible. */ static tree -fold_builtin_object_size (tree ptr, tree ost) +fold_builtin_object_size (tree ptr, tree ost, enum built_in_function fcode) { tree bytes; int object_size_type; @@ -10248,6 +10250,9 @@ fold_builtin_object_size (tree ptr, tree ost) if (TREE_SIDE_EFFECTS (ptr)) return build_int_cst_type (size_type_node, object_size_type < 2 ? -1 : 0); + if (fcode == BUILT_IN_DYNAMIC_OBJECT_SIZE) + object_size_type |= OST_DYNAMIC; + if (TREE_CODE (ptr) == ADDR_EXPR) { compute_builtin_object_size (ptr, object_size_type, &bytes); diff --git a/gcc/builtins.def b/gcc/builtins.def index 45a09b4d42d..a92948de2b8 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -972,6 +972,7 @@ DEF_BUILTIN_STUB (BUILT_IN_STRNCMP_EQ, "__builtin_strncmp_eq") /* Object size checking builtins. */ DEF_GCC_BUILTIN (BUILT_IN_OBJECT_SIZE, "object_size", BT_FN_SIZE_CONST_PTR_INT, ATTR_CONST_NOTHROW_LEAF_LIST) +DEF_GCC_BUILTIN (BUILT_IN_DYNAMIC_OBJECT_SIZE, "dynamic_object_size", BT_FN_SIZE_CONST_PTR_INT, ATTR_PURE_NOTHROW_LEAF_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMCPY_CHK, "__memcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF) DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMMOVE_CHK, "__memmove_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_NOTHROW_NONNULL_LEAF) DEF_EXT_LIB_BUILTIN (BUILT_IN_MEMPCPY_CHK, "__mempcpy_chk", BT_FN_PTR_PTR_CONST_PTR_SIZE_SIZE, ATTR_RETNONNULL_NOTHROW_LEAF) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index ef654d7b878..7bb3c5b3410 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -12712,6 +12712,7 @@ __atomic_store_n(&lockvar, 0, __ATOMIC_RELEASE|__ATOMIC_HLE_RELEASE); @node Object Size Checking @section Object Size Checking Built-in Functions @findex __builtin_object_size +@findex __builtin_dynamic_object_size @findex __builtin___memcpy_chk @findex __builtin___mempcpy_chk @findex __builtin___memmove_chk @@ -12779,6 +12780,18 @@ assert (__builtin_object_size (q, 1) == sizeof (var.b)); @end smallexample @end deftypefn +@deftypefn {Built-in Function} {size_t} __builtin_dynamic_object_size (const void * @var{ptr}, int @var{type}) +is similar to @code{__builtin_object_size} in that it returns a number of bytes +from @var{ptr} to the end of the object @var{ptr} pointer points to, except +that the size returned may not be a constant. This results in successful +evaluation of object size estimates in a wider range of use cases and can be +more precise than @code{__builtin_object_size}, but it incurs a performance +penalty since it may add a runtime overhead on size computation. Semantics of +@var{type} as well as return values in case it is not possible to determine +which objects @var{ptr} points to at compile time are the same as in the case +of @code{__builtin_object_size}. +@end deftypefn + There are built-in functions added for many common string operation functions, e.g., for @code{memcpy} @code{__builtin___memcpy_chk} built-in is provided. This built-in has an additional last argument, diff --git a/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size1.C b/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size1.C new file mode 100644 index 00000000000..b11ac200751 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size1.C @@ -0,0 +1,5 @@ +// { dg-do run } +// { dg-options "-O2" } + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size1.C" diff --git a/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size2.C b/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size2.C new file mode 100644 index 00000000000..6e52cf38533 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/builtin-dynamic-object-size2.C @@ -0,0 +1,5 @@ +// { dg-do run } +// { dg-options "-O2" } + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size2.C" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-alloc-size.c b/gcc/testsuite/gcc.dg/builtin-dynamic-alloc-size.c new file mode 100644 index 00000000000..9d0eadd6be4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-alloc-size.c @@ -0,0 +1,7 @@ +/* { dg-do compile } + { dg-require-effective-target alloca } + { dg-additional-options "-O2 -fdump-tree-optimized" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-alloc-size.c" +/* { dg-final { scan-tree-dump-not "abort" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c new file mode 100644 index 00000000000..7cc8b1c9488 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-1.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target alloca } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-1.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c new file mode 100644 index 00000000000..bc880a589ae --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-early_objsz-details" } */ +// { dg-skip-if "packed attribute missing for drone_source_packet" { "epiphany-*-*" } } + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-10.c" + +/* { dg-final { scan-tree-dump "maximum object size 21" "early_objsz" } } */ +/* { dg-final { scan-tree-dump "maximum subobject size 16" "early_objsz" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-11.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-11.c new file mode 100644 index 00000000000..65dcec9fcae --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-11.c @@ -0,0 +1,7 @@ +/* PR48985 */ +/* { dg-do run } */ +/* { dg-options "-std=gnu89" } */ +/* { dg-skip-if "packed attribute missing for struct s" { "epiphany-*-*" } } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-11.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-12.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-12.c new file mode 100644 index 00000000000..f0ce050a943 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-12.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-12.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-13.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-13.c new file mode 100644 index 00000000000..555e23522dc --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-13.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-13.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-14.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-14.c new file mode 100644 index 00000000000..26207200191 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-14.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-14.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-15.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-15.c new file mode 100644 index 00000000000..cd8a941438d --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-15.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-15.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-16.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-16.c new file mode 100644 index 00000000000..cc775089410 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-16.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O0" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +char ax2[]; /* { dg-warning "assumed to have one element" } */ +#include "builtin-object-size-16.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-17.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-17.c new file mode 100644 index 00000000000..f5c57a8788d --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-17.c @@ -0,0 +1,7 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -fdump-tree-ssa" } */ + +char ax2[]; /* { dg-warning "assumed to have one element" } */ +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-17.c" +/* { dg-final { scan-tree-dump-not "failure_on_line" "ssa" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-18.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-18.c new file mode 100644 index 00000000000..70c1ebcff21 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-18.c @@ -0,0 +1,8 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* __stpncpy_chk could return buf up to buf + 64, so + the minimum object size might be far smaller than 64. */ +/* { dg-final { scan-tree-dump-not "return 64;" "optimized" } } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-18.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-19.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-19.c new file mode 100644 index 00000000000..44141a38607 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-19.c @@ -0,0 +1,104 @@ +/* PR tree-optimization/88372 - alloc_size attribute is ignored + on function pointers { dg-do compile } + { dg-options "-O2 -fdump-tree-optimized" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-18.c" + +typedef __SIZE_TYPE__ size_t; + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) +#define CONCAT(x, y) x ## y +#define CAT(x, y) CONCAT (x, y) +#define FAILNAME(name) CAT (call_ ## name ##_on_line_, __LINE__) + +#define FAIL(name) do { \ + extern void FAILNAME (name) (void); \ + FAILNAME (name)(); \ + } while (0) + +/* Macro to emit a call to function named + call_in_true_branch_not_eliminated_on_line_NNN() + for each call that's expected to be eliminated. The dg-final + scan-tree-dump-time directive at the bottom of the test verifies + that no such call appears in output. */ +#define ELIM(expr) \ + if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0 + +void sink (void*); + +#define T(alloc, n) do { \ + void *p = alloc; \ + sink (p); \ + ELIM (n == __builtin_object_size (p, 0)); \ + ELIM (n == __builtin_object_size (p, 1)); \ + ELIM (n == __builtin_object_size (p, 2)); \ + ELIM (n == __builtin_object_size (p, 3)); \ + } while (0) + + +ATTR (alloc_size (1)) void* (*alloc_1_x)(size_t, size_t); +ATTR (alloc_size (2)) void* (*alloc_x_2)(size_t, size_t); + +/* Verify that things work when attribute alloc_size is applied + to a typedef that is then used to declared a pointer. */ +typedef ATTR (alloc_size (1, 2)) void* (alloc_1_2_t)(size_t, size_t); + +void test_alloc_ptr (alloc_1_2_t *alloc_1_2) +{ + T (alloc_1_x (0, 0), 0); + T (alloc_1_x (1, 0), 1); + T (alloc_1_x (3, 0), 3); + T (alloc_1_x (9, 5), 9); + + T (alloc_x_2 (0, 0), 0); + T (alloc_x_2 (1, 0), 0); + T (alloc_x_2 (0, 1), 1); + T (alloc_x_2 (9, 5), 5); + + T (alloc_1_2 (0, 0), 0); + T (alloc_1_2 (1, 0), 0); + T (alloc_1_2 (0, 1), 0); + T (alloc_1_2 (9, 5), 45); +} + +/* Verify that object size is detected even in indirect calls via + function pointers to built-in allocation functions, even without + explicit use of attribute alloc_size on the pointers. */ + +typedef void *(allocfn_1) (size_t); +typedef void *(allocfn_1_2) (size_t, size_t); + +static inline void * +call_alloc (allocfn_1 *fn1, allocfn_1_2 *fn2, size_t n1, size_t n2) +{ + return fn1 ? fn1 (n1) : fn2 (n1, n2); +} + +static inline void * +call_malloc (size_t n) +{ + return call_alloc (__builtin_malloc, 0, n, 0); +} + +static inline void * +call_calloc (size_t n1, size_t n2) +{ + return call_alloc (0, __builtin_calloc, n1, n2); +} + +void test_builtin_ptr (void) +{ + T (call_malloc (0), 0); + T (call_malloc (1), 1); + T (call_malloc (9), 9); + + T (call_calloc (0, 0), 0); + T (call_calloc (0, 1), 0); + T (call_calloc (1, 0), 0); + T (call_calloc (1, 1), 1); + T (call_calloc (1, 3), 3); + T (call_calloc (2, 3), 6); +} + +/* { dg-final { scan-tree-dump-not "not_eliminated" "optimized" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c new file mode 100644 index 00000000000..267dbf48ca7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-2.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target alloca } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-2.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c new file mode 100644 index 00000000000..fb9dc56da7e --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-3.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target alloca } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-3.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c new file mode 100644 index 00000000000..870548b4206 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-4.c @@ -0,0 +1,6 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ +/* { dg-require-effective-target alloca } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-4.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c new file mode 100644 index 00000000000..698b03c34be --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-5.c @@ -0,0 +1,7 @@ +/* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-5.c" + +/* { dg-final { scan-assembler-not "abort" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-6.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-6.c new file mode 100644 index 00000000000..6a275ce5b37 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-6.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-6.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-7.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-7.c new file mode 100644 index 00000000000..e2a65994687 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-7.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-7.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-8.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-8.c new file mode 100644 index 00000000000..e7af383d9b6 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-8.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-8.c" diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-9.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-9.c new file mode 100644 index 00000000000..19021bc2ce9 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-9.c @@ -0,0 +1,5 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +#define __builtin_object_size __builtin_dynamic_object_size +#include "builtin-object-size-9.c" diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-16.c b/gcc/testsuite/gcc.dg/builtin-object-size-16.c index 48229390bfd..f26d5d97a5e 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-16.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-16.c @@ -54,7 +54,9 @@ static int nfails; typedef __SIZE_TYPE__ size_t; extern char ax[]; +#ifndef __builtin_object_size char ax2[]; /* { dg-warning "assumed to have one element" } */ +#endif extern char a0[0]; static char a1[1]; diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-17.c b/gcc/testsuite/gcc.dg/builtin-object-size-17.c index 0497bbf4505..28f8414636b 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-17.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-17.c @@ -49,7 +49,9 @@ typedef __SIZE_TYPE__ size_t; extern char ax[]; +#ifndef __builtin_object_size char ax2[]; /* { dg-warning "assumed to have one element" } */ +#endif extern char a0[0]; static char a1[1]; diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 1a1e3d56126..969e01e70fb 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-cfg.h" #include "stringpool.h" #include "attribs.h" +#include "builtins.h" struct object_size_info { @@ -45,13 +46,6 @@ struct object_size_info unsigned int *stack, *tos; }; -enum -{ - OST_SUBOBJECT = 1, - OST_MINIMUM = 2, - OST_END = 4, -}; - static tree compute_object_offset (const_tree, const_tree); static bool addr_object_size (struct object_size_info *, const_tree, int, tree *, tree *t = NULL); @@ -755,8 +749,9 @@ compute_builtin_object_size (tree ptr, int object_size_type, object_sizes_grow (object_size_type); if (dump_file) { - fprintf (dump_file, "Computing %s %sobject size for ", + fprintf (dump_file, "Computing %s %s%sobject size for ", (object_size_type & OST_MINIMUM) ? "minimum" : "maximum", + (object_size_type & OST_DYNAMIC) ? "dynamic " : "", (object_size_type & OST_SUBOBJECT) ? "sub" : ""); print_generic_expr (dump_file, ptr, dump_flags); fprintf (dump_file, ":\n"); @@ -845,9 +840,10 @@ compute_builtin_object_size (tree ptr, int object_size_type, print_generic_expr (dump_file, ssa_name (i), dump_flags); fprintf (dump_file, - ": %s %sobject size ", + ": %s %s%sobject size ", ((object_size_type & OST_MINIMUM) ? "minimum" : "maximum"), + (object_size_type & OST_DYNAMIC) ? "dynamic " : "", (object_size_type & OST_SUBOBJECT) ? "sub" : ""); print_generic_expr (dump_file, object_sizes_get (&osi, i), dump_flags); @@ -1397,8 +1393,85 @@ do_valueize (tree t) return t; } +/* Process a __builtin_object_size or __builtin_dynamic_object_size call in + CALL early for subobjects before any object information is lost due to + optimization. Insert a MIN or MAX expression of the result and + __builtin_object_size at I so that it may be processed in the second pass. + __builtin_dynamic_object_size is treated like __builtin_object_size here + since we're only looking for constant bounds. */ + +static void +early_object_sizes_execute_one (gimple_stmt_iterator *i, gimple *call) +{ + tree ost = gimple_call_arg (call, 1); + tree lhs = gimple_call_lhs (call); + gcc_assert (lhs != NULL_TREE); + + if (!tree_fits_uhwi_p (ost)) + return; + + unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost); + tree ptr = gimple_call_arg (call, 0); + + if (object_size_type != 1 && object_size_type != 3) + return; + + if (TREE_CODE (ptr) != ADDR_EXPR && TREE_CODE (ptr) != SSA_NAME) + return; + + tree type = TREE_TYPE (lhs); + tree bytes; + if (!compute_builtin_object_size (ptr, object_size_type, &bytes) + || !int_fits_type_p (bytes, type)) + return; + + tree tem = make_ssa_name (type); + gimple_call_set_lhs (call, tem); + enum tree_code code = object_size_type & OST_MINIMUM ? MAX_EXPR : MIN_EXPR; + tree cst = fold_convert (type, bytes); + gimple *g = gimple_build_assign (lhs, code, tem, cst); + gsi_insert_after (i, g, GSI_NEW_STMT); + update_stmt (call); +} + +/* Attempt to fold one __builtin_dynamic_object_size call in CALL into an + expression and insert it at I. Return true if it succeeds. */ + +static bool +dynamic_object_sizes_execute_one (gimple_stmt_iterator *i, gimple *call) +{ + gcc_assert (gimple_call_num_args (call) == 2); + + tree args[2]; + args[0] = gimple_call_arg (call, 0); + args[1] = gimple_call_arg (call, 1); + + location_t loc = EXPR_LOC_OR_LOC (args[0], input_location); + tree result_type = gimple_call_return_type (as_a (call)); + tree result = fold_builtin_call_array (loc, result_type, + gimple_call_fn (call), 2, args); + + if (!result) + return false; + + /* fold_builtin_call_array may wrap the result inside a + NOP_EXPR. */ + STRIP_NOPS (result); + gimplify_and_update_call_from_tree (i, result); + + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, "Simplified (dynamic)\n "); + print_gimple_stmt (dump_file, call, 0, dump_flags); + fprintf (dump_file, " to "); + print_generic_expr (dump_file, result); + fprintf (dump_file, "\n"); + } + return true; +} + static unsigned int -object_sizes_execute (function *fun, bool insert_min_max_p) +object_sizes_execute (function *fun, bool early) { basic_block bb; FOR_EACH_BB_FN (bb, fun) @@ -1407,8 +1480,12 @@ object_sizes_execute (function *fun, bool insert_min_max_p) for (i = gsi_start_bb (bb); !gsi_end_p (i); gsi_next (&i)) { tree result; + bool dynamic = false; + gimple *call = gsi_stmt (i); - if (!gimple_call_builtin_p (call, BUILT_IN_OBJECT_SIZE)) + if (gimple_call_builtin_p (call, BUILT_IN_DYNAMIC_OBJECT_SIZE)) + dynamic = true; + else if (!gimple_call_builtin_p (call, BUILT_IN_OBJECT_SIZE)) continue; tree lhs = gimple_call_lhs (call); @@ -1417,42 +1494,39 @@ object_sizes_execute (function *fun, bool insert_min_max_p) init_object_sizes (); - /* If insert_min_max_p, only attempt to fold + /* If early, only attempt to fold __builtin_object_size (x, 1) and __builtin_object_size (x, 3), and rather than folding the builtin to the constant if any, create a MIN_EXPR or MAX_EXPR of the __builtin_object_size - call result and the computed constant. */ - if (insert_min_max_p) + call result and the computed constant. Do the same for + __builtin_dynamic_object_size too. */ + if (early) { - tree ost = gimple_call_arg (call, 1); - if (tree_fits_uhwi_p (ost)) + early_object_sizes_execute_one (&i, call); + continue; + } + + if (dynamic) + { + if (dynamic_object_sizes_execute_one (&i, call)) + continue; + else { - unsigned HOST_WIDE_INT object_size_type = tree_to_uhwi (ost); - tree ptr = gimple_call_arg (call, 0); - if ((object_size_type & OST_SUBOBJECT) - && (TREE_CODE (ptr) == ADDR_EXPR - || TREE_CODE (ptr) == SSA_NAME)) + /* If we could not find a suitable size expression, lower to + __builtin_object_size so that we may at least get a + constant lower or higher estimate. */ + tree bosfn = builtin_decl_implicit (BUILT_IN_OBJECT_SIZE); + gimple_call_set_fndecl (call, bosfn); + update_stmt (call); + + if (dump_file && (dump_flags & TDF_DETAILS)) { - tree type = TREE_TYPE (lhs); - tree bytes; - if (compute_builtin_object_size (ptr, object_size_type, - &bytes) - && int_fits_type_p (bytes, type)) - { - tree tem = make_ssa_name (type); - gimple_call_set_lhs (call, tem); - enum tree_code code - = (object_size_type & OST_MINIMUM - ? MAX_EXPR : MIN_EXPR); - tree cst = fold_convert (type, bytes); - gimple *g - = gimple_build_assign (lhs, code, tem, cst); - gsi_insert_after (&i, g, GSI_NEW_STMT); - update_stmt (call); - } + print_generic_expr (dump_file, gimple_call_arg (call, 0), + dump_flags); + fprintf (dump_file, + ": Retrying as __builtin_object_size\n"); } } - continue; } result = gimple_fold_stmt_to_constant (call, do_valueize); diff --git a/gcc/tree-object-size.h b/gcc/tree-object-size.h index b2d6a58324c..f4f438c10a8 100644 --- a/gcc/tree-object-size.h +++ b/gcc/tree-object-size.h @@ -20,6 +20,16 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_TREE_OBJECT_SIZE_H #define GCC_TREE_OBJECT_SIZE_H +/* Bits in object_size_type. */ + +enum +{ + OST_SUBOBJECT = 1, + OST_MINIMUM = 2, + OST_DYNAMIC = 4, + OST_END = 8, +}; + extern void init_object_sizes (void); extern void fini_object_sizes (void); extern bool compute_builtin_object_size (tree, int, tree *); From patchwork Fri Nov 26 05:28:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 48174 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 88AC83857823 for ; Fri, 26 Nov 2021 05:32:46 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from bee.birch.relay.mailchannels.net (bee.birch.relay.mailchannels.net [23.83.209.14]) by sourceware.org (Postfix) with ESMTPS id BB9593857C5E for ; Fri, 26 Nov 2021 05:29:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org BB9593857C5E Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 4C3741A0B6E; Fri, 26 Nov 2021 05:29:19 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id D3F081A0BBE; Fri, 26 Nov 2021 05:29:18 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.124.138.98 (trex/6.4.3); Fri, 26 Nov 2021 05:29:19 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Eight-Stretch: 60eec6912c066451_1637904559142_383929205 X-MC-Loop-Signature: 1637904559142:513029313 X-MC-Ingress-Time: 1637904559142 Received: from rhbox.intra.reserved-bit.com (unknown [1.186.223.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4J0jwX4qp6z1V0; Thu, 25 Nov 2021 21:29:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1637904558; bh=vA1t1bdD8KcuGXJ1fPbPEnxRNjY=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=wMcfqRnENL+ok86Ubrl2iMBrlPy5bbkthRWuPfgajtI89/C3KBv4sCTKFG/ghO+sL eMKz03udhtuPwUEZhUTmoJaFcThL25mt4kbOCyLhQ9GAb6Ath6iuLAKE2O53hNU4H1 Og3USpVF7/UsNtnZzmQ4bF/iTBUsKxr9WIb1uoTU= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v3 5/8] tree-object-size: Support dynamic sizes in conditions Date: Fri, 26 Nov 2021 10:58:48 +0530 Message-Id: <20211126052851.2176408-6-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211126052851.2176408-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211126052851.2176408-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Handle GIMPLE_PHI and conditionals specially for dynamic objects, returning PHI/conditional expressions instead of just a MIN/MAX estimate. This makes the returned object size variable for loops and conditionals, so tests need to be adjusted to look for precise size in some cases. builtin-dynamic-object-size-5.c had to be modified to only look for success in maximum object size case and skip over the minimum object size tests because the result is no longer a compile time constant. I also added some simple tests to exercise conditionals with dynamic object sizes. gcc/ChangeLog: * builtins.c (fold_builtin_object_size): Adjust for dynamic size expressions. * tree-object-size.c: Include gimplify-me.h. (struct object_size_info): New member UNKNOWNS. (size_initval_p, object_sizes_get_raw): New functions. (object_sizes_get): Return suitable gimple variable for object size. (object_sizes_initialize): Reuse existing object size TREE_VEC during gimplification. (bundle_sizes): New function. (object_sizes_set): Use it and handle dynamic object size expressions. (object_sizes_set_temp): New function. (size_for_offset): Adjust for dynamic size expressions. (emit_phi_nodes, propagate_unknowns, gimplify_size_expressions): New functions. (compute_builtin_object_size): Call gimplify_size_expressions for OST_DYNAMIC. (dynamic_object_size): New function. (cond_expr_object_size): Use it. (phi_dynamic_object_size): New function. (collect_object_sizes_for): Call it for OST_DYNAMIC. Adjust to accommodate dynamic object sizes. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: New tests. * gcc.dg/builtin-dynamic-object-size-10.c: Add comment. * gcc.dg/builtin-object-size-1.c [__builtin_object_size]: Expect exact size expressions for __builtin_dynamic_object_size. * gcc.dg/builtin-object-size-2.c [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-3.c [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-4.c [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-5.c [__builtin_object_size]: Likewise. Signed-off-by: Siddhesh Poyarekar --- Changes from v2: - Incorporated review suggestions. - Delay generating PHI nodes until gimplification so that it doesn't have to be undone if it was found to be unknown. - Adapt to retaining the multipass approach for static object sizes. gcc/builtins.c | 6 +- .../gcc.dg/builtin-dynamic-object-size-0.c | 72 +++ .../gcc.dg/builtin-dynamic-object-size-10.c | 2 + gcc/testsuite/gcc.dg/builtin-object-size-1.c | 119 ++++- gcc/testsuite/gcc.dg/builtin-object-size-2.c | 92 ++++ gcc/testsuite/gcc.dg/builtin-object-size-3.c | 121 +++++ gcc/testsuite/gcc.dg/builtin-object-size-4.c | 78 +++ gcc/testsuite/gcc.dg/builtin-object-size-5.c | 12 + gcc/tree-object-size.c | 494 +++++++++++++++++- 9 files changed, 966 insertions(+), 30 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c diff --git a/gcc/builtins.c b/gcc/builtins.c index 573f7e9b9df..9770e13353d 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -10256,7 +10256,8 @@ fold_builtin_object_size (tree ptr, tree ost, enum built_in_function fcode) if (TREE_CODE (ptr) == ADDR_EXPR) { compute_builtin_object_size (ptr, object_size_type, &bytes); - if (int_fits_type_p (bytes, size_type_node)) + if ((object_size_type & OST_DYNAMIC) + || int_fits_type_p (bytes, size_type_node)) return fold_convert (size_type_node, bytes); } else if (TREE_CODE (ptr) == SSA_NAME) @@ -10265,7 +10266,8 @@ fold_builtin_object_size (tree ptr, tree ost, enum built_in_function fcode) later. Maybe subsequent passes will help determining it. */ if (compute_builtin_object_size (ptr, object_size_type, &bytes) - && int_fits_type_p (bytes, size_type_node)) + && ((object_size_type & OST_DYNAMIC) + || int_fits_type_p (bytes, size_type_node))) return fold_convert (size_type_node, bytes); } diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c new file mode 100644 index 00000000000..ddedf6a49bd --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -0,0 +1,72 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +typedef __SIZE_TYPE__ size_t; +#define abort __builtin_abort + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi (int cond) +{ + void *ret; + + if (cond) + ret = __builtin_malloc (32); + else + ret = __builtin_malloc (64); + + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) +{ + struct + { + int a; + char b; + } bin[cnt]; + + char *ch = __builtin_calloc (cnt, sz); + + return __builtin_dynamic_object_size (cond ? ch : (void *) &bin, 0); +} + +size_t +__attribute__ ((noinline)) +test_deploop (size_t sz, size_t cond) +{ + char *bin = __builtin_alloca (32); + + for (size_t i = 0; i < sz; i++) + if (i == cond) + bin = __builtin_alloca (64); + + return __builtin_dynamic_object_size (bin, 0); +} + +unsigned nfails = 0; + +#define FAIL() ({ \ + __builtin_printf ("Failure at line: %d\n", __LINE__); \ + nfails++; \ +}) + +int +main (int argc, char **argv) +{ + if (test_builtin_malloc_condphi (1) != 32) + FAIL (); + if (test_builtin_malloc_condphi (0) != 64) + FAIL (); + if (test_builtin_calloc_condphi (128, 1, 0) == 128) + FAIL (); + if (test_deploop (128, 129) != 32) + FAIL (); + + if (nfails > 0) + __builtin_abort (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c index bc880a589ae..3a2d9821a44 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-10.c @@ -5,5 +5,7 @@ #define __builtin_object_size __builtin_dynamic_object_size #include "builtin-object-size-10.c" +/* early_objsz should resolve __builtin_dynamic_object_size like + __builtin_object_size. */ /* { dg-final { scan-tree-dump "maximum object size 21" "early_objsz" } } */ /* { dg-final { scan-tree-dump "maximum subobject size 16" "early_objsz" } } */ diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 0154f4e9695..265c87ed6fb 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -42,9 +42,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 0) != (size_t) -1) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 0) + != (x < 0 + ? sizeof (a) - __builtin_offsetof (struct A, a) - 9 + : sizeof (a) - __builtin_offsetof (struct A, c) - 1)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a) - __builtin_offsetof (struct A, a) - 9) abort (); +#endif if (x < 6) r = &w[2].a[1]; else @@ -58,9 +66,17 @@ test1 (void *q, int x) if (__builtin_object_size (&y.b, 0) != sizeof (a) - __builtin_offsetof (struct A, b)) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 0) + != (x < 6 + ? 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1 + : sizeof (a) - __builtin_offsetof (struct A, a) - 6)) + abort (); +#else if (__builtin_object_size (r, 0) != 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1) abort (); +#endif if (x < 20) r = malloc (30); else @@ -165,6 +181,7 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; + size_t res; if (sizeof (a) != 20) return; @@ -181,7 +198,24 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } - if (__builtin_object_size (r, 0) != 20) +#ifdef __builtin_object_size + res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } +#else + res = 20; +#endif + if (__builtin_object_size (r, 0) != res) abort (); r = &buf3[20]; for (i = 0; i < 4; ++i) @@ -195,13 +229,45 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } - if (__builtin_object_size (r, 0) != 15) +#ifdef __builtin_object_size + res = sizeof (buf3) - 20; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 7; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } + if (__builtin_object_size (r, 0) != res) + abort (); +#else + res = 15; +#endif + if (__builtin_object_size (r, 0) != res) abort (); r += 8; +#ifdef __builtin_object_size + res -= 8; + if (__builtin_object_size (r, 0) != res) + abort (); + if (res >= 6) + { + if (__builtin_object_size (r + 6, 0) != res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 0) != 0) + abort (); +#else if (__builtin_object_size (r, 0) != 7) abort (); if (__builtin_object_size (r + 6, 0) != 1) abort (); +#endif r = &buf3[18]; for (i = 0; i < 4; ++i) { @@ -214,8 +280,31 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef __builtin_object_size + res = sizeof (buf3) - 18; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + else if (i == l1) + res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 9; + else if (i == l1 + 1) + res = sizeof (buf3) - 5; + else if (i == l1 + 2) + res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (res >= 12) + { + if (__builtin_object_size (r + 12, 0) != res - 12) + abort (); + } + else if (__builtin_object_size (r + 12, 0) != 0) + abort (); +#else if (__builtin_object_size (r + 12, 0) != 4) abort (); +#endif } void @@ -358,6 +447,10 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 0) != sizeof (buf) - 8 - 4 * x) + abort (); +#else /* My understanding of ISO C99 6.5.6 is that a conforming program will not end up with p equal to &buf[0] through &buf[7], i.e. calling this function with say @@ -367,6 +460,7 @@ test5 (size_t x) it would be 64 (or conservative (size_t) -1 == unknown). */ if (__builtin_object_size (p, 0) != sizeof (buf) - 8) abort (); +#endif memset (p, ' ', sizeof (buf) - 8 - 4 * 4); } @@ -380,8 +474,13 @@ test6 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 0) != sizeof (t) - 8 - 4 * x) + abort (); +#else if (__builtin_object_size (p, 0) != sizeof (t) - 8) abort (); +#endif memset (p, ' ', sizeof (t) - 8 - 4 * 4); } @@ -436,21 +535,37 @@ test9 (unsigned cond) else p = &buf2[4]; +#ifdef __builtin_object_size + if (__builtin_object_size (&p[-4], 0) != (cond ? 6 : 10)) + abort (); +#else if (__builtin_object_size (&p[-4], 0) != 10) abort (); +#endif for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 0) != ((cond ? 2 : 6) + cond)) + abort (); +#else if (__builtin_object_size (p, 0) != 10) abort (); +#endif p = &y.c[8]; for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 0) + != sizeof (y) - __builtin_offsetof (struct A, c) - 8 + cond) + abort (); +#else if (__builtin_object_size (p, 0) != sizeof (y)) abort (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index 5cf29291aff..5051fea47c3 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -43,8 +43,15 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 1) != (size_t) -1) abort (); +#ifdef __builtin_object_size + if (x < 0 + ? __builtin_object_size (r, 1) != sizeof (a.a) - 9 + : __builtin_object_size (r, 1) != sizeof (a.c) - 1) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a.c) - 1) abort (); +#endif if (x < 6) r = &w[2].a[1]; else @@ -55,8 +62,15 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&y.b, 1) != sizeof (a.b)) abort (); +#ifdef __builtin_object_size + if (x < 6 + ? __builtin_object_size (r, 1) != sizeof (a.a) - 1 + : __builtin_object_size (r, 1) != sizeof (a.a) - 6) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a.a) - 1) abort (); +#endif if (x < 20) r = malloc (30); else @@ -185,6 +199,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef __builtin_object_size + size_t dyn_res; +#endif if (sizeof (a) != 20) return; @@ -201,8 +218,26 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef __builtin_object_size + dyn_res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 9; + } + if (__builtin_object_size (r, 1) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3)) abort (); +#endif r = &buf3[20]; for (i = 0; i < 4; ++i) { @@ -215,13 +250,50 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef __builtin_object_size + dyn_res = sizeof (buf3) - 20; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 7; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 9; + } + if (__builtin_object_size (r, 1) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3) - 5) abort (); +#endif r += 8; +#ifdef __builtin_object_size + if (dyn_res >= 8) + { + dyn_res -= 8; + if (__builtin_object_size (r, 1) != dyn_res) + abort (); + + if (dyn_res >= 6) + { + if (__builtin_object_size (r + 6, 1) != dyn_res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 1) != 0) + abort (); + } + else if (__builtin_object_size (r, 1) != 0) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (buf3) - 13) abort (); if (__builtin_object_size (r + 6, 1) != sizeof (buf3) - 19) abort (); +#endif } void @@ -339,8 +411,13 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 1) != sizeof (t.buf) - 8 - 4 * x) + abort (); +#else if (__builtin_object_size (p, 1) != sizeof (t.buf) - 8) abort (); +#endif memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4); } @@ -394,21 +471,36 @@ test8 (unsigned cond) else p = &buf2[4]; +#ifdef __builtin_object_size + if (__builtin_object_size (&p[-4], 1) != (cond ? 6 : 10)) + abort (); +#else if (__builtin_object_size (&p[-4], 1) != 10) abort (); +#endif for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 1) != ((cond ? 2 : 6) + cond)) + abort (); +#else if (__builtin_object_size (p, 1) != 10) abort (); +#endif p = &y.c[8]; for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 1) != sizeof (y.c) - 8 + cond) + abort (); +#else if (__builtin_object_size (p, 1) != sizeof (y.c)) abort (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index 3a692c4e3d2..1d92627266b 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -71,23 +71,45 @@ test1 (void *q, int x) r = malloc (30); else r = calloc (2, 14); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 2) != (x < 20 ? 30 : 2 * 14)) + abort (); +#else if (__builtin_object_size (r, 2) != 2 * 14) abort (); +#endif if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef __builtin_object_size + size_t objsz = (x < 30 ? sizeof (a) + : sizeof (a) - __builtin_offsetof (struct A, a) - 3); + if (__builtin_object_size (r, 2) != objsz) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3) abort (); +#endif r = memcpy (r, "a", 2); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 2) != objsz) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3) abort (); +#endif r = memcpy (r + 2, "b", 2) + 2; +#ifdef __builtin_object_size + if (__builtin_object_size (r, 2) != objsz - 4) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 3 - 4) abort (); +#endif r = &a.a[4]; r = memset (r, 'a', 2); if (__builtin_object_size (r, 2) @@ -164,6 +186,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef __builtin_object_size + size_t dyn_res; +#endif if (sizeof (a) != 20) return; @@ -180,8 +205,26 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[9]; } +#ifdef __builtin_object_size + dyn_res = sizeof (buf3); + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 7; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + } + if (__builtin_object_size (r, 2) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 2) != 3) abort (); +#endif r = &buf3[20]; for (i = 0; i < 4; ++i) { @@ -208,13 +251,44 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef __builtin_object_size + dyn_res = sizeof (buf3) - 2; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 1; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 2; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (__builtin_object_size (r, 2) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 2) != 15) abort (); +#endif r += 8; +#ifdef __builtin_object_size + dyn_res -= 8; + if (__builtin_object_size (r, 2) != dyn_res) + abort (); + if (dyn_res >= 6) + { + if (__builtin_object_size (r + 6, 2) != dyn_res - 6) + abort (); + } + else if (__builtin_object_size (r + 6, 2) != 0) + abort (); +#else if (__builtin_object_size (r, 2) != 7) abort (); if (__builtin_object_size (r + 6, 2) != 1) abort (); +#endif r = &buf3[18]; for (i = 0; i < 4; ++i) { @@ -227,8 +301,31 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[4]; } +#ifdef __builtin_object_size + dyn_res = sizeof (buf3) - 18; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 9; + else if (i == l1) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf2) - 9; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a) - __builtin_offsetof (struct B, buf1) - 4; + } + if (dyn_res >= 12) + { + if (__builtin_object_size (r + 12, 2) != dyn_res - 12) + abort (); + } + else if (__builtin_object_size (r + 12, 2) != 0) + abort (); +#else if (__builtin_object_size (r + 12, 2) != 0) abort (); +#endif } void @@ -371,7 +468,11 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 2) != sizeof (buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 2) != 0) +#endif abort (); memset (p, ' ', sizeof (buf) - 8 - 4 * 4); } @@ -386,7 +487,11 @@ test6 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 2) != sizeof (t) - 8 - 4 * x) +#else if (__builtin_object_size (p, 2) != 0) +#endif abort (); memset (p, ' ', sizeof (t) - 8 - 4 * 4); } @@ -442,22 +547,38 @@ test9 (unsigned cond) else p = &buf2[4]; +#ifdef __builtin_object_size + if (__builtin_object_size (&p[-4], 2) != (cond ? 6 : 10)) + abort (); +#else if (__builtin_object_size (&p[-4], 2) != 6) abort (); +#endif for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 2) != ((cond ? 2 : 6) + cond)) + abort (); +#else if (__builtin_object_size (p, 2) != 2) abort (); +#endif p = &y.c[8]; for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 2) + != sizeof (y) - __builtin_offsetof (struct A, c) - 8 + cond) + abort (); +#else if (__builtin_object_size (p, 2) != sizeof (y) - __builtin_offsetof (struct A, c) - 8) abort (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index 87381620cc9..9da3537a5f7 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -43,7 +43,12 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 3) != 0) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 3) + != (x < 0 ? sizeof (a.a) - 9 : sizeof (a.c) - 1)) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 9) +#endif abort (); if (x < 6) r = &w[2].a[1]; @@ -55,31 +60,57 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&y.b, 3) != sizeof (a.b)) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 3) + != (x < 6 ? sizeof (w[2].a) - 1 : sizeof (a.a) - 6)) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 6) +#endif abort (); if (x < 20) r = malloc (30); else r = calloc (2, 16); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 3) != (x < 20 ? 30 : 2 * 16)) +#else if (__builtin_object_size (r, 3) != 30) +#endif abort (); if (x < 20) r = malloc (30); else r = calloc (2, 14); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 3) != (x < 20 ? 30 : 2 * 14)) +#else if (__builtin_object_size (r, 3) != 2 * 14) +#endif abort (); if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef __builtin_object_size + size_t objsz = x < 30 ? sizeof (a) : sizeof (a.a) - 3; + if (__builtin_object_size (r, 3) != objsz) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3) +#endif abort (); r = memcpy (r, "a", 2); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 3) != objsz) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3) +#endif abort (); r = memcpy (r + 2, "b", 2) + 2; +#ifdef __builtin_object_size + if (__builtin_object_size (r, 3) != objsz - 4) +#else if (__builtin_object_size (r, 3) != sizeof (a.a) - 3 - 4) +#endif abort (); r = &a.a[4]; r = memset (r, 'a', 2); @@ -184,6 +215,9 @@ test2 (void) struct B { char buf1[10]; char buf2[10]; } a; char *r, buf3[20]; int i; +#ifdef __builtin_object_size + size_t dyn_res = 0; +#endif if (sizeof (a) != 20) return; @@ -228,13 +262,38 @@ test2 (void) else if (i == l1 + 2) r = &a.buf1[2]; } +#ifdef __builtin_object_size + dyn_res = sizeof (buf3) - 1; + + for (i = 0; i < 4; ++i) + { + if (i == l1 - 1) + dyn_res = sizeof (a.buf1) - 6; + else if (i == l1) + dyn_res = sizeof (a.buf2) - 4; + else if (i == l1 + 1) + dyn_res = sizeof (buf3) - 5; + else if (i == l1 + 2) + dyn_res = sizeof (a.buf1) - 2; + } + if (__builtin_object_size (r, 3) != dyn_res) + abort (); +#else if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 6) abort (); +#endif r += 2; +#ifdef __builtin_object_size + if (__builtin_object_size (r, 3) != dyn_res - 2) + abort (); + if (__builtin_object_size (r + 1, 3) != dyn_res - 3) + abort (); +#else if (__builtin_object_size (r, 3) != sizeof (a.buf1) - 6 - 2) abort (); if (__builtin_object_size (r + 1, 3) != sizeof (a.buf1) - 6 - 3) abort (); +#endif } void @@ -352,7 +411,11 @@ test5 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 3) != sizeof (t.buf) - 8 - 4 * x) +#else if (__builtin_object_size (p, 3) != 0) +#endif abort (); memset (p, ' ', sizeof (t.buf) - 8 - 4 * 4); } @@ -407,21 +470,36 @@ test8 (unsigned cond) else p = &buf2[4]; +#ifdef __builtin_object_size + if (__builtin_object_size (&p[-4], 3) != (cond ? 6 : 10)) + abort (); +#else if (__builtin_object_size (&p[-4], 3) != 6) abort (); +#endif for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 3) != ((cond ? 2 : 6) + cond)) + abort (); +#else if (__builtin_object_size (p, 3) != 2) abort (); +#endif p = &y.c[8]; for (unsigned i = cond; i > 0; i--) p--; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 3) != sizeof (y.c) - 8 + cond) + abort (); +#else if (__builtin_object_size (p, 3) != sizeof (y.c) - 8) abort (); +#endif } int diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-5.c b/gcc/testsuite/gcc.dg/builtin-object-size-5.c index 8e63d9c7a5e..904e616949d 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-5.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-5.c @@ -1,5 +1,7 @@ /* { dg-do compile { target i?86-*-linux* i?86-*-gnu* x86_64-*-linux* } } */ /* { dg-options "-O2" } */ +/* For dynamic object sizes we 'succeed' if the returned size is known for + maximum object size. */ typedef __SIZE_TYPE__ size_t; extern void abort (void); @@ -13,7 +15,11 @@ test1 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 0) == -1) +#else if (__builtin_object_size (p, 0) != sizeof (buf) - 8) +#endif abort (); } @@ -25,10 +31,15 @@ test2 (size_t x) for (i = 0; i < x; ++i) p = p + 4; +#ifdef __builtin_object_size + if (__builtin_object_size (p, 1) == -1) +#else if (__builtin_object_size (p, 1) != sizeof (buf) - 8) +#endif abort (); } +#ifndef __builtin_object_size void test3 (size_t x) { @@ -52,6 +63,7 @@ test4 (size_t x) if (__builtin_object_size (p, 3) != 0) abort (); } +#endif void test5 (void) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 969e01e70fb..5b4dcb619cd 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -35,13 +35,14 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "builtins.h" +#include "gimplify-me.h" struct object_size_info { int object_size_type; unsigned char pass; bool changed; - bitmap visited, reexamine; + bitmap visited, reexamine, unknowns; unsigned int *depths; unsigned int *stack, *tos; }; @@ -70,7 +71,11 @@ static void check_for_plus_in_loops_1 (struct object_size_info *, tree, object_sizes[1] is upper bound for the object size and number of bytes till the end of the subobject (innermost array or field with address taken). object_sizes[2] is lower bound for the object size and number of bytes till - the end of the object and object_sizes[3] lower bound for subobject. */ + the end of the object and object_sizes[3] lower bound for subobject. + + For static object sizes, both elements of the TREE_VEC are INTEGER_CST. In + the dynamic case, each element is finally a gimple variable or an + INTEGER_CST. */ static vec object_sizes[OST_END]; /* Bitmaps what object sizes have been computed already. */ @@ -96,6 +101,15 @@ unknown (int object_size_type) return ~initval (object_size_type); } +/* Return true if VAL is represents an initial size for OBJECT_SIZE_TYPE. */ + +static inline bool +size_initval_p (tree val, int object_size_type) +{ + return (tree_fits_uhwi_p (val) + && tree_to_uhwi (val) == initval (object_size_type)); +} + /* Return true if VAL is represents an unknown size for OBJECT_SIZE_TYPE. */ static inline bool @@ -147,14 +161,39 @@ object_sizes_unknown_p (int object_size_type, unsigned varno) object_size_type); } -/* Return size for VARNO corresponding to OSI. If WHOLE is true, return the - whole object size. */ +/* Return the raw size expression for VARNO corresponding to OSI. This returns + the TREE_VEC as is and should only be used during gimplification. */ + +static inline tree +object_sizes_get_raw (struct object_size_info *osi, unsigned varno) +{ + gcc_assert (osi->pass != 0); + return object_sizes[osi->object_size_type][varno]; +} + +/* Return a size tree for VARNO corresponding to OSI. If WHOLE is true, return + the whole object size. Use this for building size expressions based on size + of VARNO. */ static inline tree object_sizes_get (struct object_size_info *osi, unsigned varno, bool whole = false) { - return TREE_VEC_ELT (object_sizes[osi->object_size_type][varno], whole); + tree ret = TREE_VEC_ELT (object_sizes[osi->object_size_type][varno], whole); + int object_size_type = osi->object_size_type; + + if (object_size_type & OST_DYNAMIC) + { + if (TREE_CODE (ret) == MODIFY_EXPR) + return TREE_OPERAND (ret, 0); + else if (TREE_CODE (ret) == TREE_VEC) + return TREE_VEC_ELT (ret, TREE_VEC_LENGTH (ret) - 1); + else + gcc_checking_assert (is_gimple_variable (ret) + || TREE_CODE (ret) == INTEGER_CST); + } + + return ret; } /* Set size for VARNO corresponding to OSI to VAL. */ @@ -164,35 +203,127 @@ object_sizes_initialize (struct object_size_info *osi, unsigned varno, tree val, tree wholeval) { int object_size_type = osi->object_size_type; + tree res; + + if (osi->pass != 0) + res = object_sizes_get_raw (osi, varno); + else + { + res = make_tree_vec (2); + object_sizes[object_size_type][varno] = res; + } - tree res = make_tree_vec (2); TREE_VEC_ELT (res, 0) = val; TREE_VEC_ELT (res, 1) = wholeval; +} - object_sizes[object_size_type][varno] = res; +/* Return a MODIFY_EXPR for cases where SSA and EXPR have the same type. The + TREE_VEC is returned only in case of PHI nodes. */ + +static tree +bundle_sizes (tree ssa, tree expr) +{ + gcc_checking_assert (TREE_TYPE (ssa) == sizetype); + + if (!TREE_TYPE (expr)) + { + gcc_checking_assert (TREE_CODE (expr) == TREE_VEC); + TREE_VEC_ELT (expr, TREE_VEC_LENGTH (expr) - 1) = ssa; + return expr; + } + + gcc_checking_assert (types_compatible_p (TREE_TYPE (expr), sizetype)); + return size_binop (MODIFY_EXPR, ssa, expr); } /* Set size for VARNO corresponding to OSI to VAL if it is the new minimum or - maximum. */ + maximum. For static sizes, each element of TREE_VEC is always INTEGER_CST + throughout the computation. For dynamic sizes, each element may either be a + gimple variable, a MODIFY_EXPR or a TREE_VEC. The MODIFY_EXPR is for + expressions that need to be gimplified. TREE_VECs are special, they're + emitted only for GIMPLE_PHI and the PHI result variable is the last element + of the vector. */ -static inline bool +static bool object_sizes_set (struct object_size_info *osi, unsigned varno, tree val, tree wholeval) { int object_size_type = osi->object_size_type; tree size = object_sizes[object_size_type][varno]; + bool changed = true; tree oldval = TREE_VEC_ELT (size, 0); tree old_wholeval = TREE_VEC_ELT (size, 1); - enum tree_code code = object_size_type & OST_MINIMUM ? MIN_EXPR : MAX_EXPR; + if (object_size_type & OST_DYNAMIC) + { + if (bitmap_bit_p (osi->reexamine, varno)) + { + if (size_unknown_p (val, object_size_type)) + { + oldval = object_sizes_get (osi, varno); + old_wholeval = object_sizes_get (osi, varno, true); + bitmap_set_bit (osi->unknowns, SSA_NAME_VERSION (oldval)); + bitmap_set_bit (osi->unknowns, SSA_NAME_VERSION (old_wholeval)); + bitmap_clear_bit (osi->reexamine, varno); + } + else + { + val = bundle_sizes (oldval, val); + wholeval = bundle_sizes (old_wholeval, wholeval); + } + } + else + { + gcc_checking_assert (size_initval_p (oldval, object_size_type)); + gcc_checking_assert (size_initval_p (old_wholeval, + object_size_type)); + /* For dynamic object sizes, all object sizes that are not gimple + variables will need to be gimplified. */ + if (TREE_CODE (wholeval) != INTEGER_CST + && !is_gimple_variable (wholeval)) + { + bitmap_set_bit (osi->reexamine, varno); + wholeval = bundle_sizes (make_ssa_name (sizetype), wholeval); + } + if (TREE_CODE (val) != INTEGER_CST && !is_gimple_variable (val)) + { + bitmap_set_bit (osi->reexamine, varno); + val = bundle_sizes (make_ssa_name (sizetype), val); + } + /* If the new value is a temporary variable, mark it for + reexamination. */ + else if (TREE_CODE (val) == SSA_NAME && !SSA_NAME_DEF_STMT (val)) + bitmap_set_bit (osi->reexamine, varno); + } + } + else + { + enum tree_code code = (object_size_type & OST_MINIMUM + ? MIN_EXPR : MAX_EXPR); - val = size_binop (code, val, oldval); - wholeval = size_binop (code, wholeval, old_wholeval); + val = size_binop (code, val, oldval); + wholeval = size_binop (code, wholeval, old_wholeval); + changed = tree_int_cst_compare (val, oldval) != 0; + } TREE_VEC_ELT (size, 0) = val; TREE_VEC_ELT (size, 1) = wholeval; - return tree_int_cst_compare (oldval, val) != 0; + return changed; +} + +/* Set temporary SSA names for object size and whole size to resolve dependency + loops in dynamic size computation. */ + +static inline void +object_sizes_set_temp (struct object_size_info *osi, unsigned varno) +{ + tree val = object_sizes_get (osi, varno); + + if (size_initval_p (val, osi->object_size_type)) + object_sizes_set (osi, varno, + make_ssa_name (sizetype), + make_ssa_name (sizetype)); } /* Initialize OFFSET_LIMIT variable. */ @@ -214,14 +345,15 @@ static tree size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) { gcc_checking_assert (TREE_CODE (offset) == INTEGER_CST); - gcc_checking_assert (TREE_CODE (sz) == INTEGER_CST); gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype)); /* For negative offsets, if we have a distinct WHOLESIZE, use it to get a net offset from the whole object. */ - if (wholesize && tree_int_cst_compare (sz, wholesize)) + if (wholesize + && (TREE_CODE (sz) != INTEGER_CST + || TREE_CODE (wholesize) != INTEGER_CST + || tree_int_cst_compare (sz, wholesize))) { - gcc_checking_assert (TREE_CODE (wholesize) == INTEGER_CST); gcc_checking_assert (types_compatible_p (TREE_TYPE (wholesize), sizetype)); @@ -238,13 +370,16 @@ size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) if (!types_compatible_p (TREE_TYPE (offset), sizetype)) fold_convert (sizetype, offset); - if (integer_zerop (offset)) - return sz; + if (TREE_CODE (offset) == INTEGER_CST) + { + if (integer_zerop (offset)) + return sz; - /* Negative or too large offset even after adjustment, cannot be within - bounds of an object. */ - if (compare_tree_int (offset, offset_limit) > 0) - return size_zero_node; + /* Negative or too large offset even after adjustment, cannot be within + bounds of an object. */ + if (compare_tree_int (offset, offset_limit) > 0) + return size_zero_node; + } return size_binop (MINUS_EXPR, size_binop (MAX_EXPR, sz, offset), offset); } @@ -681,6 +816,205 @@ pass_through_call (const gcall *call) return NULL_TREE; } +/* Emit PHI nodes for size expressions fo. */ + +static void +emit_phi_nodes (gimple *stmt, tree size_expr) +{ + tree size = TREE_VEC_ELT (size_expr, 0); + tree wholesize = TREE_VEC_ELT (size_expr, 1); + + tree phires = TREE_VEC_ELT (wholesize, TREE_VEC_LENGTH (wholesize) - 1); + gphi *wholephi = create_phi_node (phires, gimple_bb (stmt)); + phires = TREE_VEC_ELT (size, TREE_VEC_LENGTH (size) - 1); + gphi *phi = create_phi_node (phires, gimple_bb (stmt)); + gphi *obj_phi = as_a (stmt); + + gcc_checking_assert (TREE_CODE (wholesize) == TREE_VEC); + gcc_checking_assert (TREE_CODE (size) == TREE_VEC); + + for (unsigned i = 0; i < gimple_phi_num_args (stmt); i++) + { + gimple_seq seq = NULL; + tree wsz = TREE_VEC_ELT (wholesize, i); + tree sz = TREE_VEC_ELT (size, i); + + /* If we built an expression, we will need to build statements + and insert them on the edge right away. */ + if (!is_gimple_variable (wsz)) + wsz = force_gimple_operand (wsz, &seq, true, NULL); + if (!is_gimple_variable (sz)) + { + gimple_seq s; + sz = force_gimple_operand (sz, &s, true, NULL); + gimple_seq_add_seq (&seq, s); + } + + if (seq) + { + edge e = gimple_phi_arg_edge (obj_phi, i); + + /* Put the size definition before the last statement of the source + block of the PHI edge. This ensures that any branches at the end + of the source block remain the last statement. We are OK even if + the last statement is the definition of the object since it will + succeed any definitions that contribute to its size and the size + expression will succeed them too. */ + gimple_stmt_iterator gsi = gsi_last_bb (e->src); + gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); + } + + add_phi_arg (wholephi, wsz, + gimple_phi_arg_edge (obj_phi, i), + gimple_phi_arg_location (obj_phi, i)); + + add_phi_arg (phi, sz, + gimple_phi_arg_edge (obj_phi, i), + gimple_phi_arg_location (obj_phi, i)); + } +} + +/* Descend through EXPR and return size_unknown if it uses any SSA variable + object_size_set or object_size_set_temp generated, which turned out to be + size_unknown, as noted in UNKNOWNS. */ + +static tree +propagate_unknowns (object_size_info *osi, tree expr) +{ + int object_size_type = osi->object_size_type; + + switch (TREE_CODE (expr)) + { + case SSA_NAME: + if (bitmap_bit_p (osi->unknowns, SSA_NAME_VERSION (expr))) + return size_unknown (object_size_type); + return expr; + + case MIN_EXPR: + case MAX_EXPR: + { + tree res = propagate_unknowns (osi, TREE_OPERAND (expr, 0)); + if (size_unknown_p (res, object_size_type)) + return res; + + res = propagate_unknowns (osi, TREE_OPERAND (expr, 1)); + if (size_unknown_p (res, object_size_type)) + return res; + + return expr; + } + case MODIFY_EXPR: + { + tree res = propagate_unknowns (osi, TREE_OPERAND (expr, 1)); + if (size_unknown_p (res, object_size_type)) + return res; + return expr; + } + case TREE_VEC: + for (int i = 0; i < TREE_VEC_LENGTH (expr); i++) + { + tree res = propagate_unknowns (osi, TREE_VEC_ELT (expr, i)); + if (size_unknown_p (res, object_size_type)) + return res; + } + return expr; + case PLUS_EXPR: + case MINUS_EXPR: + { + tree res = propagate_unknowns (osi, TREE_OPERAND (expr, 0)); + if (size_unknown_p (res, object_size_type)) + return res; + + return expr; + } + default: + return expr; + } +} + +/* Walk through size expressions that need reexamination and generate + statements for them. */ + +static void +gimplify_size_expressions (object_size_info *osi) +{ + int object_size_type = osi->object_size_type; + bitmap_iterator bi; + unsigned int i; + bool changed; + + /* Step 1: Propagate unknowns into expressions. */ + bitmap reexamine = BITMAP_ALLOC (NULL); + bitmap_copy (reexamine, osi->reexamine); + do + { + changed = false; + EXECUTE_IF_SET_IN_BITMAP (reexamine, 0, i, bi) + { + tree cur = object_sizes_get_raw (osi, i); + + if (size_unknown_p (propagate_unknowns (osi, cur), object_size_type)) + { + object_sizes_set (osi, i, + size_unknown (object_size_type), + size_unknown (object_size_type)); + changed = true; + } + } + bitmap_copy (reexamine, osi->reexamine); + } + while (changed); + + /* Release all unknowns. */ + EXECUTE_IF_SET_IN_BITMAP (osi->unknowns, 0, i, bi) + release_ssa_name (ssa_name (i)); + + /* Expand all size expressions to put their definitions close to the objects + for whom size is being computed. */ + EXECUTE_IF_SET_IN_BITMAP (osi->reexamine, 0, i, bi) + { + gimple_seq seq = NULL; + tree size_expr = object_sizes_get_raw (osi, i); + + gimple *stmt = SSA_NAME_DEF_STMT (ssa_name (i)); + enum gimple_code code = gimple_code (stmt); + + /* PHI nodes need special attention. */ + if (code == GIMPLE_PHI) + emit_phi_nodes (stmt, size_expr); + else + { + /* Bundle wholesize in with the size to gimplify if needed. */ + if (!is_gimple_variable (TREE_VEC_ELT (size_expr, 1)) + && TREE_CODE (TREE_VEC_ELT (size_expr, 1)) != INTEGER_CST) + size_expr = size_binop (COMPOUND_EXPR, + TREE_VEC_ELT (size_expr, 1), + TREE_VEC_ELT (size_expr, 0)); + else if (!is_gimple_variable (TREE_VEC_ELT (size_expr, 0)) + && TREE_CODE (TREE_VEC_ELT (size_expr, 0)) != INTEGER_CST) + size_expr = TREE_VEC_ELT (size_expr, 0); + else + size_expr = NULL_TREE; + + if (size_expr) + { + gimple_stmt_iterator gsi; + if (code == GIMPLE_NOP) + gsi = gsi_start_bb (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); + else + gsi = gsi_for_stmt (stmt); + + force_gimple_operand (size_expr, &seq, true, NULL); + gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING); + } + } + + /* We're done, so replace the MODIFY_EXPRs with the SSA names. */ + object_sizes_initialize (osi, i, + object_sizes_get (osi, i), + object_sizes_get (osi, i, true)); + } +} /* Compute __builtin_object_size value for PTR and set *PSIZE to the resulting value. If the declared object is known and PDECL @@ -759,9 +1093,15 @@ compute_builtin_object_size (tree ptr, int object_size_type, osi.visited = BITMAP_ALLOC (NULL); osi.reexamine = BITMAP_ALLOC (NULL); - osi.depths = NULL; - osi.stack = NULL; - osi.tos = NULL; + + if (object_size_type & OST_DYNAMIC) + osi.unknowns = BITMAP_ALLOC (NULL); + else + { + osi.depths = NULL; + osi.stack = NULL; + osi.tos = NULL; + } /* First pass: walk UD chains, compute object sizes that can be computed. osi.reexamine bitmap at the end will @@ -771,6 +1111,14 @@ compute_builtin_object_size (tree ptr, int object_size_type, osi.changed = false; collect_object_sizes_for (&osi, ptr); + if (object_size_type & OST_DYNAMIC) + { + osi.pass = 1; + gimplify_size_expressions (&osi); + BITMAP_FREE (osi.unknowns); + bitmap_clear (osi.reexamine); + } + /* Second pass: keep recomputing object sizes of variables that need reexamination, until no object sizes are increased or all object sizes are computed. */ @@ -1015,6 +1363,25 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) return reexamine; } +static void +dynamic_object_size (struct object_size_info *osi, tree var, + tree *size, tree *wholesize) +{ + int object_size_type = osi->object_size_type; + + if (TREE_CODE (var) == SSA_NAME) + { + unsigned varno = SSA_NAME_VERSION (var); + + collect_object_sizes_for (osi, var); + *size = object_sizes_get (osi, varno); + *wholesize = object_sizes_get (osi, varno, true); + } + else if (TREE_CODE (var) == ADDR_EXPR) + addr_object_size (osi, var, object_size_type, size, wholesize); + else + *size = *wholesize = size_unknown (object_size_type); +} /* Compute object_sizes for VAR, defined at STMT, which is a COND_EXPR. Return true if the object size might need reexamination @@ -1036,6 +1403,33 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) then_ = gimple_assign_rhs2 (stmt); else_ = gimple_assign_rhs3 (stmt); + if (object_size_type & OST_DYNAMIC) + { + tree then_size, then_wholesize, else_size, else_wholesize; + + dynamic_object_size (osi, then_, &then_size, &then_wholesize); + if (!size_unknown_p (then_size, object_size_type)) + dynamic_object_size (osi, else_, &else_size, &else_wholesize); + + tree cond_size, cond_wholesize; + if (size_unknown_p (then_size, object_size_type) + || size_unknown_p (else_size, object_size_type)) + cond_size = cond_wholesize = size_unknown (object_size_type); + else + { + cond_size = fold_build3 (COND_EXPR, sizetype, + gimple_assign_rhs1 (stmt), + then_size, else_size); + cond_wholesize = fold_build3 (COND_EXPR, sizetype, + gimple_assign_rhs1 (stmt), + then_wholesize, else_wholesize); + } + + object_sizes_set (osi, varno, cond_size, cond_wholesize); + + return false; + } + if (TREE_CODE (then_) == SSA_NAME) reexamine |= merge_object_sizes (osi, var, then_); else @@ -1052,6 +1446,44 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) return reexamine; } +/* Compute an object size expression for VAR, which is the result of a PHI + node. */ + +static void +phi_dynamic_object_size (struct object_size_info *osi, tree var) +{ + int object_size_type = osi->object_size_type; + unsigned int varno = SSA_NAME_VERSION (var); + gimple *stmt = SSA_NAME_DEF_STMT (var); + unsigned i, num_args = gimple_phi_num_args (stmt); + + /* The extra space is for the PHI result at the end, which object_sizes_set + sets for us. */ + tree sizes = make_tree_vec (num_args + 1); + tree wholesizes = make_tree_vec (num_args + 1); + + /* Bail out if the size of any of the PHI arguments cannot be + determined. */ + for (i = 0; i < num_args; i++) + { + tree rhs = gimple_phi_arg_def (stmt, i); + tree size, wholesize; + + dynamic_object_size (osi, rhs, &size, &wholesize); + + if (size_unknown_p (size, object_size_type)) + break; + + TREE_VEC_ELT (sizes, i) = size; + TREE_VEC_ELT (wholesizes, i) = wholesize; + } + + if (i < num_args) + sizes = wholesizes = size_unknown (object_size_type); + + object_sizes_set (osi, varno, sizes, wholesizes); +} + /* Compute object sizes for VAR. For ADDR_EXPR an object size is the number of remaining bytes to the end of the object (where what is considered an object depends on @@ -1097,6 +1529,9 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { /* Found a dependency loop. Mark the variable for later re-examination. */ + if (object_size_type & OST_DYNAMIC) + object_sizes_set_temp (osi, varno); + bitmap_set_bit (osi->reexamine, varno); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -1178,6 +1613,12 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) { unsigned i; + if (object_size_type & OST_DYNAMIC) + { + phi_dynamic_object_size (osi, var); + break; + } + for (i = 0; i < gimple_phi_num_args (stmt); i++) { tree rhs = gimple_phi_arg (stmt, i)->def; @@ -1200,7 +1641,8 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) if (! reexamine || object_sizes_unknown_p (object_size_type, varno)) { bitmap_set_bit (computed[object_size_type], varno); - bitmap_clear_bit (osi->reexamine, varno); + if (!(object_size_type & OST_DYNAMIC)) + bitmap_clear_bit (osi->reexamine, varno); } else { From patchwork Fri Nov 26 05:28:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 48173 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 937D23858400 for ; Fri, 26 Nov 2021 05:32:16 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from beige.elm.relay.mailchannels.net (beige.elm.relay.mailchannels.net [23.83.212.16]) by sourceware.org (Postfix) with ESMTPS id 96DF7385780F for ; Fri, 26 Nov 2021 05:29:24 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 96DF7385780F Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id ECF4E72112B; Fri, 26 Nov 2021 05:29:22 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id A649F7210FA; Fri, 26 Nov 2021 05:29:21 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.124.138.98 (trex/6.4.3); Fri, 26 Nov 2021 05:29:22 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Obese-Desert: 4bf26cf6124c4f6c_1637904562799_1334057822 X-MC-Loop-Signature: 1637904562799:3840310647 X-MC-Ingress-Time: 1637904562799 Received: from rhbox.intra.reserved-bit.com (unknown [1.186.223.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4J0jwb2SKYz3Z; Thu, 25 Nov 2021 21:29:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1637904560; bh=gPc1RMyB93FMCKeRY1AxByC8b1I=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=F7Oth0Z9EZKMP835BJCynhHOXqFg3BgFV7TRMvcRVWY2mrogPRnfGpVzuOnxIQOUh Z8n1SG70WmrW/SX5znZIFdOIoMyWntSNziqtOM3BB97BMbsQMKuYobiqi45tv4/ezU CClBhxgMWObqAvJT7Sx7Gkhg/k4y9buKO5fOKTko= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v3 6/8] tree-object-size: Handle function parameters Date: Fri, 26 Nov 2021 10:58:49 +0530 Message-Id: <20211126052851.2176408-7-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211126052851.2176408-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211126052851.2176408-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Handle hints provided by __attribute__ ((access (...))) to compute dynamic sizes for objects. gcc/ChangeLog: * tree-object-size.c: Include tree-dfa.h. (parm_object_size): New function. (collect_object_sizes_for): Call it. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c (test_parmsz_simple): New function. (main): Call it. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 11 ++++ gcc/tree-object-size.c | 50 ++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c index ddedf6a49bd..ce0f4eb17f3 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -46,6 +46,14 @@ test_deploop (size_t sz, size_t cond) return __builtin_dynamic_object_size (bin, 0); } +size_t +__attribute__ ((access (__read_write__, 1, 2))) +__attribute__ ((noinline)) +test_parmsz_simple (void *obj, size_t sz) +{ + return __builtin_dynamic_object_size (obj, 0); +} + unsigned nfails = 0; #define FAIL() ({ \ @@ -64,6 +72,9 @@ main (int argc, char **argv) FAIL (); if (test_deploop (128, 129) != 32) FAIL (); + if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1) + != __builtin_strlen (argv[0]) + 1) + FAIL (); if (nfails > 0) __builtin_abort (); diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 5b4dcb619cd..48b1ec6e26a 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -32,6 +32,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-fold.h" #include "gimple-iterator.h" #include "tree-cfg.h" +#include "tree-dfa.h" #include "stringpool.h" #include "attribs.h" #include "builtins.h" @@ -1446,6 +1447,53 @@ cond_expr_object_size (struct object_size_info *osi, tree var, gimple *stmt) return reexamine; } +/* Find size of an object passed as a parameter to the function. */ + +static void +parm_object_size (struct object_size_info *osi, tree var) +{ + int object_size_type = osi->object_size_type; + tree parm = SSA_NAME_VAR (var); + + if (!(object_size_type & OST_DYNAMIC) || !POINTER_TYPE_P (TREE_TYPE (parm))) + expr_object_size (osi, var, parm); + + /* Look for access attribute. */ + rdwr_map rdwr_idx; + + tree fndecl = cfun->decl; + const attr_access *access = get_parm_access (rdwr_idx, parm, fndecl); + tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm))); + tree sz = NULL_TREE; + + if (access && access->sizarg != UINT_MAX) + { + tree fnargs = DECL_ARGUMENTS (fndecl); + tree arg = NULL_TREE; + unsigned argpos = 0; + + /* Walk through the parameters to pick the size parameter and safely + scale it by the type size. */ + for (arg = fnargs; argpos != access->sizarg && arg; + arg = TREE_CHAIN (arg), ++argpos); + + if (arg != NULL_TREE && INTEGRAL_TYPE_P (TREE_TYPE (arg))) + { + sz = get_or_create_ssa_default_def (cfun, arg); + if (sz != NULL_TREE) + { + sz = fold_convert (sizetype, sz); + if (typesize) + sz = size_binop (MULT_EXPR, sz, typesize); + } + } + } + if (!sz) + sz = size_unknown (object_size_type); + + object_sizes_set (osi, SSA_NAME_VERSION (var), sz, sz); +} + /* Compute an object size expression for VAR, which is the result of a PHI node. */ @@ -1603,7 +1651,7 @@ collect_object_sizes_for (struct object_size_info *osi, tree var) case GIMPLE_NOP: if (SSA_NAME_VAR (var) && TREE_CODE (SSA_NAME_VAR (var)) == PARM_DECL) - expr_object_size (osi, var, SSA_NAME_VAR (var)); + parm_object_size (osi, var); else /* Uninitialized SSA names point nowhere. */ unknown_object_size (osi, var); From patchwork Fri Nov 26 05:28:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 48175 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4A40F3858038 for ; Fri, 26 Nov 2021 05:33:16 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from dragonfly.birch.relay.mailchannels.net (dragonfly.birch.relay.mailchannels.net [23.83.209.51]) by sourceware.org (Postfix) with ESMTPS id 722FF3858439 for ; Fri, 26 Nov 2021 05:29:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 722FF3858439 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id CA5342C1351; Fri, 26 Nov 2021 05:29:23 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 5E8452C1428; Fri, 26 Nov 2021 05:29:23 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.124.138.98 (trex/6.4.3); Fri, 26 Nov 2021 05:29:23 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Keen-Language: 20717bb866f5d42d_1637904563673_2508787475 X-MC-Loop-Signature: 1637904563673:3333928515 X-MC-Ingress-Time: 1637904563673 Received: from rhbox.intra.reserved-bit.com (unknown [1.186.223.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4J0jwd53fBz1QQ; Thu, 25 Nov 2021 21:29:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1637904563; bh=P/MijYKZL+uS7m0NQrYEyp6OfKA=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=io5vRxG6n6qMvtjWXbBl0ib8nMkOEhO8mOVueb0gmebSIaw/sHrzEVFn09URa57US OBDY6/82Ib6wTqOayP4q0ndcHvg0vQSzpsV8XqulvLBzDY/GQalNPkrtFBewpK0K+8 PPwU5DWufC/I/UfTdLpeUbrm7Frc7+1+MyhcUssQ= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v3 7/8] tree-object-size: Handle GIMPLE_CALL Date: Fri, 26 Nov 2021 10:58:50 +0530 Message-Id: <20211126052851.2176408-8-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211126052851.2176408-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211126052851.2176408-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.7 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Handle non-constant expressions in GIMPLE_CALL arguments. Also handle alloca. gcc/ChangeLog: * tree-object-size.c (alloc_object_size): Make and return non-constant size expression. (call_object_size): Return expression or unknown based on whether dynamic object size is requested. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: Add new tests. * gcc.dg/builtin-object-size-1.c (test1) [__builtin_object_size]: Alter expected result for dynamic object size. * gcc.dg/builtin-object-size-2.c (test1) [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-3.c (test1) [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-4.c (test1) [__builtin_object_size]: Likewise. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 227 +++++++++++++++++- gcc/testsuite/gcc.dg/builtin-object-size-1.c | 7 + gcc/testsuite/gcc.dg/builtin-object-size-2.c | 14 ++ gcc/testsuite/gcc.dg/builtin-object-size-3.c | 7 + gcc/testsuite/gcc.dg/builtin-object-size-4.c | 14 ++ gcc/tree-object-size.c | 22 +- 6 files changed, 282 insertions(+), 9 deletions(-) diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c index ce0f4eb17f3..2db0e0d1aa2 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -4,12 +4,71 @@ typedef __SIZE_TYPE__ size_t; #define abort __builtin_abort +void * +__attribute__ ((alloc_size (1))) +__attribute__ ((__nothrow__ , __leaf__)) +__attribute__ ((noinline)) +alloc_func (size_t sz) +{ + return __builtin_malloc (sz); +} + +void * +__attribute__ ((alloc_size (1, 2))) +__attribute__ ((__nothrow__ , __leaf__)) +__attribute__ ((noinline)) +calloc_func (size_t cnt, size_t sz) +{ + return __builtin_calloc (cnt, sz); +} + +void * +__attribute__ ((noinline)) +unknown_allocator (size_t cnt, size_t sz) +{ + return __builtin_calloc (cnt, sz); +} + +size_t +__attribute__ ((noinline)) +test_unknown (size_t cnt, size_t sz) +{ + void *ret = unknown_allocator (cnt, sz); + return __builtin_dynamic_object_size (ret, 0); +} + +/* Malloc-like allocator. */ + +size_t +__attribute__ ((noinline)) +test_malloc (size_t sz) +{ + void *ret = alloc_func (sz); + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc (size_t sz) +{ + void *ret = __builtin_malloc (sz); + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_cond (int cond) +{ + void *ret = __builtin_malloc (cond ? 32 : 64); + return __builtin_dynamic_object_size (ret, 0); +} + size_t __attribute__ ((noinline)) test_builtin_malloc_condphi (int cond) { void *ret; - + if (cond) ret = __builtin_malloc (32); else @@ -18,6 +77,79 @@ test_builtin_malloc_condphi (int cond) return __builtin_dynamic_object_size (ret, 0); } +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi2 (int cond, size_t in) +{ + void *ret; + + if (cond) + ret = __builtin_malloc (in); + else + ret = __builtin_malloc (64); + + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi3 (int cond, size_t in, size_t in2) +{ + void *ret; + + if (cond) + ret = __builtin_malloc (in); + else + ret = __builtin_malloc (in2); + + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi4 (size_t sz, int cond) +{ + char *a = __builtin_malloc (sz); + char b[sz / 2]; + + return __builtin_dynamic_object_size (cond ? b : (void *) &a, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_malloc_condphi5 (size_t sz, int cond, char *c) +{ + char *a = __builtin_malloc (sz); + + return __builtin_dynamic_object_size (cond ? c : (void *) &a, 0); +} + +/* Calloc-like allocator. */ + +size_t +__attribute__ ((noinline)) +test_calloc (size_t cnt, size_t sz) +{ + void *ret = calloc_func (cnt, sz); + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_calloc (size_t cnt, size_t sz) +{ + void *ret = __builtin_calloc (cnt, sz); + return __builtin_dynamic_object_size (ret, 0); +} + +size_t +__attribute__ ((noinline)) +test_builtin_calloc_cond (int cond1, int cond2) +{ + void *ret = __builtin_calloc (cond1 ? 32 : 64, cond2 ? 1024 : 16); + return __builtin_dynamic_object_size (ret, 0); +} + size_t __attribute__ ((noinline)) test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) @@ -33,6 +165,47 @@ test_builtin_calloc_condphi (size_t cnt, size_t sz, int cond) return __builtin_dynamic_object_size (cond ? ch : (void *) &bin, 0); } +/* Passthrough functions. */ + +size_t +__attribute__ ((noinline)) +test_passthrough (size_t sz, char *in) +{ + char *bin = __builtin_malloc (sz); + char *dest = __builtin_memcpy (bin, in, sz); + + return __builtin_dynamic_object_size (dest, 0); +} + +size_t +__attribute__ ((noinline)) +test_passthrough_nonssa (char *in) +{ + char bin[__builtin_strlen (in) + 1]; + char *dest = __builtin_memcpy (bin, in, __builtin_strlen (in) + 1); + + return __builtin_dynamic_object_size (dest, 0); +} + +/* Variable length arrays. */ +size_t +__attribute__ ((noinline)) +test_dynarray (size_t sz) +{ + char bin[sz]; + + return __builtin_dynamic_object_size (bin, 0); +} + +size_t +__attribute__ ((noinline)) +test_dynarray_cond (int cond) +{ + char bin[cond ? 8 : 16]; + + return __builtin_dynamic_object_size (bin, 0); +} + size_t __attribute__ ((noinline)) test_deploop (size_t sz, size_t cond) @@ -41,7 +214,7 @@ test_deploop (size_t sz, size_t cond) for (size_t i = 0; i < sz; i++) if (i == cond) - bin = __builtin_alloca (64); + bin = __builtin_alloca (sz); return __builtin_dynamic_object_size (bin, 0); } @@ -64,12 +237,62 @@ unsigned nfails = 0; int main (int argc, char **argv) { + size_t outsz = test_unknown (32, 42); + if (outsz != -1 && outsz != 32) + FAIL (); + if (test_malloc (2048) != 2048) + FAIL (); + if (test_builtin_malloc (2048) != 2048) + FAIL (); + if (test_builtin_malloc_cond (1) != 32) + FAIL (); + if (test_builtin_malloc_cond (0) != 64) + FAIL (); if (test_builtin_malloc_condphi (1) != 32) FAIL (); if (test_builtin_malloc_condphi (0) != 64) FAIL (); + if (test_builtin_malloc_condphi2 (1, 128) != 128) + FAIL (); + if (test_builtin_malloc_condphi2 (0, 128) != 64) + FAIL (); + if (test_builtin_malloc_condphi3 (1, 128, 256) != 128) + FAIL (); + if (test_builtin_malloc_condphi3 (0, 128, 256) != 256) + FAIL (); + if (test_builtin_malloc_condphi4 (128, 1) != 64) + FAIL (); + if (test_builtin_malloc_condphi4 (128, 0) != sizeof (void *)) + FAIL (); + if (test_builtin_malloc_condphi5 (128, 0, argv[0]) != -1) + FAIL (); + if (test_calloc (2048, 4) != 2048 * 4) + FAIL (); + if (test_builtin_calloc (2048, 8) != 2048 * 8) + FAIL (); + if (test_builtin_calloc_cond (0, 0) != 64 * 16) + FAIL (); + if (test_builtin_calloc_cond (1, 1) != 32 * 1024) + FAIL (); + if (test_builtin_calloc_condphi (128, 1, 1) != 128) + FAIL (); if (test_builtin_calloc_condphi (128, 1, 0) == 128) FAIL (); + if (test_builtin_calloc_condphi (128, 1, 0) == -1) + FAIL (); + if (test_passthrough (__builtin_strlen (argv[0]) + 1, argv[0]) + != __builtin_strlen (argv[0]) + 1) + FAIL (); + if (test_passthrough_nonssa (argv[0]) != __builtin_strlen (argv[0]) + 1) + FAIL (); + if (test_dynarray (__builtin_strlen (argv[0])) != __builtin_strlen (argv[0])) + FAIL (); + if (test_dynarray_cond (0) != 16) + FAIL (); + if (test_dynarray_cond (1) != 8) + FAIL (); + if (test_deploop (128, 4) != 128) + FAIL (); if (test_deploop (128, 129) != 32) FAIL (); if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 265c87ed6fb..06d442796cb 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -135,10 +135,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extb[5], 0) != sizeof (extb) - 5) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (var, 0) != x + 10) + abort (); + if (__builtin_object_size (var + 10, 0) != x) + abort (); +#else if (__builtin_object_size (var, 0) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 0) != (size_t) -1) abort (); +#endif if (__builtin_object_size (&var[5], 0) != (size_t) -1) abort (); if (__builtin_object_size (zerol, 0) != 0) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index 5051fea47c3..2364f2d6afd 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -137,16 +137,30 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extc[5].c[3], 1) != (size_t) -1) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (var, 1) != x + 10) + abort (); + if (__builtin_object_size (var + 10, 1) != x) + abort (); +#else if (__builtin_object_size (var, 1) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 1) != (size_t) -1) abort (); +#endif if (__builtin_object_size (&var[5], 1) != (size_t) -1) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A)) + abort (); + if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A)) + abort (); +#else if (__builtin_object_size (vara, 1) != (size_t) -1) abort (); if (__builtin_object_size (vara + 10, 1) != (size_t) -1) abort (); +#endif if (__builtin_object_size (&vara[5], 1) != (size_t) -1) abort (); if (__builtin_object_size (&vara[0].a, 1) != sizeof (vara[0].a)) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index 1d92627266b..753ee4a1a4f 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -140,10 +140,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extb[5], 2) != sizeof (extb) - 5) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (var, 2) != x + 10) + abort (); + if (__builtin_object_size (var + 10, 2) != x) + abort (); +#else if (__builtin_object_size (var, 2) != 0) abort (); if (__builtin_object_size (var + 10, 2) != 0) abort (); +#endif if (__builtin_object_size (&var[5], 2) != 0) abort (); if (__builtin_object_size (zerol, 2) != 0) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index 9da3537a5f7..c383385e060 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -150,16 +150,30 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extc[5].c[3], 3) != 0) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (var, 3) != x + 10) + abort (); + if (__builtin_object_size (var + 10, 3) != x) + abort (); +#else if (__builtin_object_size (var, 3) != 0) abort (); if (__builtin_object_size (var + 10, 3) != 0) abort (); +#endif if (__builtin_object_size (&var[5], 3) != 0) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A)) + abort (); + if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A)) + abort (); +#else if (__builtin_object_size (vara, 3) != 0) abort (); if (__builtin_object_size (vara + 10, 3) != 0) abort (); +#endif if (__builtin_object_size (&vara[5], 3) != 0) abort (); if (__builtin_object_size (&vara[0].a, 3) != sizeof (vara[0].a)) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 48b1ec6e26a..f03714c4f18 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -755,7 +755,8 @@ alloc_object_size (const gcall *call, int object_size_type) gcc_assert (is_gimple_call (call)); tree calltype; - if (tree callfn = gimple_call_fndecl (call)) + tree callfn = gimple_call_fndecl (call); + if (callfn) calltype = TREE_TYPE (callfn); else calltype = gimple_call_fntype (call); @@ -775,12 +776,13 @@ alloc_object_size (const gcall *call, int object_size_type) if (TREE_CHAIN (p)) arg2 = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (p)))-1; } + else if (gimple_call_builtin_p (call, BUILT_IN_NORMAL) + && callfn && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callfn))) + arg1 = 0; - if (arg1 < 0 || arg1 >= (int)gimple_call_num_args (call) - || TREE_CODE (gimple_call_arg (call, arg1)) != INTEGER_CST - || (arg2 >= 0 - && (arg2 >= (int)gimple_call_num_args (call) - || TREE_CODE (gimple_call_arg (call, arg2)) != INTEGER_CST))) + /* Non-const arguments are OK here, let the caller handle constness. */ + if (arg1 < 0 || arg1 >= (int) gimple_call_num_args (call) + || arg2 >= (int) gimple_call_num_args (call)) return size_unknown (object_size_type); tree bytes = NULL_TREE; @@ -791,7 +793,10 @@ alloc_object_size (const gcall *call, int object_size_type) else if (arg1 >= 0) bytes = fold_convert (sizetype, gimple_call_arg (call, arg1)); - return bytes; + if (bytes) + return STRIP_NOPS (bytes); + + return size_unknown (object_size_type); } @@ -1250,6 +1255,9 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) gcc_assert (osi->pass == 0); tree bytes = alloc_object_size (call, object_size_type); + if (!(object_size_type & OST_DYNAMIC) && TREE_CODE (bytes) != INTEGER_CST) + bytes = size_unknown (object_size_type); + object_sizes_set (osi, varno, bytes, bytes); } From patchwork Fri Nov 26 05:28:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Siddhesh Poyarekar X-Patchwork-Id: 48176 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DDE303858036 for ; Fri, 26 Nov 2021 05:33:51 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from donkey.elm.relay.mailchannels.net (donkey.elm.relay.mailchannels.net [23.83.212.49]) by sourceware.org (Postfix) with ESMTPS id 1C7333858017 for ; Fri, 26 Nov 2021 05:29:28 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 1C7333858017 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=gotplt.org Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gotplt.org X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from relay.mailchannels.net (localhost [127.0.0.1]) by relay.mailchannels.net (Postfix) with ESMTP id 9B5B81215F6; Fri, 26 Nov 2021 05:29:27 +0000 (UTC) Received: from pdx1-sub0-mail-a305.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 00BE41215DA; Fri, 26 Nov 2021 05:29:25 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a305.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.99.149.17 (trex/6.4.3); Fri, 26 Nov 2021 05:29:27 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Unite-Minister: 5640981511f92a31_1637904567126_3548022977 X-MC-Loop-Signature: 1637904567126:4011973441 X-MC-Ingress-Time: 1637904567125 Received: from rhbox.intra.reserved-bit.com (unknown [1.186.223.60]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: siddhesh@gotplt.org) by pdx1-sub0-mail-a305.dreamhost.com (Postfix) with ESMTPSA id 4J0jwh0RYlz3C; Thu, 25 Nov 2021 21:29:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1637904565; bh=jl0TWg6VHhulHW+kvBG3410SCus=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=k+iKho757DqSp8EEMcGGmE9ubo5T160pBEkx1PD1bHENZhb4KimmMgVNAhqw8cQS6 GEhnXyCiH89SzLrOWZNBCYiuqs9Vvwu0ekJoldO/+ALjSpyDZoddk+0XWbVTRsWD7+ 9aIEmJcEAIUrLvPU8YQ4bOzkcR+kfr9Iue6GihQ4= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Subject: [PATCH v3 8/8] tree-object-size: Dynamic sizes for ADDR_EXPR Date: Fri, 26 Nov 2021 10:58:51 +0530 Message-Id: <20211126052851.2176408-9-siddhesh@gotplt.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20211126052851.2176408-1-siddhesh@gotplt.org> References: <20211109190137.1107736-1-siddhesh@gotplt.org> <20211126052851.2176408-1-siddhesh@gotplt.org> MIME-Version: 1.0 X-Spam-Status: No, score=-3038.8 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: jakub@redhat.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Allow returning dynamic expressions from ADDR_EXPR for __builtin_dynamic_object_size and also allow offsets to be dynamic. gcc/ChangeLog: * tree-object-size.c (size_valid_p): New function. (size_for_offset): Remove OFFSET constness assertion. (addr_object_size): Build dynamic expressions for object sizes and use size_valid_p to decide if it is valid for the given OBJECT_SIZE_TYPE. (compute_builtin_object_size): Allow dynamic offsets when computing size at O0. (call_object_size): Call size_valid_p. (plus_stmt_object_size): Allow non-constant offset and use size_valid_p to decide if it is valid for the given OBJECT_SIZE_TYPE. gcc/testsuite/ChangeLog: * gcc.dg/builtin-dynamic-object-size-0.c: Add new tests. * gcc.dg/builtin-object-size-1.c (test1) [__builtin_object_size]: Adjust expected output for dynamic object sizes. * gcc.dg/builtin-object-size-2.c (test1) [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-3.c (test1) [__builtin_object_size]: Likewise. * gcc.dg/builtin-object-size-4.c (test1) [__builtin_object_size]: Likewise. Signed-off-by: Siddhesh Poyarekar --- .../gcc.dg/builtin-dynamic-object-size-0.c | 158 ++++++++++++++++++ gcc/testsuite/gcc.dg/builtin-object-size-1.c | 30 +++- gcc/testsuite/gcc.dg/builtin-object-size-2.c | 43 ++++- gcc/testsuite/gcc.dg/builtin-object-size-3.c | 25 ++- gcc/testsuite/gcc.dg/builtin-object-size-4.c | 17 +- gcc/tree-object-size.c | 91 +++++----- 6 files changed, 300 insertions(+), 64 deletions(-) diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c index 2db0e0d1aa2..4a1f4965ebd 100644 --- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c +++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c @@ -219,6 +219,79 @@ test_deploop (size_t sz, size_t cond) return __builtin_dynamic_object_size (bin, 0); } +/* Address expressions. */ + +struct dynarray_struct +{ + long a; + char c[16]; + int b; +}; + +size_t +__attribute__ ((noinline)) +test_dynarray_struct (size_t sz, size_t off) +{ + struct dynarray_struct bin[sz]; + + return __builtin_dynamic_object_size (&bin[off].c, 0); +} + +size_t +__attribute__ ((noinline)) +test_dynarray_struct_subobj (size_t sz, size_t off) +{ + struct dynarray_struct bin[sz]; + + return __builtin_dynamic_object_size (&bin[off].c[4], 1); +} + +size_t +__attribute__ ((noinline)) +test_dynarray_struct_subobj2 (size_t sz, size_t off, size_t *objsz) +{ + struct dynarray_struct2 + { + long a; + int b; + char c[sz]; + }; + + struct dynarray_struct2 bin; + + *objsz = sizeof (bin); + + return __builtin_dynamic_object_size (&bin.c[off], 1); +} + +size_t +__attribute__ ((noinline)) +test_substring (size_t sz, size_t off) +{ + char str[sz]; + + return __builtin_dynamic_object_size (&str[off], 0); +} + +size_t +__attribute__ ((noinline)) +test_substring_ptrplus (size_t sz, size_t off) +{ + int str[sz]; + + return __builtin_dynamic_object_size (str + off, 0); +} + +size_t +__attribute__ ((noinline)) +test_substring_ptrplus2 (size_t sz, size_t off, size_t off2) +{ + int str[sz]; + int *ptr = &str[off]; + + return __builtin_dynamic_object_size (ptr + off2, 0); +} + size_t __attribute__ ((access (__read_write__, 1, 2))) __attribute__ ((noinline)) @@ -227,6 +300,40 @@ test_parmsz_simple (void *obj, size_t sz) return __builtin_dynamic_object_size (obj, 0); } +size_t +__attribute__ ((noinline)) +__attribute__ ((access (__read_write__, 1, 2))) +test_parmsz (void *obj, size_t sz, size_t off) +{ + return __builtin_dynamic_object_size (obj + off, 0); +} + +size_t +__attribute__ ((noinline)) +__attribute__ ((access (__read_write__, 1, 2))) +test_parmsz_scale (int *obj, size_t sz, size_t off) +{ + return __builtin_dynamic_object_size (obj + off, 0); +} + +size_t +__attribute__ ((noinline)) +__attribute__ ((access (__read_write__, 1, 2))) +test_loop (int *obj, size_t sz, size_t start, size_t end, int incr) +{ + int *ptr = obj + start; + + for (int i = start; i != end; i = i + incr) + { + ptr = ptr + incr; + if (__builtin_dynamic_object_size (ptr, 0) == 0) + return 0; + } + + return __builtin_dynamic_object_size (ptr, 0); +} + + unsigned nfails = 0; #define FAIL() ({ \ @@ -287,6 +394,31 @@ main (int argc, char **argv) FAIL (); if (test_dynarray (__builtin_strlen (argv[0])) != __builtin_strlen (argv[0])) FAIL (); + if (test_dynarray_struct (42, 4) != + ((42 - 4) * sizeof (struct dynarray_struct) + - __builtin_offsetof (struct dynarray_struct, c))) + FAIL (); + if (test_dynarray_struct (42, 48) != 0) + FAIL (); + if (test_substring (128, 4) != 128 - 4) + FAIL (); + if (test_substring (128, 142) != 0) + FAIL (); + if (test_dynarray_struct_subobj (42, 4) != 16 - 4) + FAIL (); + if (test_dynarray_struct_subobj (42, 48) != 0) + FAIL (); + size_t objsz = 0; + if (test_dynarray_struct_subobj2 (42, 4, &objsz) != objsz - 4 - 12) + FAIL (); + if (test_substring_ptrplus (128, 4) != (128 - 4) * sizeof (int)) + FAIL (); + if (test_substring_ptrplus (128, 142) != 0) + FAIL (); + if (test_substring_ptrplus2 (128, 4, 4) != (128 - 8) * sizeof (int)) + FAIL (); + if (test_substring_ptrplus2 (128, 4, -3) != (128 - 1) * sizeof (int)) + FAIL (); if (test_dynarray_cond (0) != 16) FAIL (); if (test_dynarray_cond (1) != 8) @@ -298,6 +430,32 @@ main (int argc, char **argv) if (test_parmsz_simple (argv[0], __builtin_strlen (argv[0]) + 1) != __builtin_strlen (argv[0]) + 1) FAIL (); + if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, -1) != 0) + FAIL (); + if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, 0) + != __builtin_strlen (argv[0]) + 1) + FAIL (); + if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, + __builtin_strlen (argv[0])) != 1) + FAIL (); + if (test_parmsz (argv[0], __builtin_strlen (argv[0]) + 1, + __builtin_strlen (argv[0]) + 2) != 0) + FAIL (); + int in[42]; + if (test_parmsz_scale (in, 42, 2) != 40 * sizeof (int)) + FAIL (); + if (test_loop (in, 42, 0, 32, 1) != 10 * sizeof (int)) + FAIL (); + if (test_loop (in, 42, 32, -1, -1) != 0) + FAIL (); + if (test_loop (in, 42, 32, 10, -1) != 32 * sizeof (int)) + FAIL (); + if (test_loop (in, 42, 42, 0, -1) != 42 * sizeof (int)) + FAIL (); + if (test_loop (in, 42, 44, 0, -1) != 0) + FAIL (); + if (test_loop (in, 42, 20, 52, 1) != 0) + FAIL (); if (nfails > 0) __builtin_abort (); diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 06d442796cb..161f426ec0b 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -81,30 +81,56 @@ test1 (void *q, int x) r = malloc (30); else r = calloc (2, 16); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 0) != (x < 20 ? 30 : 2 * 16)) + abort (); +#else /* We may duplicate this test onto the two exit paths. On one path the size will be 32, the other it will be 30. If we don't duplicate this test, then the size will be 32. */ if (__builtin_object_size (r, 0) != 2 * 16 && __builtin_object_size (r, 0) != 30) abort (); +#endif if (x < 20) r = malloc (30); else r = calloc (2, 14); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 0) != (x < 20 ? 30 : 2 * 14)) + abort (); +#else if (__builtin_object_size (r, 0) != 30) abort (); +#endif if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef __builtin_object_size + if (__builtin_object_size (r, 0) != (x < 30 ? sizeof (a) : sizeof (a) - 3)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a)) abort (); +#endif r = memcpy (r, "a", 2); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 0) != (x < 30 ? sizeof (a) : sizeof (a) - 3)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a)) abort (); +#endif r = memcpy (r + 2, "b", 2) + 2; +#ifdef __builtin_object_size + if (__builtin_object_size (r, 0) + != (x < 30 ? sizeof (a) - 4 : sizeof (a) - 7)) + abort (); +#else if (__builtin_object_size (r, 0) != sizeof (a) - 4) abort (); +#endif r = &a.a[4]; r = memset (r, 'a', 2); if (__builtin_object_size (r, 0) @@ -140,14 +166,16 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (var + 10, 0) != x) abort (); + if (__builtin_object_size (&var[5], 0) != x + 5) + abort (); #else if (__builtin_object_size (var, 0) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 0) != (size_t) -1) abort (); -#endif if (__builtin_object_size (&var[5], 0) != (size_t) -1) abort (); +#endif if (__builtin_object_size (zerol, 0) != 0) abort (); if (__builtin_object_size (&zerol, 0) != 0) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index 2364f2d6afd..2729538da17 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -75,30 +75,56 @@ test1 (void *q, int x) r = malloc (30); else r = calloc (2, 16); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 1) != (x < 20 ? 30 : 2 * 16)) + abort (); +#else /* We may duplicate this test onto the two exit paths. On one path the size will be 32, the other it will be 30. If we don't duplicate this test, then the size will be 32. */ if (__builtin_object_size (r, 1) != 2 * 16 && __builtin_object_size (r, 1) != 30) abort (); +#endif if (x < 20) r = malloc (30); else r = calloc (2, 14); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 1) != (x < 20 ? 30 : 2 * 14)) + abort (); +#else if (__builtin_object_size (r, 1) != 30) abort (); +#endif if (x < 30) r = malloc (sizeof (a)); else r = &a.a[3]; +#ifdef __builtin_object_size + if (__builtin_object_size (r, 1) != (x < 30 ? sizeof (a) : sizeof (a) - 3)) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a)) abort (); +#endif r = memcpy (r, "a", 2); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 1) != (x < 30 ? sizeof (a) : sizeof (a) - 3)) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a)) abort (); +#endif r = memcpy (r + 2, "b", 2) + 2; +#ifdef __builtin_object_size + if (__builtin_object_size (r, 0) + != (x < 30 ? sizeof (a) - 4 : sizeof (a) - 7)) + abort (); +#else if (__builtin_object_size (r, 1) != sizeof (a) - 4) abort (); +#endif r = &a.a[4]; r = memset (r, 'a', 2); if (__builtin_object_size (r, 1) != sizeof (a.a) - 4) @@ -142,27 +168,28 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (var + 10, 1) != x) abort (); + if (__builtin_object_size (&var[5], 1) != x + 5) + abort (); + if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A)) + abort (); + if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A)) + abort (); + if (__builtin_object_size (&vara[5], 1) != (x + 5) * sizeof (struct A)) + abort (); #else if (__builtin_object_size (var, 1) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 1) != (size_t) -1) abort (); -#endif if (__builtin_object_size (&var[5], 1) != (size_t) -1) abort (); -#ifdef __builtin_object_size - if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A)) - abort (); - if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A)) - abort (); -#else if (__builtin_object_size (vara, 1) != (size_t) -1) abort (); if (__builtin_object_size (vara + 10, 1) != (size_t) -1) abort (); -#endif if (__builtin_object_size (&vara[5], 1) != (size_t) -1) abort (); +#endif if (__builtin_object_size (&vara[0].a, 1) != sizeof (vara[0].a)) abort (); if (__builtin_object_size (&vara[10].a[0], 1) != sizeof (vara[0].a)) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c index 753ee4a1a4f..db31171a8bd 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c @@ -42,9 +42,17 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (q, 2) != 0) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 2) + != (x < 0 + ? sizeof (a) - __builtin_offsetof (struct A, a) - 9 + : sizeof (a) - __builtin_offsetof (struct A, c) - 1)) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, c) - 1) abort (); +#endif if (x < 6) r = &w[2].a[1]; else @@ -58,15 +66,28 @@ test1 (void *q, int x) if (__builtin_object_size (&y.b, 2) != sizeof (a) - __builtin_offsetof (struct A, b)) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 2) + != (x < 6 + ? 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1 + : sizeof (a) - __builtin_offsetof (struct A, a) - 6)) + abort (); +#else if (__builtin_object_size (r, 2) != sizeof (a) - __builtin_offsetof (struct A, a) - 6) abort (); +#endif if (x < 20) r = malloc (30); else r = calloc (2, 16); +#ifdef __builtin_object_size + if (__builtin_object_size (r, 2) != (x < 20 ? 30 : 2 * 16)) + abort (); +#else if (__builtin_object_size (r, 2) != 30) abort (); +#endif if (x < 20) r = malloc (30); else @@ -145,14 +166,16 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (var + 10, 2) != x) abort (); + if (__builtin_object_size (&var[5], 2) != x + 5) + abort (); #else if (__builtin_object_size (var, 2) != 0) abort (); if (__builtin_object_size (var + 10, 2) != 0) abort (); -#endif if (__builtin_object_size (&var[5], 2) != 0) abort (); +#endif if (__builtin_object_size (zerol, 2) != 0) abort (); if (__builtin_object_size (&zerol, 2) != 0) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c index c383385e060..f644890dd14 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c @@ -155,27 +155,28 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (var + 10, 3) != x) abort (); + if (__builtin_object_size (&var[5], 3) != x + 5) + abort (); + if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A)) + abort (); + if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A)) + abort (); + if (__builtin_object_size (&vara[5], 3) != (x + 5) * sizeof (struct A)) + abort (); #else if (__builtin_object_size (var, 3) != 0) abort (); if (__builtin_object_size (var + 10, 3) != 0) abort (); -#endif if (__builtin_object_size (&var[5], 3) != 0) abort (); -#ifdef __builtin_object_size - if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A)) - abort (); - if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A)) - abort (); -#else if (__builtin_object_size (vara, 3) != 0) abort (); if (__builtin_object_size (vara + 10, 3) != 0) abort (); -#endif if (__builtin_object_size (&vara[5], 3) != 0) abort (); +#endif if (__builtin_object_size (&vara[0].a, 3) != sizeof (vara[0].a)) abort (); if (__builtin_object_size (&vara[10].a[0], 3) != sizeof (vara[0].a)) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index f03714c4f18..86cfb16855e 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -120,6 +120,14 @@ size_unknown_p (tree val, int object_size_type) && tree_to_uhwi (val) == unknown (object_size_type)); } +/* Return true if VAL is represents a valid size for OBJECT_SIZE_TYPE. */ + +static inline bool +size_valid_p (tree val, int object_size_type) +{ + return ((object_size_type & OST_DYNAMIC) || TREE_CODE (val) == INTEGER_CST); +} + /* Return a tree with initial value for OBJECT_SIZE_TYPE. */ static inline tree @@ -345,7 +353,6 @@ init_offset_limit (void) static tree size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) { - gcc_checking_assert (TREE_CODE (offset) == INTEGER_CST); gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype)); /* For negative offsets, if we have a distinct WHOLESIZE, use it to get a net @@ -544,18 +551,11 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, sz = wholesize = size_unknown (object_size_type); } if (!size_unknown_p (sz, object_size_type)) - { - tree offset = TREE_OPERAND (pt_var, 1); - if (TREE_CODE (offset) != INTEGER_CST - || TREE_CODE (sz) != INTEGER_CST) - sz = wholesize = size_unknown (object_size_type); - else - sz = size_for_offset (sz, offset, wholesize); - } + sz = size_for_offset (sz, TREE_OPERAND (pt_var, 1), wholesize); if (!size_unknown_p (sz, object_size_type) - && TREE_CODE (sz) == INTEGER_CST - && compare_tree_int (sz, offset_limit) < 0) + && (TREE_CODE (sz) != INTEGER_CST + || compare_tree_int (sz, offset_limit) < 0)) { pt_var_size = sz; pt_var_wholesize = wholesize; @@ -575,8 +575,9 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, if (pt_var_size) { - /* Validate the size determined above. */ - if (compare_tree_int (pt_var_size, offset_limit) >= 0) + /* Validate the size determined above if it is a constant. */ + if (TREE_CODE (pt_var_size) == INTEGER_CST + && compare_tree_int (pt_var_size, offset_limit) >= 0) return false; } @@ -600,7 +601,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, var = TREE_OPERAND (var, 0); if (! TYPE_SIZE_UNIT (TREE_TYPE (var)) || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var))) - || (pt_var_size + || (pt_var_size && TREE_CODE (pt_var_size) == INTEGER_CST && tree_int_cst_lt (pt_var_size, TYPE_SIZE_UNIT (TREE_TYPE (var))))) var = pt_var; @@ -614,17 +615,11 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, switch (TREE_CODE (v)) { case ARRAY_REF: - if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0))) - && TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST) + if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))) { tree domain = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0))); - if (domain - && TYPE_MAX_VALUE (domain) - && TREE_CODE (TYPE_MAX_VALUE (domain)) - == INTEGER_CST - && tree_int_cst_lt (TREE_OPERAND (v, 1), - TYPE_MAX_VALUE (domain))) + if (domain && TYPE_MAX_VALUE (domain)) { v = NULL_TREE; break; @@ -691,20 +686,20 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, var = pt_var; if (var != pt_var) - var_size = TYPE_SIZE_UNIT (TREE_TYPE (var)); + { + var_size = TYPE_SIZE_UNIT (TREE_TYPE (var)); + if (!TREE_CONSTANT (var_size)) + var_size = get_or_create_ssa_default_def (cfun, var_size); + if (!var_size) + return false; + } else if (!pt_var_size) return false; else var_size = pt_var_size; bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var); if (bytes != error_mark_node) - { - if (TREE_CODE (bytes) == INTEGER_CST - && tree_int_cst_lt (var_size, bytes)) - bytes = size_zero_node; - else - bytes = size_binop (MINUS_EXPR, var_size, bytes); - } + bytes = size_for_offset (var_size, bytes); if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF @@ -713,11 +708,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var); if (bytes2 != error_mark_node) { - if (TREE_CODE (bytes2) == INTEGER_CST - && tree_int_cst_lt (pt_var_size, bytes2)) - bytes2 = size_zero_node; - else - bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2); + bytes2 = size_for_offset (pt_var_size, bytes2); bytes = size_binop (MIN_EXPR, bytes, bytes2); } } @@ -733,14 +724,18 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, wholebytes = pt_var_wholesize; } - if (TREE_CODE (bytes) != INTEGER_CST - || TREE_CODE (wholebytes) != INTEGER_CST) - return false; + if (!size_unknown_p (bytes, object_size_type) + && size_valid_p (bytes, object_size_type) + && !size_unknown_p (bytes, object_size_type) + && size_valid_p (wholebytes, object_size_type)) + { + *psize = bytes; + if (pwholesize) + *pwholesize = wholebytes; + return true; + } - *psize = bytes; - if (pwholesize) - *pwholesize = wholebytes; - return true; + return false; } @@ -1066,11 +1061,11 @@ compute_builtin_object_size (tree ptr, int object_size_type, tree offset = gimple_assign_rhs2 (def); ptr = gimple_assign_rhs1 (def); - if (tree_fits_shwi_p (offset) + if (((object_size_type & OST_DYNAMIC) + || tree_fits_shwi_p (offset)) && compute_builtin_object_size (ptr, object_size_type, psize)) { - /* Return zero when the offset is out of bounds. */ *psize = size_for_offset (*psize, offset); return true; } @@ -1255,7 +1250,7 @@ call_object_size (struct object_size_info *osi, tree ptr, gcall *call) gcc_assert (osi->pass == 0); tree bytes = alloc_object_size (call, object_size_type); - if (!(object_size_type & OST_DYNAMIC) && TREE_CODE (bytes) != INTEGER_CST) + if (!size_valid_p (bytes, object_size_type)) bytes = size_unknown (object_size_type); object_sizes_set (osi, varno, bytes, bytes); @@ -1335,7 +1330,7 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) return false; /* Handle PTR + OFFSET here. */ - if (TREE_CODE (op1) == INTEGER_CST + if (((object_size_type & OST_DYNAMIC) || TREE_CODE (op1) == INTEGER_CST) && (TREE_CODE (op0) == SSA_NAME || TREE_CODE (op0) == ADDR_EXPR)) { @@ -1368,6 +1363,10 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) else bytes = wholesize = size_unknown (object_size_type); + if (!size_valid_p (bytes, object_size_type) + || !size_valid_p (wholesize, object_size_type)) + bytes = wholesize = size_unknown (object_size_type); + osi->changed = object_sizes_set (osi, varno, bytes, wholesize); return reexamine; }