From patchwork Fri Sep 17 00:28:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Sebor X-Patchwork-Id: 45109 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 AFDBD385742E for ; Fri, 17 Sep 2021 00:29:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org AFDBD385742E DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1631838568; bh=xpNlf200EBZF8MRiAq9ycUoiiqxZWn6puD9RE1WoubU=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=J1WfHVWsFUZ9SF9HXADbEM+hyIXZydrFBH2VdXw32bpa520v7SCz4QWA5//NjhsYa mgNMDqJI3Ezfw9zG8V4Cxs5GEK7tnfocMFANGXzu/orTtJqMZnCJot1+D10OtxM1Xs L6xfQcWHS3jGWxbPstPGm9BvAQjDYUeKKhjKvYmU= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-qk1-x731.google.com (mail-qk1-x731.google.com [IPv6:2607:f8b0:4864:20::731]) by sourceware.org (Postfix) with ESMTPS id EB180385841D for ; Fri, 17 Sep 2021 00:28:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EB180385841D Received: by mail-qk1-x731.google.com with SMTP id 72so352602qkk.7 for ; Thu, 16 Sep 2021 17:28:57 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:to:from:subject:message-id:date:user-agent :mime-version:content-language; bh=xpNlf200EBZF8MRiAq9ycUoiiqxZWn6puD9RE1WoubU=; b=xqq9f/+E7Gx1NyMfaWotVb/idSVPH708vwSaBq+qDppzj6bcyjq5qC+r3QlydhM9v5 UMhXeRxU91DqUrv76iX9tOcYP+3uQoKtRIoAGM2sASbcGmoqRuS9wH7MXRNHfzs0RMUs fY3C+pPlnzl5cIG1ex4Gtj6nOiLHUrs4tUdHJO+aH1Ghhyvb6f5OgVcHpMWRS395cs0h 20feKsoOmG3D7eZ2FU8QmNEsTXxaAFbtI1n/ROox8Ztwwt98o0lnLqgrXRt0tBL81dnq MZZB2Pk2WYWPkNjADlWnDVCzFsBSazKY7EEHVP5CsjqwTrqzuzIF3aRVDPU1iVlEWB97 zrlQ== X-Gm-Message-State: AOAM531IFdI8W4Gv7xJr8wJiJfu7reXempz/3cphDfklVbvpyowQLOY0 Mf+OC3Z7ZUXTH6OToeK8Ot/vJKQt9qc= X-Google-Smtp-Source: ABdhPJwYT+jAvUZQXpVG92+ucC8apOAafqVE6W+txnx9zi3c7xxHmUmKjLX1xbDeM/eYtEQ2zAEL7Q== X-Received: by 2002:a05:620a:444b:: with SMTP id w11mr7821271qkp.479.1631838537375; Thu, 16 Sep 2021 17:28:57 -0700 (PDT) Received: from [192.168.0.41] (97-118-96-133.hlrn.qwest.net. [97.118.96.133]) by smtp.gmail.com with ESMTPSA id r139sm2088960qke.84.2021.09.16.17.28.56 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 16 Sep 2021 17:28:56 -0700 (PDT) To: gcc-patches Subject: [PATCH] better handle MIN/MAX_EXPR of unrelated objects [PR102200] Message-ID: <0e9718c5-3c42-4f32-da36-200272b77f09@gmail.com> Date: Thu, 16 Sep 2021 18:28:55 -0600 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.2.2 MIME-Version: 1.0 Content-Language: en-US X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, 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: , X-Patchwork-Original-From: Martin Sebor via Gcc-patches From: Martin Sebor Reply-To: Martin Sebor Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" When computing the size of an object pointed to by the result of a MIN/MAX_EXPR, the handle_min_max_size() function tries to deal gracefully with operands that designate distinct objects. But the handling fails to consider an edge case when one of the operands is a PHI one of whose operands references the same MIN/MAX_EXPR. This ultimately results in attempting to cache as the result of the MIN/MAX_EXPR two different object references, which triggers an ICE in the cache consistency checking. The attached fix avoids the problem by instead caching the SSA_NAME that's the result of the MIN/MAX_EXPR when its operands might reference distinct objects, and by enhancing the infor_access() function to handle this case. Besides the absence if the ICE the two additional tests verify that the right subobject of the MIN/MAX_EXPR is used under the various combinations of conditions. Tested on x86_64-linux. Martin PR middle-end/102200 - ICE on a min of a decl and pointer in a loop gcc/ChangeLog: PR middle-end/102200 * pointer-query.cc (access_ref::inform_access): Handle MIN/MAX_EXPR. (handle_min_max_size): Change argument. Store original SSA_NAME for operands to potentially distinct (sub)objects. (compute_objsize_r): Adjust call to the above. gcc/testsuite/ChangeLog: PR middle-end/102200 * gcc.dg/Wstringop-overflow-62.c: Adjust text of an expected note. * gcc.dg/Warray-bounds-89.c: New test. * gcc.dg/Wstringop-overflow-74.c: New test. * gcc.dg/Wstringop-overflow-75.c: New test. * gcc.dg/Wstringop-overflow-76.c: New test. diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index 4ad28796e57..83b1f0fc866 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -1087,6 +1087,34 @@ access_ref::inform_access (access_mode mode) const else if (gimple_nop_p (stmt)) /* Handle DECL_PARM below. */ ref = SSA_NAME_VAR (ref); + else if (is_gimple_assign (stmt) + && (gimple_assign_rhs_code (stmt) == MIN_EXPR + || gimple_assign_rhs_code (stmt) == MAX_EXPR)) + { + /* MIN or MAX_EXPR here implies a reference to a known object + and either an unknown or distinct one (the latter being + the result of an invalid relational expression). Determine + the identity of the former and point to it in the note. + TODO: Consider merging with PHI handling. */ + access_ref arg_ref[2]; + tree arg = gimple_assign_rhs1 (stmt); + compute_objsize (arg, /* ostype = */ 1 , &arg_ref[0]); + arg = gimple_assign_rhs2 (stmt); + compute_objsize (arg, /* ostype = */ 1 , &arg_ref[1]); + + /* Use the argument that references a known object with more + space remaining. */ + const bool idx + = (!arg_ref[0].ref || !arg_ref[0].base0 + || (arg_ref[0].base0 && arg_ref[1].base0 + && (arg_ref[0].size_remaining () + < arg_ref[1].size_remaining ()))); + + arg_ref[idx].offrng[0] = offrng[0]; + arg_ref[idx].offrng[1] = offrng[1]; + arg_ref[idx].inform_access (mode); + return; + } } if (DECL_P (ref)) @@ -1463,15 +1491,18 @@ pointer_query::dump (FILE *dump_file, bool contents /* = false */) } /* A helper of compute_objsize_r() to determine the size from an assignment - statement STMT with the RHS of either MIN_EXPR or MAX_EXPR. */ + statement STMT with the RHS of either MIN_EXPR or MAX_EXPR. On success + set PREF->REF to the operand with more or less space remaining, + respectively, if both refer to the same (sub)object, or to PTR if they + might not, and return true. Otherwise, if the identity of neither + operand can be determined, return false. */ static bool -handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, +handle_min_max_size (tree ptr, int ostype, access_ref *pref, ssa_name_limit_t &snlim, pointer_query *qry) { - tree_code code = gimple_assign_rhs_code (stmt); - - tree ptr = gimple_assign_rhs1 (stmt); + const gimple *stmt = SSA_NAME_DEF_STMT (ptr); + const tree_code code = gimple_assign_rhs_code (stmt); /* In a valid MAX_/MIN_EXPR both operands must refer to the same array. Determine the size/offset of each and use the one with more or less @@ -1479,7 +1510,8 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, determined from the other instead, adjusted up or down as appropriate for the expression. */ access_ref aref[2] = { *pref, *pref }; - if (!compute_objsize_r (ptr, ostype, &aref[0], snlim, qry)) + tree arg1 = gimple_assign_rhs1 (stmt); + if (!compute_objsize_r (arg1, ostype, &aref[0], snlim, qry)) { aref[0].base0 = false; aref[0].offrng[0] = aref[0].offrng[1] = 0; @@ -1487,8 +1519,8 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, aref[0].set_max_size_range (); } - ptr = gimple_assign_rhs2 (stmt); - if (!compute_objsize_r (ptr, ostype, &aref[1], snlim, qry)) + tree arg2 = gimple_assign_rhs2 (stmt); + if (!compute_objsize_r (arg2, ostype, &aref[1], snlim, qry)) { aref[1].base0 = false; aref[1].offrng[0] = aref[1].offrng[1] = 0; @@ -1517,6 +1549,13 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, *pref = aref[i1]; else *pref = aref[i0]; + + if (aref[i0].ref != aref[i1].ref) + /* If the operands don't refer to the same (sub)object set + PREF->REF to the SSA_NAME from which STMT was obtained + so that both can be identified in a diagnostic. */ + pref->ref = ptr; + return true; } @@ -1537,6 +1576,10 @@ handle_min_max_size (gimple *stmt, int ostype, access_ref *pref, pref->offrng[0] = aref[i0].offrng[0]; pref->offrng[1] = aref[i0].offrng[1]; } + + /* Replace PTR->REF with the SSA_NAME to indicate the expression + might not refer to the same (sub)object. */ + pref->ref = ptr; return true; } @@ -2009,8 +2052,9 @@ compute_objsize_r (tree ptr, int ostype, access_ref *pref, if (code == MAX_EXPR || code == MIN_EXPR) { - if (!handle_min_max_size (stmt, ostype, pref, snlim, qry)) + if (!handle_min_max_size (ptr, ostype, pref, snlim, qry)) return false; + qry->put_ref (ptr, *pref); return true; } diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-89.c b/gcc/testsuite/gcc.dg/Warray-bounds-89.c new file mode 100644 index 00000000000..2604f65e6d5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-89.c @@ -0,0 +1,139 @@ +/* Verify warnings and notes for MIN_EXPRs involving either pointers + to distinct objects or one to a known object and the other to + an unknown one. The relational expressions are strictly invalid + but that should be diagnosed by a separate warning. + { dg-do compile } + { dg-options "-O2 -Warray-bounds -Wno-stringop-overflow" } */ + +/* Verify the note points to the larger of the two objects and mentions + the offset into it (alhough the offset would ideally be a part of + the warning). */ +extern char a3[3]; +extern char a5[5]; // { dg-message "at offset 5 into object 'a5' of size 5" "note" } + +void min_a3_a5 (int i) +{ + char *p = a3 + i; + char *q = a5 + i; + + /* The relational expression below is invalid and should be diagnosed + by its own warning independently of -Warray-bounds. */ + char *d = p < q ? p : q; + + d[4] = 0; + + /* Verify the type in the warning corresponds to the larger of the two + objects. */ + d[5] = 0; // { dg-warning "subscript 5 is outside array bounds of 'char\\\[5]'" } +} + + +// Same as above but with the larger array as the first MIN_EXPR operand. +extern char b4[4]; +extern char b6[6]; // { dg-message "at offset 6 into object 'b6' of size 6" "note" } + +void min_b6_b4 (int i) +{ + char *p = b6 + i; + char *q = b4 + i; + char *d = p < q ? p : q; + + d[5] = 0; + d[6] = 0; // { dg-warning "subscript 6 is outside array bounds of 'char\\\[6]'" } +} + + +/* Same as above but with the first MIN_EXPR operand pointing to an unknown + object. */ +extern char c7[7]; // { dg-message "at offset 7 into object 'c7' of size 7" "note" } + +void min_p_c7 (char *p, int i) +{ + char *q = c7 + i; + char *d = p < q ? p : q; + + d[6] = 0; + d[7] = 0; // { dg-warning "subscript 7 is outside array bounds of 'char\\\[7]'" } +} + + +/* Same as above but with the second MIN_EXPR operand pointing to an unknown + object. */ +extern char d8[8]; // { dg-message "at offset 8 into object 'd8' of size 8" "note" } + +void min_d8_p (char *q, int i) +{ + char *p = d8 + i; + char *d = p < q ? p : q; + + d[7] = 0; + d[8] = 0; // { dg-warning "subscript 8 is outside array bounds of 'char\\\[8]'" } +} + + +/* The following are diagnosed by -Wstringop-overflow but, as a result + of PR 101374, not by -Warray-bounds. */ + +struct A3_5 +{ + char a3[3]; + char a5[5]; // { dg-message "at offset 5 into object 'a5' of size 5" "note" { xfail *-*-* } } +}; + +void min_A3_A5 (int i, struct A3_5 *pa3_5) +{ + char *p = pa3_5->a3 + i; + char *q = pa3_5->a5 + i; + + char *d = p < q ? p : q; + + // d[4] = 0; + d[5] = 0; // { dg-warning "subscript 5 is outside array bounds of 'char\\\[5]'" "pr??????" { xfail *-*-* } } +} + + +struct B4_B6 +{ + char b4[4]; + char b6[6]; // { dg-message "at offset 6 into object 'b6' of size 6" "note" { xfail *-*-* } } +}; + +void min_B6_B4 (int i, struct B4_B6 *pb4_b6) +{ + char *p = pb4_b6->b6 + i; + char *q = pb4_b6->b4 + i; + char *d = p < q ? p : q; + + d[5] = 0; + d[6] = 0; // { dg-warning "subscript 6 is outside array bounds of 'char\\\[6]'" "pr??????" { xfail *-*-* } } +} + + +struct C7 +{ + char c7[7]; // { dg-message "at offset 7 into object 'c7' of size 7" "note" { xfail *-*-* } } +}; + +void min_p_C7 (char *p, int i, struct C7 *pc7) +{ + char *q = pc7->c7 + i; + char *d = p < q ? p : q; + + d[6] = 0; + d[7] = 0; // { dg-warning "subscript 7 is outside array bounds of 'char\\\[7]'" "pr??????" { xfail *-*-* } } +} + + +struct D8 +{ + char d8[8]; // { dg-message "at offset 8 into object 'd8' of size 8" "note" { xfail *-*-* } } +}; + +void min_D8_p (char *q, int i, struct D8 *pd8) +{ + char *p = pd8->d8 + i; + char *d = p < q ? p : q; + + d[7] = 0; + d[8] = 0; // { dg-warning "subscript 8 is outside array bounds of 'char\\\[8]'" "pr??????" { xfail *-*-* } } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c index 318d9bd1f94..4b6d1ab83c5 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-62.c @@ -117,7 +117,7 @@ void test_min (void) { /* Exercise a pointer pointing to a known object plus constant offset with one pointing to an unknown object. */ - char a6[6]; // { dg-message ": destination object 'a6'" "note" } + char a6[6]; // { dg-message "(at offset 1 into )?destination object 'a6'" "note" } char *p1 = ptr; char *p2 = a6 + 1; char *q = MIN (p1, p2); diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-74.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-74.c new file mode 100644 index 00000000000..bacec964d36 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-74.c @@ -0,0 +1,22 @@ +/* PR middle-end/102200 - ICE on a min of a decl and pointer in a loop + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +extern char a[], n; + +void f (void) +{ + char *p = a; + size_t end = 1; + + while (n) + { + if (p < (char*)end) + *p = ';'; + + if (p > (char*)&end) + p = (char*)&end; + } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-75.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-75.c new file mode 100644 index 00000000000..2ebadc649a5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-75.c @@ -0,0 +1,133 @@ +/* Verify warnings and notes for MIN_EXPRs involving either pointers + to distinct objects or one to a known object and the other to + an unknown one. The relational expressions are strictly invalid + but that should be diagnosed by a separate warning. + { dg-do compile } + { dg-options "-O2 -Wno-array-bounds" } */ + +/* Verify the note points to the larger of the two objects and mentions + the offset into it (alhough the offset would ideally be a part of + the warning). */ +extern char a3[3]; +extern char a5[5]; // { dg-message "at offset 5 into destination object 'a5' of size 5" "note" } + +void min_a3_a5 (int i) +{ + char *p = a3 + i; + char *q = a5 + i; + + /* The relational expression below is invalid and should be diagnosed + by its own warning independently of -Wstringop-overflow. */ + char *d = p < q ? p : q; + + d[4] = 0; + d[5] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +// Same as above but with the larger array as the first MIN_EXPR operand. +extern char b4[4]; +extern char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } + +void min_b6_b4 (int i) +{ + char *p = b6 + i; + char *q = b4 + i; + char *d = p < q ? p : q; + + d[5] = 0; + d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +/* Same as above but with the first MIN_EXPR operand pointing to an unknown + object. */ +extern char c7[7]; // { dg-message "at offset 7 into destination object 'c7' of size 7" "note" } + +void min_p_c7 (char *p, int i) +{ + char *q = c7 + i; + char *d = p < q ? p : q; + + d[6] = 0; + d[7] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +/* Same as above but with the second MIN_EXPR operand pointing to an unknown + object. */ +extern char d8[8]; // { dg-message "at offset 8 into destination object 'd8' of size 8" "note" } + +void min_d8_p (char *q, int i) +{ + char *p = d8 + i; + char *d = p < q ? p : q; + + d[7] = 0; + d[8] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct A3_5 +{ + char a3[3]; + char a5[5]; // { dg-message "at offset 5 into destination object 'a5' of size 5" "note" } +}; + +void min_A3_A5 (int i, struct A3_5 *pa3_5) +{ + char *p = pa3_5->a3 + i; + char *q = pa3_5->a5 + i; + + char *d = p < q ? p : q; + + // d[4] = 0; + d[5] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct B4_B6 +{ + char b4[4]; + char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } +}; + +void min_B6_B4 (int i, struct B4_B6 *pb4_b6) +{ + char *p = pb4_b6->b6 + i; + char *q = pb4_b6->b4 + i; + char *d = p < q ? p : q; + + d[5] = 0; + d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct C7 +{ + char c7[7]; // { dg-message "at offset 7 into destination object 'c7' of size 7" "note" } +}; + +void min_p_C7 (char *p, int i, struct C7 *pc7) +{ + char *q = pc7->c7 + i; + char *d = p < q ? p : q; + + d[6] = 0; + d[7] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct D8 +{ + char d8[8]; // { dg-message "at offset 8 into destination object 'd8' of size 8" "note" } +}; + +void min_D8_p (char *q, int i, struct D8 *pd8) +{ + char *p = pd8->d8 + i; + char *d = p < q ? p : q; + + d[7] = 0; + d[8] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-76.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-76.c new file mode 100644 index 00000000000..18191a1aa5e --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-76.c @@ -0,0 +1,148 @@ +/* Verify warnings and notes for MAX_EXPRs involving either pointers + to distinct objects or one to a known object and the other to + an unknown one. Unlike for the same object, for unrelated objects + the expected warnings and notes are the same as for MIN_EXPR: when + the order of the objects in the address space cannot be determined + the larger of them is assumed to be used. (This is different for + distinct struct members where the order is given.) + The relational expressions are strictly invalid but that should be + diagnosed by a separate warning. + { dg-do compile } + { dg-options "-O2 -Wno-array-bounds" } */ + +#define MAX(p, q) ((p) > (q) ? (p) : (q)) + +/* Verify that even for MAX_EXPR and like for MIN_EXPR, the note points + to the larger of the two objects and mentions the offset into it + (although the offset might be better included in the warning). */ +extern char a3[3]; +extern char a5[5]; // { dg-message "at offset 5 into destination object 'a5' of size 5" "note" } + +void max_a3_a5 (int i) +{ + char *p = a3 + i; + char *q = a5 + i; + + /* The relational expression below is invalid and should be diagnosed + by its own warning independently of -Wstringop-overflow. */ + char *d = MAX (p, q); + + d[2] = 0; + d[3] = 0; + d[4] = 0; + d[5] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +// Same as above but with the larger array as the first MAX_EXPR operand. +extern char b4[4]; +extern char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } + +void max_b6_b4 (int i) +{ + char *p = b6 + i; + char *q = b4 + i; + char *d = MAX (p, q); + + d[3] = 0; + d[4] = 0; + d[5] = 0; + d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +/* Same as above but with the first MAX_EXPR operand pointing to an unknown + object. */ +extern char c7[7]; // { dg-message "at offset 7 into destination object 'c7' of size 7" "note" } + +void max_p_c7 (char *p, int i) +{ + char *q = c7 + i; + char *d = MAX (p, q); + + d[6] = 0; + d[7] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +/* Same as above but with the second MIN_EXPR operand pointing to an unknown + object. */ +extern char d8[8]; // { dg-message "at offset 8 into destination object 'd8' of size 8" "note" } + +void max_d8_p (char *q, int i) +{ + char *p = d8 + i; + char *d = MAX (p, q); + + d[7] = 0; + d[8] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct A3_5 +{ + char a3[3]; // { dg-message "at offset 3 into destination object 'a3' of size 3" "pr??????" { xfail *-*-* } } + char a5[5]; // { dg-message "at offset 5 into destination object 'a5' of size 5" "note" } +}; + +void max_A3_A5 (int i, struct A3_5 *pa3_5) +{ + char *p = pa3_5->a3 + i; + char *q = pa3_5->a5 + i; + + char *d = MAX (p, q); + + d[2] = 0; + d[3] = 0; // { dg-warning "writing 1 byte into a region of size 0" "pr??????" { xfail *-*-* } } + d[4] = 0; + d[5] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct B4_B6 +{ + char b4[4]; + char b6[6]; // { dg-message "at offset 6 into destination object 'b6' of size 6" "note" } +}; + +void max_B6_B4 (int i, struct B4_B6 *pb4_b6) +{ + char *p = pb4_b6->b6 + i; + char *q = pb4_b6->b4 + i; + char *d = MAX (p, q); + + d[3] = 0; + d[4] = 0; + d[5] = 0; + d[6] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct C7 +{ + char c7[7]; // { dg-message "at offset 7 into destination object 'c7' of size 7" "note" } +}; + +void max_p_C7 (char *p, int i, struct C7 *pc7) +{ + char *q = pc7->c7 + i; + char *d = MAX (p, q); + + d[6] = 0; + d[7] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +} + + +struct D8 +{ + char d8[8]; // { dg-message "at offset 8 into destination object 'd8' of size 8" "note" } +}; + +void max_D8_p (char *q, int i, struct D8 *pd8) +{ + char *p = pd8->d8 + i; + char *d = MAX (p, q); + + d[7] = 0; + d[8] = 0; // { dg-warning "writing 1 byte into a region of size 0" } +}