aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2022-01-14 11:13:08 -0700
committerMartin Sebor <msebor@redhat.com>2022-01-14 11:13:08 -0700
commit72332337e3d8acbb21398b8d123f1bfe77a8327e (patch)
tree94b31c445e4d8804a4bd5e3abc3b2d63fec14e82
parent1e6294bb15d2169147c7838f89a9168980b94b47 (diff)
downloadgcc-72332337e3d8acbb21398b8d123f1bfe77a8327e.zip
gcc-72332337e3d8acbb21398b8d123f1bfe77a8327e.tar.gz
gcc-72332337e3d8acbb21398b8d123f1bfe77a8327e.tar.bz2
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.
-rw-r--r--gcc/pointer-query.cc48
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-15.c14
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-68.c29
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-88.c327
4 files changed, 383 insertions, 35 deletions
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 <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)
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" }
+}