From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from bee.birch.relay.mailchannels.net (bee.birch.relay.mailchannels.net [23.83.209.14]) by sourceware.org (Postfix) with ESMTPS id 7F00B3858400 for ; Wed, 5 Jan 2022 13:21:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 7F00B3858400 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 0490C2A193F; Wed, 5 Jan 2022 13:21:11 +0000 (UTC) Received: from pdx1-sub0-mail-a304.dreamhost.com (unknown [127.0.0.6]) (Authenticated sender: dreamhost) by relay.mailchannels.net (Postfix) with ESMTPA id 2C3FD2A1885; Wed, 5 Jan 2022 13:21:10 +0000 (UTC) X-Sender-Id: dreamhost|x-authsender|siddhesh@gotplt.org Received: from pdx1-sub0-mail-a304.dreamhost.com (pop.dreamhost.com [64.90.62.162]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384) by 100.121.9.225 (trex/6.4.3); Wed, 05 Jan 2022 13:21:10 +0000 X-MC-Relay: Neutral X-MailChannels-SenderId: dreamhost|x-authsender|siddhesh@gotplt.org X-MailChannels-Auth-Id: dreamhost X-Gusty-Shoe: 22d4e3c62f7b984e_1641388870818_439993166 X-MC-Loop-Signature: 1641388870818:2432646271 X-MC-Ingress-Time: 1641388870817 Received: from rhbox.redhat.com (unknown [1.186.123.58]) (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-a304.dreamhost.com (Postfix) with ESMTPSA id 4JTVVX3vk8z2k; Wed, 5 Jan 2022 05:21:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gotplt.org; s=gotplt.org; t=1641388869; bh=hZSCNMTqmkHOmfAHNejhUglqulA=; h=From:To:Cc:Subject:Date:Content-Transfer-Encoding; b=caAWvr03BbRvQCkmfLdTQZMHKRjUkLbNoDNEN3+FRjxZNSmaFVB2DgMIE2v5BSSSQ NnYKD2V7SMCF9xaIelC/ufdXCzv1tTC1sSVBcPWpfUyfMNTwaTN2jFAQ+PmFfEaBvz qc52wpVu1SMIqLMrUSqbqiHh6MSVTvtf7Pg2YOmw= From: Siddhesh Poyarekar To: gcc-patches@gcc.gnu.org Cc: jakub@redhat.com Subject: [PATCH] middle-end/77608: object size estimate with variable offsets Date: Wed, 5 Jan 2022 18:50:58 +0530 Message-Id: <20220105132058.1073416-1-siddhesh@gotplt.org> X-Mailer: git-send-email 2.33.1 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3037.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_SBL, 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: , X-List-Received-Date: Wed, 05 Jan 2022 13:21:15 -0000 This partially fixes middle-end/77608 by making __builtin_object_size return the whole object size instead of bailing out in case the offset in the object is variable and the maximum estimate is requested. gcc/ChangeLog: PR middle-end/77608 * tree-object-size.c (size_for_offset): New object_size_type parameter. Return known whole size if offset is not constant. (addr_object_size, compute_builtin_object_size): Adjust. (plus_stmt_object_size): Defer constness check of offset to size_for_offset. gcc/testsuite/ChangeLog: PR middle-end/77608 * gcc.dg/builtin-object-size-1.c (test1): Add tests. * gcc.dg/builtin-object-size-2.c (test1): Likewise. Signed-off-by: Siddhesh Poyarekar --- This applies on top of the __builtin_dynamic_object_size patchset. It should be possible to process trees with side effects and fully fix 77608, but I'll do that later since it would be a bit more involved. Tested with a full bootstrap on x86_64 and ubsan bootstrap. gcc/testsuite/gcc.dg/builtin-object-size-1.c | 16 ++++ gcc/testsuite/gcc.dg/builtin-object-size-2.c | 37 ++++++++++ gcc/tree-object-size.c | 77 +++++++++++--------- 3 files changed, 97 insertions(+), 33 deletions(-) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c index 161f426ec0b..0f92713b141 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c @@ -22,6 +22,8 @@ struct A extern char exta[]; extern char extb[30]; extern struct A zerol[0]; +int off = 2; +int off2 = -3; void __attribute__ ((noinline)) @@ -162,6 +164,13 @@ test1 (void *q, int x) if (__builtin_object_size (&extb[5], 0) != sizeof (extb) - 5) abort (); #ifdef __builtin_object_size + if (__builtin_object_size (&extb[off], 0) != sizeof (extb) - off) + abort (); + r = &extb[5]; + if (__builtin_object_size (r + off, 0) != sizeof (extb) - 5 - off) + abort (); + if (__builtin_object_size (r + off2, 0) != sizeof (extb) - 5 - off2) + abort (); if (__builtin_object_size (var, 0) != x + 10) abort (); if (__builtin_object_size (var + 10, 0) != x) @@ -169,6 +178,13 @@ test1 (void *q, int x) if (__builtin_object_size (&var[5], 0) != x + 5) abort (); #else + if (__builtin_object_size (&extb[off], 0) != sizeof (extb)) + abort (); + r = &extb[5]; + if (__builtin_object_size (r + off, 0) != sizeof (extb)) + abort (); + if (__builtin_object_size (r + off2, 0) != sizeof (extb)) + abort (); if (__builtin_object_size (var, 0) != (size_t) -1) abort (); if (__builtin_object_size (var + 10, 0) != (size_t) -1) diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c index 2729538da17..62a5af1384a 100644 --- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c +++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c @@ -24,6 +24,9 @@ extern char extb[30]; extern struct A extc[]; struct A zerol[0]; +int off = 3; +int off2 = -3; + void __attribute__ ((noinline)) test1 (void *q, int x) @@ -151,6 +154,23 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&extb[5], 1) != sizeof (extb) - 5) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (&extb[off], 1) != sizeof (extb) - off) + abort (); + r = &extb[5]; + if (__builtin_object_size (r + off, 1) != sizeof (extb) - 5 - off) + abort (); + if (__builtin_object_size (r + off2, 0) != sizeof (extb) - 5 - off2) + abort (); +#else + if (__builtin_object_size (&extb[off], 1) != sizeof (extb)) + abort (); + r = &extb[5]; + if (__builtin_object_size (r + off, 1) != sizeof (extb)) + abort (); + if (__builtin_object_size (r + off2, 0) != sizeof (extb)) + abort (); +#endif if (__builtin_object_size (extc, 1) != (size_t) -1) abort (); if (__builtin_object_size (extc + 10, 1) != (size_t) -1) @@ -200,6 +220,23 @@ test1 (void *q, int x) abort (); if (__builtin_object_size (&vara[7].c[7], 1) != sizeof (vara[0].c) - 7) abort (); +#ifdef __builtin_object_size + if (__builtin_object_size (&vara[5].c[off], 1) != sizeof (vara[0].c) - off) + abort (); + r = &vara[1].c[5]; + if (__builtin_object_size (r + off, 1) != sizeof (vara[0].c) - 5 - off) + abort (); + if (__builtin_object_size (r + off2, 1) != sizeof (vara[0].c) - 5 - off2) + abort (); +#else + if (__builtin_object_size (&vara[5].c[off], 1) != sizeof (vara[0].c)) + abort (); + r = &vara[1].c[5]; + if (__builtin_object_size (r + off, 1) != sizeof (vara[0].c)) + abort (); + if (__builtin_object_size (r + off2, 1) != sizeof (vara[0].c)) + abort (); +#endif if (__builtin_object_size (zerol, 1) != 0) abort (); if (__builtin_object_size (&zerol, 1) != 0) diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index bf45adc7307..b5cb637f207 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -347,10 +347,21 @@ init_offset_limit (void) be positive and hence, be within OFFSET_LIMIT for valid offsets. */ static tree -size_for_offset (tree sz, tree offset, tree wholesize = NULL_TREE) +size_for_offset (int object_size_type,tree sz, tree offset, + tree wholesize = NULL_TREE) { gcc_checking_assert (types_compatible_p (TREE_TYPE (sz), sizetype)); + /* When maximum size is requested and the offset is non-constant, return the + whole size instead of bailing out in __builtin_object_size. */ + if (!(object_size_type & (OST_MINIMUM | OST_DYNAMIC)) + && TREE_CODE (offset) != INTEGER_CST) + { + if (wholesize) + sz = wholesize; + offset = size_zero_node; + } + /* For negative offsets, if we have a distinct WHOLESIZE, use it to get a net offset from the whole object. */ if (wholesize && wholesize != sz @@ -547,7 +558,8 @@ 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)) - sz = size_for_offset (sz, TREE_OPERAND (pt_var, 1), wholesize); + sz = size_for_offset (object_size_type, sz, TREE_OPERAND (pt_var, 1), + wholesize); if (!size_unknown_p (sz, object_size_type) && (TREE_CODE (sz) != INTEGER_CST @@ -695,7 +707,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, var_size = pt_var_size; bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var); if (bytes != error_mark_node) - bytes = size_for_offset (var_size, bytes); + bytes = size_for_offset (object_size_type, var_size, bytes); if (var != pt_var && pt_var_size && TREE_CODE (pt_var) == MEM_REF @@ -704,7 +716,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) { - bytes2 = size_for_offset (pt_var_size, bytes2); + bytes2 = size_for_offset (object_size_type, pt_var_size, bytes2); bytes = size_binop (MIN_EXPR, bytes, bytes2); } } @@ -1058,7 +1070,7 @@ compute_builtin_object_size (tree ptr, int object_size_type, && compute_builtin_object_size (ptr, object_size_type, psize)) { - *psize = size_for_offset (*psize, offset); + *psize = size_for_offset (object_size_type, *psize, offset); return true; } } @@ -1323,43 +1335,42 @@ plus_stmt_object_size (struct object_size_info *osi, tree var, gimple *stmt) return false; /* Handle PTR + OFFSET here. */ - if (((object_size_type & OST_DYNAMIC) || TREE_CODE (op1) == INTEGER_CST) - && (TREE_CODE (op0) == SSA_NAME - || TREE_CODE (op0) == ADDR_EXPR)) + if (TREE_CODE (op0) == SSA_NAME) { - if (TREE_CODE (op0) == SSA_NAME) - { - if (osi->pass == 0) - collect_object_sizes_for (osi, op0); + 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 - { - /* 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); + 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 if (TREE_CODE (op0) == ADDR_EXPR) + { + /* 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); } else - bytes = wholesize = size_unknown (object_size_type); + { + bytes = wholesize = size_unknown (object_size_type); + goto out; + } + + /* 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 (object_size_type, bytes, op1, wholesize); if (!size_valid_p (bytes, object_size_type) || !size_valid_p (wholesize, object_size_type)) bytes = wholesize = size_unknown (object_size_type); +out: if (object_sizes_set (osi, varno, bytes, wholesize)) osi->changed = true; return reexamine; -- 2.33.1