Extend the offset and size of merged object references [PR103215].
Resolves:
PR tree-optimization/103215 - bogus -Warray-bounds with two pointers with different offsets each
gcc/ChangeLog:
PR tree-optimization/103215
* pointer-query.cc (access_ref::merge_ref): Extend the offset and
size of the merged object instead of using the larger.
gcc/testsuite/ChangeLog:
PR tree-optimization/103215
* gcc.dg/Wstringop-overflow-58.c: Adjust and xfail expected warnings.
* gcc.dg/Wstringop-overflow-59.c: Same.
* gcc.dg/warn-strnlen-no-nul.c: Same.
* gcc.dg/Warray-bounds-91.c: New test.
* gcc.dg/Warray-bounds-92.c: New test.
* gcc.dg/Wstringop-overflow-83.c: New test.
* gcc.dg/Wstringop-overflow-85.c: New test.
@@ -686,27 +686,32 @@ access_ref::merge_ref (vec<access_ref> *all_refs, tree arg, gimple *stmt,
if (known_size && aref.sizrng[0] < minsize)
minsize = aref.sizrng[0];
- /* Determine the amount of remaining space in the argument. */
- offset_int argrem[2];
- argrem[1] = aref.size_remaining (argrem);
+ /* Extend the size and offset of *THIS to account for AREF. The result
+ can be cached but results in false negatives. */
- /* Determine the amount of remaining space computed so far and
- if the remaining space in the argument is more use it instead. */
- offset_int merged_rem[2];
- merged_rem[1] = size_remaining (merged_rem);
+ offset_int orng[2];
+ if (sizrng[1] < aref.sizrng[1])
+ {
+ orng[0] = offrng[0];
+ orng[1] = offrng[1];
+ *this = aref;
+ }
+ else
+ {
+ orng[0] = aref.offrng[0];
+ orng[1] = aref.offrng[1];
+ }
+
+ if (orng[0] < offrng[0])
+ offrng[0] = orng[0];
+ if (offrng[1] < orng[1])
+ offrng[1] = orng[1];
/* Reset the PHI's BASE0 flag if any of the nonnull arguments
refers to an object at an unknown offset. */
if (!aref.base0)
base0 = false;
- if (merged_rem[1] < argrem[1]
- || (merged_rem[1] == argrem[1]
- && sizrng[1] < aref.sizrng[1]))
- /* Use the argument with the most space remaining as the result,
- or the larger one if the space is equal. */
- *this = aref;
-
sizrng[0] = minsize;
parmarray = merged_parmarray;
new file mode 100644
@@ -0,0 +1,145 @@
+/* PR middle-end/103215 - bogus -Warray-bounds with two pointers with
+ different offsets each
+ Test for accesses into the same array through pointers with different
+ offsets each.
+ { dg-do compile }
+ { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+#define NOIPA __attribute__ ((noipa))
+
+#define A(p, off) ((p)[off] = __COUNTER__)
+
+extern int a4[4];
+
+
+NOIPA void p0_p1 (int i)
+{
+ int *p0 = a4 + 0;
+ int *p1 = a4 + 1;
+ int *q = i ? p0 : p1;
+ A (q, -2); // { dg-warning "-Warray-bounds" }
+ A (q, -1); A (q, 0); A (q, 1); A (q, 2);
+ /* Since q points to a4 and -1 is a valid subscript, +3 must be invalid.
+ But the warning for each subscript is independent of prior subscripts
+ into the same object. That should be improved. */
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Warray-bounds" }
+}
+
+NOIPA void p1_p0 (int i)
+{
+ int *p1 = a4 + 1;
+ int *p0 = a4 + 0;
+ int *q = i ? p0 : p1;
+ A (q, -2); // { dg-warning "-Warray-bounds" }
+ A (q, -1); A (q, 0); A (q, 1); A (q, 2);
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void p1_p2 (int i)
+{
+ int *p1 = a4 + 1;
+ int *p2 = a4 + 2;
+ int *q = i ? p1 : p2;
+ A (q, -3); // { dg-warning "-Warray-bounds" }
+ A (q, -2); A (q, -1); A (q, 0); A (q, 1);
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" }
+}
+
+NOIPA void p2_p1 (int i)
+{
+ int *p2 = a4 + 2;
+ int *p1 = a4 + 1;
+ int *q = i ? p1 : p2;
+ A (q, -3); // { dg-warning "-Warray-bounds" }
+ A (q, -2); A (q, -1); A (q, 0); A (q, 1);
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void p1_p3 (int i)
+{
+ int *p1 = a4 + 1;
+ int *p3 = a4 + 3;
+ int *q = i ? p1 : p3;
+ A (q, -4); // { dg-warning "-Warray-bounds" }
+ A (q, -3); A (q, -2); A (q, -1); A (q, 0);
+ A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" }
+}
+
+NOIPA void p3_p1 (int i)
+{
+ int *p3 = a4 + 3;
+ int *p1 = a4 + 1;
+ int *q = i ? p1 : p3;
+ A (q, -4); // { dg-warning "-Warray-bounds" }
+ A (q, -3); A (q, -2); A (q, -1); A (q, 0);
+ A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void p1_p4 (int i)
+{
+ int *p1 = a4 + 1;
+ int *p4 = a4 + 4;
+ int *q = i ? p1 : p4;
+ A (q, -5); // { dg-warning "-Warray-bounds" }
+ A (q, -4); A (q, -3); A (q, -2); A (q, -1);
+ A (q, 0); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" }
+}
+
+NOIPA void p4_p1 (int i)
+{
+ int *p4 = a4 + 4;
+ int *p1 = a4 + 1;
+ int *q = i ? p1 : p4;
+ A (q, -5); // { dg-warning "-Warray-bounds" }
+ A (q, -4); A (q, -3); A (q, -2); A (q, -1);
+ A (q, 0); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void p0_p1_p2 (int i)
+{
+ int *p0 = a4 + 0;
+ int *p1 = a4 + 1;
+ int *p2 = a4 + 2;
+ int *q = i < 0 ? p1 : 0 < i ? p2 : p0;
+ A (q, -3); // { dg-warning "-Warray-bounds" }
+ A (q, -2); A (q, -1); A (q, 0); A (q, 1);
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void p0_p1_p2_p3_p4 (int i)
+{
+ int *p0 = a4 + 0;
+ int *p1 = a4 + 1;
+ int *p2 = a4 + 2;
+ int *p3 = a4 + 3;
+ int *p4 = a4 + 4;
+ int *q = i < -1 ? p1 : i < 0 ? p2 : 1 < i ? p4 : 0 < i ? p3 : p0;
+ A (q, -5); // { dg-warning "-Warray-bounds" }
+ A (q, -4); A (q, -3); A (q, -2); A (q, -1);
+ A (q, 0); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Warray-bounds" }
+}
new file mode 100644
@@ -0,0 +1,149 @@
+/* PR middle-end/103215 - bogus -Warray-bounds with two pointers with
+ different offsets each
+ Test for accesses into distinct arrays through pointers with different
+ offsets each.
+
+ If/when -Warray-bounds is enhanced to issue "maybe" kinds of warnings
+ some of the accesses here will trigger those and will need updating.
+
+ { dg-do compile }
+ { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+#define NOIPA __attribute__ ((noipa))
+
+#define A(p, off) ((p)[off] = __COUNTER__)
+
+extern int a4[4], a8[8];
+
+
+NOIPA void a4_p1_a8_p3 (int i)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p3 = a8 + 3;
+ int *q = i ? a4_p1 : a8_p3;
+ A (q, -4); // { dg-warning "-Warray-bounds" }
+ /* Because -3 is a valid offset into a8 but not a4, q must point
+ to the former and so subscripts between -3 and +4 refer to its
+ elements. */
+ A (q, -3); A (q, -2); A (q, -1); A (q, 0);
+ A (q, 1); A (q, 2); A (q, 3); A (q, 4);
+ A (q, 5); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ /* Both of the following are definitely out of bounds but the first isn't
+ diagnosed because the code conservatively merges the offsets into A4
+ and A8. */
+ A (q, 7); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void a4_p1_a8_p5 (int i)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p5 = a8 + 5;
+ int *q = i ? a4_p1 : a8_p5;
+ A (q, -6); // { dg-warning "-Warray-bounds" }
+ /* Similarly to the above, because -5 is a valid offset into a8 but
+ not a4, q must point to the former and so subscripts between -5
+ and +2 refer to its elements. */
+ A (q, -5); A (q, -4); A (q, -3); A (q, -2);
+ A (q, -1); A (q, 0); A (q, 1); A (q, 2);
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 7); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void a4_p1_a8_p7 (int i)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p7 = a8 + 7;
+ int *q = i ? a4_p1 : a8_p7;
+ A (q, -8); // { dg-warning "-Warray-bounds" }
+ A (q, -7); A (q, -6); A (q, -5); A (q, -4);
+ A (q, -3); A (q, -2); A (q, -1); A (q, 0);
+ /* Since -7 is valid, q must point to a8 and the last valid subscript
+ must be 0. */
+ A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 7); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void mp_1_a4_p1_a8_p7 (int i, int j)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p7 = a8 + 7;
+ int *p = i ? a4_p1 : a8_p7;
+ int *q = j ? p + 1 : p - 1;
+
+ A (q, -9); // { dg-warning "-Warray-bounds" }
+
+ /* q points either to a8 + [6, 8] or a4 + [0, 2]. */
+ A (q, -8); A (q, -7); A (q, -6); A (q, -5);
+ A (q, -4); A (q, -3); A (q, -2); A (q, -1);
+
+ /* Since all the above are valid, q must point to a8 + 8. But as
+ mentioned above, the warning for each subscript is independent
+ of prior subscripts into the same object so the access below
+ aren't diagnosed. */
+ A (q, 0); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 1); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 8); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void mp1_a4_p1_a8_p5 (int i, int j)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p5 = a8 + 5;
+ int *p = i ? a4_p1 : a8_p5;
+
+ int *q = j ? p + 1 : p - 1;
+
+ // q is assumed to point to a8 + 6
+ A (q, -7); // { dg-warning "-Warray-bounds" }
+ A (q, -6); A (q, -5); A (q, -4); A (q, -3);
+ A (q, -2); A (q, -1); A (q, 0); A (q, 1);
+ /* Even though the above accesses rule it out, q is now assumed
+ to point to either a4 + [0, 2] or a8 + [4, 5]. */
+ A (q, 2);
+ /* q is now assumed to point tp a4. Given that, only the first store
+ is valid. */
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 5); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 6); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 7); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 8); // { dg-warning "-Warray-bounds" }
+}
+
+
+NOIPA void mp1_a4_p1_a8_p4 (int i, int j)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p4 = a8 + 4;
+ int *p = i ? a4_p1 : a8_p4;
+
+ int *q = j ? p + 1 : p - 1;
+
+ // q is assumed to point to a8 + 5
+ A (q, -6); // { dg-warning "-Warray-bounds" }
+ A (q, -5);
+ A (q, -4);
+ A (q, -3);
+ A (q, -2);
+ A (q, -1);
+ A (q, 0);
+ A (q, 1);
+ A (q, 2);
+ /* Even though the above accesses rule it out, q is now assumed
+ to point tp a4. Given that, only the first store is valid. */
+ A (q, 3); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 5); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 6); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 7); // { dg-warning "-Warray-bounds" "pr??????" { xfail *-*-* } }
+ A (q, 8); // { dg-warning "-Warray-bounds" }
+}
@@ -182,8 +182,8 @@ void memset_decl_2_off (void)
int i2 = SR (2, INT_MAX);
{
- char a5[5]; // { dg-warning "at offset [1, 5] into destination object 'a5'
- char a7[7]; // { dg-warning "at offset [2, 7] into destination object 'a7'
+ char a5[5]; // { dg-message "at offset \\\[1, 5] into destination object 'a5'" "note" }
+ char a7[7]; // { dg-message "at offset \\\[2, 7] into destination object 'a7'" "note" }
char *p5_p1 = a5 + i1;
char *p7_p2 = a7 + i2;
char *p5_7 = cond1 ? p5_p1 : p7_p2;
@@ -193,7 +193,11 @@ void memset_decl_2_off (void)
memset (p5_7, 0, 3);
memset (p5_7, 0, 4);
memset (p5_7, 0, 5);
- memset (p5_7, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5 " }
+ /* The warning code conservatively "merges" both the sizes and the offsets
+ into A5 and A7 and so only the second store below is diagnosed but not
+ the first. See PR 103215. The logic needs to be tightened up. */
+ memset (p5_7, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5 " "pr??????" { xfail *-*-* } }
+ memset (p5_7, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6 " }
}
int i3 = SR (3, INT_MAX);
@@ -208,7 +212,8 @@ void memset_decl_2_off (void)
// { dg-message "at offset \\\[4, 9] into destination object 'a9'" "note" { target *-*-* } .-1 }
// { dg-message "at offset \\\[3, 9] into destination object 'a9'" "note" { target *-*-* } .-2 }
// { dg-message "at offset \\\[2, 9] into destination object 'a9'" "note" { target *-*-* } .-3 }
- // { dg-message ": destination object 'a9'" "note" { target *-*-* } .-4 }
+ // { dg-message "at offset \\\[1, 9] into destination object 'a9'" "note" { target *-*-* } .-4 }
+ // { dg-message ": destination object 'a9'" "pr??????" { xfail *-*-* } .-5 }
char *p5_p2 = a5 + i2; // 3 bytes left
char *p9_p3 = a9 + i3; // 6 bytes left
char *p =
@@ -220,7 +225,8 @@ void memset_decl_2_off (void)
memset (q, 0, 3);
memset (q, 0, 4);
memset (q, 0, 5);
- memset (q, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5" }
+ memset (q, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5" "pr??????" { xfail *-*-* } }
+ memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" }
--q; // [3 - 6] bytes left
memset (q, 0, 1);
@@ -229,7 +235,8 @@ void memset_decl_2_off (void)
memset (q, 0, 4);
memset (q, 0, 5);
memset (q, 0, 6);
- memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" }
+ memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" "pr??????" { xfail *-*-* } }
+ memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" }
--q; // [4 - 7] bytes left
memset (q, 0, 1);
@@ -239,7 +246,8 @@ void memset_decl_2_off (void)
memset (q, 0, 5);
memset (q, 0, 6);
memset (q, 0, 7);
- memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" }
+ memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" "pr??????" { xfail *-*-* } }
+ memset (q, 0, 9); // { dg-warning "memset' writing 9 bytes into a region of size 8" }
int m1_x = SR (-1, INT_MAX);
int m2_x = SR (-2, INT_MAX);
@@ -200,7 +200,11 @@ void memset_malloc_2_off (void)
memset (p5_7, 0, 3);
memset (p5_7, 0, 4);
memset (p5_7, 0, 5);
- memset (p5_7, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5 " }
+ /* The warning code conservatively "merges" both the sizes and the offsets
+ into A5 and A7 and so only the second store below is diagnosed but not
+ the first. See PR 103215. The logic needs to be tightened up. */
+ memset (p5_7, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5 " "pr??????" { xfail *-*-* } }
+ memset (p5_7, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6 " }
}
int i3 = SR (3, INT_MAX);
@@ -215,7 +219,8 @@ void memset_malloc_2_off (void)
// { dg-message "at offset \\\[4, 9] into destination object 'a9'" "note" { target *-*-* } .-1 }
// { dg-message "at offset \\\[3, 9] into destination object 'a9'" "note" { target *-*-* } .-2 }
// { dg-message "at offset \\\[2, 9] into destination object 'a9'" "note" { target *-*-* } .-3 }
- // { dg-message ": destination object 'a9'" "note" { target *-*-* } .-4 }
+ // { dg-message "at offset \\\[1, 9] into destination object 'a9'" "note" { target *-*-* } .-4 }
+ // { dg-message ": destination object 'a9'" "pr??????" { xfail *-*-* } .-5 }
char *p5_p2 = a5 + i2; // 3 bytes left
char *p9_p3 = a9 + i3; // 6 bytes left
char *p =
@@ -227,7 +232,8 @@ void memset_malloc_2_off (void)
memset (q, 0, 3);
memset (q, 0, 4);
memset (q, 0, 5);
- memset (q, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5" }
+ memset (q, 0, 6); // { dg-warning "memset' writing 6 bytes into a region of size 5" "pr??????" { xfail *-*-* } }
+ memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" }
--q; // [3 - 6] bytes left
memset (q, 0, 1);
@@ -236,7 +242,8 @@ void memset_malloc_2_off (void)
memset (q, 0, 4);
memset (q, 0, 5);
memset (q, 0, 6);
- memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" }
+ memset (q, 0, 7); // { dg-warning "memset' writing 7 bytes into a region of size 6" "pr??????" { xfail *-*-* } }
+ memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" }
--q; // [4 - 7] bytes left
memset (q, 0, 1);
@@ -246,7 +253,8 @@ void memset_malloc_2_off (void)
memset (q, 0, 5);
memset (q, 0, 6);
memset (q, 0, 7);
- memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" }
+ memset (q, 0, 8); // { dg-warning "memset' writing 8 bytes into a region of size 7" "pr??????" { xfail *-*-* } }
+ memset (q, 0, 9); // { dg-warning "memset' writing 9 bytes into a region of size 8" }
int m1_x = SR (-1, INT_MAX);
int m2_x = SR (-2, INT_MAX);
new file mode 100644
@@ -0,0 +1,147 @@
+/* PR middle-end/103215 - bogus -Warray-bounds with two pointers with
+ different offsets each
+ Test for accesses by a user-defined function into the same array
+ through pointers with different offsets each. See Warray-bounds-91.c
+ for the corresponding test exercising -Warray-bounds for direct accesses.
+ { dg-do compile }
+ { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+#define NOIPA __attribute__ ((noipa))
+
+void sink (int[1]);
+#define A(p, off) sink (p + off)
+
+extern int a4[4];
+
+
+NOIPA void p0_p1 (int i)
+{
+ int *p0 = a4 + 0;
+ int *p1 = a4 + 1;
+ int *q = i ? p0 : p1;
+ A (q, -2); // { dg-warning "-Wstringop-overflow" }
+ A (q, -1); A (q, 0); A (q, 1); A (q, 2);
+ /* Since q points to a4 and -1 is a valid subscript, +3 must be invalid.
+ But the warning for each subscript is independent of prior subscripts
+ into the same object. That should be improved. */
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Wstringop-overflow" }
+}
+
+NOIPA void p1_p0 (int i)
+{
+ int *p1 = a4 + 1;
+ int *p0 = a4 + 0;
+ int *q = i ? p0 : p1;
+ A (q, -2); // { dg-warning "-Wstringop-overflow" }
+ A (q, -1); A (q, 0); A (q, 1); A (q, 2);
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void p1_p2 (int i)
+{
+ int *p1 = a4 + 1;
+ int *p2 = a4 + 2;
+ int *q = i ? p1 : p2;
+ A (q, -3); // { dg-warning "-Wstringop-overflow" }
+ A (q, -2); A (q, -1); A (q, 0); A (q, 1);
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" }
+}
+
+NOIPA void p2_p1 (int i)
+{
+ int *p2 = a4 + 2;
+ int *p1 = a4 + 1;
+ int *q = i ? p1 : p2;
+ A (q, -3); // { dg-warning "-Wstringop-overflow" }
+ A (q, -2); A (q, -1); A (q, 0); A (q, 1);
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void p1_p3 (int i)
+{
+ int *p1 = a4 + 1;
+ int *p3 = a4 + 3;
+ int *q = i ? p1 : p3;
+ A (q, -4); // { dg-warning "-Wstringop-overflow" }
+ A (q, -3); A (q, -2); A (q, -1); A (q, 0);
+ A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" }
+}
+
+NOIPA void p3_p1 (int i)
+{
+ int *p3 = a4 + 3;
+ int *p1 = a4 + 1;
+ int *q = i ? p1 : p3;
+ A (q, -4); // { dg-warning "-Wstringop-overflow" }
+ A (q, -3); A (q, -2); A (q, -1); A (q, 0);
+ A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void p1_p4 (int i)
+{
+ int *p1 = a4 + 1;
+ int *p4 = a4 + 4;
+ int *q = i ? p1 : p4;
+ A (q, -5); // { dg-warning "-Wstringop-overflow" }
+ A (q, -4); A (q, -3); A (q, -2); A (q, -1);
+ A (q, 0); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" }
+}
+
+NOIPA void p4_p1 (int i)
+{
+ int *p4 = a4 + 4;
+ int *p1 = a4 + 1;
+ int *q = i ? p1 : p4;
+ A (q, -5); // { dg-warning "-Wstringop-overflow" }
+ A (q, -4); A (q, -3); A (q, -2); A (q, -1);
+ A (q, 0); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void p0_p1_p2 (int i)
+{
+ int *p0 = a4 + 0;
+ int *p1 = a4 + 1;
+ int *p2 = a4 + 2;
+ int *q = i < 0 ? p1 : 0 < i ? p2 : p0;
+ A (q, -3); // { dg-warning "-Wstringop-overflow" }
+ A (q, -2); A (q, -1); A (q, 0); A (q, 1);
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void p0_p1_p2_p3_p4 (int i)
+{
+ int *p0 = a4 + 0;
+ int *p1 = a4 + 1;
+ int *p2 = a4 + 2;
+ int *p3 = a4 + 3;
+ int *p4 = a4 + 4;
+ int *q = i < -1 ? p1 : i < 0 ? p2 : 1 < i ? p4 : 0 < i ? p3 : p0;
+ A (q, -5); // { dg-warning "-Wstringop-overflow" }
+ A (q, -4); A (q, -3); A (q, -2); A (q, -1);
+ A (q, 0); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Wstringop-overflow" }
+}
new file mode 100644
@@ -0,0 +1,153 @@
+/* PR middle-end/103215 - bogus -Wstringop-overflow with two pointers with
+ different offsets each
+ Test for accesses into distinct arrays through pointers with different
+ offsets each.
+
+ If/when -Wstringop-overflow is enhanced to issue "maybe" kinds of
+ warnings some of the accesses here will trigger those and will need
+ updating.
+
+ { dg-do compile }
+ { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+#define NOIPA __attribute__ ((noipa))
+
+void sink (int[1]);
+#define A(p, off) sink (p + off)
+
+extern int a4[4], a8[8];
+
+
+
+
+NOIPA void a4_p1_a8_p3 (int i)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p3 = a8 + 3;
+ int *q = i ? a4_p1 : a8_p3;
+ A (q, -4); // { dg-warning "-Wstringop-overflow" }
+ /* Because -3 is a valid offset into a8 but not a4, q must point
+ to the former and so subscripts between -3 and +4 refer to its
+ elements. */
+ A (q, -3); A (q, -2); A (q, -1); A (q, 0);
+ A (q, 1); A (q, 2); A (q, 3); A (q, 4);
+ A (q, 5); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ /* Both of the following are definitely out of bounds but the first isn't
+ diagnosed because the code conservatively merges the offsets into A4
+ and A8. */
+ A (q, 7); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void a4_p1_a8_p5 (int i)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p5 = a8 + 5;
+ int *q = i ? a4_p1 : a8_p5;
+ A (q, -6); // { dg-warning "-Wstringop-overflow" }
+ /* Similarly to the above, because -5 is a valid offset into a8 but
+ not a4, q must point to the former and so subscripts between -5
+ and +2 refer to its elements. */
+ A (q, -5); A (q, -4); A (q, -3); A (q, -2);
+ A (q, -1); A (q, 0); A (q, 1); A (q, 2);
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 7); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void a4_p1_a8_p7 (int i)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p7 = a8 + 7;
+ int *q = i ? a4_p1 : a8_p7;
+ A (q, -8); // { dg-warning "-Wstringop-overflow" }
+ A (q, -7); A (q, -6); A (q, -5); A (q, -4);
+ A (q, -3); A (q, -2); A (q, -1); A (q, 0);
+ /* Since -7 is valid, q must point to a8 and the last valid subscript
+ must be 0. */
+ A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 7); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void mp_1_a4_p1_a8_p7 (int i, int j)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p7 = a8 + 7;
+ int *p = i ? a4_p1 : a8_p7;
+ int *q = j ? p + 1 : p - 1;
+
+ A (q, -9); // { dg-warning "-Wstringop-overflow" }
+
+ /* q points either to a8 + [6, 8] or a4 + [0, 2]. */
+ A (q, -8); A (q, -7); A (q, -6); A (q, -5);
+ A (q, -4); A (q, -3); A (q, -2); A (q, -1);
+
+ /* Since all the above are valid, q must point to a8 + 8. But as
+ mentioned above, the warning for each subscript is independent
+ of prior subscripts into the same object so the access below
+ aren't diagnosed. */
+ A (q, 0); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 1); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 2); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 8); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void mp1_a4_p1_a8_p5 (int i, int j)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p5 = a8 + 5;
+ int *p = i ? a4_p1 : a8_p5;
+
+ int *q = j ? p + 1 : p - 1;
+
+ // q is assumed to point to a8 + 6
+ A (q, -7); // { dg-warning "-Wstringop-overflow" }
+ A (q, -6); A (q, -5); A (q, -4); A (q, -3);
+ A (q, -2); A (q, -1); A (q, 0); A (q, 1);
+ /* Even though the above accesses rule it out, q is now assumed
+ to point to either a4 + [0, 2] or a8 + [4, 5]. */
+ A (q, 2);
+ /* q is now assumed to point tp a4. Given that, only the first store
+ is valid. */
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 5); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 6); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 7); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 8); // { dg-warning "-Wstringop-overflow" }
+}
+
+
+NOIPA void mp1_a4_p1_a8_p4 (int i, int j)
+{
+ int *a4_p1 = a4 + 1;
+ int *a8_p4 = a8 + 4;
+ int *p = i ? a4_p1 : a8_p4;
+
+ int *q = j ? p + 1 : p - 1;
+
+ // q is assumed to point to a8 + 5
+ A (q, -6); // { dg-warning "-Wstringop-overflow" }
+ A (q, -5);
+ A (q, -4);
+ A (q, -3);
+ A (q, -2);
+ A (q, -1);
+ A (q, 0);
+ A (q, 1);
+ A (q, 2);
+ /* Even though the above accesses rule it out, q is now assumed
+ to point tp a4. Given that, only the first store is valid. */
+ A (q, 3); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 4); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 5); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 6); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 7); // { dg-warning "-Wstringop-overflow" "pr??????" { xfail *-*-* } }
+ A (q, 8); // { dg-warning "-Wstringop-overflow" }
+}
@@ -143,17 +143,18 @@ T (v0 ? b[1] : "", bsz);
T (v0 ? b[2] : "", bsz);
T (v0 ? b[3] : "", bsz);
-/* The warnings below are strictly correct but the strnlen calls are safe
- because the reads are bounded by the length of the constant arguments.
- It might make sense to relax the warning to avoid triggering for them. */
+/* Warning for the calls below would be strictly correct even though
+ the strnlen calls are safe because the reads are bounded by
+ the length of the constant arguments. Most of the calls are
+ not diagnosed anymore as a result of the fix for PR 103215. */
T (v0 ? "" : b[0], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? "" : b[1], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? "" : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? "" : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? "" : b[1], bsz + 1);
+T (v0 ? "" : b[2], bsz + 1);
+T (v0 ? "" : b[3], bsz + 1);
T (v0 ? b[0] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? b[1] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? b[2] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? b[3] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? b[1] : "", bsz + 1);
+T (v0 ? b[2] : "", bsz + 1);
+T (v0 ? b[3] : "", bsz + 1);
T (v0 ? "" : b[i0], bsz);
T (v0 ? "" : b[i1], bsz);
@@ -167,11 +168,11 @@ T (v0 ? b[i3] : "", bsz);
T (v0 ? "" : b[i0], bsz + 1);
T (v0 ? "" : b[i1], bsz + 1);
T (v0 ? "" : b[i2], bsz + 1);
-T (v0 ? "" : b[i3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr86937" } */
+T (v0 ? "" : b[i3], bsz + 1);
T (v0 ? b[i0] : "", bsz + 1);
T (v0 ? b[i1] : "", bsz + 1);
T (v0 ? b[i2] : "", bsz + 1);
-T (v0 ? b[i3] : "", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr86937" } */
+T (v0 ? b[i3] : "", bsz + 1);
T (v0 ? "1234" : b[3], bsz);
T (v0 ? "1234" : b[i3], bsz);
@@ -183,14 +184,16 @@ T (v0 ? b[0] : b[2], bsz);
T (v0 ? b[2] : b[3], bsz);
T (v0 ? b[3] : b[2], bsz);
-T (v0 ? "1234" : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? "1234" : b[i3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? b[3] : "1234", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? b[i3] : "1234", bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
+T (v0 ? "1234" : b[3], bsz + 1);
+T (v0 ? "1234" : b[i3], bsz + 1);
+T (v0 ? b[3] : "1234", bsz + 1);
+T (v0 ? b[i3] : "1234", bsz + 1);
-T (v0 ? a : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? b[0] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
-T (v0 ? b[2] : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
+/* That the following are not diagnosed is a bug/limitation resulting from
+ the fix for PR 103215. */
+T (v0 ? a : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr??????" { xfail *-*-* } } */
+T (v0 ? b[0] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr??????" { xfail *-*-* } } */
+T (v0 ? b[2] : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr??????" { xfail *-*-* } } */
T (v0 ? b[3] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" } */
struct A { char a[5], b[5]; };