From 243a980437b5e7fca56587bf86667005bdf343a7 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 9 Dec 2021 12:49:28 -0700 Subject: [PATCH] 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-85.c: New test. * gcc.dg/Wstringop-overflow-87.c: New test. --- gcc/pointer-query.cc | 33 +++--- gcc/testsuite/gcc.dg/Warray-bounds-91.c | 145 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/Warray-bounds-92.c | 149 ++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/Wstringop-overflow-58.c | 22 ++-- gcc/testsuite/gcc.dg/Wstringop-overflow-59.c | 18 +++- gcc/testsuite/gcc.dg/Wstringop-overflow-85.c | 153 +++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/Wstringop-overflow-87.c | 147 +++++++++++++++++++++++++ gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c | 43 ++++---- 8 files changed, 664 insertions(+), 46 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-91.c create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-92.c create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-85.c create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-87.c diff --git a/gcc/pointer-query.cc b/gcc/pointer-query.cc index e618c4d..4bedf7f 100644 --- a/gcc/pointer-query.cc +++ b/gcc/pointer-query.cc @@ -688,27 +688,32 @@ access_ref::merge_ref (vec *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; diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-91.c b/gcc/testsuite/gcc.dg/Warray-bounds-91.c new file mode 100644 index 0000000..1c81091 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-91.c @@ -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" } +} diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-92.c b/gcc/testsuite/gcc.dg/Warray-bounds-92.c new file mode 100644 index 0000000..8c8f5f7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-92.c @@ -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" } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-58.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-58.c index b81186c..e0a4078 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-58.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-58.c @@ -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); diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-59.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-59.c index c45a92d..b6265e3 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow-59.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-59.c @@ -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); diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-85.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-85.c new file mode 100644 index 0000000..ac61e0a --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-85.c @@ -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" } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-87.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-87.c new file mode 100644 index 0000000..bc12192 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-87.c @@ -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" } +} diff --git a/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c b/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c index 846e930..70f6a43 100644 --- a/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c +++ b/gcc/testsuite/gcc.dg/warn-strnlen-no-nul.c @@ -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,15 +184,17 @@ 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 ? 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" } */ -T (v0 ? b[3] : b[2], 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); + +/* 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" "pr103215" { xfail *-*-* } } */ +T (v0 ? b[0] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */ +T (v0 ? b[2] : b[3], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */ +T (v0 ? b[3] : b[2], bsz + 1); /* { dg-warning "bound 6 exceeds source size 5" "pr103215" { xfail *-*-* } } */ struct A { char a[5], b[5]; }; -- 2.7.4