diff options
author | Martin Sebor <msebor@redhat.com> | 2017-11-10 16:35:26 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2017-11-10 09:35:26 -0700 |
commit | 025d57f037ad13eb479818b677ef4be4d97b639c (patch) | |
tree | 28c279950fb42d8f67b86b9a2193b3acc6a669f2 /gcc/testsuite | |
parent | e89ce41dbab07a9acafd900a3ab57eeb5d499276 (diff) | |
download | gcc-025d57f037ad13eb479818b677ef4be4d97b639c.zip gcc-025d57f037ad13eb479818b677ef4be4d97b639c.tar.gz gcc-025d57f037ad13eb479818b677ef4be4d97b639c.tar.bz2 |
PR c/81117 - Improve buffer overflow checking in strncpy
gcc/ChangeLog:
PR c/81117
* builtins.c (compute_objsize): Handle arrays that
compute_builtin_object_size likes to fail for. Make extern.
* builtins.h (compute_objsize): Declare.
(check_strncpy_sizes): New function.
(expand_builtin_strncpy): Call check_strncpy_sizes.
* gimple-fold.c (gimple_fold_builtin_strncpy): Implement
-Wstringop-truncation.
(gimple_fold_builtin_strncat): Same.
* gimple.c (gimple_build_call_from_tree): Set call location.
* tree-ssa-strlen.c (strlen_to_stridx): New global variable.
(maybe_diag_bound_equal_length, is_strlen_related_p): New functions.
(handle_builtin_stxncpy, handle_builtin_strncat): Same.
(handle_builtin_strlen): Use strlen_to_stridx.
(strlen_optimize_stmt): Handle flavors of strncat, strncpy, and
stpncpy.
Use strlen_to_stridx.
(pass_strlen::execute): Release strlen_to_stridx.
* doc/invoke.texi (-Wsizeof-pointer-memaccess): Document enhancement.
(-Wstringop-truncation): Document new option.
gcc/ada/ChangeLog:
PR c/81117
* ada/adadecode.c (__gnat_decode): Use memcpy instead of strncpy.
* ada/argv.c (__gnat_fill_arg, __gnat_fill_env): Same.
gcc/c-family/ChangeLog:
PR c/81117
* c-common.c (catenate_strings): Use memcpy instead of strncpy.
* c-warn.c (sizeof_pointer_memaccess_warning): Handle arrays.
* c.opt (-Wstringop-truncation): New option.
gcc/fortran/ChangeLog:
PR c/81117
* gcc/fortran/decl.c (build_sym): Use strcpy instead of strncpy.
gcc/objc/ChangeLog:
PR c/81117
* objc-encoding.c (encode_type): Use memcpy instead of strncpy.
gcc/testsuite/ChangeLog:
PR c/81117
* c-c++-common/Wsizeof-pointer-memaccess3.c: New test.
* c-c++-common/Wstringop-overflow.c: Same.
* c-c++-common/Wstringop-truncation.c: Same.
* c-c++-common/Wsizeof-pointer-memaccess2.c: Adjust.
* c-c++-common/attr-nonstring-2.c: New test.
* g++.dg/torture/Wsizeof-pointer-memaccess1.C: Adjust.
* g++.dg/torture/Wsizeof-pointer-memaccess2.C: Same.
* gcc.dg/torture/pr63554.c: Same.
* gcc.dg/Walloca-1.c: Disable macro tracking.
From-SVN: r254630
Diffstat (limited to 'gcc/testsuite')
-rw-r--r-- | gcc/testsuite/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c | 15 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess3.c | 132 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/Wstringop-overflow.c | 158 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/Wstringop-truncation.c | 448 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/attr-nonstring-1.c | 60 | ||||
-rw-r--r-- | gcc/testsuite/c-c++-common/attr-nonstring-2.c | 123 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C | 15 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C | 11 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/Walloca-1.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/builtin-stpncpy.c | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c | 15 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/torture/pr63554.c | 5 |
13 files changed, 981 insertions, 26 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 72dea0a..948c8b1 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,17 @@ +2017-11-10 Martin Sebor <msebor@redhat.com> + + PR c/81117 + * c-c++-common/Wsizeof-pointer-memaccess3.c: New test. + * c-c++-common/Wstringop-overflow.c: Same. + * c-c++-common/Wstringop-truncation.c: Same. + * c-c++-common/Wsizeof-pointer-memaccess2.c: Adjust. + * c-c++-common/attr-nonstring-2.c: New test. + * gcc/testsuite/gcc.dg/builtin-stpncpy.c: Adjust. + * g++.dg/torture/Wsizeof-pointer-memaccess1.C: Same. + * g++.dg/torture/Wsizeof-pointer-memaccess2.C: Same. + * gcc.dg/torture/pr63554.c: Same. + * gcc.dg/Walloca-1.c: Disable macro tracking. + 2017-11-10 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/82929 diff --git a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c index 895a50e..f7bfa35 100644 --- a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c +++ b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c @@ -1,7 +1,7 @@ /* Test -Wsizeof-pointer-memaccess warnings. */ /* { dg-do compile } */ -/* { dg-options "-Wall -O2 -Wno-sizeof-array-argument -ftrack-macro-expansion=0" } */ -/* { dg-options "-Wall -O2 -Wno-sizeof-array-argument -Wno-c++-compat -ftrack-macro-expansion=0" {target c} } */ +/* { dg-options "-Wall -O2 -Wno-sizeof-array-argument -Wno-stringop-truncation -ftrack-macro-expansion=0" } */ +/* { dg-options "-Wall -O2 -Wno-sizeof-array-argument -Wno-stringop-truncation -Wno-c++-compat -ftrack-macro-expansion=0" {target c} } */ /* { dg-require-effective-target alloca } */ #define bos(ptr) __builtin_object_size (ptr, 1) @@ -473,12 +473,15 @@ f4 (char *x, char **y, int z, char w[64]) strncat (w, s2, sizeof (w)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ stpncpy (w, s1, sizeof (w)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ - /* These are correct, no warning. */ + /* These are pointless when the destination is large enough, and + cause overflow otherwise. If the copies are guaranteed to be + safe the calls might as well be replaced by strcat(), strcpy(), + or memcpy(). */ const char s3[] = "foobarbaz"; const char s4[] = "abcde12345678"; - strncpy (x, s3, sizeof (s3)); - strncat (x, s4, sizeof (s4)); - stpncpy (x, s3, sizeof (s3)); + strncpy (x, s3, sizeof (s3)); /* { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } */ + strncat (x, s4, sizeof (s4)); /* { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } */ + stpncpy (x, s3, sizeof (s3)); /* { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } */ } /* { dg-prune-output "\[\n\r\]*writing\[\n\r\]*" } */ diff --git a/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess3.c b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess3.c new file mode 100644 index 0000000..97598c4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess3.c @@ -0,0 +1,132 @@ +/* Test -Wsizeof-pointer-memaccess warnings. */ +/* { dg-do compile } */ +/* { dg-options "-Wsizeof-pointer-memaccess -Wno-stringop-overflow -Wno-stringop-truncation -ftrack-macro-expansion=0" } */ + +#define bos(ptr) __builtin_object_size (ptr, 1) +#define bos0(ptr) __builtin_object_size (ptr, 0) + +#define memset(dst, val, sz) \ + (FUNC (memset, dst, val, sz, bos (dst)), sink ((dst))) + +#define memcpy(dst, src, sz) \ + (FUNC (memcpy, dst, src, sz, bos (dst)), sink ((dst))) + +#define memmove(dst, src, sz) \ + (FUNC (memmove, dst, src, sz, bos (dst)), sink ((dst))) + +#define mempcpy(dst, src, sz) \ + (FUNC (mempcpy, dst, src, sz, bos (dst)), sink ((dst))) + +#define strncpy(dst, src, sz) \ + (FUNC (strncpy, dst, src, sz, bos (dst)), sink (dst)) + +#define strncat(dst, src, sz) \ + (FUNC (strncat, dst, src, sz, bos (dst)), sink (dst)) + +#define stpncpy(dst, src, sz) \ + (FUNC (stpncpy, dst, src, sz, bos (dst)), sink (dst)) + +void sink (void*); + +#define S10 "123456789" +extern char a10[10]; + +void test_string_literal (char *dst) +{ +#define FUNC(f, d, s, n, x) __builtin_ ## f (d, s, n) + + /* It's common to call memcpy and other raw memory functions with + size drerived from the source argument. Verify that no warning + is ussued for such calls. */ + memcpy (dst, S10, sizeof S10); + mempcpy (dst, S10, sizeof S10); + memmove (dst, S10, sizeof S10); + + memset (dst, 0, sizeof S10); + + stpncpy (dst, S10, sizeof S10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + strncpy (dst, S10, sizeof S10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + strncat (dst, S10, sizeof S10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + /* Unlike in the cases above, even though the calls below are likely + wrong, it's not easy to detect that the expression (sizeof X - 1) + involves sizeof of the source, so no warning is issued here, as + helpful as one might be. Whether -Wstringop-truncation is issued + is tested elsewhere. */ + stpncpy (dst, S10, sizeof S10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ + + strncpy (dst, S10, sizeof S10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ + + strncat (dst, S10, sizeof S10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ +} + + +void test_char_array (char *dst) +{ + memcpy (dst, a10, sizeof a10); + mempcpy (dst, a10, sizeof a10); + memmove (dst, a10, sizeof a10); + + memset (dst, 0, sizeof a10); + + stpncpy (dst, a10, sizeof a10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + strncpy (dst, a10, sizeof a10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + strncat (dst, a10, sizeof a10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + stpncpy (dst, a10, sizeof a10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ + + strncpy (dst, a10, sizeof a10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ + + strncat (dst, a10, sizeof a10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ +} + + +#undef FUNC +#define FUNC(f, d, s, n, os) __builtin___ ## f ## _chk (d, s, n, os) + +void test_char_array_chk (char *dst) +{ + memcpy (dst, S10, sizeof S10); + mempcpy (dst, S10, sizeof S10); + memmove (dst, S10, sizeof S10); + + memset (dst, 0, sizeof S10); + + stpncpy (dst, S10, sizeof S10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + strncpy (dst, S10, sizeof S10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + strncat (dst, S10, sizeof S10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + stpncpy (dst, S10, sizeof S10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ + + strncpy (dst, S10, sizeof S10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ + + strncat (dst, S10, sizeof S10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ +} + + +void test_string_literal_chk (char *dst) +{ + memcpy (dst, a10, sizeof a10); + mempcpy (dst, a10, sizeof a10); + memmove (dst, a10, sizeof a10); + + memset (dst, 0, sizeof a10); + + stpncpy (dst, a10, sizeof a10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + strncpy (dst, a10, sizeof a10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + strncat (dst, a10, sizeof a10); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" } */ + + stpncpy (dst, a10, sizeof a10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ + + strncpy (dst, a10, sizeof a10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ + + strncat (dst, a10, sizeof a10 - 1); /* { dg-warning "\\\[-Wsizeof-pointer-memaccess]" "" { xfail *-*-* } } */ +} diff --git a/gcc/testsuite/c-c++-common/Wstringop-overflow.c b/gcc/testsuite/c-c++-common/Wstringop-overflow.c new file mode 100644 index 0000000..53f5166 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wstringop-overflow.c @@ -0,0 +1,158 @@ +/* PR middle-end/81117 - Improve buffer overflow checking in strncpy + { dg-do compile } + { dg-options "-O2 -Wstringop-overflow -Wno-stringop-truncation -ftrack-macro-expansion=0" } */ + +typedef __SIZE_TYPE__ size_t; + +#if __cplusplus +extern "C" { +#endif + +size_t strlen (const char*); +char* strncat (char*, const char*, size_t); +char* strncpy (char*, const char*, size_t); +#if __cplusplus +} +#endif + +const char ar[] = "123"; + +void test_strncat (char **d, const char* s, int i) +{ + /* Use a fresh pointer for each test to prevent the optimizer from + eliminating redundant writes into the same destination. Avoid + calling functions like sink() on the result that would have to + be assumed to change the source string by the alias oracle. */ +#define T(d, s, len) strncat (*d++, (s), (len)) + + T (d, "", 0); + T (d, "", 1); + T (d, "", 2); + T (d, "", 3); + T (d, "123", 0); + /* The following two calls truncate the copy and are diagnosed + by -Wstringop-truncation but there is evidence of overflow so + they're not diagnosed by -Wstringop-overflow. */ + T (d, "123", 1); + T (d, "123", 2); + + T (d, "123", 3); /* { dg-warning ".strncat\[^\n\r\]* specified bound 3 equals source length" } */ + T (d, "123", 4); + T (d, "123", 9); + + T (d, s, strlen (s)); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + T (d, s, strlen (s) + 1); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + /* The following could also be diagnosed by -Wstringop-truncation + (with some effort to distinguish the pattern from others like + the one above. */ + T (d, s, strlen (s) - 1); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + T (d, s, strlen (s) - i); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + + /* The following is dubious but not necessarily a smoking gun. */ + T (d, s, strlen (s) - strlen (s)); + + { + signed char n = strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + } + + { + short n = strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + } + + { + int n = strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + } + + { + unsigned n = strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + } + + { + size_t n; + n = strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + } + + { + size_t n; + n = strlen (s) - 1; /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-message ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + } + + { + /* This doesn't overflow so iit should not be diagnosed. */ + size_t n = strlen (s) - strlen (s); + T (d, s, n); + } + + { + size_t n = i < strlen (s) ? i : strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-message ".strncat\[^\n\r\]* specified bound depends on the length of the source argument" } */ + } +} + + +void test_strncpy (char **d, const char* s, int i) +{ +#undef T +#define T(d, s, len) strncpy (*d++, (s), (len)) + + T (d, "", 0); + T (d, "", 1); + T (d, "", 2); + T (d, "", 3); + T (d, "123", 0); + T (d, "123", 1); + T (d, "123", 2); + T (d, "123", 3); + T (d, "123", 4); + T (d, "123", 9); + + T (d, "123", sizeof "123"); + T (d, ar, sizeof ar); + + T (d, s, strlen (s)); /* { dg-warning "\\\[-Wstringop-overflow=]" } */ + + { + int n = strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning "\\\[-Wstringop-overflow=]" } */ + } + + { + unsigned n = strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning "\\\[-Wstringop-overflow=]" } */ + } + + { + size_t n; + n = strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning "\\\[-Wstringop-overflow=]" } */ + } + + { + size_t n; + n = strlen (s) - 1; /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-warning "\\\[-Wstringop-overflow=]" } */ + } + + { + /* This is diagnosed by -Wstringop-truncation. Verify that it isn't + also diagnosed by -Wstringop-overflow. */ + size_t n = strlen (s) - strlen (s); + T (d, s, n); + } + + { + /* This use of strncpy is certainly dubious and it could well be + diagnosed by -Wstringop-truncation but it isn't. That it is + diagnosed with -Wstringop-overflow is more by accident than + by design. -Wstringop-overflow considers any dependency of + the bound on strlen(s) a potential bug. */ + size_t n = i < strlen (s) ? i : strlen (s); /* { dg-message "length computed here" } */ + T (d, s, n); /* { dg-message ".strncpy\[^\n\r]* specified bound depends on the length of the source argument" } */ + } +} diff --git a/gcc/testsuite/c-c++-common/Wstringop-truncation.c b/gcc/testsuite/c-c++-common/Wstringop-truncation.c new file mode 100644 index 0000000..c536a13 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wstringop-truncation.c @@ -0,0 +1,448 @@ +/* PR middle-end/81117 - Improve buffer overflow checking in strncpy + { dg-do compile } + { dg-options "-O2 -Wstringop-truncation -Wno-stringop-overflow -ftrack-macro-expansion=0" } */ + + +typedef __SIZE_TYPE__ size_t; + +#if __cplusplus +extern "C" { +#endif + +size_t strlen (const char*); +char* strncat (char*, const char*, size_t); +char* strncpy (char*, const char*, size_t); + +#if __cplusplus +} +#endif + +extern size_t unsigned_value (void) +{ + extern volatile size_t unsigned_value_source; + return unsigned_value_source; +} + +size_t unsigned_range (size_t min, size_t max) +{ + size_t val = unsigned_value (); + return val < min || max < val ? min : val; +} + +#define UR(min, max) unsigned_range (min, max) + +void sink (void*); + +#define S4 "123" +const char a4[] = "123"; + +#define CHOOSE(a, b) (unsigned_value () & 1 ? a : b) + + +typedef struct Dest +{ + char a5[5]; + char b7[7]; + char c3ns[3] __attribute__ ((nonstring)); +} Dest; + +char dst7[7]; +char dst2_5[2][5]; + +/* Verify strncat warnings for arrays of known bounds. */ + +void test_strncat_array (Dest *pd) +{ +#define CAT(d, s, len) (strncat ((d), (s), (len)), sink (d)) + + CAT (dst7, S4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + + CAT (dst7, a4, 1); /* { dg-warning "output truncated copying 1 byte from a string of length 3" } */ + + /* There is no truncation here but possible overflow so these + are diagnosed by -Wstringop-overflow: + CAT (dst7, S4, 3); + CAT (dst7, a4, 3); + */ + + CAT (pd->a5, S4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + CAT (pd->a5, S4, 1); /* { dg-warning "output truncated copying 1 byte from a string of length 3" } */ +} + +/* Verify strncat warnings for arrays of known bounds and a non-const + character count in some range. */ + +void test_strncat_array_range (Dest *pd) +{ + CAT (dst7, S4, UR (0, 1)); /* { dg-warning "output truncated copying between 0 and 1 bytes from a string of length 3" } */ + CAT (dst7, S4, UR (0, 2)); /* { dg-warning "output truncated copying between 0 and 2 bytes from a string of length 3" } */ + CAT (dst7, S4, UR (1, 3)); /* { dg-warning "output truncated copying between 1 and 3 bytes from a string of length 3" } */ + CAT (dst7, S4, UR (2, 4)); /* { dg-warning "output may be truncated copying between 2 and 4 bytes from a string of length 3" } */ + + CAT (dst7, S4, UR (0, 7)); + CAT (dst7, S4, UR (1, 7)); + CAT (dst7, S4, UR (6, 7)); + + CAT (dst7, S4, UR (0, 99)); + + CAT (dst7, S4, UR (0, 99)); +} + +/* Verify strncat warnings for arrays of unknown bounds. */ + +void test_strncat_vla (char *d, unsigned n) +{ + CAT (d, S4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + CAT (d, S4, 4); + + CAT (d, a4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + + /* There is no truncation here but possible overflow so these + are diagnosed by -Wstringop-overflow: + CAT (d, S4, 3); + CAT (d, a4, 3); + */ + CAT (d, a4, 4); + + char vla[n]; + + CAT (vla, S4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + + CAT (vla, S4, 4); + CAT (vla, S4, n); + + CAT (vla, a4, 2); /* { dg-warning "output truncated copying 2 bytes from a string of length 3" } */ + + CAT (vla, a4, 4); + CAT (vla, a4, n); + + CAT (d, vla, 1); + CAT (d, vla, 3); + CAT (d, vla, 4); + CAT (d, vla, n); + + /* There is no truncation here but possible overflow so these + are diagnosed by -Wstringop-overflow: + CAT (vla, S4, 3); + CAT (vla, a4, 3); + */ +} + +/* Verify strncpy warnings with at least one pointer to an object + or string of unknown size (destination) or length (source). */ + +void test_strncpy_ptr (char *d, const char* s, const char *t, int i) +{ +#define CPY(d, s, len) (strncpy ((d), (s), (len)), sink (d)) + + /* Strncpy doesn't nul-terminate so the following is diagnosed. */ + CPY (d, "", 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + CPY (d, s, 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + + /* This is safe. */ + CPY (d, "", 1); + CPY (d, "", 2); + + /* This could be safe. */ + CPY (d, s, 1); + CPY (d, s, 2); + + /* Truncation. */ + CPY (d, "123", 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 3" } */ + CPY (d, "123", 2); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 2 bytes from a string of length 3" } */ + CPY (d, "123", 3); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + CPY (d, "123", 4); + CPY (d, "123", 9); + + CPY (d, S4, sizeof S4); /* Covered by -Wsizeof-pointer-memaccess. */ + CPY (d, S4, sizeof S4 - 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + + CPY (d, a4, sizeof a4); /* Covered by -Wsizeof-pointer-memaccess. */ + CPY (d, a4, sizeof a4 - 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + CPY (d, a4, sizeof a4 - 3); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 3" } */ + CPY (d, a4, sizeof a4 - 4); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes from a string of length 3" } */ + + CPY (d, S4, strlen (S4)); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + /* Likely buggy but no truncation. Diagnosed by -Wstringop-overflow. */ + CPY (d, a4, strlen (a4) + 1); + CPY (d, S4, strlen (S4) + i); + + CPY (d, a4, strlen (a4)); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + /* As above, buggy but no evidence of truncation. */ + CPY (d, S4, strlen (S4) + 1); + + CPY (d, CHOOSE ("", "1"), 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + CPY (d, CHOOSE ("1", "12"), 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + + CPY (d, CHOOSE ("", "1"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 1" } */ + CPY (d, CHOOSE ("1", ""), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 1" } */ + CPY (d, CHOOSE (s, "1"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 1" } */ + CPY (d, CHOOSE (s, t), 1); + + CPY (d, CHOOSE ("", "1"), 2); + CPY (d, CHOOSE ("1", ""), 2); + CPY (d, CHOOSE ("1", "2"), 2); + CPY (d, CHOOSE ("1", s), 2); + CPY (d, CHOOSE (s, "1"), 2); + CPY (d, CHOOSE (s, t), 2); + + CPY (d, CHOOSE ("", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output may be truncated copying 1 byte from a string of length 3" } */ + CPY (d, CHOOSE ("1", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 1" } */ + CPY (d, CHOOSE ("12", "123"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */ + CPY (d, CHOOSE ("123", "12"), 1); /* { dg-warning ".strncpy\[^\n\r\]* output truncated copying 1 byte from a string of length 2" } */ + + { + signed char n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + short n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + int n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + unsigned n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + size_t n; + n = strlen (s); /* { dg-message "length computed here" } */ + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + size_t n; + char *dp2 = d + 1; + n = strlen (s); /* { dg-message "length computed here" } */ + CPY (dp2, s, n); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying as many bytes from a string as its length" } */ + } + + { + /* The following is likely buggy but there's no apparent truncation + so it's not diagnosed by -Wstringop-truncation. Instead, it is + diagnosed by -Wstringop-overflow (tested elsewhere). */ + int n; + n = strlen (s) - 1; + CPY (d, s, n); + } + + { + /* Same as above. */ + size_t n; + n = strlen (s) - 1; + CPY (d, s, n); + } + + { + size_t n = strlen (s) - strlen (s); + CPY (d, s, n); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + } + + { + /* This use of strncpy is dubious but it's probably not worth + worrying about (truncation may not actually take place when + i is the result). It is diagnosed with -Wstringop-overflow + (although more by accident than by design). + + size_t n = i < strlen (s) ? i : strlen (s); + CPY (d, s, n); + */ + } +} + + +/* Verify strncpy warnings for arrays of known bounds. */ + +void test_strncpy_array (Dest *pd, int i, const char* s) +{ +#undef CPY +#define CPY(d, s, len) (strncpy ((d), (s), (len)), sink (d)) + + CPY (dst7, s, 7); /* { dg-warning "specified bound 7 equals destination size" } */ + CPY (dst7, s, sizeof dst7); /* { dg-warning "specified bound 7 equals destination size" } */ + + CPY (dst2_5[0], s, sizeof dst2_5[0]); /* { dg-warning "specified bound 5 equals destination size" "bug 77293" { xfail *-*-* } } */ + CPY (dst2_5[1], s, sizeof dst2_5[1]); /* { dg-warning "specified bound 5 equals destination size" } */ + + /* Verify that copies that nul-terminate are not diagnosed. */ + CPY (dst7, "", sizeof dst7); + CPY (dst7 + 6, "", sizeof dst7 - 6); + CPY (dst7, "1", sizeof dst7); + CPY (dst7 + 1, "1", sizeof dst7 - 1); + CPY (dst7, "123456", sizeof dst7); + CPY (dst7 + 1, "12345", sizeof dst7 - 1); + + CPY (dst7 + i, s, 6); + CPY (dst7 + i, s, 7); /* { dg-warning "specified bound 7 equals destination size" } */ + /* The following two calls are diagnosed by -Wstringop-overflow. */ + CPY (dst7 + i, s, 8); + CPY (dst7 + i, s, UR (8, 9)); + + /* No nul-termination here. */ + CPY (dst7 + 2, "12345", sizeof dst7 - 2); /* { dg-warning "output truncated before terminating nul copying 5 bytes from a string of the same length" } */ + + /* Because strnlen appends as many NULs as necessary to write the specified + number of byts the following doesn't (necessarily) truncate but rather + overflow, and so is diagnosed by -Wstringop-overflow. */ + CPY (dst7, s, 8); + + CPY (dst7 + 1, s, 6); /* { dg-warning "specified bound 6 equals destination size" } */ + CPY (dst7 + 6, s, 1); /* { dg-warning "specified bound 1 equals destination size" } */ + + CPY (pd->a5, s, 5); /* { dg-warning "specified bound 5 equals destination size" } */ + CPY (pd->a5, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" } */ + + /* The following is not yet handled. */ + CPY (pd->a5 + i, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" "member array" { xfail *-*-* } } */ + + /* Verify that a copy that nul-terminates is not diagnosed. */ + CPY (pd->a5, "1234", sizeof pd->a5); + + /* Same above, diagnosed by -Wstringop-overflow. */ + CPY (pd->a5, s, 6); + + /* Exercise destination with attribute "nonstring". */ + CPY (pd->c3ns, "", 3); + CPY (pd->c3ns, "", 1); + /* Truncation is still diagnosed -- using strncpy in this case is + pointless and should be replaced with memcpy. */ + CPY (pd->c3ns, "12", 1); /* { dg-warning "output truncated copying 1 byte from a string of length 2" } */ + CPY (pd->c3ns, "12", 2); + CPY (pd->c3ns, "12", 3); + CPY (pd->c3ns, "123", 3); + CPY (pd->c3ns, s, 3); + CPY (pd->c3ns, s, sizeof pd->c3ns); + + /* Verify that the idiom of calling strncpy with a bound equal to + the size of the destination (and thus potentially without NUL- + terminating it) immediately followed by setting the last element + of the array to NUL is not diagnosed. */ + { + /* This might be better written using memcpy() but it's safe so + it probably shouldn't be diagnosed. It currently triggers + a warning because of bug 81704. */ + strncpy (dst7, "0123456", sizeof dst7); /* { dg-bogus "truncated" "bug 81704" { xfail *-*-* } } */ + dst7[sizeof dst7 - 1] = '\0'; + sink (dst7); + } + + { + const char a[] = "0123456789"; + strncpy (dst7, a, sizeof dst7); + dst7[sizeof dst7 - 1] = '\0'; + sink (dst7); + } + + { + strncpy (dst7, s, sizeof dst7); + dst7[sizeof dst7 - 1] = '\0'; + sink (dst7); + } + + { + strncpy (pd->a5, "01234", sizeof pd->a5); /* { dg-bogus "truncated" "bug 81704" { xfail *-*-* } } */ + pd->a5[sizeof pd->a5 - 1] = '\0'; + sink (pd); + } + + { + strncpy (pd->a5, s, sizeof pd->a5); + pd->a5[sizeof pd->a5 - 1] = '\0'; + sink (pd); + } + + { + unsigned n = 7; + char *p = (char*)__builtin_malloc (n); + strncpy (p, s, n); + p[n - 1] = '\0'; + sink (p); + } + + { + /* This should be diagnosed because the NUL-termination doesn't + immediately follow the strncpy call (sink may expect pd->a5 + to be NUL-terminated). */ + strncpy (pd->a5, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" } */ + sink (pd); + pd->a5[sizeof pd->a5] = '\0'; + sink (pd); + } +} + +typedef struct Flex +{ + size_t n; + char a0[0]; + char ax[]; +} Flex; + +extern char array[]; + +/* Verify that no warning is issued for array of unknown bound, flexible + array members, or zero-length arrays, except when the source is definitely + truncated. */ + +void test_strncpy_flexarray (Flex *pf, const char* s) +{ +#undef CPY +#define CPY(d, s, len) (strncpy ((d), (s), (len)), sink (d)) + + CPY (array, "12345", 7); + CPY (array, "12345", 123); + + CPY (array, s, 7); + CPY (array, s, 123); + + CPY (pf->a0, s, 1); + CPY (pf->a0, s, 1234); + + CPY (pf->a0, "", 1); + CPY (pf->a0, "12345", 5); /* { dg-warning "output truncated before terminating nul copying 5 bytes from a string of the same length" } */ + CPY (pf->a0, "12345", 1234); + + CPY (pf->ax, s, 5); + CPY (pf->ax, s, 12345); + + CPY (pf->ax, "1234", 5); + CPY (pf->ax, "12345", 5); /* { dg-warning "output truncated before terminating nul copying 5 bytes from a string of the same length" } */ + CPY (pf->ax, "12345", 12345); +} + +/* Verify warnings for dynamically allocated objects. */ + +void test_strncpy_alloc (const char* s) +{ + size_t n = 7; + char *d = (char *)__builtin_malloc (n); + + CPY (d, s, n); /* { dg-warning "specified bound 7 equals destination size" "bug 79016" { xfail *-*-* } } */ + + Dest *pd = (Dest *)__builtin_malloc (sizeof *pd * n); + CPY (pd->a5, s, 5); /* { dg-warning "specified bound 5 equals destination size" } */ + CPY (pd->a5, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" } */ +} + +/* Verify warnings for VLAs. */ + +void test_strncpy_vla (unsigned n, const char* s) +{ + char vla[n]; + CPY (vla, s, 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + + CPY (vla, s, 1); + CPY (vla, s, 2); + CPY (vla, s, n); + + CPY (vla, "", 0); /* { dg-warning ".strncpy\[^\n\r\]* destination unchanged after copying no bytes" } */ + CPY (vla, "", 1); + CPY (vla, S4, 3); /* { dg-warning ".strncpy\[^\n\r\]* output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + CPY (vla, S4, n); +} diff --git a/gcc/testsuite/c-c++-common/attr-nonstring-1.c b/gcc/testsuite/c-c++-common/attr-nonstring-1.c new file mode 100644 index 0000000..10a6688 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-nonstring-1.c @@ -0,0 +1,60 @@ +/* Test to exercise attribute "nonstring" syntax. + { dg-do compile } + { dg-options "-Wattributes" } */ + +#define ATTR(list) __attribute__ (list) +#define NONSTR ATTR ((nonstring)) + +/* Verify it's accepted on char arrays. */ +extern NONSTR char nsx_1[]; +extern char NONSTR nsx_2[]; +extern char nsx_3[] NONSTR; + +extern NONSTR char ns1[1]; +extern char NONSTR ns3[3]; +extern char ns5[5] NONSTR; + +/* Verify it's accepted on char pointers. */ +extern NONSTR char* pns_1; +extern char NONSTR* pns_2; +extern char* NONSTR pns_3; + +struct S +{ +/* Verify it's accepted on char member pointers. */ + NONSTR char* mpns_1; + char NONSTR* mpns_2; + char* NONSTR mpns_3; + +/* Verify it's accepted on char member arrays. */ + NONSTR char mns1[1]; + char NONSTR mns3[3]; + char mns5[5] NONSTR; + +/* Verify it's accepted on char flexible array members. */ + char mnsx[] NONSTR; +}; + +/* Verify it's rejected on non-array and non-pointer objects. */ +extern NONSTR char c1; /* { dg-warning ".nonstring. attribute ignored on objects of type .char." } */ + +extern NONSTR int i1; /* { dg-warning ".nonstring. attribute ignored on objects of type .int." } */ + +extern NONSTR int ia1[]; /* { dg-warning ".nonstring. attribute ignored on objects of type .int *\\\[\\\]." } */ + +extern NONSTR int* pi1; /* { dg-warning ".nonstring. attribute ignored on objects of type .int *\\*." } */ + +extern NONSTR +void f (void); /* { dg-warning ".nonstring. attribute does not apply to functions" } */ + +struct NONSTR +NonStrType { int i; }; /* { dg-warning ".nonstring. attribute does not apply to types" } */ + +typedef char NONSTR nschar_t; /* { dg-warning ".nonstring. attribute does not apply to types" } */ + +void func (NONSTR char *pns1, char NONSTR *pns2, char* NONSTR pns3) +{ + (void)pns1; + (void)pns2; + (void)pns3; +} diff --git a/gcc/testsuite/c-c++-common/attr-nonstring-2.c b/gcc/testsuite/c-c++-common/attr-nonstring-2.c new file mode 100644 index 0000000..6e273e7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-nonstring-2.c @@ -0,0 +1,123 @@ +/* Test to exercise attribute "nonstring". + { dg-do compile } + { dg-options "-O2 -Wattributes -Wstringop-truncation -ftrack-macro-expansion=0" } */ + +#define ATTR(list) __attribute__ (list) +#define NONSTR ATTR ((nonstring)) +#define strncpy(d, s, n) (__builtin_strncpy ((d), (s), (n)), sink (d)) + +void sink (void*); + +/* Global string with an unknown bound. */ +extern char gsx[]; + +/* Global string with an known bound. */ +extern char gs3[3]; + +/* Global non-strings with an unknown bound. */ +extern NONSTR char gax_1[]; +extern char NONSTR gax_2[]; +extern char gax_3[] NONSTR; + +/* Global non-strings with a known bound. */ +NONSTR char gns3[3]; +char NONSTR gns4[4]; +char gns5[5] NONSTR; + +/* Global string pointer. */ +extern char *ps_1; + +/* Global non-string pointers. */ +extern NONSTR char *pns_1; +extern char* NONSTR pns_2; +extern char *pns_3 NONSTR; + +struct MemArrays +{ + NONSTR char ma3[3]; + char NONSTR ma4[4]; + char ma5[5] NONSTR; + char max[] NONSTR; +}; + + +void test_array (const char *s, unsigned n) +{ + const char s7[] = "1234567"; + + strncpy (gs3, "", 0); /* { dg-warning "destination unchanged after copying no bytes" } */ + strncpy (gs3, "a", 1); /* { dg-warning "output truncated before terminating nul copying 1 byte from a string of the same length" } */ + strncpy (gs3, "a", 2); + strncpy (gs3, "a", 3); + strncpy (gs3, "ab", 3); + strncpy (gs3, "abc", 3); /* { dg-warning "output truncated before terminating nul copying 3 bytes from a string of the same length" } */ + + /* It might perhaps be helpful to diagnose certain truncation even + for non-strings. Then again, since the destination has been + explicitly annotated as non-string, it might be viewed as a false + positive. A valid use case seen in Glibc goes something like this: + + #if FOO + # define S "1234" + #else + # define S "12345678" + #endif + + strncpy (d, S, 8); + */ + strncpy (gax_3, s7, 3); + + strncpy (gax_1, "a", 1); + strncpy (gax_2, "ab", 2); + strncpy (gax_3, "abc", 3); + strncpy (gax_3, s7, 3); + + strncpy (gax_1, s, 1); + strncpy (gax_2, s, 1); + strncpy (gax_3, s, 1); + + strncpy (gax_1, s, n); + strncpy (gax_2, s, n); + strncpy (gax_3, s, n); +} + + +void test_pointer (const char *s, unsigned n) +{ + const char s7[] = "1234567"; + + strncpy (pns_1, "a", 1); + strncpy (pns_2, "ab", 2); + strncpy (pns_3, "abc", 3); + strncpy (pns_3, s7, 3); /* { dg-warning "output truncated copying 3 bytes from a string of length 7" } */ + + strncpy (pns_1, s, 1); + strncpy (pns_2, s, 1); + strncpy (pns_3, s, 1); + + strncpy (pns_1, s, n); + strncpy (pns_2, s, n); + strncpy (pns_3, s, n); +} + + +void test_member_array (struct MemArrays *p, const char *s, unsigned n) +{ + const char s7[] = "1234567"; + + strncpy (p->ma3, "a", 1); + strncpy (p->ma4, "ab", 2); + strncpy (p->ma5, "abc", 3); + strncpy (p->max, "abcd", 4); + strncpy (p->max, s7, 5); + + strncpy (p->ma3, s, 1); + strncpy (p->ma4, s, 1); + strncpy (p->ma5, s, 1); + strncpy (p->max, s, 1); + + strncpy (p->ma3, s7, n); + strncpy (p->ma4, s7, n); + strncpy (p->ma5, s7, n); + strncpy (p->max, s7, n); +} diff --git a/gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C b/gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C index c72532b..5bc5c4c 100644 --- a/gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C +++ b/gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C @@ -1,6 +1,6 @@ // Test -Wsizeof-pointer-memaccess warnings. // { dg-do compile } -// { dg-options "-Wall -Wno-sizeof-array-argument -Wno-stringop-overflow" } +// { dg-options "-Wall -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-truncation" } // Test just twice, once with -O0 non-fortified, once with -O2 fortified. // { dg-skip-if "" { *-*-* } { "*" } { "-O0" "-O2" } } // { dg-skip-if "" { *-*-* } { "-flto" } { "" } } @@ -698,12 +698,17 @@ f4 (char *x, char **y, int z, char w[64]) strncat (w, s2, sizeof (w)); // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } stpncpy (w, s1, sizeof (w)); // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } - // These are correct, no warning. const char s3[] = "foobarbaz"; const char s4[] = "abcde12345678"; - strncpy (x, s3, sizeof (s3)); - strncat (x, s4, sizeof (s4)); - stpncpy (x, s3, sizeof (s3)); + + // These are pointless when the destination is large enough, and + // cause overflow otherwise. They might as well be replaced by + // strcpy() or memcpy(). + strncpy (x, s3, sizeof (s3)); // { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } + strncat (x, s4, sizeof (s4)); // { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } + stpncpy (x, s3, sizeof (s3)); // { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } + + // These are safe, no warning. y[1] = strndup (s3, sizeof (s3)); z += strncmp (s3, s4, sizeof (s3)); z += strncmp (s3, s4, sizeof (s4)); diff --git a/gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C b/gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C index a216f47..f2c864b 100644 --- a/gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C +++ b/gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C @@ -1,6 +1,6 @@ // Test -Wsizeof-pointer-memaccess warnings. // { dg-do compile } -// { dg-options "-Wall -Wno-sizeof-array-argument -Wno-stringop-overflow" } +// { dg-options "-Wall -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-truncation" } // Test just twice, once with -O0 non-fortified, once with -O2 fortified, // suppressing buffer overflow warnings. // { dg-skip-if "" { *-*-* } { "*" } { "-O0" "-O2" } } @@ -703,12 +703,13 @@ f4 (char *x, char **y, int z, char w[64]) strncat (w, s2, sizeof (w)); // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } stpncpy (w, s1, sizeof (w)); // { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } - // These are correct, no warning. const char s3[] = "foobarbaz"; const char s4[] = "abcde12345678"; - strncpy (x, s3, sizeof (s3)); - strncat (x, s4, sizeof (s4)); - stpncpy (x, s3, sizeof (s3)); + strncpy (x, s3, sizeof (s3)); // { dg-warning "call is the same expression as the source; did you mean to use the size of the destination" } + strncat (x, s4, sizeof (s4)); // { dg-warning "call is the same expression as the source; did you mean to use the size of the destination" } + stpncpy (x, s3, sizeof (s3)); // { dg-warning "call is the same expression as the source; did you mean to use the size of the destination" } + + // These are safe, no warning. y[1] = strndup (s3, sizeof (s3)); z += strncmp (s3, s4, sizeof (s3)); z += strncmp (s3, s4, sizeof (s4)); diff --git a/gcc/testsuite/gcc.dg/Walloca-1.c b/gcc/testsuite/gcc.dg/Walloca-1.c index ad39373..85e9160 100644 --- a/gcc/testsuite/gcc.dg/Walloca-1.c +++ b/gcc/testsuite/gcc.dg/Walloca-1.c @@ -1,6 +1,6 @@ /* { dg-do compile } */ /* { dg-require-effective-target alloca } */ -/* { dg-options "-Walloca-larger-than=2000 -O2" } */ +/* { dg-options "-Walloca-larger-than=2000 -O2 -ftrack-macro-expansion=0" } */ #define alloca __builtin_alloca diff --git a/gcc/testsuite/gcc.dg/builtin-stpncpy.c b/gcc/testsuite/gcc.dg/builtin-stpncpy.c index e4290d5..9200798 100644 --- a/gcc/testsuite/gcc.dg/builtin-stpncpy.c +++ b/gcc/testsuite/gcc.dg/builtin-stpncpy.c @@ -1,6 +1,6 @@ /* PR tree-optimization/80669 - Bad -Wstringop-overflow warnings for stpncpy { dg-do compile } - { dg-options "-O2 -Wall" } */ + { dg-options "-O2 -Wall -Wno-stringop-truncation" } */ #define SIZE_MAX __SIZE_MAX__ @@ -18,7 +18,9 @@ size_t range (size_t min, size_t max) return val < min || max < val ? min : val; } -/* Verify that no warning is issued for stpncpy with constant size. */ +/* Verify that no -Wstringop-overflow warning is issued for stpncpy + with constant size. (Some tests cause -Wstringop-truncation and + that's expected). */ void test_cst (char *d) { __builtin_stpncpy (d, "123", 0); @@ -37,7 +39,8 @@ void test_cst (char *d) } -/* Verify that no warning is issued for stpncpy with size in some range. */ +/* Verify that no -Wstringop-overflow warning is issued for stpncpy + with size in some range. */ void test_rng (char *d) { #define R(min, max) range (min, max) diff --git a/gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c b/gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c index f9bc57c..cd9dc72 100644 --- a/gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c +++ b/gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c @@ -1,6 +1,6 @@ /* Test -Wsizeof-pointer-memaccess warnings. */ /* { dg-do compile } */ -/* { dg-options "-Wall -Wno-sizeof-array-argument -Wno-stringop-overflow" } */ +/* { dg-options "-Wall -Wno-sizeof-array-argument -Wno-stringop-overflow -Wno-stringop-truncation" } */ /* Test just twice, once with -O0 non-fortified, once with -O2 fortified. */ /* { dg-skip-if "" { *-*-* } { "*" } { "-O0" "-O2" } } */ /* { dg-skip-if "" { *-*-* } { "-flto" } { "" } } */ @@ -704,12 +704,17 @@ f4 (char *x, char **y, int z, char w[64]) strncat (w, s2, sizeof (w)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ stpncpy (w, s1, sizeof (w)); /* { dg-warning "call is the same expression as the destination; did you mean to provide an explicit length" } */ - /* These are correct, no warning. */ + /* These are pointless when the destination is large enough, and + cause overflow otherwise. If the copies are guaranteed to be + safe the calls might as well be replaced by strcat(), strcpy(), + or memcpy(). */ const char s3[] = "foobarbaz"; const char s4[] = "abcde12345678"; - strncpy (x, s3, sizeof (s3)); - strncat (x, s4, sizeof (s4)); - stpncpy (x, s3, sizeof (s3)); + strncpy (x, s3, sizeof (s3)); /* { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } */ + strncat (x, s4, sizeof (s4)); /* { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } */ + stpncpy (x, s3, sizeof (s3)); /* { dg-warning "call is the same expression as the source; did you mean to use the size of the destination?" } */ + + /* These are correct, no warning. */ y[1] = strndup (s3, sizeof (s3)); z += strncmp (s3, s4, sizeof (s3)); z += strncmp (s3, s4, sizeof (s4)); diff --git a/gcc/testsuite/gcc.dg/torture/pr63554.c b/gcc/testsuite/gcc.dg/torture/pr63554.c index fa06c5a..9162266 100644 --- a/gcc/testsuite/gcc.dg/torture/pr63554.c +++ b/gcc/testsuite/gcc.dg/torture/pr63554.c @@ -1,4 +1,5 @@ -/* { dg-do compile } */ +/* PR c/63554 - ice in "execute_todo, at passes.c:1797" with -O3 + { dg-do compile } */ char *a; void @@ -7,3 +8,5 @@ nssutil_ReadSecmodDB (void) long b = __builtin_object_size (0, 0); a = __builtin___strncat_chk (a, " ", 1, b); } + +/* { dg-prune-output "\\\[-Wstringop-overflow=]" } */ |