Commit 71b633aa by David Malcolm

analyzer: fix ICE with -Wanalyzer-null-dereference [PR 93950]

PR analyzer/93950 reports an ICE when pruning the path of a
-Wanalyzer-null-dereference diagnostic.

The root cause is a bug in the state-tracking code, in which the
variable of interest is tracked from the callee to a "nullptr" param
at the caller, whereupon we have an INTEGER_CST "variable", and
the attempt to look up its lvalue fails.

This code could use a rewrite; in the meantime this patch extends
the bulletproofing from g:8525d1f5
for PR analyzer/93544 to all of the various places where var can
be updated, fixing the ICE.

gcc/analyzer/ChangeLog:
	PR analyzer/93950
	* diagnostic-manager.cc
	(diagnostic_manager::prune_for_sm_diagnostic): Assert that var is
	either NULL or not a constant.  When updating var, bulletproof
	against constant values.

gcc/testsuite/ChangeLog:
	PR analyzer/93950
	* g++.dg/analyzer/pr93950.C: New test.
parent 0ba70d1b
2020-02-26 David Malcolm <dmalcolm@redhat.com> 2020-02-26 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93950
* diagnostic-manager.cc
(diagnostic_manager::prune_for_sm_diagnostic): Assert that var is
either NULL or not a constant. When updating var, bulletproof
against constant values.
2020-02-26 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93947 PR analyzer/93947
* region-model.cc (region_model::get_fndecl_for_call): Gracefully * region-model.cc (region_model::get_fndecl_for_call): Gracefully
fail for fn_decls that don't have a cgraph_node. fail for fn_decls that don't have a cgraph_node.
......
...@@ -1105,6 +1105,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, ...@@ -1105,6 +1105,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
else else
log ("considering event %i", idx); log ("considering event %i", idx);
} }
gcc_assert (var == NULL || !CONSTANT_CLASS_P (var));
switch (base_event->m_kind) switch (base_event->m_kind)
{ {
default: default:
...@@ -1164,6 +1165,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, ...@@ -1164,6 +1165,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
log ("event %i: switching var of interest from %qE to %qE", log ("event %i: switching var of interest from %qE to %qE",
idx, var, state_change->m_origin); idx, var, state_change->m_origin);
var = state_change->m_origin; var = state_change->m_origin;
if (var && CONSTANT_CLASS_P (var))
{
log ("new var is a constant; setting var to NULL");
var = NULL_TREE;
}
} }
log ("event %i: switching state of interest from %qs to %qs", log ("event %i: switching state of interest from %qs to %qs",
idx, sm->get_state_name (state_change->m_to), idx, sm->get_state_name (state_change->m_to),
...@@ -1260,6 +1266,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, ...@@ -1260,6 +1266,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
var = caller_var; var = caller_var;
if (expr.param_p ()) if (expr.param_p ())
event->record_critical_state (var, state); event->record_critical_state (var, state);
if (var && CONSTANT_CLASS_P (var))
{
log ("new var is a constant; setting var to NULL");
var = NULL_TREE;
}
} }
} }
break; break;
...@@ -1285,6 +1296,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path, ...@@ -1285,6 +1296,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
var = callee_var; var = callee_var;
if (expr.return_value_p ()) if (expr.return_value_p ())
event->record_critical_state (var, state); event->record_critical_state (var, state);
if (var && CONSTANT_CLASS_P (var))
{
log ("new var is a constant; setting var to NULL");
var = NULL_TREE;
}
} }
} }
} }
......
2020-02-26 David Malcolm <dmalcolm@redhat.com> 2020-02-26 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93950
* g++.dg/analyzer/pr93950.C: New test.
2020-02-26 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93947 PR analyzer/93947
* gcc.dg/analyzer/torture/pr93947.c: New test. * gcc.dg/analyzer/torture/pr93947.c: New test.
......
// { dg-do compile { target c++11 } }
struct d
{
struct e
{
int f;
int *g;
};
void h (e * i)
{
void *j = nullptr; // { dg-bogus "NULL" "" { xfail *-*-* } }
// TODO(xfail): we report "'i' is NULL" above, which is the wrong location
i->f = *i->g; // { dg-warning "dereference of NULL 'i'" }
}
virtual void c (int, int)
{
int *j = nullptr;
h (nullptr);
}
};
void
foo ()
{
d ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment