summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2022-07-27 17:38:55 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2022-07-27 17:54:37 -0400
commit09cb9c88ef8e2c0c89ada9cde2caf1a960db7a77 (patch)
tree78ec5491cb0c1e9e213fbfcf1f09ef1833cc1446
parent9fa11419ef59fde9d00ea8458235baa2bc83cd7a (diff)
analyzer: fix uninit false positive with -ftrivial-auto-var-init= [PR106204]
(cherry picked from r13-1517-gb33dd7874523af) -fanalyzer handles -ftrivial-auto-var-init= by special-casing IFN_DEFERRED_INIT to be a no-op, so that e.g.: len_2 = .DEFERRED_INIT (4, 2, &"len"[0]); is treated as a no-op, so that len_2 is still uninitialized after the stmt. PR analyzer/106204 reports that -fanalyzer gives false positives from -Wanalyzer-use-of-uninitialized-value on locals that have their address taken, due to e.g.: _1 = .DEFERRED_INIT (4, 2, &"len"[0]); len = _1; where -fanalyzer leaves _1 uninitialized, and then complains about the assignment to "len". Fixed thusly by suppressing the warning when assigning from such SSA names. gcc/analyzer/ChangeLog: PR analyzer/106204 * region-model.cc (within_short_circuited_stmt_p): Move extraction of assign_stmt to caller. (due_to_ifn_deferred_init_p): New. (region_model::check_for_poison): Move extraction of assign_stmt from within_short_circuited_stmt_p to here. Share logic with call to due_to_ifn_deferred_init_p. gcc/testsuite/ChangeLog: PR analyzer/106204 * gcc.dg/analyzer/torture/uninit-pr106204.c: New test. * gcc.dg/analyzer/uninit-pr106204.c: New test. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
-rw-r--r--gcc/analyzer/region-model.cc69
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/torture/uninit-pr106204.c13
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/uninit-pr106204.c17
3 files changed, 86 insertions, 13 deletions
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 816b4100f3a..23837a17346 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -895,17 +895,9 @@ region_model::get_gassign_result (const gassign *assign,
static bool
within_short_circuited_stmt_p (const region_model *model,
- region_model_context *ctxt)
+ const gassign *assign_stmt)
{
- gcc_assert (ctxt);
- const gimple *curr_stmt = ctxt->get_stmt ();
- if (curr_stmt == NULL)
- return false;
-
/* We must have an assignment to a temporary of _Bool type. */
- const gassign *assign_stmt = dyn_cast <const gassign *> (curr_stmt);
- if (!assign_stmt)
- return false;
tree lhs = gimple_assign_lhs (assign_stmt);
if (TREE_TYPE (lhs) != boolean_type_node)
return false;
@@ -958,6 +950,47 @@ within_short_circuited_stmt_p (const region_model *model,
return true;
}
+/* Workaround for discarding certain false positives from
+ -Wanalyzer-use-of-uninitialized-value
+ seen with -ftrivial-auto-var-init=.
+
+ -ftrivial-auto-var-init= will generate calls to IFN_DEFERRED_INIT.
+
+ If the address of the var is taken, gimplification will give us
+ something like:
+
+ _1 = .DEFERRED_INIT (4, 2, &"len"[0]);
+ len = _1;
+
+ The result of DEFERRED_INIT will be an uninit value; we don't
+ want to emit a false positive for "len = _1;"
+
+ Return true if ASSIGN_STMT is such a stmt. */
+
+static bool
+due_to_ifn_deferred_init_p (const gassign *assign_stmt)
+
+{
+ /* We must have an assignment to a decl from an SSA name that's the
+ result of a IFN_DEFERRED_INIT call. */
+ if (gimple_assign_rhs_code (assign_stmt) != SSA_NAME)
+ return false;
+ tree lhs = gimple_assign_lhs (assign_stmt);
+ if (TREE_CODE (lhs) != VAR_DECL)
+ return false;
+ tree rhs = gimple_assign_rhs1 (assign_stmt);
+ if (TREE_CODE (rhs) != SSA_NAME)
+ return false;
+ const gimple *def_stmt = SSA_NAME_DEF_STMT (rhs);
+ const gcall *call = dyn_cast <const gcall *> (def_stmt);
+ if (!call)
+ return false;
+ if (gimple_call_internal_p (call)
+ && gimple_call_internal_fn (call) == IFN_DEFERRED_INIT)
+ return true;
+ return false;
+}
+
/* Check for SVAL being poisoned, adding a warning to CTXT.
Return SVAL, or, if a warning is added, another value, to avoid
repeatedly complaining about the same poisoned value in followup code. */
@@ -981,10 +1014,20 @@ region_model::check_for_poison (const svalue *sval,
&& is_empty_type (sval->get_type ()))
return sval;
- /* Special case to avoid certain false positives. */
- if (pkind == POISON_KIND_UNINIT
- && within_short_circuited_stmt_p (this, ctxt))
- return sval;
+ if (pkind == POISON_KIND_UNINIT)
+ if (const gimple *curr_stmt = ctxt->get_stmt ())
+ if (const gassign *assign_stmt
+ = dyn_cast <const gassign *> (curr_stmt))
+ {
+ /* Special case to avoid certain false positives. */
+ if (within_short_circuited_stmt_p (this, assign_stmt))
+ return sval;
+
+ /* Special case to avoid false positive on
+ -ftrivial-auto-var-init=. */
+ if (due_to_ifn_deferred_init_p (assign_stmt))
+ return sval;
+ }
/* If we have an SSA name for a temporary, we don't want to print
'<unknown>'.
diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/uninit-pr106204.c b/gcc/testsuite/gcc.dg/analyzer/torture/uninit-pr106204.c
new file mode 100644
index 00000000000..25edcf5eecc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/torture/uninit-pr106204.c
@@ -0,0 +1,13 @@
+/* { dg-additional-options "-ftrivial-auto-var-init=zero" } */
+
+int foo(unsigned *len);
+int test_1()
+{
+ unsigned len; /* { dg-bogus "uninit" } */
+ int rc;
+
+ rc = foo(&len);
+ if (!rc)
+ rc = len;
+ return rc;
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/uninit-pr106204.c b/gcc/testsuite/gcc.dg/analyzer/uninit-pr106204.c
new file mode 100644
index 00000000000..7d7cf7bfc7e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/uninit-pr106204.c
@@ -0,0 +1,17 @@
+/* { dg-additional-options "-ftrivial-auto-var-init=zero" } */
+
+int foo(unsigned *len);
+
+/* Modified version of reproducer that does use "len" before init. */
+
+int test_2()
+{
+ unsigned len;
+ int rc;
+
+ rc = len; /* { dg-warning "use of uninitialized value 'len'" } */
+ rc = foo(&len);
+ if (!rc)
+ rc = len;
+ return rc;
+}