aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2021-07-27 16:02:54 -0600
committerMartin Sebor <msebor@redhat.com>2021-07-27 16:02:54 -0600
commit6aacd901b800ee8a2a03123669b299a08aad0504 (patch)
tree92b704e894cabafe841d622922d28b8ad2dfa540 /gcc
parent9360d6cd1706882dfffd3c7a08b5956c37207a11 (diff)
downloadgcc-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.c39
-rw-r--r--gcc/testsuite/gcc.dg/uninit-41.c121
-rw-r--r--gcc/tree-ssa-uninit.c67
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;