analyzer: fix ICE on COMPONENT_REF of ARRAY_TYPE [PR 93778]

PR analyzer/93778 reports an ICE with -fanalyzer on a gfortran test case
at this gimple stmt:

  _gfortran_st_set_nml_var (&dt_parm.0, &ro.xi.jq, &"ro%xi%jq"[1]{lb: 1 sz: 1}, 4, 0, D.3913);

where ro.xi.jq is a COMPONENT_REF, but ro.xi is of type "struct bl[3]".

The analyzer's handling of COMPONENT_REF assumes that the type of the
1st argument is a RECORD_TYPE or UNION_TYPE, whereas in this case it's
an ARRAY_TYPE, leading to a failed as_a inside
region_model::get_field_region.

This patch fixes the ICE by generalizing the "give up on this tree code"
logic from r10-6667-gf76a88ebf089871dcce215aa0cb1956ccc060895 for
PR analyzer/93388, so that the analyzer gives up when it needs to get an
lvalue for a COMPONENT_REF on something other than a RECORD_TYPE or
UNION_TYPE.

gcc/analyzer/ChangeLog:
	PR analyzer/93778
	* engine.cc (impl_region_model_context::on_unknown_tree_code):
	Rename to...
	(impl_region_model_context::on_unexpected_tree_code): ...this and
	convert first argument from path_var to tree.
	(exploded_node::on_stmt): Pass ctxt to purge_for_unknown_fncall.
	* exploded-graph.h (region_model_context::on_unknown_tree_code):
	Rename to...
	(region_model_context::on_unexpected_tree_code): ...this and
	convert first argument from path_var to tree.
	* program-state.cc (sm_state_map::purge_for_unknown_fncall): Add
	ctxt param and pass on to calls to get_rvalue.
	* program-state.h (sm_state_map::purge_for_unknown_fncall): Add
	ctxt param.
	* region-model.cc (region_model::handle_unrecognized_call): Pass
	ctxt on to call to get_rvalue.
	(region_model::get_lvalue_1): Move body of default case to
	region_model::make_region_for_unexpected_tree_code and call it.
	Within COMPONENT_REF case, reject attempts to handle types other
	than RECORD_TYPE and UNION_TYPE.
	(region_model::make_region_for_unexpected_tree_code): New
	function, based on default case of region_model::get_lvalue_1.
	* region-model.h
	(region_model::make_region_for_unexpected_tree_code): New decl.
	(region_model::on_unknown_tree_code): Rename to...
	(region_model::on_unexpected_tree_code): ...this and convert first
	argument from path_var to tree.
	(class test_region_model_context): Update vfunc implementation for
	above change.

gcc/testsuite/ChangeLog:
	PR analyzer/93778
	* gfortran.dg/analyzer/pr93778.f90: New test.
This commit is contained in:
David Malcolm 2020-02-17 16:43:46 -05:00
parent a674c7b8b8
commit 2e6233935c
9 changed files with 98 additions and 31 deletions

View File

@ -1,3 +1,35 @@
2020-02-18 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93778
* engine.cc (impl_region_model_context::on_unknown_tree_code):
Rename to...
(impl_region_model_context::on_unexpected_tree_code): ...this and
convert first argument from path_var to tree.
(exploded_node::on_stmt): Pass ctxt to purge_for_unknown_fncall.
* exploded-graph.h (region_model_context::on_unknown_tree_code):
Rename to...
(region_model_context::on_unexpected_tree_code): ...this and
convert first argument from path_var to tree.
* program-state.cc (sm_state_map::purge_for_unknown_fncall): Add
ctxt param and pass on to calls to get_rvalue.
* program-state.h (sm_state_map::purge_for_unknown_fncall): Add
ctxt param.
* region-model.cc (region_model::handle_unrecognized_call): Pass
ctxt on to call to get_rvalue.
(region_model::get_lvalue_1): Move body of default case to
region_model::make_region_for_unexpected_tree_code and call it.
Within COMPONENT_REF case, reject attempts to handle types other
than RECORD_TYPE and UNION_TYPE.
(region_model::make_region_for_unexpected_tree_code): New
function, based on default case of region_model::get_lvalue_1.
* region-model.h
(region_model::make_region_for_unexpected_tree_code): New decl.
(region_model::on_unknown_tree_code): Rename to...
(region_model::on_unexpected_tree_code): ...this and convert first
argument from path_var to tree.
(class test_region_model_context): Update vfunc implementation for
above change.
2020-02-18 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93774

