[committed] analyzer: fix ICE on unreachable calls [PR 93947]

Message ID 20200227020755.30092-1-dmalcolm@redhat.com
State New
Headers show
Series
  • [committed] analyzer: fix ICE on unreachable calls [PR 93947]
Related show

Commit Message

David Malcolm Feb. 27, 2020, 2:07 a.m.
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

-- 
2.21.0

Patch

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 ();
+    }
+}