analyzer: fix false NULL deref warning after previous deref [PR96792]
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 27 Aug 2020 11:42:27 +0000 (07:42 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Tue, 1 Sep 2020 14:56:34 +0000 (10:56 -0400)
gcc/analyzer/ChangeLog:
PR analyzer/96792
* region-model.cc (region_model::deref_rvalue): Add the constraint
that PTR_SVAL is non-NULL.

gcc/testsuite/ChangeLog:
PR analyzer/96792
* gcc.dg/analyzer/pr96792.c: New test.

gcc/analyzer/region-model.cc
gcc/testsuite/gcc.dg/analyzer/pr96792.c [new file with mode: 0644]

index d47e8960296b3742c61c7f58fb90365351cd80ed..a7bc48115eec7b6a57d91a32a6ac0a1f43eec6ef 100644 (file)
@@ -1398,6 +1398,15 @@ region_model::deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
 {
   gcc_assert (ptr_sval);
 
+  /* If we're dereferencing PTR_SVAL, assume that it is non-NULL; add this
+     as a constraint.  This suppresses false positives from
+     -Wanalyzer-null-dereference for the case where we later have an
+     if (PTR_SVAL) that would occur if we considered the false branch
+     and transitioned the malloc state machine from start->null.  */
+  tree null_ptr_cst = build_int_cst (ptr_sval->get_type (), 0);
+  const svalue *null_ptr = m_mgr->get_or_create_constant_svalue (null_ptr_cst);
+  m_constraints->add_constraint (ptr_sval, NE_EXPR, null_ptr);
+
   switch (ptr_sval->get_kind ())
     {
     default:
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96792.c b/gcc/testsuite/gcc.dg/analyzer/pr96792.c
new file mode 100644 (file)
index 0000000..7757645
--- /dev/null
@@ -0,0 +1,39 @@
+#define NULL (void *)0
+
+struct block
+{
+  void *function;
+  const struct block *superblock;
+};
+
+struct global_block
+{
+  struct block block;
+  void *compunit_symtab;
+};
+
+extern const struct block *block_global_block (const struct block *block);
+
+void *
+block_objfile (const struct block *block)
+{
+  const struct global_block *global_block;
+
+  if (block->function != NULL)
+    return block->function;
+
+  global_block = (struct global_block *) block_global_block (block);
+  return global_block->compunit_symtab;
+}
+
+const struct block *
+block_global_block (const struct block *block)
+{
+  if (block == NULL)
+    return NULL;
+
+  while (block->superblock != NULL)
+    block = block->superblock;
+
+  return block;
+}