View File

@ -684,18 +684,18 @@ impl_region_model_context::on_phi (const gphi *phi, tree rhs)
}
}
/* Implementation of region_model_context::on_unknown_tree_code vfunc.
/* Implementation of region_model_context::on_unexpected_tree_code vfunc.
Mark the new state as being invalid for further exploration.
TODO(stage1): introduce a warning for when this occurs. */
void
impl_region_model_context::on_unknown_tree_code (path_var pv,
const dump_location_t &loc)
impl_region_model_context::on_unexpected_tree_code (tree t,
const dump_location_t &loc)
{
logger * const logger = get_logger ();
if (logger)
logger->log ("unhandled tree code: %qs in %qs at %s:%i",
get_tree_code_name (TREE_CODE (pv.m_tree)),
get_tree_code_name (TREE_CODE (t)),
loc.get_impl_location ().m_function,
loc.get_impl_location ().m_file,
loc.get_impl_location ().m_line);
@ -1093,7 +1093,8 @@ exploded_node::on_stmt (exploded_graph &eg,
if (!fndecl_has_gimple_body_p (callee_fndecl))
new_smap->purge_for_unknown_fncall (eg, sm, call, callee_fndecl,
state->m_region_model);
state->m_region_model,
&ctxt);
}
}
if (*old_smap != *new_smap)

View File

@ -76,8 +76,8 @@ class impl_region_model_context : public region_model_context
void on_phi (const gphi *phi, tree rhs) FINAL OVERRIDE;
void on_unknown_tree_code (path_var pv,
const dump_location_t &loc) FINAL OVERRIDE;
void on_unexpected_tree_code (tree t,
const dump_location_t &loc) FINAL OVERRIDE;
exploded_graph *m_eg;
log_user m_logger;

View File

@ -380,7 +380,8 @@ sm_state_map::purge_for_unknown_fncall (const exploded_graph &eg,
const state_machine &sm,
const gcall *call,
tree fndecl,
region_model *new_model)
region_model *new_model,
region_model_context *ctxt)
{
logger * const logger = eg.get_logger ();
if (logger)
@ -413,7 +414,7 @@ sm_state_map::purge_for_unknown_fncall (const exploded_graph &eg,
continue;
}
tree parm = gimple_call_arg (call, arg_idx);
svalue_id parm_sid = new_model->get_rvalue (parm, NULL);
svalue_id parm_sid = new_model->get_rvalue (parm, ctxt);
set_state (new_model, parm_sid, 0, svalue_id::null ());
/* Also clear sm-state from svalue_ids that are passed via a
@ -421,7 +422,7 @@ sm_state_map::purge_for_unknown_fncall (const exploded_graph &eg,
if (TREE_CODE (parm) == ADDR_EXPR)
{
tree pointee = TREE_OPERAND (parm, 0);
svalue_id parm_sid = new_model->get_rvalue (pointee, NULL);
svalue_id parm_sid = new_model->get_rvalue (pointee, ctxt);
set_state (new_model, parm_sid, 0, svalue_id::null ());
}
}
@ -429,7 +430,7 @@ sm_state_map::purge_for_unknown_fncall (const exploded_graph &eg,
/* Purge any state for any LHS. */
if (tree lhs = gimple_call_lhs (call))
{
svalue_id lhs_sid = new_model->get_rvalue (lhs, NULL);
svalue_id lhs_sid = new_model->get_rvalue (lhs, ctxt);
set_state (new_model, lhs_sid, 0, svalue_id::null ());
}
}

View File

@ -179,7 +179,8 @@ public:
void purge_for_unknown_fncall (const exploded_graph &eg,
const state_machine &sm,
const gcall *call, tree fndecl,
region_model *new_model);
region_model *new_model,
region_model_context *ctxt);
void remap_svalue_ids (const svalue_id_map &map);

View File

