aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2020-10-09 14:48:43 -0600
committerMartin Sebor <msebor@redhat.com>2020-10-12 09:05:55 -0600
commit83685efd5fd1623cfc4e4c435ce2773d95d458d1 (patch)
tree5a6514717cd82b39bcec8872ba61871599c5684a /gcc/testsuite/gcc.dg
parentde05c19d5fd661ae16dd75a895b49d32d12f5edc (diff)
downloadgcc-83685efd5fd1623cfc4e4c435ce2773d95d458d1.zip
gcc-83685efd5fd1623cfc4e4c435ce2773d95d458d1.tar.gz
gcc-83685efd5fd1623cfc4e4c435ce2773d95d458d1.tar.bz2
Generalize compute_objsize to return maximum size/offset instead of failing (PR middle-end/97023).
Also resolves: PR middle-end/97342 - bogus -Wstringop-overflow with nonzero signed and unsigned offsets PR middle-end/97023 - missing warning on buffer overflow in chained mempcpy PR middle-end/96384 - bogus -Wstringop-overflow= storing into multidimensional array with index in range gcc/ChangeLog: PR middle-end/97342 PR middle-end/97023 PR middle-end/96384 * builtins.c (access_ref::access_ref): Initialize new member. Use new enum. (access_ref::size_remaining): Define new member function. (inform_access): Handle expressions referencing objects. (gimple_call_alloc_size): Call get_size_range instead of get_range. (gimple_call_return_array): New function. (get_range): Rename... (get_offset_range): ...to this. Improve detection of ranges from types of expressions. (gimple_call_return_array): Adjust calls to get_range per above. (compute_objsize): Same. Set maximum size or offset instead of failing for unknown objects and handle more kinds of expressions. (compute_objsize): Call access_ref::size_remaining. (compute_objsize): Have transitional wrapper fail for pointers into unknown objects. (expand_builtin_strncmp): Call access_ref::size_remaining and handle new cases. * builtins.h (access_ref::size_remaining): Declare new member function. (access_ref::set_max_size_range): Define new member function. (access_ref::add_ofset, access_ref::add_max_ofset): Same. (access_ref::add_base0): New data member. * calls.c (get_size_range): Change argument type. Handle new condition. * calls.h (get_size_range): Adjust signature. (enum size_range_flags): Define new type. * gimple-ssa-warn-restrict.c (builtin_memref::builtin_memref): Correct argument to get_size_range. * tree-ssa-strlen.c (get_range): Handle anti-ranges. (maybe_warn_overflow): Check DECL_P before assuming it's one. gcc/testsuite/ChangeLog: PR middle-end/97342 PR middle-end/97023 PR middle-end/96384 * c-c++-common/Wrestrict.c: Adjust comment. * gcc.dg/Wstringop-overflow-34.c: Remove xfail. * gcc.dg/Wstringop-overflow-43.c: Remove xfails. Adjust regex patterns. * gcc.dg/pr51683.c: Prune out expected warning. * gcc.target/i386/pr60693.c: Same. * g++.dg/warn/Wplacement-new-size-8.C: New test. * gcc.dg/Wstringop-overflow-41.c: New test. * gcc.dg/Wstringop-overflow-44.s: New test. * gcc.dg/Wstringop-overflow-45.c: New test. * gcc.dg/Wstringop-overflow-46.c: New test. * gcc.dg/Wstringop-overflow-47.c: New test. * gcc.dg/Wstringop-overflow-49.c: New test. * gcc.dg/Wstringop-overflow-50.c: New test. * gcc.dg/Wstringop-overflow-51.c: New test. * gcc.dg/Wstringop-overflow-52.c: New test. * gcc.dg/Wstringop-overflow-53.c: New test. * gcc.dg/Wstringop-overflow-54.c: New test. * gcc.dg/Wstringop-overflow-55.c: New test. * gcc.dg/Wstringop-overread-5.c: New test.
Diffstat (limited to 'gcc/testsuite/gcc.dg')
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-34.c2
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-41.c120
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-43.c9
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-44.s271
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-45.c255
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-46.c97
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-47.c69
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-49.c146
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-50.c125
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-51.c34
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-52.c62
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-53.c116
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-54.c103
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overflow-55.c97
-rw-r--r--gcc/testsuite/gcc.dg/Wstringop-overread-5.c76
-rw-r--r--gcc/testsuite/gcc.dg/pr51683.c3
16 files changed, 1580 insertions, 5 deletions
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-34.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-34.c
index fd43f3a..a1b1039 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-34.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-34.c
@@ -112,7 +112,7 @@ void s2_warn_cstoff_cstidx (struct S2 *p)
void s2_warn_varoff_cstdix (struct S2 *p, int i)
{
char *q = p->a + i;
- q[2] = __LINE__; // { dg-warning "\\\[-Wstringop-overflow" "pr?????" { xfail *-*-* } }
+ q[2] = __LINE__; // { dg-warning "\\\[-Wstringop-overflow" }
}
void s2_warn_cstoff_varidx (struct S2 *p, int i)
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-41.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-41.c
new file mode 100644
index 0000000..9b2d2cb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-41.c
@@ -0,0 +1,120 @@
+/* Verify that writes at excessive offsets into declared or allocated
+ objects of unknown size are diagnosed.
+ { dg-do compile }
+ { dg-options "-O2" } */
+
+#define DIFF_MAX __PTRDIFF_MAX__
+
+typedef __SIZE_TYPE__ size_t;
+
+void* malloc (size_t);
+void* memcpy (void*, const void*, size_t);
+void* memset (void*, int, size_t);
+
+void sink (void*);
+
+
+void char_array_cst_off_cst_size (void)
+{
+ extern char caxcc[]; // { dg-message "at offset \\d+ into destination object 'caxcc'" }
+
+ char *p = caxcc;
+ size_t idx = DIFF_MAX - 3;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
+ sink (p);
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 1" "pr?????" { xfail ilp32 } }
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 0" }
+ sink (p);
+}
+
+
+void char_array_var_off_cst_size (size_t idx)
+{
+ /* The offset is a range with a very large lower bound and an upper
+ bound of DIFF_MAX. There's not point in also mentioning the latter
+ (it wouldn't make the note any more meaningful) so verify it only
+ mentions the lower bound. */
+ extern char caxvc[]; // { dg-message "at offset \\d+ into destination object 'caxvc'" "note" }
+
+ char *p = caxvc;
+
+ if (idx < DIFF_MAX - 3)
+ idx = DIFF_MAX - 3;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+ sink (p);
+}
+
+
+void char_array_var_off_var_size (size_t idx, size_t n)
+{
+ extern char caxvv[]; // { dg-message "at offset \\d+ into destination object 'caxvv'" "note" }
+
+ char *p = caxvv;
+
+ if (idx < DIFF_MAX - 3)
+ idx = DIFF_MAX - 3;
+
+ if (n < 3 || 7 < n)
+ n = 3;
+
+ memset (p + idx, 0, n);
+ sink (p);
+
+ ++n;
+ memset (p + idx, 0, n); // { dg-warning "writing between 4 and 8 bytes into a region of size 3" }
+ sink (p);
+}
+
+
+void alloc_array_var_off_cst_size (size_t n, size_t idx)
+{
+ char *p = malloc (n); // { dg-message "at offset \\d+ into destination object" "note" }
+
+ if (idx < DIFF_MAX - 3)
+ idx = DIFF_MAX - 3;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+ sink (p);
+}
+
+
+void int_array_cst_off_cst_size (void)
+{
+ extern int iaxc[]; // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'iaxc'" }
+
+ int *p = iaxc;
+ size_t idx = DIFF_MAX / sizeof *iaxc;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+ sink (p);
+}
+
+
+void* nowarn_anti_range_1 (char *p, char *q)
+{
+ size_t n = q - p;
+ if (!n) return 0;
+
+ char *d = __builtin_malloc (n + 1);
+ memcpy (d, p, n + 1); // { dg-bogus "-Wstringop-overflow" }
+ return d;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-43.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-43.c
index 3ac5a88..14ab925 100644
--- a/gcc/testsuite/gcc.dg/Wstringop-overflow-43.c
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-43.c
@@ -159,9 +159,10 @@ void warn_memset_reversed_range (void)
char *p = &a11[11];
- /* The below is represented as a true anti-range as opposed to a range
- with reversed bounds and the former aren't handled. */
- T1 (p, SAR (INT_MIN, -11), n11); // { dg-warning "writing 11 or more bytes into a region of size 0" "pr?????" { xfail *-*-* } }
+ /* Since the offset is excessive, either starting before &a11[0]
+ ot just past &a[11], the region size in the warning should
+ probably be zero, but accept other sizes too. */
+ T1 (p, SAR (INT_MIN, -11), n11); // { dg-warning "writing 11 or more bytes into a region of size \\d+" }
/* The following are represented as ordinary ranges with reversed bounds
and those are handled. */
@@ -171,7 +172,7 @@ void warn_memset_reversed_range (void)
T1 (p, SAR (INT_MIN, 1), n11); // { dg-warning "writing 11 or more bytes into a region of size 0" "pr?????" { xfail ilp32 } }
T1 (p, SAR (INT_MIN, 0), n11); // { dg-warning "writing 11 or more bytes into a region of size 0" }
/* Also represented as a true anti-range. */
- T1 (p, SAR ( -12, -11), n11); // { dg-warning "writing 11 or more bytes into a region of size 0" "pr?????" { xfail *-*-* } }
+ T1 (p, SAR ( -12, -11), n11); // { dg-warning "writing 11 or more bytes into a region of size \\d+" }
T1 (p, SAR ( -12, -1), n11); // { dg-warning "writing 11 or more bytes into a region of size 0" }
T1 (p, SAR ( -11, 0), n11); // { dg-warning "writing 11 or more bytes into a region of size 0" }
T1 (p, SAR ( -11, 11), n11); // { dg-warning "writing 11 or more bytes into a region of size 0" }
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-44.s b/gcc/testsuite/gcc.dg/Wstringop-overflow-44.s
new file mode 100644
index 0000000..0fc73a9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-44.s
@@ -0,0 +1,271 @@
+ .file "Wstringop-overflow-44.c"
+ .text
+ .p2align 4
+ .globl f0
+ .type f0, @function
+f0:
+.LFB0:
+ .cfi_startproc
+ ret
+ .cfi_endproc
+.LFE0:
+ .size f0, .-f0
+ .p2align 4
+ .globl f1
+ .type f1, @function
+f1:
+.LFB1:
+ .cfi_startproc
+ ret
+ .cfi_endproc
+.LFE1:
+ .size f1, .-f1
+ .p2align 4
+ .globl f2
+ .type f2, @function
+f2:
+.LFB2:
+ .cfi_startproc
+ movl n(%rip), %eax
+ testl %eax, %eax
+ jle .L12
+.L4:
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L12:
+ movslq %eax, %rdx
+ movq d(%rip), %rcx
+ testq %rdx, %rdx
+ je .L4
+ xorl %eax, %eax
+.L6:
+ movb $0, (%rcx,%rax)
+ addq $1, %rax
+ cmpq %rdx, %rax
+ jb .L6
+ ret
+ .cfi_endproc
+.LFE2:
+ .size f2, .-f2
+ .p2align 4
+ .globl f3
+ .type f3, @function
+f3:
+.LFB3:
+ .cfi_startproc
+ movslq n(%rip), %rdx
+ testl %edx, %edx
+ jle .L15
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L15:
+ movq %rdi, %rsi
+ movq d(%rip), %rdi
+ jmp strncpy
+ .cfi_endproc
+.LFE3:
+ .size f3, .-f3
+ .p2align 4
+ .globl f4
+ .type f4, @function
+f4:
+.LFB4:
+ .cfi_startproc
+ movl n(%rip), %eax
+ testl %eax, %eax
+ jle .L18
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L18:
+ movq d(%rip), %rax
+ movq %rdi, %rsi
+ movb $0, (%rax)
+ movslq n(%rip), %rdx
+ movq d(%rip), %rdi
+ jmp strncat
+ .cfi_endproc
+.LFE4:
+ .size f4, .-f4
+ .p2align 4
+ .globl g0
+ .type g0, @function
+g0:
+.LFB5:
+ .cfi_startproc
+ movl n(%rip), %eax
+ testl %eax, %eax
+ jle .L25
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L25:
+ subq $24, %rsp
+ .cfi_def_cfa_offset 32
+ leaq 15(%rsp), %rdi
+ call sink
+ addq $24, %rsp
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
+.LFE5:
+ .size g0, .-g0
+ .p2align 4
+ .globl g1
+ .type g1, @function
+g1:
+.LFB6:
+ .cfi_startproc
+ movl n(%rip), %eax
+ testl %eax, %eax
+ jle .L32
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L32:
+ subq $24, %rsp
+ .cfi_def_cfa_offset 32
+ leaq 15(%rsp), %rdi
+ call sink
+ addq $24, %rsp
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
+.LFE6:
+ .size g1, .-g1
+ .p2align 4
+ .globl g2
+ .type g2, @function
+g2:
+.LFB7:
+ .cfi_startproc
+ movl n(%rip), %eax
+ testl %eax, %eax
+ jle .L45
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L45:
+ movslq %eax, %rdx
+ subq $24, %rsp
+ .cfi_def_cfa_offset 32
+ testq %rdx, %rdx
+ je .L36
+ xorl %eax, %eax
+.L35:
+ movb $0, 15(%rsp,%rax)
+ addq $1, %rax
+ cmpq %rdx, %rax
+ jb .L35
+.L36:
+ leaq 15(%rsp), %rdi
+ call sink
+ addq $24, %rsp
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
+.LFE7:
+ .size g2, .-g2
+ .p2align 4
+ .globl g3
+ .type g3, @function
+g3:
+.LFB8:
+ .cfi_startproc
+ movslq n(%rip), %rdx
+ testl %edx, %edx
+ jle .L52
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L52:
+ subq $24, %rsp
+ .cfi_def_cfa_offset 32
+ movq %rdi, %rsi
+ leaq 15(%rsp), %rdi
+ call strncpy
+ leaq 15(%rsp), %rdi
+ call sink
+ addq $24, %rsp
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
+.LFE8:
+ .size g3, .-g3
+ .p2align 4
+ .globl g4
+ .type g4, @function
+g4:
+.LFB9:
+ .cfi_startproc
+ movslq n(%rip), %rdx
+ testl %edx, %edx
+ jle .L59
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L59:
+ subq $24, %rsp
+ .cfi_def_cfa_offset 32
+ movq %rdi, %rsi
+ leaq 15(%rsp), %rdi
+ movb $0, 15(%rsp)
+ call strncat
+ leaq 15(%rsp), %rdi
+ call sink
+ addq $24, %rsp
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
+.LFE9:
+ .size g4, .-g4
+ .p2align 4
+ .globl h0
+ .type h0, @function
+h0:
+.LFB10:
+ .cfi_startproc
+ movl n(%rip), %eax
+ testl %eax, %eax
+ jle .L66
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L66:
+ subq $8, %rsp
+ .cfi_def_cfa_offset 16
+ movl $1, %edi
+ call malloc
+ movq %rax, d(%rip)
+ addq $8, %rsp
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
+.LFE10:
+ .size h0, .-h0
+ .p2align 4
+ .globl h1
+ .type h1, @function
+h1:
+.LFB16:
+ .cfi_startproc
+ movl n(%rip), %eax
+ testl %eax, %eax
+ jle .L73
+ ret
+ .p2align 4,,10
+ .p2align 3
+.L73:
+ subq $8, %rsp
+ .cfi_def_cfa_offset 16
+ movl $1, %edi
+ call malloc
+ movq %rax, d(%rip)
+ addq $8, %rsp
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
+.LFE16:
+ .size h1, .-h1
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-45.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-45.c
new file mode 100644
index 0000000..112d79a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-45.c
@@ -0,0 +1,255 @@
+/* PR middle-end/97023 - missing warning on buffer overflow in chained mempcpy
+ Verify that out of bounds writes by built-ins to objects through pointers
+ returned by other built-ins are diagnosed.
+ { dg-do compile }
+ { dg-options "-O2" } */
+
+#include "range.h"
+
+void* malloc (size_t);
+void* memcpy (void*, const void*, size_t);
+void* memmove (void*, const void*, size_t);
+void* mempcpy (void*, const void*, size_t);
+
+void sink (void*, ...);
+
+
+void nowarn_memcpy (const void *s)
+{
+ extern char cpy_a4[4];
+ unsigned n = sizeof cpy_a4;
+
+ void *p = cpy_a4;
+ p = memcpy (p, s, n);
+ sink (p);
+ memcpy (p, s, n);
+ sink (p);
+
+ p = cpy_a4 + 1;
+ p = memcpy (p, s, n - 1);
+ sink (p);
+ memcpy (p, s, n - 1);
+ sink (p);
+
+ p = cpy_a4 + 2;
+ p = memcpy (p, s, n - 2);
+ sink (p);
+ memcpy (p, s, n - 2);
+ sink (p);
+
+ p = cpy_a4 + 3;
+ p = memcpy (p, s, n - 3);
+ sink (p);
+ memcpy (p, s, n - 3);
+ sink (p);
+
+ p = cpy_a4 + 4;
+ p = memcpy (p, s, n - 4);
+ sink (p);
+ memcpy (p, s, n - 4);
+ sink (p);
+}
+
+
+void nowarn_memcpy_chain (const void *s)
+{
+ extern char cpy_a8[8];
+
+ char *p = cpy_a8;
+
+ p = memcpy (p + 1, s, 7);
+ sink (p);
+
+ p = memcpy (p + 2 , s, 5);
+ sink (p);
+
+ p = memcpy (p + 3 , s, 2);
+ sink (p);
+
+ p = memcpy (p + 1 , s, 1);
+ sink (p);
+
+ p = memcpy (p - 7 , s, 8);
+ sink (p);
+
+ memcpy (p + 1, s, 7);
+}
+
+
+void warn_memcpy (const void *s)
+{
+ extern char cpy_a5[5]; // { dg-message "destination object 'cpy_a5'" "note" }
+
+ unsigned n = sizeof cpy_a5;
+ void *p = cpy_a5;
+
+ p = memcpy (p, s, n);
+ sink (p);
+ memcpy (p, s, n + 1); // { dg-warning "writing 6 bytes into a region of size 5" }
+ sink (p);
+
+ p = cpy_a5;
+ p = memcpy (p, s, n);
+ sink (p);
+ memcpy (p, s, n + 1); // { dg-warning "writing 6 bytes into a region of size 5" }
+ sink (p);
+
+ p = cpy_a5 + 1;
+ p = memcpy (p, s, n - 1);
+ sink (p);
+ memcpy (p, s, n); // { dg-warning "writing 5 bytes into a region of size 4" }
+ sink (p);
+}
+
+
+void warn_memcpy_chain (const void *s)
+{
+ extern char cpy_a8[8]; // { dg-message "destination object 'cpy_a8'" "note" }
+
+ char *p = cpy_a8;
+
+ p = memcpy (p, s, 9); // { dg-warning "writing 9 bytes into a region of size 8" }
+ sink (p);
+
+ p = memcpy (p + 2, s, 7); // { dg-warning "writing 7 bytes into a region of size 6" }
+ sink (p);
+
+ p = memcpy (p + 3, s, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+ sink (p);
+
+ p = memcpy (p + 3, s, 3); // { dg-warning "writing 3 bytes into a region of size 0" }
+ sink (p);
+}
+
+
+void nowarn_mempcpy (const void *s)
+{
+ extern char a4[4];
+ unsigned n = sizeof a4;
+
+ char *p = mempcpy (a4, s, n);
+ sink (p);
+ mempcpy (p - 4, s, n);
+ sink (p);
+
+ p = mempcpy (a4 + 1, s, n - 1);
+ sink (p);
+ mempcpy (p - 4, s, n);
+ sink (p);
+
+ p = mempcpy (a4 + 2, s, n - 2);
+ sink (p);
+ mempcpy (p - 4, s, n);
+ sink (p);
+
+ p = mempcpy (a4 + 3, s, n - 3);
+ sink (p);
+ mempcpy (p - 4, s, n);
+ sink (p);
+
+ p = mempcpy (a4 + 4, s, n - 4);
+ sink (p);
+ mempcpy (p - 4, s, n);
+ sink (p);
+}
+
+
+void nowarn_mempcpy_chain (const void *s)
+{
+ extern char pcpy_a8[8];
+
+ char *p = pcpy_a8;
+
+ p = mempcpy (p + 1, s, 7);
+ sink (p);
+
+ p = mempcpy (p - 7 , s, 7);
+ sink (p);
+
+ p = mempcpy (p - 5 , s, 5);
+ sink (p);
+
+ p = mempcpy (p - 3 , s, 3);
+ sink (p);
+
+ p = mempcpy (p - 2 , s, 2);
+ sink (p);
+
+ mempcpy (p - 1, s, 1);
+ sink (p);
+
+ mempcpy (p - 8, s, 8);
+}
+
+
+void warn_mempcpy (const void *s)
+{
+ extern char pcpy_a5[5]; // { dg-message "destination object 'pcpy_a5'" "note" }
+
+ char *p = pcpy_a5;
+
+ p = mempcpy (p, s, 5);
+ sink (p);
+ mempcpy (p - 5, s, 6); // { dg-warning "writing 6 bytes into a region of size 5 " }
+ sink (p);
+
+ p = pcpy_a5;
+ p = mempcpy (p, s, 3);
+ sink (p);
+ mempcpy (p, s, 3); // { dg-warning "writing 3 bytes into a region of size 2 " }
+ sink (p);
+
+ p = pcpy_a5 + 1;
+ p = mempcpy (p, s, 3);
+ sink (p);
+ mempcpy (p - 1, s, 5); // { dg-warning "writing 5 bytes into a region of size 2 " }
+ sink (p);
+}
+
+
+void warn_mempcpy_chain_3 (const void *s)
+{
+ char *p = malloc (5); // { dg-message "at offset \\\[3, 5] into destination object of size 5" "note" }
+ p = mempcpy (p, s, UR (1, 2));
+ p = mempcpy (p, s, UR (2, 3));
+ p = mempcpy (p, s, UR (3, 4)); // { dg-warning "writing between 3 and 4 bytes into a region of size 2 " }
+
+ sink (p);
+}
+
+void warn_mempcpy_offrng_chain_3 (const void *s)
+{
+ char *p = malloc (11); // { dg-message "at offset \\\[9, 11] into destination object of size 11 " "note" }
+ size_t r1_2 = UR (1, 2);
+ size_t r2_3 = r1_2 + 1;
+ size_t r3_4 = r2_3 + 1;
+
+ p = mempcpy (p + r1_2, s, r1_2);
+ p = mempcpy (p + r2_3, s, r2_3);
+ p = mempcpy (p + r3_4, s, r3_4); // { dg-warning "writing between 3 and 4 bytes into a region of size 2 " }
+
+ sink (p);
+}
+
+void warn_mempcpy_chain_4 (const void *s)
+{
+ char *p = malloc (9); // { dg-message "at offset \\\[6, 9] into destination object of size 9 " "note" }
+ p = mempcpy (p, s, UR (1, 2));
+ p = mempcpy (p, s, UR (2, 3));
+ p = mempcpy (p, s, UR (3, 4));
+ p = mempcpy (p, s, UR (4, 5)); // { dg-warning "writing between 4 and 5 bytes into a region of size 3 " }
+
+ sink (p);
+}
+
+void warn_mempcpy_chain_5 (const void *s)
+{
+ char *p = malloc (14); // { dg-message "at offset \\\[10, 14] into destination object of size 14 " "note" }
+ p = mempcpy (p, s, UR (1, 2));
+ p = mempcpy (p, s, UR (2, 3));
+ p = mempcpy (p, s, UR (3, 4));
+ p = mempcpy (p, s, UR (4, 5));
+ p = mempcpy (p, s, UR (5, 6)); // { dg-warning "writing between 5 and 6 bytes into a region of size 4 " }
+
+ sink (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-46.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-46.c
new file mode 100644
index 0000000..a4d78b2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-46.c
@@ -0,0 +1,97 @@
+/* PR middle-end/97023 - missing warning on buffer overflow in chained mempcpy
+ Verify that out of bounds writes by built-ins to objects through pointers
+ returned by memchr() are diagnosed.
+ { dg-do compile }
+ { dg-options "-O2" } */
+
+#include "range.h"
+
+void* malloc (size_t);
+void* memchr (void*, int, size_t);
+void* memset (void*, int, size_t);
+
+void sink (void*, ...);
+
+void nowarn_memchr_cst_memset_cst (const void *s)
+{
+ char *p = malloc (4);
+ sink (p);
+
+ p = memchr (p, '1', 4);
+ memset (p, 0, 4);
+}
+
+void nowarn_memchr_uint_memset_cst (const void *s, unsigned n)
+{
+ char *p = malloc (4);
+ sink (p);
+
+ p = memchr (p, '1', n);
+ memset (p, 0, 4);
+}
+
+void nowarn_memchr_sz_memset_cst (const void *s, size_t n)
+{
+ char *p = malloc (4);
+ sink (p);
+
+ p = memchr (p, '1', n);
+ memset (p, 0, 4);
+}
+
+void nowarn_memchr_anti_range_memset_cst (const void *s, size_t n)
+{
+ char *p = malloc (4);
+ sink (p);
+
+ if (n == 0)
+ n = 1;
+
+ p = memchr (p, '1', n);
+ memset (p, 0, 4);
+}
+
+void warn_memchr_cst_memset_cst (const void *s)
+{
+ char *p = malloc (4); // { dg-message "at offset \\\[0, 4] into destination object of size 4 " "note" }
+ sink (p);
+
+ p = memchr (p, '1', 4);
+ memset (p, 0, 5); // { dg-warning "writing 5 bytes into a region of size 4 " }
+}
+
+void warn_memchr_var_memset_cst (const void *s, unsigned n)
+{
+ char *p = malloc (4); // { dg-message "at offset \\\[0, 4] into destination object of size 4 " "note" }
+ sink (p);
+
+ p = memchr (p, '1', n);
+ memset (p, 0, 5); // { dg-warning "writing 5 bytes into a region of size 4 " }
+}
+
+void warn_memchr_var_memset_range (const void *s, unsigned n)
+{
+ /* The offsets in the first two notes are bounded by the size of
+ the allocated object. The real upper bound of the offset in
+ the last note includes the upper bound f the offset of the pointer
+ returned from the previous memchr() call, but it ends up getting
+ constrained to the bounds of the allocated object so it's the same
+ as in the first two notes. The exact value probably isn't too
+ important. */
+ char *p0 = malloc (UR (5, 7));
+ // { dg-message "at offset \\\[0, 7] into destination object of size \\\[5, 7]" "note" { target *-*-* } .-1 }
+ // { dg-message "at offset \\\[1, 7] into destination object of size \\\[5, 7]" "note" { target *-*-* } .-2 }
+ // { dg-message "at offset \\\[2, 7] into destination object of size \\\[5, 7]" "note" { target *-*-* } .-3 }
+
+ sink (p0);
+ char *p1 = memchr (p0, '1', n);
+ memset (p1, 0, UR (8, 9)); // { dg-warning "writing between 8 and 9 bytes into a region of size 7 " }
+
+ sink (p0);
+ p1 = memchr (p0 + 1, '2', n);
+ memset (p1, 0, UR (7, 9)); // { dg-warning "writing between 7 and 9 bytes into a region of size 6 " }
+
+ sink (p0);
+ char *p2 = memchr (p1 + 1, '3', n);
+ memset (p2, 0, UR (6, 9)); // { dg-warning "writing between 6 and 9 bytes into a region of size 5 " }
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-47.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-47.c
new file mode 100644
index 0000000..02b14ee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-47.c
@@ -0,0 +1,69 @@
+/* Verify that storing a bigger vector into smaller space is diagnosed.
+ { dg-do compile }
+ { dg-options "-O2" } */
+
+typedef __INT16_TYPE__ int16_t;
+typedef __attribute__ ((__vector_size__ (32))) char C32;
+
+typedef __attribute__ ((__vector_size__ (64))) int16_t I16_64;
+
+void sink (void*);
+
+
+void nowarn_c32 (char c)
+{
+ extern char nowarn_a32[32];
+
+ void *p = nowarn_a32;
+ *(C32*)p = (C32){ c };
+ sink (p);
+
+ char a32[32];
+ p = a32;
+ *(C32*)p = (C32){ c };
+ sink (p);
+}
+
+void warn_c32 (char c)
+{
+ extern char warn_a32[32]; // { dg-message "at offset 32 to object 'warn_a32' with size 32" }
+
+ void *p = warn_a32 + 1;
+ *(C32*)p = (C32){ c }; // { dg-warning "writing 1 byte into a region of size 0" }
+
+ /* Verify a local variable too. */
+ char a32[32];
+ p = a32 + 1;
+ *(C32*)p = (C32){ c }; // { dg-warning "writing 1 byte into a region of size 0" }
+ sink (p);
+}
+
+
+void nowarn_i16_64 (int16_t i)
+{
+ extern char nowarn_a64[64];
+
+ void *p = nowarn_a64;
+ I16_64 *q = (I16_64*)p;
+ *q = (I16_64){ i };
+
+ char a64[64];
+ q = (I16_64*)a64;
+ *q = (I16_64){ i };
+ sink (q);
+}
+
+void warn_i16_64 (int16_t i)
+{
+ extern char warn_a64[64]; // { dg-message "at offset 128 to object 'warn_a64' with size 64" "pr97027" { xfail *-*-* } }
+
+ void *p = warn_a64 + 1;
+ I16_64 *q = (I16_64*)p;
+ *q = (I16_64){ i }; // { dg-warning "writing 1 byte into a region of size 0" "pr97027" { xfail *-*-* } }
+
+ char a64[64];
+ p = a64 + 1;
+ q = (I16_64*)p;
+ *q = (I16_64){ i }; // { dg-warning "writing 1 byte into a region of size 0" "pr97027" { xfail *-*-* } }
+ sink (p);
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-49.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-49.c
new file mode 100644
index 0000000..84b6c94
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-49.c
@@ -0,0 +1,146 @@
+/* Verify the handling of anti-ranges/multi-ranges by allocation functions
+ and subsequent accesses.
+ { dg-do compile }
+ { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+void* malloc (size_t);
+void bzero (void*, size_t);
+void* memset (void*, int, size_t);
+
+
+/* Exercise size_t (via malloc and memset) and unsigned/signed int. */
+
+__attribute__ ((alloc_size (1))) void*
+alloc_int (int);
+
+__attribute__ ((access (write_only, 1, 2))) void
+access_int (void*, int);
+
+__attribute__ ((alloc_size (1))) void*
+alloc_uint (unsigned);
+
+__attribute__ ((access (write_only, 1, 2))) void
+access_uint (void*, unsigned);
+
+
+void* nowarn_malloc_memset_same_anti_range (size_t n)
+{
+ /* Set N to the anti-range ~[3, 3]. */
+ if (n == 3)
+ n = 4;
+ void *p = malloc (n);
+
+ /* Verify there is no warning for an access to N bytes at P.
+ This means the warning has to assume the value of N in the call
+ to alloc() is in the larger subrange [4, UINT_MAX], while in
+ the call to access() in [0, 3]. */
+ return memset (p, 0, n);
+}
+
+/* Same as above but with two valid ranges. */
+
+void* nowarn_malloc_memset_anti_range (size_t n1, size_t n2)
+{
+ /* Set N1 to the anti-range ~[3, 3]. */
+ if (n1 == 3)
+ n1 = 4;
+ void *p = malloc (n1);
+
+ /* Set N2 to the anti-range ~[7, 7]. */
+ if (n2 == 7)
+ n2 = 8;
+
+ return memset (p, 0, n2);
+}
+
+
+void nowarn_alloc_access_same_anti_range_int (int n)
+{
+ /* Set N to the anti-range ~[3, 3]. */
+ if (n == 3)
+ n = 4;
+ void *p = alloc_int (n);
+
+ /* Verify there is no warning for an access to N bytes at P.
+ This means the warning has to assume the value of N in the call
+ to alloc() is in the larger subrange [4, UINT_MAX], while in
+ the call to access() in [0, 3]. */
+ access_int (p, n);
+}
+
+/* Same as above but with two valid ranges. */
+
+void nowarn_alloc_access_anti_range_int (int n1, int n2)
+{
+ /* Set N1 to the anti-range ~[3, 3]. */
+ if (n1 == 3)
+ n1 = 4;
+ void *p = alloc_int (n1);
+
+ /* Set N2 to the anti-range ~[7, 7]. */
+ if (n2 == 7)
+ n2 = 8;
+
+ access_int (p, n2);
+}
+
+
+void nowarn_alloc_access_same_anti_range_uint (unsigned n)
+{
+ /* Set N to the anti-range ~[3, 3]. */
+ if (n == 3)
+ n = 4;
+ void *p = alloc_uint (n);
+
+ /* Verify there is no warning for an access to N bytes at P.
+ This means the warning has to assume the value of N in the call
+ to alloc() is in the larger subrange [4, UINT_MAX], while in
+ the call to access() in [0, 3]. */
+ access_uint (p, n);
+}
+
+/* Same as above but with two valid ranges. */
+
+void nowarn_alloc_access_anti_range_uint (unsigned n1, unsigned n2)
+{
+ /* Set N1 to the anti-range ~[3, 3]. */
+ if (n1 == 3)
+ n1 = 4;
+ void *p = alloc_uint (n1);
+
+ /* Set N2 to the anti-range ~[7, 7]. */
+ if (n2 == 7)
+ n2 = 8;
+
+ access_uint (p, n2);
+}
+
+
+void* nowarn_malloc_anti_range_memset_range (size_t n1, size_t n2)
+{
+ /* Set N1 to the anti-range ~[3, 3]. */
+ if (n1 == 3)
+ n1 = 4;
+ void *p = malloc (n1);
+
+ /* Set N2 to the range [5, MAX]. */
+ if (n2 < 5)
+ n2 = 5;
+ return memset (p, 0, n2);
+}
+
+void* nowarn_malloc_range_bzero_anti_range (size_t n1, size_t n2)
+{
+ /* Set N1 to the anti-range ~[3, 3]. */
+ if (n1 > 4)
+ n1 = 4;
+ void *p = malloc (n1);
+
+ /* Set N2 to the range [5, MAX]. */
+ if (n2 <= 3 || 5 <= n2)
+ n2 = 4;
+ bzero (p, n2);
+ return p;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-50.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-50.c
new file mode 100644
index 0000000..7df58e5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-50.c
@@ -0,0 +1,125 @@
+/* Verify that writes at excessive offsets into objects of unknown size
+ pointed to by function arguments are diagnosed.
+ { dg-do compile }
+ { dg-options "-O2" } */
+
+#define DIFF_MAX __PTRDIFF_MAX__
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__ size_t;
+
+void* memset (void*, int, size_t);
+
+void sink (void*);
+
+char* fcall (void);
+
+void char_ptr_cst_off_cst_size (char *p)
+ // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'p'" "note" { target *-*-* } .-1 }
+{
+ size_t idx = DIFF_MAX - 3;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
+ sink (p);
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 1" }
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 0" }
+}
+
+
+void char_ptr_var_difoff_cst_size (ptrdiff_t idx)
+{
+ char *p = fcall ();
+ /* The offset is a range with a very large lower bound and an upper
+ bound of DIFF_MAX. There's not point in also mentioning the latter
+ (it wouldn't make the note any more meaningful) so verify it only
+ mentions the lower bound.
+ { dg-message "at offset \\d+ into destination object of size \\\[0, \\d+] (allocated|returned) by 'fcall'" "note" { target *-*-* } .-5 } */
+
+ if (idx < DIFF_MAX - 3)
+ idx = DIFF_MAX - 3;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+}
+
+
+void char_ptr_var_szoff_cst_size (size_t idx)
+{
+ extern char* gptr;
+ // { dg-message "at offset \\d+ into destination object 'gptr'" "note" { target *-*-* } .-1 }
+
+ char *p = gptr;
+
+ if (idx < DIFF_MAX - 3)
+ idx = DIFF_MAX - 3;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" "" { xfail *-*-* } }
+
+ if (idx > DIFF_MAX)
+ idx = DIFF_MAX;
+
+ memset (p + idx, 0, 7); // { dg-warning "writing 7 bytes into a region of size 3" }
+}
+
+
+void char_ptr_var_difoff_var_size (char *p, ptrdiff_t idx, size_t n)
+ // { dg-message "at offset \\d+ into destination object 'p'" "note" { target *-*-* } .-1 }
+{
+ if (idx < DIFF_MAX - 3)
+ idx = DIFF_MAX - 3;
+
+ if (n < 3 || 7 < n)
+ n = 3;
+
+ memset (p + idx, 0, n);
+ sink (p);
+
+ ++n;
+ memset (p + idx, 0, n); // { dg-warning "writing between 4 and 8 bytes into a region of size 3" }
+}
+
+
+void char_ptr_var_szoff_var_size (char *p, size_t idx, size_t n)
+ // { dg-message "at offset \\\[\[1-9\]\[0-9\]+, \[1-9\]\[0-9\]+] into destination object 'p'" "note" { xfail *-*-* } .-1 }
+{
+ if (idx < DIFF_MAX - 3)
+ idx = DIFF_MAX - 3;
+
+ if (n < 3 || 7 < n)
+ n = 3;
+
+ memset (p + idx, 0, n);
+ sink (p);
+
+ ++n;
+ /* With an unsigned offset large values are interpreted as negative
+ so the addition (p + idx) is effectively treated as subtraction,
+ making an overflow indistinguishable from a valid (if unlikely)
+ store. */
+ memset (p + idx, 0, n); // { dg-warning "writing between 4 and 8 bytes into a region of size 3" "pr?????" { xfail *-*-* } }
+}
+
+
+void int_ptr_cst_off_cst_size (int *p)
+ // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'p'" "note" { target *-*-* } .-1 }
+{
+ size_t idx = DIFF_MAX / sizeof *p;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-51.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-51.c
new file mode 100644
index 0000000..6f36643
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-51.c
@@ -0,0 +1,34 @@
+/* Test case derived from Binutils/GDB's readline/readline/histexpand.c.
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+char *
+get_subst_pattern (char *str, int *iptr, int delimiter, int is_rhs, int *lenptr)
+{
+ int si, i, j, k;
+ char *s;
+
+ s = 0;
+ i = *iptr;
+
+ for (si = i; str[si] && str[si] != delimiter; si++)
+ if (str[si] == '\\' && str[si + 1] == delimiter)
+ si++;
+
+ if (si > i || is_rhs)
+ {
+ s = (char *)__builtin_malloc (si - i + 1);
+ for (j = 0, k = i; k < si; j++, k++)
+ {
+ /* Remove a backslash quoting the search string delimiter. */
+ if (str[k] == '\\' && str[k + 1] == delimiter)
+ k++;
+ s[j] = str[k]; // { dg-bogus "-Wstringop-overflow" }
+ }
+ s[j] = '\0';
+ if (lenptr)
+ *lenptr = j;
+ }
+
+ return s;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-52.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-52.c
new file mode 100644
index 0000000..a289655
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-52.c
@@ -0,0 +1,62 @@
+
+/* PR middle-end/97023 - missing warning on buffer overflow in chained mempcpy
+ Verify that writes by built-in functions to objects through pointers
+ returned by ordinary (non-built-int) function are assumed to point to
+ the beginning of objects.
+ { dg-do compile }
+ { dg-options "-O2" } */
+
+#include "range.h"
+
+void* memcpy (void*, const void*, size_t);
+void* memset (void*, int, size_t);
+
+void sink (void*, ...);
+
+extern char* arrptr[];
+extern char* ptr;
+extern char* retptr (void);
+struct S { char *p; };
+extern struct S retstruct (void);
+
+void nowarn_ptr (void)
+{
+ {
+ void *p = arrptr;
+ memset (p - 1, 0, 12345); // { dg-warning "\\\[-Wstringop-overflow" }
+ memset (p,0, 12345);
+ memset (p,0, DIFF_MAX - 1);
+ }
+
+ {
+ char *p = arrptr[0];
+ memset (p - 1, 0, 12345);
+ memset (p - 12345, 0, 12345);
+ memset (p - 1234, 0, DIFF_MAX - 1);
+ memset (p - DIFF_MAX + 1, 0, 12345);
+ }
+
+ {
+ char *p = ptr;
+ memset (p - 1, 0, 12345);
+ memset (p - 12345, 0, 12345);
+ memset (p - 1234, 0, DIFF_MAX - 1);
+ memset (p - DIFF_MAX + 1, 0, 12345);
+ }
+
+ {
+ char *p = retptr ();
+ memset (p - 1, 0, 12345);
+ memset (p - 12345, 0, 12345);
+ memset (p - 1234, 0, DIFF_MAX - 1);
+ memset (p - DIFF_MAX + 1, 0, 12345);
+ }
+
+ {
+ char *p = retstruct ().p;
+ memset (p - 1, 0, 12345);
+ memset (p - 12345, 0, 12345);
+ memset (p - 1234, 0, DIFF_MAX - 1);
+ memset (p - DIFF_MAX + 1, 0, 12345);
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-53.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-53.c
new file mode 100644
index 0000000..cd8fa32
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-53.c
@@ -0,0 +1,116 @@
+/* PR middle-end/96384 - bogus -Wstringop-overflow= storing into
+ multidimensional array with index in range
+ { dg-do compile }
+ { dg-options "-O2 -Wall" } */
+
+#define SHRT_MAX __SHRT_MAX__
+#define SHRT_MIN (-SHRT_MAX - 1)
+#define INT_MAX __INT_MAX__
+#define INT_MIN (-INT_MAX - 1)
+#define LONG_MAX __LONG_MAX__
+#define LONG_MIN (-LONG_MAX - 1)
+
+#define USHRT_MAX (SHRT_MAX * 2 + 1)
+#define UINT_MAX ~0U
+#define ULONG_MAX ~0LU
+
+char ca3_5_7[3][5][7];
+
+void nowarn_ca_3_5_ssi (short i)
+{
+ if (i > SHRT_MAX - 1)
+ i = SHRT_MAX - 1;
+
+ ca3_5_7[i][0][0] = __LINE__;
+ ca3_5_7[i][0][1] = __LINE__;
+ ca3_5_7[i][0][2] = __LINE__;
+ ca3_5_7[i][0][3] = __LINE__;
+ ca3_5_7[i][0][4] = __LINE__;
+ ca3_5_7[i][0][5] = __LINE__;
+ ca3_5_7[i][0][6] = __LINE__;
+
+ ca3_5_7[i][1][0] = __LINE__;
+ ca3_5_7[i][1][1] = __LINE__;
+ ca3_5_7[i][1][2] = __LINE__;
+ ca3_5_7[i][1][3] = __LINE__;
+ ca3_5_7[i][1][4] = __LINE__;
+ ca3_5_7[i][1][5] = __LINE__;
+ ca3_5_7[i][1][6] = __LINE__;
+
+ ca3_5_7[i][2][0] = __LINE__;
+ ca3_5_7[i][2][1] = __LINE__;
+ ca3_5_7[i][2][2] = __LINE__;
+ ca3_5_7[i][2][3] = __LINE__;
+ ca3_5_7[i][2][4] = __LINE__;
+ ca3_5_7[i][2][5] = __LINE__;
+ ca3_5_7[i][2][6] = __LINE__;
+
+ ca3_5_7[i][3][0] = __LINE__;
+ ca3_5_7[i][3][1] = __LINE__;
+ ca3_5_7[i][3][2] = __LINE__;
+ ca3_5_7[i][3][3] = __LINE__;
+ ca3_5_7[i][3][4] = __LINE__;
+ ca3_5_7[i][3][5] = __LINE__;
+ ca3_5_7[i][3][6] = __LINE__;
+
+ ca3_5_7[i][4][0] = __LINE__;
+ ca3_5_7[i][4][1] = __LINE__;
+ ca3_5_7[i][4][2] = __LINE__;
+ ca3_5_7[i][4][3] = __LINE__;
+ ca3_5_7[i][4][4] = __LINE__;
+ ca3_5_7[i][4][5] = __LINE__;
+ ca3_5_7[i][4][6] = __LINE__;
+
+ ca3_5_7[1][i][5] = __LINE__;
+ ca3_5_7[2][3][i] = __LINE__;
+}
+
+void nowarn_ca_3_5_usi (unsigned short i)
+{
+ if (i > USHRT_MAX - 1)
+ i = USHRT_MAX - 1;
+
+ ca3_5_7[i][3][5] = __LINE__;
+ ca3_5_7[1][i][5] = __LINE__;
+ ca3_5_7[2][3][i] = __LINE__;
+}
+
+void nowarn_ca_3_5_si (int i)
+{
+ if (i > INT_MAX - 1)
+ i = INT_MAX - 1;
+
+ ca3_5_7[i][3][5] = __LINE__;
+ ca3_5_7[1][i][5] = __LINE__;
+ ca3_5_7[2][3][i] = __LINE__;
+}
+
+void nowarn_ca_3_5_ui (unsigned i)
+{
+ if (i > UINT_MAX - 1)
+ i = UINT_MAX - 1;
+
+ ca3_5_7[i][3][5] = __LINE__;
+ ca3_5_7[1][i][5] = __LINE__;
+ ca3_5_7[2][3][i] = __LINE__;
+}
+
+void nowarn_ca_3_5_li (long i)
+{
+ if (i > LONG_MAX - 1)
+ i = LONG_MAX - 1;
+
+ ca3_5_7[i][3][5] = __LINE__;
+ ca3_5_7[1][i][5] = __LINE__;
+ ca3_5_7[2][3][i] = __LINE__;
+}
+
+void nowarn_ca_3_5_uli (unsigned long i)
+{
+ if (i > ULONG_MAX - 1)
+ i = ULONG_MAX - 1;
+
+ ca3_5_7[i][3][5] = __LINE__;
+ ca3_5_7[1][i][5] = __LINE__;
+ ca3_5_7[2][3][i] = __LINE__;
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-54.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-54.c
new file mode 100644
index 0000000..26568f8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-54.c
@@ -0,0 +1,103 @@
+/* Verify that writes at excessive offsets into flexible array members
+ of extern or allocated objects of unknow size are diagnosed.
+ { dg-do compile }
+ { dg-options "-O2" } */
+
+#define DIFF_MAX __PTRDIFF_MAX__
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__ size_t;
+
+void* memset (void*, int, size_t);
+
+void sink (void*);
+
+void char_flexarray_cst_off_cst_size (void)
+{
+ extern struct { char n, a[]; }
+ caxcc; // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'caxcc'" }
+
+ char *p = caxcc.a;
+ size_t idx = DIFF_MAX - 4;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
+ sink (p);
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 1" }
+
+ ++idx;
+ memset (p + idx, 0, 3); // { dg-warning "writing 3 bytes into a region of size 0" }
+}
+
+
+void char_flexarray_var_off_cst_size (ptrdiff_t idx)
+{
+ extern struct { char n, a[]; }
+ caxvc; // { dg-message "destination object 'caxvc'" }
+
+ char *p = caxvc.a;
+
+ if (idx < DIFF_MAX - 4)
+ idx = DIFF_MAX - 4;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+}
+
+
+void char_flexarray_var_off_var_size (size_t n, ptrdiff_t idx)
+{
+ extern struct { char n, a[]; }
+ caxvv; // { dg-message "destination object 'caxvv'" }
+
+ char *p = caxvv.a;
+
+ if (idx < DIFF_MAX - 4)
+ idx = DIFF_MAX - 4;
+
+ if (n < 3 || 7 < n)
+ n = 3;
+
+ memset (p + idx, 0, n);
+ sink (p);
+
+ ++n;
+ memset (p + idx, 0, n); // { dg-warning "writing between 4 and 8 bytes into a region of size 3" }
+}
+
+
+void alloc_array_var_off_cst_size (size_t n, ptrdiff_t idx)
+{
+ struct { char n, a[]; }
+ *p = __builtin_malloc (n); // { dg-message "at offset \\d+ into destination object" }
+
+ if (idx < DIFF_MAX - 4)
+ idx = DIFF_MAX - 4;
+
+ memset (p->a + idx, 0, 3);
+ sink (p);
+
+ memset (p->a + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+}
+
+
+void int_array_cst_off_cst_size (void)
+{
+ extern struct { int n, a[]; }
+ iaxc; // { dg-message "at offset \[1-9\]\[0-9\]+ into destination object 'iaxc'" }
+
+ int *p = iaxc.a;
+ size_t idx = DIFF_MAX / sizeof *p - 1;
+
+ memset (p + idx, 0, 3);
+ sink (p);
+
+ memset (p + idx, 0, 5); // { dg-warning "writing 5 bytes into a region of size 3" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
new file mode 100644
index 0000000..25f5b82
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-55.c
@@ -0,0 +1,97 @@
+/* Verify that offsets in "anti-ranges" are handled correctly.
+ { dg-do compile }
+ { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+typedef __SIZE_TYPE__ size_t;
+
+void* memset (void*, int, size_t);
+
+void sink (void*, ...);
+#define T(x) sink (x)
+
+
+void int_range_add_sub_ (int i, int j)
+{
+ if (i < 1) i = 1;
+ if (j > -1) j = -1;
+
+ char ca5[5]; // { dg-message "at offset \\\[1, 5]" "note" }
+ char *p0 = ca5; // offset
+ char *p1 = p0 + i; // 1-5
+ char *p2 = p1 + i; // 2-5
+ char *p3 = p2 + j; // 0-4
+ char *p4 = p3 + j; // 0-3
+ char *p5 = p4 + j; // 0-2
+ char *p6 = p5 + j; // 0-1
+ char *p7 = p6 + i; // 1-2
+
+ memset (p7, 0, 5); // { dg-warning "writing 5 bytes into a region of size 4" }
+
+ sink (p0, p1, p2, p3, p4, p5, p6, p7);
+}
+
+
+void ruint_arint_add (unsigned i, int j)
+{
+ i |= 1; // [1, UINT_MAX]
+ j |= 1; // [INT_MIN + 1, -1] U [1, INT_MAX]
+
+ char a[5]; // { dg-message "at offset \\\[1, 5]" "note" }
+ char *p0 = a; // offset
+ char *p1 = p0 + i; // 1-5
+ T (memset (p1, 0, 4));
+
+ char *p2 = p1 + j; // 0-5
+ T (memset (p2, 0, 5));
+
+ char *p3 = p2 + i; // 1-5
+ T (memset (p3, 0, 4));
+
+ char *p4 = p3 + j; // 0-5
+ T (memset (p4, 0, 5));
+
+ char *p5 = p4 + i; // 1-5
+ T (memset (p5, 0, 4));
+
+ char *p6 = p5 + j; // 0-5
+ T (memset (p6, 0, 5));
+
+ char *p7 = p6 + i; // 1-5
+ T (memset (p7, 0, 5)); // { dg-warning "writing 5 bytes into a region of size 4" "" }
+}
+
+
+void warn_ptrdiff_anti_range_add (ptrdiff_t i)
+{
+ i |= 1;
+
+ char ca5[5]; // { dg-message "at offset \\\[1, 5]" "pr?????" { xfail *-*-* } }
+ char *p0 = ca5; // offset
+ char *p1 = p0 + i; // 1-5
+ char *p2 = p1 + i; // 2-5
+ char *p3 = p2 + i; // 3-5
+ char *p4 = p3 + i; // 4-5
+ char *p5 = p4 + i; // 5
+
+ memset (p5, 0, 5); // { dg-warning "writing 5 bytes into a region of size 0" "pr?????" { xfail *-*-* } }
+
+ sink (p0, p1, p2, p3, p4, p5);
+}
+
+void warn_int_anti_range (int i)
+{
+ i |= 1;
+
+ char ca5[5]; // { dg-message "at offset \\\[1, 5]" "pr?????" { xfail *-*-* } }
+ char *p0 = ca5; // offset
+ char *p1 = p0 + i; // 1-5
+ char *p2 = p1 + i; // 2-5
+ char *p3 = p2 + i; // 3-5
+ char *p4 = p3 + i; // 4-5
+ char *p5 = p4 + i; // 5
+
+ memset (p5, 0, 5); // { dg-warning "writing 5 bytes into a region of size 0" "pr?????" { xfail *-*-* } }
+
+ sink (p0, p1, p2, p3, p4, p5);
+}
diff --git a/gcc/testsuite/gcc.dg/Wstringop-overread-5.c b/gcc/testsuite/gcc.dg/Wstringop-overread-5.c
new file mode 100644
index 0000000..b75002b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-overread-5.c
@@ -0,0 +1,76 @@
+/* Verify -Wstringop-overread with a source pointer pointing either
+ before the beginning or past the end of an object.
+ { dg-do compile }
+ { dg-options "-O -Wall -Wno-array-bounds" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+size_t strlen (const char *);
+
+void sink (void*, ...);
+
+void off_sz_or_1 (size_t i)
+{
+ i |= 1;
+
+ /* Verify the offset in the notes only mentions the meaningful lower
+ bound and not a range with the excessive (and meaningless) upper
+ bound like [2, 9223372036854775807]. */
+ extern char a[1];
+ // { dg-message "at offset 1 into source object 'a'" "note" { target *-*-* } .-1 }
+ // { dg-message "at offset 2 " "note" { target *-*-* } .-2 }
+
+ char *p1 = a + i;
+ char *p2 = p1 + 1;
+ char *p3 = p1 - 1;
+
+ size_t n = 0;
+ n += strlen (p1); // { dg-warning "reading 1 or more bytes from a region of size 0" }
+ n += strlen (p2); // { dg-warning "reading 1 or more bytes from a region of size 0" }
+ n += strlen (p3);
+
+ sink (p1, p2, p3, n);
+}
+
+
+void off_sz_or_2 (size_t i)
+{
+ i |= 2;
+
+ extern char b[2];
+ // { dg-message "at offset 2 " "note" { target *-*-* } .-1 }
+ // { dg-message "at offset 3 " "note" { target *-*-* } .-2 }
+
+ char *p1 = b + i;
+ char *p2 = p1 + 1;
+ char *p3 = p1 - 1;
+
+ size_t n = 0;
+ n += strlen (p1); // { dg-warning "reading 1 or more bytes from a region of size 0" }
+ n += strlen (p2); // { dg-warning "reading 1 or more bytes from a region of size 0" }
+ n += strlen (p3);
+
+ sink (p1, p2, p3, n);
+}
+
+
+void off_sz_or_4 (size_t i)
+{
+ i |= 4;
+
+ extern char c[3];
+ // { dg-message "at offset 4 " "note" { target *-*-* } .-1 }
+ // { dg-message "at offset 5 " "note" { target *-*-* } .-2 }
+ // { dg-message "at offset 3 " "note" { target *-*-* } .-3 }
+
+ char *p1 = c + i;
+ char *p2 = p1 + 1;
+ char *p3 = p1 - 1;
+
+ size_t n = 0;
+ n += strlen (p1); // { dg-warning "reading 1 or more bytes from a region of size 0" }
+ n += strlen (p2); // { dg-warning "reading 1 or more bytes from a region of size 0" }
+ n += strlen (p3); // { dg-warning "reading 1 or more bytes from a region of size 0" }
+
+ sink (p1, p2, p3, n);
+}
diff --git a/gcc/testsuite/gcc.dg/pr51683.c b/gcc/testsuite/gcc.dg/pr51683.c
index c477cd8..7a624e4 100644
--- a/gcc/testsuite/gcc.dg/pr51683.c
+++ b/gcc/testsuite/gcc.dg/pr51683.c
@@ -12,6 +12,9 @@ void *
foo (void *p)
{
return bar ((void *) 0x12345000, p, 256);
+ /* Integers converted to pointers are assumed to be the result of
+ (invalid) arithmetic on null pointers.
+ { dg-prune-output "writing 256 bytes into a region of size 0" } */
}
/* { dg-final { scan-tree-dump "memcpy" "optimized" } } */