From patchwork Wed Apr 22 21:36:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 1275423 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=gcc.gnu.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=FsDnNGGD; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 496v0F16R1z9sSM for ; Thu, 23 Apr 2020 07:36:59 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 80EFA3952501; Wed, 22 Apr 2020 21:36:56 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 80EFA3952501 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1587591416; bh=Fo3gjH7J8LzAUaR1DwnBYaX8g6Nal8cq4Je4IVZ+ZO4=; h=Subject:To:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=FsDnNGGDFsmfCkntM0TBfuuxzvIV0zNsdtd/KWsKbKdESynH4HtJxNzs/X1litnOz yz5R7LwF+ejzvdUHBxW3PzMgwIkdJDwjn2gLaKBssOYtHk3vcgXg2dA6+usYC0Fl4V MrQ3Hmrmr9YujBvR9KHUzbBfLfAWKNQmk8W1HZFw= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-qk1-x72e.google.com (mail-qk1-x72e.google.com [IPv6:2607:f8b0:4864:20::72e]) by sourceware.org (Postfix) with ESMTPS id 0B974385DC1F for ; Wed, 22 Apr 2020 21:36:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 0B974385DC1F Received: by mail-qk1-x72e.google.com with SMTP id b188so2565815qkd.9 for ; Wed, 22 Apr 2020 14:36:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:subject:to:message-id:date:user-agent :mime-version:content-language; bh=Fo3gjH7J8LzAUaR1DwnBYaX8g6Nal8cq4Je4IVZ+ZO4=; b=JT9iJ8YL5E3PqWUCRwEgAhYJnd4J8KeJmRo7WxRl8wNrg4LNpqEhxon3Qv1GSPiQdY CFEoAQGF9T/nRAld33BXNBQl3kZOmQgHCREupH3O5k+ouWsg9yyDyBx3FARYGyqRCRf6 7Z7/T/Us7V/l4NXvrK0uT6K+OFxLkjG3AT3tR1fPbWDRnEN6RGhwcXK0dpI811Z57YPA +uHjZsRPMD5MCxv/bsOD1gqH+DrFHRTyzRRXcu2+cgNrLaJiFQBDlYm3eKlAga0yXLqs zXUBPnzI/k6HqyO1JvCiDBQz+pFZu6PZemKjV+4d2wBvrukRI/IfIgnkR0dl5JM/R036 1kgg== X-Gm-Message-State: AGi0PubA8OHqB0s0W60acWQCoMG4+/40JbZCRzg4h6BNRzbKGNrFZiP0 GsJCrow5ckBNbtc0SfKvm77n2YLa X-Google-Smtp-Source: APiQypIq4vBxnJhxFO2JLyJ3+8l1ZicqMtHjybLH/+IP9ft1K5Wr3g2qoNSO7RgQvjiR/YAp3nqjDw== X-Received: by 2002:a37:7a84:: with SMTP id v126mr320699qkc.423.1587591412435; Wed, 22 Apr 2020 14:36:52 -0700 (PDT) Received: from [192.168.0.41] (71-218-0-44.hlrn.qwest.net. [71.218.0.44]) by smtp.gmail.com with ESMTPSA id a17sm314093qka.37.2020.04.22.14.36.51 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Wed, 22 Apr 2020 14:36:51 -0700 (PDT) Subject: [PATCH] handle initialized flexible array members in __builtin_object_size [PR92815] To: gcc-patches Message-ID: <9962840d-d5e0-7cdc-8e46-ade42ae1d18d@gmail.com> Date: Wed, 22 Apr 2020 15:36:50 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.6.1 MIME-Version: 1.0 Content-Language: en-US X-Spam-Status: No, score=-21.0 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) 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-Patchwork-Original-From: Martin Sebor via Gcc-patches From: Martin Sebor Reply-To: Martin Sebor Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" When computing the size of an object with a flexible array member the object size pass doesn't consider that the initializer of such an object can result in its size being in excess of the size of the enclosing type. As a result, stores into such objects by string functions causes false positive warnings and can abort at runtime. The warnings are an old regression but as more of them make use of the object size results more of them are affected by the bug. The abort goes back to when support for _FORTIFY_SOURCE was added. The same problem has already been independently fixed in GCC 10 for -Warray-bounds which doesn't use the object size checking pass, but the object size bug still remains. The attached patch corrects it as well. Tested on x86_64-linux. Martin PR middle-end/92815 - spurious -Wstringop-overflow writing into a flexible array of an extern struct gcc/ChangeLog: PR middle-end/92815 * tree-object-size.c (decl_init_size): New function. (addr_object_size): Call it. * tree.h (last_field): Declare. (first_field): Add attribute nonnull. gcc/testsuite/ChangeLog: PR middle-end/92815 * gcc.dg/Warray-bounds-56.c: Remove xfails. * gcc.dg/builtin-object-size-20.c: New test. diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-56.c b/gcc/testsuite/gcc.dg/Warray-bounds-56.c index 399c9b263b3..04c26a659ad 100644 --- a/gcc/testsuite/gcc.dg/Warray-bounds-56.c +++ b/gcc/testsuite/gcc.dg/Warray-bounds-56.c @@ -42,8 +42,8 @@ struct Flex f3 = { 3, { 1, 2, 3 } }; NOIPA void test_strcpy_flexarray (void) { - T (S (0), fx); // { dg-bogus "\\\[-Warray-bounds" "pr92815" { xfail *-*-*} } - T (S (9), fx); // { dg-bogus "\\\[-Warray-bounds" "pr92815" { xfail *-*-*} } + T (S (0), fx); // { dg-bogus "\\\[-Warray-bounds" "pr92815" } + T (S (9), fx); // { dg-bogus "\\\[-Warray-bounds" "pr92815" } T (S (0), f1); T (S (1), f1); // { dg-warning "\\\[-Warray-bounds" } diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-20.c b/gcc/testsuite/gcc.dg/builtin-object-size-20.c new file mode 100644 index 00000000000..47821c06d76 --- /dev/null +++ b/gcc/testsuite/gcc.dg/builtin-object-size-20.c @@ -0,0 +1,315 @@ +/* PR middle-end/92815 - spurious -Wstringop-overflow writing into + a flexible array of an extern struct + { dg-do compile } + { dg-options "-Wall -fdump-tree-optimized" } */ + +#define ASSERT(expr) ((expr) ? (void)0 : fail (__LINE__)) +#define bos0(expr) __builtin_object_size (expr, 1) +#define bos1(expr) __builtin_object_size (expr, 1) +#define bos2(expr) __builtin_object_size (expr, 2) +#define bos3(expr) __builtin_object_size (expr, 3) + +typedef __INT16_TYPE__ int16_t; +typedef __INT32_TYPE__ int32_t; +typedef __INT64_TYPE__ int64_t; +typedef __SIZE_TYPE__ size_t; + + +extern void fail (int); + + +/* Verify sizes of a struct with a flexible array member and no padding. */ + +struct ACX { char n, a[]; }; + +struct ACX ac0 = { }; +struct ACX ac1 = { 1, { 1 } }; +struct ACX ac2 = { 2, { 1, 2 } }; +struct ACX ac3 = { 3, { 1, 2, 3 } }; + +extern struct ACX eacx; + +void facx (void) +{ + ASSERT (bos0 (&ac0) == sizeof ac0); + ASSERT (bos0 (&ac1) == 2); + ASSERT (bos0 (&ac2) == 3); + ASSERT (bos0 (&ac3) == 4); + ASSERT (bos0 (&eacx) == (size_t)-1); + + ASSERT (bos1 (&ac0) == sizeof ac0); + ASSERT (bos1 (&ac1) == 2); + ASSERT (bos1 (&ac2) == 3); + ASSERT (bos1 (&ac3) == 4); + ASSERT (bos1 (&eacx) == (size_t)-1); + + ASSERT (bos2 (&ac0) == sizeof ac0); + ASSERT (bos2 (&ac1) == 2); + ASSERT (bos2 (&ac2) == 3); + ASSERT (bos2 (&ac3) == 4); + ASSERT (bos2 (&eacx) == sizeof eacx); + + ASSERT (bos3 (&ac0) == sizeof ac0); + ASSERT (bos3 (&ac1) == 2); + ASSERT (bos3 (&ac2) == 3); + ASSERT (bos3 (&ac3) == 4); + ASSERT (bos3 (&eacx) == sizeof eacx); +} + + + +/* Verify sizes of a struct with a flexible array member and 1 byte + of tail padding. */ + +struct AI16CX { int16_t i; char n, a[]; }; + +struct AI16CX ai16c0 = { 0 }; +struct AI16CX ai16c1 = { 0, 1, { 1 } }; +struct AI16CX ai16c2 = { 0, 2, { 1, 2 } }; +struct AI16CX ai16c3 = { 0, 3, { 1, 2, 3 } }; +struct AI16CX ai16c4 = { 0, 4, { 1, 2, 3, 4 } }; +struct AI16CX ai16c5 = { 0, 5, { 1, 2, 3, 4, 5 } }; +struct AI16CX ai16c6 = { 0, 6, { 1, 2, 3, 4, 5, 6 } }; +struct AI16CX ai16c7 = { 0, 7, { 1, 2, 3, 4, 5, 6, 7 } }; +struct AI16CX ai16c8 = { 0, 8, { 1, 2, 3, 4, 5, 6, 7, 8 } }; + +extern struct AI16CX eai16cx; + +void fai16cx (void) +{ + ASSERT (bos0 (&ai16c0) == sizeof ai16c0); + ASSERT (bos0 (&ai16c1) == sizeof ai16c1); + ASSERT (bos0 (&ai16c2) == sizeof ai16c2 + 1); + ASSERT (bos0 (&ai16c3) == sizeof ai16c3 + 2); + + ASSERT (bos0 (&ai16c4) == sizeof ai16c4 + 3); + ASSERT (bos0 (&ai16c5) == sizeof ai16c5 + 4); + ASSERT (bos0 (&ai16c6) == sizeof ai16c6 + 5); + ASSERT (bos0 (&ai16c7) == sizeof ai16c6 + 6); + ASSERT (bos0 (&ai16c8) == sizeof ai16c6 + 7); + + ASSERT (bos0 (&eai16cx) == (size_t)-1); + + + ASSERT (bos1 (&ai16c0) == sizeof ai16c0); + ASSERT (bos1 (&ai16c1) == sizeof ai16c1); + ASSERT (bos1 (&ai16c2) == sizeof ai16c2 + 1); + ASSERT (bos1 (&ai16c3) == sizeof ai16c3 + 2); + + ASSERT (bos1 (&ai16c4) == sizeof ai16c4 + 3); + ASSERT (bos1 (&ai16c5) == sizeof ai16c5 + 4); + ASSERT (bos1 (&ai16c6) == sizeof ai16c6 + 5); + ASSERT (bos1 (&ai16c7) == sizeof ai16c6 + 6); + ASSERT (bos1 (&ai16c8) == sizeof ai16c6 + 7); + + ASSERT (bos1 (&eai16cx) == (size_t)-1); + + + ASSERT (bos2 (&ai16c0) == sizeof ai16c0); + ASSERT (bos2 (&ai16c1) == sizeof ai16c1); + ASSERT (bos2 (&ai16c2) == sizeof ai16c2 + 1); + ASSERT (bos2 (&ai16c3) == sizeof ai16c3 + 2); + + ASSERT (bos2 (&ai16c4) == sizeof ai16c4 + 3); + ASSERT (bos2 (&ai16c5) == sizeof ai16c5 + 4); + ASSERT (bos2 (&ai16c6) == sizeof ai16c6 + 5); + ASSERT (bos2 (&ai16c7) == sizeof ai16c6 + 6); + ASSERT (bos2 (&ai16c8) == sizeof ai16c6 + 7); + + ASSERT (bos2 (&eai16cx) == sizeof eai16cx); + + + ASSERT (bos3 (&ai16c0) == sizeof ai16c0); + ASSERT (bos3 (&ai16c1) == sizeof ai16c1); + ASSERT (bos3 (&ai16c2) == sizeof ai16c2 + 1); + ASSERT (bos3 (&ai16c3) == sizeof ai16c3 + 2); + + ASSERT (bos3 (&ai16c4) == sizeof ai16c4 + 3); + ASSERT (bos3 (&ai16c5) == sizeof ai16c5 + 4); + ASSERT (bos3 (&ai16c6) == sizeof ai16c6 + 5); + ASSERT (bos3 (&ai16c7) == sizeof ai16c6 + 6); + ASSERT (bos3 (&ai16c8) == sizeof ai16c6 + 7); + + ASSERT (bos3 (&eai16cx) == sizeof eai16cx); +} + + +/* Verify sizes of a struct with a flexible array member and 3 bytes + of tail padding. */ + +struct AI32CX { int32_t i; char n, a[]; }; + +struct AI32CX ai32c0 = { 0 }; +struct AI32CX ai32c1 = { 0, 1, { 1 } }; +struct AI32CX ai32c2 = { 0, 2, { 1, 2 } }; +struct AI32CX ai32c3 = { 0, 3, { 1, 2, 3 } }; +struct AI32CX ai32c4 = { 0, 4, { 1, 2, 3, 4 } }; +struct AI32CX ai32c5 = { 0, 5, { 1, 2, 3, 4, 5 } }; +struct AI32CX ai32c6 = { 0, 6, { 1, 2, 3, 4, 5, 6 } }; +struct AI32CX ai32c7 = { 0, 7, { 1, 2, 3, 4, 5, 6, 7 } }; +struct AI32CX ai32c8 = { 0, 8, { 1, 2, 3, 4, 5, 6, 7, 8 } }; + +extern struct AI32CX eai32cx; + +void fai32cx (void) +{ + ASSERT (bos0 (&ai32c0) == sizeof ai32c0); + ASSERT (bos0 (&ai32c1) == sizeof ai32c1); + ASSERT (bos0 (&ai32c2) == sizeof ai32c2); + ASSERT (bos0 (&ai32c3) == sizeof ai32c3); + + ASSERT (bos0 (&ai32c4) == sizeof ai32c4 + 1); + ASSERT (bos0 (&ai32c5) == sizeof ai32c5 + 2); + ASSERT (bos0 (&ai32c6) == sizeof ai32c6 + 3); + ASSERT (bos0 (&ai32c7) == sizeof ai32c6 + 4); + ASSERT (bos0 (&ai32c8) == sizeof ai32c6 + 5); + + ASSERT (bos0 (&eai32cx) == (size_t)-1); + + + ASSERT (bos1 (&ai32c0) == sizeof ai32c0); + ASSERT (bos1 (&ai32c1) == sizeof ai32c1); + ASSERT (bos1 (&ai32c2) == sizeof ai32c2); + ASSERT (bos1 (&ai32c3) == sizeof ai32c3); + + ASSERT (bos1 (&ai32c4) == sizeof ai32c4 + 1); + ASSERT (bos1 (&ai32c5) == sizeof ai32c5 + 2); + ASSERT (bos1 (&ai32c6) == sizeof ai32c6 + 3); + ASSERT (bos1 (&ai32c7) == sizeof ai32c6 + 4); + ASSERT (bos1 (&ai32c8) == sizeof ai32c6 + 5); + + ASSERT (bos1 (&eai32cx) == (size_t)-1); + + + ASSERT (bos2 (&ai32c0) == sizeof ai32c0); + ASSERT (bos2 (&ai32c1) == sizeof ai32c1); + ASSERT (bos2 (&ai32c2) == sizeof ai32c2); + ASSERT (bos2 (&ai32c3) == sizeof ai32c3); + + ASSERT (bos2 (&ai32c4) == sizeof ai32c4 + 1); + ASSERT (bos2 (&ai32c5) == sizeof ai32c5 + 2); + ASSERT (bos2 (&ai32c6) == sizeof ai32c6 + 3); + ASSERT (bos2 (&ai32c7) == sizeof ai32c6 + 4); + ASSERT (bos2 (&ai32c8) == sizeof ai32c6 + 5); + + ASSERT (bos2 (&eai32cx) == sizeof eai32cx); + + + ASSERT (bos3 (&ai32c0) == sizeof ai32c0); + ASSERT (bos3 (&ai32c1) == sizeof ai32c1); + ASSERT (bos3 (&ai32c2) == sizeof ai32c2); + ASSERT (bos3 (&ai32c3) == sizeof ai32c3); + + ASSERT (bos3 (&ai32c4) == sizeof ai32c4 + 1); + ASSERT (bos3 (&ai32c5) == sizeof ai32c5 + 2); + ASSERT (bos3 (&ai32c6) == sizeof ai32c6 + 3); + ASSERT (bos3 (&ai32c7) == sizeof ai32c6 + 4); + ASSERT (bos3 (&ai32c8) == sizeof ai32c6 + 5); + + ASSERT (bos3 (&eai32cx) == sizeof eai32cx); +} + + +/* Verify sizes of a struct with a flexible array member and 7 bytes + of tail padding. */ + +struct AI64CX { int64_t i; char n, a[]; }; + +struct AI64CX ai64c0 = { 0 }; +struct AI64CX ai64c1 = { 0, 1, { 1 } }; +struct AI64CX ai64c2 = { 0, 2, { 1, 2 } }; +struct AI64CX ai64c3 = { 0, 3, { 1, 2, 3 } }; +struct AI64CX ai64c4 = { 0, 4, { 1, 2, 3, 4 } }; +struct AI64CX ai64c5 = { 0, 5, { 1, 2, 3, 4, 5 } }; +struct AI64CX ai64c6 = { 0, 6, { 1, 2, 3, 4, 5, 6 } }; +struct AI64CX ai64c7 = { 0, 7, { 1, 2, 3, 4, 5, 6, 7 } }; +struct AI64CX ai64c8 = { 0, 8, { 1, 2, 3, 4, 5, 6, 7, 8 } }; +struct AI64CX ai64c9 = { 0, 8, { 1, 2, 3, 4, 5, 6, 7, 8, 9 } }; + +extern struct AI64CX eai64cx; + +void fai64cx (void) +{ + ASSERT (bos0 (&ai64c0) == sizeof ai64c0); + ASSERT (bos0 (&ai64c1) == sizeof ai64c1); + ASSERT (bos0 (&ai64c2) == sizeof ai64c2); + ASSERT (bos0 (&ai64c3) == sizeof ai64c3); + ASSERT (bos0 (&ai64c4) == sizeof ai64c4); + ASSERT (bos0 (&ai64c5) == sizeof ai64c5); + ASSERT (bos0 (&ai64c6) == sizeof ai64c6); + ASSERT (bos0 (&ai64c7) == sizeof ai64c7); + + ASSERT (bos0 (&ai64c8) == sizeof ai64c8 + 1); + ASSERT (bos0 (&ai64c9) == sizeof ai64c9 + 2); + + ASSERT (bos0 (&eai64cx) == (size_t)-1); + + + ASSERT (bos1 (&ai64c0) == sizeof ai64c0); + ASSERT (bos1 (&ai64c1) == sizeof ai64c1); + ASSERT (bos1 (&ai64c2) == sizeof ai64c2); + ASSERT (bos1 (&ai64c3) == sizeof ai64c3); + ASSERT (bos1 (&ai64c4) == sizeof ai64c4); + ASSERT (bos1 (&ai64c5) == sizeof ai64c5); + ASSERT (bos1 (&ai64c6) == sizeof ai64c6); + ASSERT (bos1 (&ai64c7) == sizeof ai64c7); + + ASSERT (bos1 (&ai64c8) == sizeof ai64c8 + 1); + ASSERT (bos1 (&ai64c9) == sizeof ai64c9 + 2); + + ASSERT (bos1 (&eai64cx) == (size_t)-1); + + + ASSERT (bos2 (&ai64c0) == sizeof ai64c0); + ASSERT (bos2 (&ai64c1) == sizeof ai64c1); + ASSERT (bos2 (&ai64c2) == sizeof ai64c2); + ASSERT (bos2 (&ai64c3) == sizeof ai64c3); + ASSERT (bos2 (&ai64c4) == sizeof ai64c4); + ASSERT (bos2 (&ai64c5) == sizeof ai64c5); + ASSERT (bos2 (&ai64c6) == sizeof ai64c6); + ASSERT (bos2 (&ai64c7) == sizeof ai64c7); + + ASSERT (bos2 (&ai64c8) == sizeof ai64c8 + 1); + ASSERT (bos2 (&ai64c9) == sizeof ai64c9 + 2); + + ASSERT (bos2 (&eai64cx) == sizeof eai64cx); + + ASSERT (bos3 (&ai64c0) == sizeof ai64c0); + ASSERT (bos3 (&ai64c1) == sizeof ai64c1); + ASSERT (bos3 (&ai64c2) == sizeof ai64c2); + ASSERT (bos3 (&ai64c3) == sizeof ai64c3); + ASSERT (bos3 (&ai64c4) == sizeof ai64c4); + ASSERT (bos3 (&ai64c5) == sizeof ai64c5); + ASSERT (bos3 (&ai64c6) == sizeof ai64c6); + ASSERT (bos3 (&ai64c7) == sizeof ai64c7); + + ASSERT (bos3 (&ai64c8) == sizeof ai64c8 + 1); + ASSERT (bos3 (&ai64c9) == sizeof ai64c9 + 2); + + ASSERT (bos3 (&eai64cx) == sizeof eai64cx); +} + + +/* Also verify sizes of a struct with a zero length array member. */ + +struct A0C0 { char n, a[0]; }; + +struct A0C0 a0c0 = { }; +extern struct A0C0 ea0c0; + +void fa0c0 (void) +{ + ASSERT (bos0 (&a0c0) == sizeof a0c0); + ASSERT (bos0 (&ea0c0) == sizeof ea0c0); + + ASSERT (bos1 (&a0c0) == sizeof a0c0); + ASSERT (bos1 (&a0c0) == sizeof ea0c0); + + ASSERT (bos2 (&a0c0) == sizeof a0c0); + ASSERT (bos2 (&a0c0) == sizeof ea0c0); + + ASSERT (bos3 (&a0c0) == sizeof a0c0); + ASSERT (bos3 (&a0c0) == sizeof ea0c0); +} + +/* { dg-final { scan-tree-dump-not "fail" "optimized" } } */ diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c index 255ea63cab6..5d4cc485fba 100644 --- a/gcc/tree-object-size.c +++ b/gcc/tree-object-size.c @@ -166,6 +166,42 @@ compute_object_offset (const_tree expr, const_tree var) return size_binop (code, base, off); } +/* Returns the size of the object designated by DECL considering its + initializer if it either has one or if it would not affect its size, + otherwise the size of the object without the initializer when MIN + is true, else null. An object's initializer affects the object's + size if it's a struct type with a flexible array member. */ + +static tree +decl_init_size (tree decl, bool min) +{ + tree size = DECL_SIZE_UNIT (decl); + tree type = TREE_TYPE (decl); + if (TREE_CODE (type) != RECORD_TYPE) + return size; + + tree last = last_field (type); + if (!last) + return size; + + tree last_type = TREE_TYPE (last); + if (TREE_CODE (last_type) != ARRAY_TYPE + || TYPE_SIZE (last_type)) + return size; + + /* Use TYPE_SIZE_UNIT; DECL_SIZE_UNIT sometimes reflects the size + of the initializer and sometimes doesn't. */ + size = TYPE_SIZE_UNIT (type); + tree ref = build3 (COMPONENT_REF, type, decl, last, NULL_TREE); + tree compsize = component_ref_size (ref); + if (!compsize) + return min ? size : NULL_TREE; + + /* The size includes tail padding and initializer elements. */ + tree pos = byte_position (last); + size = fold_build2 (PLUS_EXPR, TREE_TYPE (size), pos, compsize); + return size; +} /* Compute __builtin_object_size for PTR, which is a ADDR_EXPR. OBJECT_SIZE_TYPE is the second argument from __builtin_object_size. @@ -242,7 +278,7 @@ addr_object_size (struct object_size_info *osi, const_tree ptr, && tree_to_uhwi (DECL_SIZE_UNIT (pt_var)) < offset_limit) { *pdecl = pt_var; - pt_var_size = DECL_SIZE_UNIT (pt_var); + pt_var_size = decl_init_size (pt_var, object_size_type & 2); } else if (pt_var && TREE_CODE (pt_var) == STRING_CST diff --git a/gcc/tree.h b/gcc/tree.h index 1c28785d411..c91a834564d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -4692,9 +4692,10 @@ extern tree nreverse (tree); extern int list_length (const_tree); -/* Returns the first FIELD_DECL in a type. */ +/* Returns the first/last FIELD_DECL in a RECORD_TYPE. */ -extern tree first_field (const_tree); +extern tree first_field (const_tree) ATTRIBUTE_NONNULL (1); +extern tree last_field (const_tree) ATTRIBUTE_NONNULL (1); /* Given an initializer INIT, return TRUE if INIT is zero or some aggregate of zeros. Otherwise return FALSE. If NONZERO is not