@ -4431,7 +4431,7 @@ region_model::handle_unrecognized_call (const gcall *call,
}
tree parm = gimple_call_arg (call, arg_idx);
svalue_id parm_sid = get_rvalue (parm, NULL);
svalue_id parm_sid = get_rvalue (parm, ctxt);
svalue *parm_sval = get_svalue (parm_sid);
if (parm_sval)
if (region_svalue *parm_ptr = parm_sval->dyn_cast_region_svalue ())
@ -4641,19 +4641,8 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
switch (TREE_CODE (expr))
{
default:
{
/* If we see a tree code we we don't know how to handle, rather than
ICE or generate bogus results, create a dummy region, and notify
CTXT so that it can mark the new state as being not properly
modelled. The exploded graph can then stop exploring that path,
since any diagnostics we might issue will have questionable
validity. */
region_id new_rid
= add_region (new symbolic_region (m_root_rid, NULL_TREE, false));
ctxt->on_unknown_tree_code (pv, dump_location_t ());
return new_rid;
}
break;
return make_region_for_unexpected_tree_code (ctxt, expr,
dump_location_t ());
case ARRAY_REF:
{
@ -4730,6 +4719,11 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
/* obj.field */
tree obj = TREE_OPERAND (expr, 0);
tree field = TREE_OPERAND (expr, 1);
tree obj_type = TREE_TYPE (obj);
if (TREE_CODE (obj_type) != RECORD_TYPE
&& TREE_CODE (obj_type) != UNION_TYPE)
return make_region_for_unexpected_tree_code (ctxt, obj_type,
dump_location_t ());
region_id obj_rid = get_lvalue (obj, ctxt);
region_id struct_or_union_rid
= get_or_create_view (obj_rid, TREE_TYPE (obj));
@ -4770,6 +4764,24 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
}
}
/* If we see a tree code we we don't know how to handle, rather than
ICE or generate bogus results, create a dummy region, and notify
CTXT so that it can mark the new state as being not properly
modelled. The exploded graph can then stop exploring that path,
since any diagnostics we might issue will have questionable
validity. */
region_id
region_model::make_region_for_unexpected_tree_code (region_model_context *ctxt,
tree t,
const dump_location_t &loc)
{
region_id new_rid
= add_region (new symbolic_region (m_root_rid, NULL_TREE, false));
ctxt->on_unexpected_tree_code (t, loc);
return new_rid;
}
/* Assert that SRC_TYPE can be converted to DST_TYPE as a no-op. */
static void

View File

@ -1835,6 +1835,10 @@ class region_model
region_id get_lvalue_1 (path_var pv, region_model_context *ctxt);
svalue_id get_rvalue_1 (path_var pv, region_model_context *ctxt);
region_id make_region_for_unexpected_tree_code (region_model_context *ctxt,
tree t,
const dump_location_t &loc);
void add_any_constraints_from_ssa_def_stmt (tree lhs,
enum tree_code op,
tree rhs,
@ -1939,9 +1943,9 @@ class region_model_context
virtual void on_phi (const gphi *phi, tree rhs) = 0;
/* Hooks for clients to be notified when the region model doesn't
know how to handle the tree code of PV at LOC. */
virtual void on_unknown_tree_code (path_var pv,
const dump_location_t &loc) = 0;
know how to handle the tree code of T at LOC. */
virtual void on_unexpected_tree_code (tree t,
const dump_location_t &loc) = 0;
};
/* A bundle of data for use when attempting to merge two region_model
@ -2123,11 +2127,11 @@ public:
{
}
void on_unknown_tree_code (path_var pv, const dump_location_t &)
void on_unexpected_tree_code (tree t, const dump_location_t &)
FINAL OVERRIDE
{
internal_error ("unhandled tree code: %qs",
get_tree_code_name (TREE_CODE (pv.m_tree)));
get_tree_code_name (TREE_CODE (t)));
}
private:

View File

@ -1,3 +1,8 @@
2020-02-18 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93778
* gfortran.dg/analyzer/pr93778.f90: New test.
2020-02-18 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93774

View File

@ -0,0 +1,11 @@
program h0
type bl
integer jq
end type bl
type qn
type (bl), dimension(3) :: xi
end type qn
type (qn) ro
namelist /i2/ ro
read(10, nml = i2)
end program h0