diff options
author | Martin Sebor <msebor@redhat.com> | 2021-07-27 16:02:54 -0600 |
---|---|---|
committer | Martin Sebor <msebor@redhat.com> | 2021-07-27 16:02:54 -0600 |
commit | 6aacd901b800ee8a2a03123669b299a08aad0504 (patch) | |
tree | 92b704e894cabafe841d622922d28b8ad2dfa540 /gcc | |
parent | 9360d6cd1706882dfffd3c7a08b5956c37207a11 (diff) | |
download | gcc-6aacd901b800ee8a2a03123669b299a08aad0504.zip gcc-6aacd901b800ee8a2a03123669b299a08aad0504.tar.gz gcc-6aacd901b800ee8a2a03123669b299a08aad0504.tar.bz2 |
Let -Wuninitialized assume built-ins don't change const arguments [PR101584].
PR tree-optimization/101584 - missing -Wuninitialized with an allocated object after a built-in call
gcc/ChangeLog:
PR tree-optimization/101584
* tree-ssa-uninit.c (builtin_call_nomodifying_p): New function.
(check_defs): Call it.
gcc/testsuite/ChangeLog:
PR tree-optimization/101584
* gcc.dg/uninit-38.c: Remove assertions.
* gcc.dg/uninit-41.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/testsuite/gcc.dg/uninit-38.c | 39 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/uninit-41.c | 121 | ||||
-rw-r--r-- | gcc/tree-ssa-uninit.c | 67 |
3 files changed, 190 insertions, 37 deletions
diff --git a/gcc/testsuite/gcc.dg/uninit-38.c b/gcc/testsuite/gcc.dg/uninit-38.c index 8dacc8c..0d70bcd 100644 --- a/gcc/testsuite/gcc.dg/uninit-38.c +++ b/gcc/testsuite/gcc.dg/uninit-38.c @@ -1,5 +1,5 @@ -/* Verify that dereferencing uninitialized allocated objects and VLAs - correctly reflects offsets into the objects. +/* Verify that dereferencing uninitialized VLAs correctly reflects + offsets into the objects. The test's main purpose is to exercise the formatting of MEM_REFs. If -Wuninitialized gets smarter and detects uninitialized accesses before they're turned into MEM_REFs the test will likely need to @@ -18,41 +18,6 @@ extern void* malloc (size_t); void sink (void*, ...); -#undef T -#define T(Type, idx, off) \ - __attribute__ ((noipa)) \ - void UNIQ (test_)(int n) \ - { \ - void *p = malloc (n); \ - Type *q = (Type*)((char*)p + off); \ - sink (p, q[idx]); \ - } \ - typedef void dummy_type - -T (int, 0, 0); // { dg-warning "'\\*\\(int \\*\\)p' is used uninitialized" } -T (int, 0, 1); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)'" } -T (int, 0, 2); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)p \\+ 2\\)'" } -T (int, 0, 3); // { dg-warning "'\\*\\(int \\*\\)\\(\\(char \\*\\)p \\+ 3\\)'" } -T (int, 0, 4); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[1]'" } -T (int, 0, 5); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[1]'" } -T (int, 0, 6); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 2\\)\\)\\\[1]'" } -T (int, 0, 7); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 3\\)\\)\\\[1]'" } -T (int, 0, 8); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[2]'" } -T (int, 0, 9); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[2]'" } - - -T (int, 1, 0); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[1]' is used uninitialized" } -T (int, 1, 1); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[1]'" } -T (int, 1, 2); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 2\\)\\)\\\[1]'" } -T (int, 1, 3); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 3\\)\\)\\\[1]'" } -T (int, 1, 4); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[2]'" } -T (int, 1, 5); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[2]'" } -T (int, 1, 6); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 2\\)\\)\\\[2]'" } -T (int, 1, 7); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 3\\)\\)\\\[2]'" } -T (int, 1, 8); // { dg-warning "'\\(\\(int \\*\\)p\\)\\\[3]'" } -T (int, 1, 9); // { dg-warning "'\\(\\(int \\*\\)\\(\\(char \\*\\)p \\+ 1\\)\\)\\\[3]'" } - -#undef T #define T(Type, idx, off) \ __attribute__ ((noipa)) \ void UNIQ (test_)(int n) \ diff --git a/gcc/testsuite/gcc.dg/uninit-41.c b/gcc/testsuite/gcc.dg/uninit-41.c new file mode 100644 index 0000000..b485611 --- /dev/null +++ b/gcc/testsuite/gcc.dg/uninit-41.c @@ -0,0 +1,121 @@ +/* Verify that calls to non-modifying built-ins aren't considered + potentially modifying. + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +void* alloca (size_t); +void* calloc (size_t, size_t); +void* malloc (size_t); +int printf (const char *, ...); +int scanf (const char *, ...); +int sprintf (char *, const char *, ...); +int snprintf (char *, size_t, const char *, ...); +int puts (const char *); +char* strcpy (char*, const char*); +size_t strlen (const char*); + +void noproto (); + +void sink (int, ...); + +extern char a[]; + +void nowarn_noproto (const char *fmt) +{ + int i; + noproto (&i); + sink (i); +} + +void nowarn_scanf (const char *fmt) +{ + int i; + scanf ("%i", &i); + sink (i); +} + +void test_puts_sprintf_alloca (const char *fmt) +{ + char *p; + { + p = alloca (8); + sprintf (a, fmt, p); // fmt might contain %n + puts (p); + } + + { + p = alloca (8); + snprintf (0, 0, fmt, p); // same as above + puts (p); + } +} + +void test_puts_alloca (const char *s) +{ + char *p = alloca (8); + + { + char a[] = "foo"; + puts (a); + } + + puts (p); // { dg-warning "-Wuninitialized" } + + { + p = alloca (strlen (s) + 1); + strcpy (p, s); + puts (p); + } + + { + /* Verify that the puts() calls above isn't considered to have + potentially modified *P, and same for the one below. */ + p = alloca (strlen (s)); + puts (p); // { dg-warning "-Wuninitialized" } + puts (p + 1); // { dg-warning "-Wuninitialized" } + } +} + + +void test_puts_malloc (const char *s, const char *t) +{ + char *p; + + { + p = malloc (strlen (s) + 1); + strcpy (p, s); + puts (p); + } + + { + p = malloc (strlen (t)); + puts (p); // { dg-warning "-Wuninitialized" } + } +} + + +void test_puts_vla (const char *s, const char *t) +{ + { + char a[strlen (s) + 1]; + strcpy (a, s); + puts (a); + } + + { + char b[strlen (t)]; + puts (b); // { dg-warning "-Wuninitialized" } + } +} + + +void test_printf_puts (const char *s) +{ + char *p = __builtin_malloc (1); + + printf ("%s", s); + + puts (p); // { dg-warning "-Wuninitialized" } +} diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c index 718b326..ab64a68 100644 --- a/gcc/tree-ssa-uninit.c +++ b/gcc/tree-ssa-uninit.c @@ -219,6 +219,70 @@ struct check_defs_data bool found_may_defs; }; +/* Return true if STMT is a call to built-in function all of whose + by-reference arguments are const-qualified (i.e., the function can + be assumed not to modify them). */ + +static bool +builtin_call_nomodifying_p (gimple *stmt) +{ + if (!gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) + return false; + + tree fndecl = gimple_call_fndecl (stmt); + if (!fndecl) + return false; + + tree fntype = TREE_TYPE (fndecl); + if (!fntype) + return false; + + /* Check the called function's signature for non-constc pointers. + If one is found, return false. */ + unsigned argno = 0; + tree argtype; + function_args_iterator it; + FOREACH_FUNCTION_ARGS (fntype, argtype, it) + { + if (VOID_TYPE_P (argtype)) + return true; + + ++argno; + + if (!POINTER_TYPE_P (argtype)) + continue; + + if (TYPE_READONLY (TREE_TYPE (argtype))) + continue; + + return false; + } + + /* If the number of actual arguments to the call is less than or + equal to the number of parameters, return false. */ + unsigned nargs = gimple_call_num_args (stmt); + if (nargs <= argno) + return false; + + /* Check arguments passed through the ellipsis in calls to variadic + functions for pointers. If one is found that's a non-constant + pointer, return false. */ + for (; argno < nargs; ++argno) + { + tree arg = gimple_call_arg (stmt, argno); + argtype = TREE_TYPE (arg); + if (!POINTER_TYPE_P (argtype)) + continue; + + if (TYPE_READONLY (TREE_TYPE (argtype))) + continue; + + return false; + } + + return true; +} + /* Callback for walk_aliased_vdefs. */ static bool @@ -261,6 +325,9 @@ check_defs (ao_ref *ref, tree vdef, void *data_) return false; } + if (builtin_call_nomodifying_p (def_stmt)) + return false; + /* Found a may-def on this path. */ data->found_may_defs = true; return true; |