]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Use enclosing object size if it's smaller than member [PR 101475].
authorMartin Sebor <msebor@redhat.com>
Fri, 14 Jan 2022 18:13:08 +0000 (11:13 -0700)
committerMartin Sebor <msebor@redhat.com>
Fri, 14 Jan 2022 18:13:08 +0000 (11:13 -0700)
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
gcc/testsuite/gcc.dg/Wstringop-overflow-15.c
gcc/testsuite/gcc.dg/Wstringop-overflow-68.c
gcc/testsuite/gcc.dg/Wstringop-overflow-88.c [new file with mode: 0644]

index 1efe7e04b02fca75dbb56c137ca6c8ade7da959a..9f932e9e7630eb34fcdd05aef156830fc5ff3fc8 100644 (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;
 }
 
index 87f8462d431f48e53c7e62b694a7270021009cbb..f7dcb94dc13180902d9cc3efe308e1a85dc9261d 100644 (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);
 }
index e69178f45384d5e9b6110954c995ace17e34cac0..4d132394f0fc7f411a59999fbf547c02997bdf73 100644 (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)
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-88.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-88.c
new file mode 100644 (file)
index 0000000..c6b443e
--- /dev/null
@@ -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" }
+}