From 72332337e3d8acbb21398b8d123f1bfe77a8327e Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Fri, 14 Jan 2022 11:13:08 -0700 Subject: [PATCH] Use enclosing object size if it's smaller than member [PR 101475]. Resolves: PR middle-end/101475 - missing -Wstringop-overflow storing a compound literal gcc/ChangeLog: PR middle-end/101475 * pointer-query.cc (handle_component_ref): Use the size of the enclosing object if it's smaller than the member. gcc/testsuite/ChangeLog: PR middle-end/101475 * gcc.dg/Wstringop-overflow-15.c: Remove xfails. * gcc.dg/Wstringop-overflow-68.c: Adjust, remove xfails. * gcc.dg/Wstringop-overflow-88.c: New test. --- gcc/pointer-query.cc | 48 ++-- gcc/testsuite/gcc.dg/Wstringop-overflow-15.c | 14 +- gcc/testsuite/gcc.dg/Wstringop-overflow-68.c | 29 +-- gcc/testsuite/gcc.dg/Wstringop-overflow-88.c | 327 +++++++++++++++++++++++++++ 4 files changed, 383 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-88.c diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index 1efe7e0..9f932e9 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -1914,36 +1914,41 @@ handle_component_ref (tree cref, gimple *stmt, bool addr, int ostype, gcc_assert (TREE_CODE (cref) == COMPONENT_REF); const tree base = TREE_OPERAND (cref, 0); + const tree field = TREE_OPERAND (cref, 1); + access_ref base_ref = *pref; + + /* Unconditionally determine the size of the base object (it could + be smaller than the referenced member when the object is stored + in a buffer with an insufficient size). */ + if (!compute_objsize_r (base, stmt, addr, 0, &base_ref, snlim, qry)) + return false; + + /* Add the offset of the member to the offset into the object computed + so far. */ + tree offset = byte_position (field); + if (TREE_CODE (offset) == INTEGER_CST) + base_ref.add_offset (wi::to_offset (offset)); + else + base_ref.add_max_offset (); + + if (!base_ref.ref) + /* PREF->REF may have been already set to an SSA_NAME earlier + to provide better context for diagnostics. In that case, + leave it unchanged. */ + base_ref.ref = base; + const tree base_type = TREE_TYPE (base); if (TREE_CODE (base_type) == UNION_TYPE) /* In accesses through union types consider the entire unions rather than just their members. */ ostype = 0; - tree field = TREE_OPERAND (cref, 1); - if (ostype == 0) { /* In OSTYPE zero (for raw memory functions like memcpy), use the maximum size instead if the identity of the enclosing object cannot be determined. */ - if (!compute_objsize_r (base, stmt, addr, ostype, pref, snlim, qry)) - return false; - - /* Otherwise, use the size of the enclosing object and add - the offset of the member to the offset computed so far. */ - tree offset = byte_position (field); - if (TREE_CODE (offset) == INTEGER_CST) - pref->add_offset (wi::to_offset (offset)); - else - pref->add_max_offset (); - - if (!pref->ref) - /* PREF->REF may have been already set to an SSA_NAME earlier - to provide better context for diagnostics. In that case, - leave it unchanged. */ - pref->ref = base; - + *pref = base_ref; return true; } @@ -1958,6 +1963,11 @@ handle_component_ref (tree cref, gimple *stmt, bool addr, int ostype, } set_component_ref_size (cref, pref); + + if (base_ref.size_remaining () < pref->size_remaining ()) + /* Use the base object if it's smaller than the member. */ + *pref = base_ref; + return true; } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-15.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-15.c index 87f8462..f7dcb94 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-15.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-15.c @@ -29,8 +29,13 @@ void vla_bounded (int n) a[0] = 0; a[1] = 1; + a[31] = 31; + + sink (&a); + a[n] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } } - a[69] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" } + a[32] = 32; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" } + a[69] = 69; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" } sink (&a); } @@ -56,8 +61,13 @@ void member_vla_bounded (int n) s.a[0] = 0; s.a[1] = 1; + s.a[31] = 31; + + sink (&s); + s.a[n] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } } - s.a[69] = n; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" { xfail *-*-* } } + s.a[32] = 32; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" } + s.a[69] = 69; // { dg-warning "\\\[-Wstringop-overflow" "pr82608" } sink (&s); } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-68.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-68.c index e69178f..4d13239 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-68.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-68.c @@ -2,7 +2,7 @@ a larger scalar into a smaller array Verify overflow by aggregate stores. { dg-do compile } - { dg-options "-O2" } */ + { dg-options "-O2 -fno-tree-vectorize" } */ #define A(N) (A ## N) #define Ac1 (AC1){ 0 } @@ -57,19 +57,20 @@ void warn_comp_lit_zero (void) void warn_comp_lit (void) { - *(AC2*)a1 = Ac2; // { dg-warning "writing 2 bytes into a region of size 1" "pr101475" { target { vect_slp_v2qi_store_unalign } } } - // After vectorization, below codes are optimized to - // MEM [(char *)&a2] = { 0, 1, 2, 3 }; - // MEM [(char *)&a3] = { 0, 1, 2, 3 }; - // MEM [(char *)&a4] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - // MEM [(char *)&a7] = { 0, 1, 2, 3, 4, 5, 6, 7 }; - // MEM [(char *)&a15] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; - // and warning should be expected, refer to PR102722. - *(AC4*)a2 = Ac4; // { dg-warning "writing 4 bytes into a region of size 2" "pr101475" { xfail { ! { vect_slp_v4qi_store_unalign_1 } } } } - *(AC4*)a3 = Ac4; // { dg-warning "writing 4 bytes into a region of size 3" "pr101475" { xfail { ! { vect_slp_v4qi_store_unalign_1 } } } } - *(AC8*)a4 = Ac8; // { dg-warning "writing 8 bytes into a region of size 4" "pr101475" { xfail { ! { vect_slp_v8qi_store_unalign_1 } } } } - *(AC8*)a7 = Ac8; // { dg-warning "writing 8 bytes into a region of size 7" "pr101475" { xfail { ! { vect_slp_v8qi_store_unalign_1 } } } } - *(AC16*)a15 = Ac16; // { dg-warning "writing 16 bytes into a region of size 15" "pr101475" { xfail { ! { vect_slp_v16qi_store_unalign_1 } } } } + /* Ideally only one warning would be issued for each of the stores + mentioning the size of the rest of the source being assigned to + the destination that doesn't fit. But without vectorization + the assignment is a series of one-character stores, except in + the first instance multiple warnings end up being issued for + each assignment, each saying "writing 1 byte into a region of + size 0". That's suboptimal and should be improved. See also + PR 92110. */ + *(AC2*)a1 = Ac2; // { dg-warning "writing (2 bytes|1 byte) into a region of size (1|0)" "pr101475" } + *(AC4*)a2 = Ac4; // { dg-warning "writing (4 bytes|1 byte) into a region of size (2|0)" "pr101475" } + *(AC4*)a3 = Ac4; // { dg-warning "writing (4 bytes|1 byte) into a region of size (3|0)" "pr101475" } + *(AC8*)a4 = Ac8; // { dg-warning "writing (8 bytes|1 byte) into a region of size (4|0)" "pr101475" } + *(AC8*)a7 = Ac8; // { dg-warning "writing (8 bytes|1 byte) into a region of size (7|0)" "pr101475" } + *(AC16*)a15 = Ac16; // { dg-warning "writing (16 bytes|1 byte) into a region of size (15|0)" "pr101475" } } void warn_aggr_decl (void) diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-88.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-88.c new file mode 100644 index 0000000..c6b443e --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-88.c @@ -0,0 +1,327 @@ +/* PR middle-end/101475 - missing -Wstringop-overflow storing a compound + literal + { dg-do compile } + { dg-options "-O2 -fno-tree-vectorize" } */ + +extern char ea1[1], ea2[2], ea3[3], ea4[4]; + +/* The trailing A member of all of Sx, S0, and S1 is treated the same: + as a flexible array member. */ +struct Sx { char n, a[]; }; +struct S0 { char n, a[0]; }; +struct S1 { char n, a[1]; }; +/* The trailing A member in both S2 and S3 is treated as an ordinary + array with exactly two elements and accesses to elements beyond + the last are diagnosed regardless of whether they are within + the bounds the enclosing object. */ +struct S2 { char n, a[2]; }; +struct S3 { char n, a[3]; }; + + +void fx_ea1 (void) +{ + struct Sx *p = (struct Sx*)ea1; + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f0_ea1 (void) +{ + struct S0 *p = (struct S0*)ea1; + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f1_ea1 (void) +{ + struct S1 *p = (struct S1*)ea1; + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f2_ea1 (void) +{ + struct S2 *p = (struct S2*)ea1; + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f3_ea1 (void) +{ + struct S3 *p = (struct S3*)ea1; + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + + +void fx_ea1_p1 (void) +{ + struct Sx *p = (struct Sx*)(ea1 + 1); + p->n = 0; // { dg-warning "-Wstringop-overflow" } + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f0_ea1_p1 (void) +{ + struct S0 *p = (struct S0*)(ea1 + 1); + p->n = 0; // { dg-warning "-Wstringop-overflow" } + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f1_ea1_p1 (void) +{ + struct S1 *p = (struct S1*)(ea1 + 1); + p->n = 0; // { dg-warning "-Wstringop-overflow" } + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f2_ea1_p1 (void) +{ + struct S2 *p = (struct S2*)(ea1 + 1); + p->n = 0; // { dg-warning "-Wstringop-overflow" } + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f3_ea1_p1 (void) +{ + struct S3 *p = (struct S3*)(ea1 + 1); + p->n = 0; // { dg-warning "-Wstringop-overflow" } + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + + +void fx_ea2 (void) +{ + struct Sx *p = (struct Sx*)ea2; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f0_ea2 (void) +{ + struct S0 *p = (struct S0*)ea2; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f1_ea2 (void) +{ + struct S1 *p = (struct S1*)ea2; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f2_ea2 (void) +{ + struct S2 *p = (struct S2*)ea2; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f3_ea2 (void) +{ + struct S3 *p = (struct S3*)ea2; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + + +void fx_ea2_p1 (void) +{ + struct Sx *p = (struct Sx*)(ea2 + 1); + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f0_ea2_p1 (void) +{ + struct S0 *p = (struct S0*)(ea2 + 1); + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f1_ea2_p1 (void) +{ + struct S1 *p = (struct S1*)(ea2 + 1); + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f2_ea2_p1 (void) +{ + struct S2 *p = (struct S2*)(ea2 + 1); + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f3_ea2_p1 (void) +{ + struct S3 *p = (struct S3*)(ea2 + 1); + p->n = 0; + p->a[0] = 0; // { dg-warning "-Wstringop-overflow" } + p->a[1] = 1; // { dg-warning "-Wstringop-overflow" } + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + + +void fx_ea3 (void) +{ + struct Sx *p = (struct Sx*)ea3; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f0_ea3 (void) +{ + struct S0 *p = (struct S0*)ea3; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f1_ea3 (void) +{ + struct S1 *p = (struct S1*)ea3; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f2_ea3 (void) +{ + struct S2 *p = (struct S2*)ea3; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f3_ea3 (void) +{ + struct S3 *p = (struct S3*)ea3; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + + +void fx_ea4 (void) +{ + struct Sx *p = (struct Sx*)ea4; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f0_ea4 (void) +{ + struct S0 *p = (struct S0*)ea4; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f1_ea4 (void) +{ + struct S1 *p = (struct S1*)ea4; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f2_ea4 (void) +{ + struct S2 *p = (struct S2*)ea4; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + /* Even though the offset of p->a[2] is within the bounds of EA4 + the warning triggers because it only considers trailing arrays + of at mnost one element as "poor man's flexible arrays." */ + p->a[2] = 2; // { dg-warning "-Wstringop-overflow" } + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} + +void f3_ea4 (void) +{ + struct S3 *p = (struct S3*)ea4; + p->n = 0; + p->a[0] = 0; + p->a[1] = 1; + p->a[2] = 2; + p->a[3] = 3; // { dg-warning "-Wstringop-overflow" } +} -- 2.7.4