From 0c344a649d803a83ed35f629d292b98143935ffa Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 1 Sep 2020 16:02:19 -0600 Subject: [PATCH] Use the determined lower bound of the range of offsets in a PLUS_EXPR. gcc/ChangeLog: * builtins.c (compute_objsize): Only replace the upper bound of a POINTER_PLUS offset when it's less than the lower bound. gcc/testsuite/ChangeLog: * gcc.dg/Wstringop-overflow.c: Remove xfails. * gcc.dg/Wstringop-overflow-42.c: New test. * gcc.dg/Wstringop-overread-4.c: New test. --- gcc/builtins.c | 9 ++- gcc/testsuite/gcc.dg/Wstringop-overflow-42.c | 58 ++++++++++++++++++++ gcc/testsuite/gcc.dg/Wstringop-overflow.c | 12 ++-- gcc/testsuite/gcc.dg/Wstringop-overread-4.c | 58 ++++++++++++++++++++ 4 files changed, 129 insertions(+), 8 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-42.c create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overread-4.c diff --git a/gcc/builtins.c b/gcc/builtins.c index bc35b071f02..97f1a184dc6 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -4367,12 +4367,17 @@ compute_objsize (tree ptr, int ostype, access_ref *pref, offset to the maximum. */ offset_int orng[2]; tree off = gimple_assign_rhs2 (stmt); - if (!get_range (off, SIGNED, orng, rvals) - || !wi::les_p (orng[0], orng[1])) + if (!get_range (off, SIGNED, orng, rvals)) { orng[0] = wi::to_offset (TYPE_MIN_VALUE (ptrdiff_type_node)); orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node)); } + else if (wi::lts_p (orng[1], orng[0])) + /* The upper bound is less than the lower bound when the integer + operand is the result of signed integer conversion to sizetype, + as in P + OFF + CST where OFF > 0. + Correct just the upper bound. */ + orng[1] = wi::to_offset (TYPE_MAX_VALUE (ptrdiff_type_node)); pref->offrng[0] += orng[0]; pref->offrng[1] += orng[1]; diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-42.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-42.c new file mode 100644 index 00000000000..21a675ab7c7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-42.c @@ -0,0 +1,58 @@ +/* Verify -Wstringop-overflow a with destination pointer pointing either + before the beginning or past the end of an object. + { dg-do compile } + { dg-options "-O -Wall -Wno-array-bounds -Wno-restrict" } */ + +typedef __SIZE_TYPE__ size_t; + +char* strcpy (char *, const char *); + + +extern char a[1]; + +volatile char *d; + +void cpy_si_1_max (int i, const char *s) +{ + if (i < 1) i = 1; + d = strcpy (a + i, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } + d = strcpy (a + i + 1, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } +} + +void cpy_ui_1_max (unsigned i, const char *s) +{ + if (i < 1) i = 1; + d = strcpy (a + i, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } + d = strcpy (a + i + 1, s); // { dg-warning "writing 1 or more bytes into a region of size 0" "" { xfail ilp32 } } +} + +void cpy_sl_1_max (long i, const char *s) +{ + if (i < 1) i = 1; + d = strcpy (a + i, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } + d = strcpy (a + i + 1, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } +} + +void cpy_ul_1_max (unsigned long i, const char *s) +{ + if (i < 1) i = 1; + d = strcpy (a + i, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } + d = strcpy (a + i + 1, s); // { dg-warning "writing 1 or more bytes into a region of size 0" "" { xfail *-*-* } } +} + + +void cpy_si_min_m1 (int i, const char *s) +{ + if (i > -1) i = -1; + d = strcpy (a + i - 1, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } + d = strcpy (a + i, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } + d = strcpy (a + i + 2, s); +} + +void cpy_sl_min_m1 (long i, const char *s) +{ + if (i > -1) i = -1; + d = strcpy (a + i - 1, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } + d = strcpy (a + i, s); // { dg-warning "writing 1 or more bytes into a region of size 0" } + d = strcpy (a + i + 2, s); +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow.c b/gcc/testsuite/gcc.dg/Wstringop-overflow.c index 2c5f4f05254..c615dae03fc 100644 --- a/gcc/testsuite/gcc.dg/Wstringop-overflow.c +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow.c @@ -51,8 +51,8 @@ void test_memcpy_array (const void *s) T (a7 + UR (8, 9), s, 7); /* { dg-warning "writing 7 bytes into a region of size 0" } */ T (a7 + UR (9, 10), s, 7); /* { dg-warning "writing 7 bytes into a region of size 0" } */ - T (a7 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), s, 7); /* { dg-warning "writing 7 bytes into a region of size 0" "pr85350" { xfail *-*-* } } */ - T (a7 + UR (DIFF_MAX, SIZE_MAX), s, 7); /* { dg-warning "writing 7 bytes into a region of size 0" "pr85350" { xfail *-*-*} } */ + T (a7 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), s, 7); /* { dg-warning "writing 7 bytes into a region of size 0" } */ + T (a7 + UR (DIFF_MAX, SIZE_MAX), s, 7); /* { dg-warning "writing 7 bytes into a region of size 0" } */ /* This is valid. */ char *d = a7 + 7; @@ -102,8 +102,8 @@ void test_strcpy_array (void) T (a7 + UR (8, 9), "012345"); /* { dg-warning "writing 7 bytes into a region of size 0" } */ T (a7 + UR (9, 10), "012345"); /* { dg-warning "writing 7 bytes into a region of size 0" } */ - T (a7 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), "012345"); /* { dg-warning "writing 7 bytes into a region of size 0" "pr85350" { xfail *-*-* } } */ - T (a7 + UR (DIFF_MAX, SIZE_MAX), "012345"); /* { dg-warning "writing 7 bytes into a region of size 0" "pr85350" { xfail *-*-* } } */ + T (a7 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), "012345"); /* { dg-warning "writing 7 bytes into a region of size 0" } */ + T (a7 + UR (DIFF_MAX, SIZE_MAX), "012345"); /* { dg-warning "writing 7 bytes into a region of size 0" } */ char *d = a7 + 7; @@ -127,6 +127,6 @@ void test_strncpy_memarray (struct MemArray *p, const void *s) T (p->a9 + UR (9, 10), s, 9); /* { dg-warning "writing 9 bytes into a region of size 0" } */ T (p->a9 + UR (10, 11), s, 9); /* { dg-warning "writing 9 bytes into a region of size 0" } */ - T (p->a9 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), s, 1); /* { dg-warning "writing 1 byte into a region of size 0" "pr85350" { xfail *-*-* } } */ - T (p->a9 + UR (DIFF_MAX, SIZE_MAX), s, 3); /* { dg-warning "writing 3 bytes into a region of size 0" "pr85350" { xfail *-*-* } } */ + T (p->a9 + UR (DIFF_MAX, DIFF_MAX + (size_t)1), s, 1); /* { dg-warning "writing 1 byte into a region of size 0" } */ + T (p->a9 + UR (DIFF_MAX, SIZE_MAX), s, 3); /* { dg-warning "writing 3 bytes into a region of size 0" } */ } diff --git a/gcc/testsuite/gcc.dg/Wstringop-overread-4.c b/gcc/testsuite/gcc.dg/Wstringop-overread-4.c new file mode 100644 index 00000000000..8248dad213b --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overread-4.c @@ -0,0 +1,58 @@ +/* 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" } */ + +typedef __SIZE_TYPE__ size_t; + +size_t strlen (const char *); + + +extern char a[1]; + +volatile size_t n; + +void len_si_1_max (int i) +{ + if (i < 1) i = 1; + n = strlen (a + i); // { dg-warning "reading 1 or more bytes from a region of size 0" } + n = strlen (a + i + 1); // { dg-warning "reading 1 or more bytes from a region of size 0" } +} + +void len_ui_1_max (unsigned i) +{ + if (i < 1) i = 1; + n = strlen (a + i); // { dg-warning "reading 1 or more bytes from a region of size 0" } + n = strlen (a + i + 1); // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail ilp32 } } +} + +void len_sl_1_max (long i) +{ + if (i < 1) i = 1; + n = strlen (a + i); // { dg-warning "reading 1 or more bytes from a region of size 0" } + n = strlen (a + i + 1); // { dg-warning "reading 1 or more bytes from a region of size 0" } +} + +void len_ul_1_max (unsigned long i) +{ + if (i < 1) i = 1; + n = strlen (a + i); // { dg-warning "reading 1 or more bytes from a region of size 0" } + n = strlen (a + i + 1); // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail *-*-* } } +} + + +void len_si_min_m1 (int i) +{ + if (i > -1) i = -1; + n = strlen (a + i - 1); // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail lp64 } } + n = strlen (a + i); // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail *-*-* } } + n = strlen (a + i + 2); +} + +void len_sl_min_m1 (long i) +{ + if (i > -1) i = -1; + n = strlen (a + i - 1); // { dg-warning "reading 1 or more bytes from a region of size 0" } + n = strlen (a + i); // { dg-warning "reading 1 or more bytes from a region of size 0" "" { xfail *-*-* } } + n = strlen (a + i + 2); +} -- 2.30.2