summaryrefslogtreecommitdiff
path: root/gcc/testsuite/c-c++-common/Wstringop-overflow.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/testsuite/c-c++-common/Wstringop-overflow.c')
-rw-r--r--gcc/testsuite/c-c++-common/Wstringop-overflow.c158
1 files changed, 158 insertions, 0 deletions
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 00000000000..53f5166f30a
--- /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" } */
+ }
+}