PR analyzer/93947 reports an ICE at -O1 when attempting to analyze a
call that has been optimized away as unreachable.

The root cause is a NULL dereference due to the fndecl having a NULL
cgraph_node: the cgraph_node was created by
pass_build_cgraph_edges::execute, but was later removed by
symbol_table::remove_unreachable_nodes before the analyzer pass.

This patch fixes it by checking for NULL before handling the
cgraph_node.

The reproducer demonstrates a weakness in the analyzer's constraint
handling, where region_model::apply_constraints_for_gswitch fails
to spot when the cases fully cover the data type, and thus make the
default impossible.  For now this is xfail-ed in the testcase.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to master as r10-6879-g0ba70d1b5ae8df6406a880b2d23e4710b393e8c9.

gcc/analyzer/ChangeLog:
        PR analyzer/93947
        * region-model.cc (region_model::get_fndecl_for_call): Gracefully
        fail for fn_decls that don't have a cgraph_node.

gcc/testsuite/ChangeLog:
        PR analyzer/93947
        * gcc.dg/analyzer/torture/pr93947.c: New test.
---
 gcc/analyzer/region-model.cc                  |  6 ++-
 .../gcc.dg/analyzer/torture/pr93947.c         | 40 +++++++++++++++++++
 2 files changed, 44 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/torture/pr93947.c

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index a71884d7b11..b2179bd220a 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -6732,8 +6732,10 @@ region_model::get_fndecl_for_call (const gcall *call,
          tree fn_decl = code->get_tree_for_child_region (fn_rid);
          if (!fn_decl)
            return NULL_TREE;
-         const cgraph_node *ultimate_node
-           = cgraph_node::get (fn_decl)->ultimate_alias_target ();
+         cgraph_node *node = cgraph_node::get (fn_decl);
+         if (!node)
+           return NULL_TREE;
+         const cgraph_node *ultimate_node = node->ultimate_alias_target ();
          if (ultimate_node)
            return ultimate_node->decl;
        }
diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/pr93947.c 
b/gcc/testsuite/gcc.dg/analyzer/torture/pr93947.c
new file mode 100644
index 00000000000..73982ef4bd3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/torture/pr93947.c
@@ -0,0 +1,40 @@
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */
+
+#include "../analyzer-decls.h"
+
+struct pf {
+  unsigned int iu : 2;
+};
+
+enum {
+  qr, jv, vm, mz,
+};
+
+int uh;
+
+void
+w9 (struct pf *x2)
+{
+  /* We ought to know the following based on the bitfield width.  */
+  __analyzer_eval (x2->iu >= 0 ); /* { dg-warning "TRUE" } */
+  __analyzer_eval (x2->iu < 4 ); /* { dg-warning "TRUE" } */
+
+  switch (x2->iu)
+    {
+    case qr:
+    case jv:
+    case vm:
+      uh = 0;
+      break;
+
+    case mz:
+      break;
+
+    default:
+      /* We ought to know from the enum values that this code is unreachable,
+        and thus not print anything.
+        TODO(xfail): currently this doesn't work.  */
+      __analyzer_eval (x2->iu); /* { dg-bogus "" "" { xfail *-*-* } } */
+      __builtin_abort ();
+    }
+}
-- 
2.21.0

Reply via email to