diff options
author | Martin Sebor <msebor@redhat.com> | 2020-10-09 14:48:43 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2020-10-12 09:05:55 -0600 |
commit | 83685efd5fd1623cfc4e4c435ce2773d95d458d1 (patch) | |
tree | 5a6514717cd82b39bcec8872ba61871599c5684a /gcc/testsuite/gcc.dg | |
parent | de05c19d5fd661ae16dd75a895b49d32d12f5edc (diff) | |
download | gcc-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.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-41.c | 120 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-43.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-44.s | 271 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-45.c | 255 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-46.c | 97 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-47.c | 69 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-49.c | 146 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-50.c | 125 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-51.c | 34 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-52.c | 62 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-53.c | 116 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-54.c | 103 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overflow-55.c | 97 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Wstringop-overread-5.c | 76 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr51683.c | 3 |
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" } } */ |