analyzer: fix uninit false positive with -ftrivial-auto-var-init= [PR106204]
authorDavid Malcolm <dmalcolm@redhat.com>
Wed, 6 Jul 2022 11:27:45 +0000 (07:27 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Wed, 6 Jul 2022 11:27:45 +0000 (07:27 -0400)
-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>
gcc/analyzer/region-model.cc
gcc/testsuite/gcc.dg/analyzer/torture/uninit-pr106204.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/uninit-pr106204.c [new file with mode: 0644]

index 5d93932..8b7b4e1 100644 (file)
@@ -896,17 +896,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;
@@ -959,6 +951,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.  */
@@ -982,10 +1015,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 (file)
index 0000000..25edcf5
--- /dev/null
@@ -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 (file)
index 0000000..7d7cf7b
--- /dev/null
@@ -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;
+}