aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gcc.dg
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2020-10-07 18:34:09 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2020-10-12 12:03:07 -0400
commit3175d40fc52fb8eb3c3b18cc343d773da24434fb (patch)
treed1c8e7c2e09a91ed75f0e5476c648c2e745aa2de /gcc/testsuite/gcc.dg
parent1be51a3a9ac3409561223c8058d4943f9b574d15 (diff)
downloadgcc-3175d40fc52fb8eb3c3b18cc343d773da24434fb.zip
gcc-3175d40fc52fb8eb3c3b18cc343d773da24434fb.tar.gz
gcc-3175d40fc52fb8eb3c3b18cc343d773da24434fb.tar.bz2
analyzer: add warnings about writes to constant regions [PR95007]
This patch adds two new warnings: -Wanalyzer-write-to-const -Wanalyzer-write-to-string-literal for code paths where the analyzer detects a write to a constant region. As noted in the documentation part of the patch, the analyzer doesn't prioritize detection of such writes, in that the state-merging logic will blithely lose the distinction between const and non-const regions. Hence false negatives are likely to arise due to state-merging. However, if the analyzer does happen to spot such a write, it seems worth reporting, hence this patch. gcc/analyzer/ChangeLog: * analyzer.opt (Wanalyzer-write-to-const): New. (Wanalyzer-write-to-string-literal): New. * region-model-impl-calls.cc (region_model::impl_call_memcpy): Call check_for_writable_region. (region_model::impl_call_memset): Likewise. (region_model::impl_call_strcpy): Likewise. * region-model.cc (class write_to_const_diagnostic): New. (class write_to_string_literal_diagnostic): New. (region_model::check_for_writable_region): New. (region_model::set_value): Call check_for_writable_region. * region-model.h (region_model::check_for_writable_region): New decl. gcc/ChangeLog: * doc/invoke.texi: Document -Wanalyzer-write-to-const and -Wanalyzer-write-to-string-literal. gcc/testsuite/ChangeLog: PR c/83347 PR middle-end/90404 PR analyzer/95007 * gcc.dg/analyzer/write-to-const-1.c: New test. * gcc.dg/analyzer/write-to-string-literal-1.c: New test.
Diffstat (limited to 'gcc/testsuite/gcc.dg')
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/write-to-const-1.c29
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-1.c58
2 files changed, 87 insertions, 0 deletions
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-const-1.c b/gcc/testsuite/gcc.dg/analyzer/write-to-const-1.c
new file mode 100644
index 0000000..dc724e2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-const-1.c
@@ -0,0 +1,29 @@
+/* PR middle-end/90404 */
+
+const int c1 = 20; /* { dg-message "declared here" } */
+int test_1 (void)
+{
+ *((int*) &c1) = 10; /* { dg-warning "write to 'const' object 'c1'" } */
+ return c1;
+}
+
+/* Example of writing to a subregion (an element within a const array). */
+
+const int c2[10]; /* { dg-message "declared here" } */
+int test_2 (void)
+{
+ ((int*) &c2)[5] = 10; /* { dg-warning "write to 'const' object 'c2'" } */
+ return c2[5];
+}
+
+const char s3[] = "012.45"; /* { dg-message "declared here" } */
+int test_3 (void)
+{
+ char *p = __builtin_strchr (s3, '.');
+ *p = 0; /* { dg-warning "write to 'const' object 's3'" } */
+
+ if (__builtin_strlen (p) != 3)
+ __builtin_abort ();
+
+ return s3[3] == 0;
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-1.c b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-1.c
new file mode 100644
index 0000000..092500e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-1.c
@@ -0,0 +1,58 @@
+#include <string.h>
+
+/* PR analyzer/95007. */
+
+void test_1 (void)
+{
+ char *s = "foo";
+ s[0] = 'g'; /* { dg-warning "write to string literal" } */
+}
+
+/* PR c/83347. */
+
+void test_2 (void)
+{
+ memcpy ("abc", "def", 3); /* { dg-warning "write to string literal" } */
+}
+
+static char * __attribute__((noinline))
+called_by_test_3 (void)
+{
+ return (char *)"foo";
+}
+
+void test_3 (void)
+{
+ char *s = called_by_test_3 ();
+ s[1] = 'a'; /* { dg-warning "write to string literal" } */
+}
+
+static char * __attribute__((noinline))
+called_by_test_4 (int flag)
+{
+ if (flag)
+ return (char *)"foo";
+ else
+ return (char *)"bar";
+}
+
+void test_4 (void)
+{
+ char *s = called_by_test_4 (0);
+ s[1] = 'z'; /* { dg-warning "write to string literal" } */
+}
+
+static char * __attribute__((noinline))
+called_by_test_5 (int flag)
+{
+ if (flag)
+ return (char *)"foo";
+ else
+ return (char *)"bar";
+}
+
+void test_5 (int flag)
+{
+ char *s = called_by_test_5 (flag);
+ s[1] = 'z'; /* We miss this one, unless we disable state merging. */
+}