diff options
author | David Malcolm <dmalcolm@redhat.com> | 2020-10-07 18:34:09 -0400 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2020-10-12 12:03:07 -0400 |
commit | 3175d40fc52fb8eb3c3b18cc343d773da24434fb (patch) | |
tree | d1c8e7c2e09a91ed75f0e5476c648c2e745aa2de /gcc/testsuite/gcc.dg | |
parent | 1be51a3a9ac3409561223c8058d4943f9b574d15 (diff) | |
download | gcc-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.c | 29 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/write-to-string-literal-1.c | 58 |
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. */ +} |