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.
This commit is contained in:
Martin Sebor 2022-01-14 11:13:08 -07:00
parent 1e6294bb15
commit 72332337e3
4 changed files with 383 additions and 35 deletions

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 <vector(4) char> [(char *)&a2] = { 0, 1, 2, 3 };
// MEM <vector(4) char> [(char *)&a3] = { 0, 1, 2, 3 };
// MEM <vector(8) char> [(char *)&a4] = { 0, 1, 2, 3, 4, 5, 6, 7 };
// MEM <vector(8) char> [(char *)&a7] = { 0, 1, 2, 3, 4, 5, 6, 7 };
// MEM <vector(16) char> [(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)

View File

@ -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" }
}