aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2017-11-10 16:35:26 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2017-11-10 09:35:26 -0700
commit025d57f037ad13eb479818b677ef4be4d97b639c (patch)
tree28c279950fb42d8f67b86b9a2193b3acc6a669f2 /gcc/testsuite
parente89ce41dbab07a9acafd900a3ab57eeb5d499276 (diff)
downloadgcc-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/ChangeLog14
-rw-r--r--gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess2.c15
-rw-r--r--gcc/testsuite/c-c++-common/Wsizeof-pointer-memaccess3.c132
-rw-r--r--gcc/testsuite/c-c++-common/Wstringop-overflow.c158
-rw-r--r--gcc/testsuite/c-c++-common/Wstringop-truncation.c448
-rw-r--r--gcc/testsuite/c-c++-common/attr-nonstring-1.c60
-rw-r--r--gcc/testsuite/c-c++-common/attr-nonstring-2.c123
-rw-r--r--gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess1.C15
-rw-r--r--gcc/testsuite/g++.dg/torture/Wsizeof-pointer-memaccess2.C11
-rw-r--r--gcc/testsuite/gcc.dg/Walloca-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/builtin-stpncpy.c9
-rw-r--r--gcc/testsuite/gcc.dg/torture/Wsizeof-pointer-memaccess1.c15
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr63554.c5
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=]" } */