mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-22 19:11:18 +08:00
analyzer: fix ICEs in region_model::get_lvalue_1 [PR 93388]
There have been various ICEs with -fanalyzer involving unhandled tree codes in region_model::get_lvalue_1; PR analyzer/93388 reports various others e.g. for IMAGPART_EXPR, REALPART_EXPR, and VIEW_CONVERT_EXPR seen when running the testsuite with -fanalyzer forcibly enabled. Whilst we could implement lvalue-handling in the region model for every tree code, for some of these we're straying far from my primary goal for GCC 10 of implementing a double-free checker for C. This patch implements a fallback for unimplemented tree codes: create a dummy region, but mark the new state as being invalid, and stop exploring state along this path. It also implements VIEW_CONVERT_EXPR. Doing so fixes the ICEs, whilst effectively turning off the analyzer along code paths that use such tree codes. Hopefully this compromise is sensible for GCC 10. gcc/analyzer/ChangeLog: PR analyzer/93388 * engine.cc (impl_region_model_context::on_unknown_tree_code): New. (exploded_graph::get_or_create_node): Reject invalid states. * exploded-graph.h (impl_region_model_context::on_unknown_tree_code): New decl. (point_and_state::point_and_state): Assert that the state is valid. * program-state.cc (program_state::program_state): Initialize m_valid to true. (program_state::operator=): Copy m_valid. (program_state::program_state): Likewise for move constructor. (program_state::print): Print m_valid. (program_state::dump_to_pp): Likewise. * program-state.h (program_state::m_valid): New field. * region-model.cc (region_model::get_lvalue_1): Implement the default case by returning a new symbolic region and calling the context's on_unknown_tree_code, rather than issuing an internal_error. Implement VIEW_CONVERT_EXPR. * region-model.h (region_model_context::on_unknown_tree_code): New vfunc. (test_region_model_context::on_unknown_tree_code): New. gcc/testsuite/ChangeLog: PR analyzer/93388 * gcc.dg/analyzer/torture/20060625-1.c: New test. * gcc.dg/analyzer/torture/pr51628-30.c: New test. * gcc.dg/analyzer/torture/pr59037.c: New test.
This commit is contained in:
parent
0993ad65cc
commit
f76a88ebf0
gcc
analyzer
testsuite
@ -1,3 +1,28 @@
|
||||
2020-02-17 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/93388
|
||||
* engine.cc (impl_region_model_context::on_unknown_tree_code):
|
||||
New.
|
||||
(exploded_graph::get_or_create_node): Reject invalid states.
|
||||
* exploded-graph.h
|
||||
(impl_region_model_context::on_unknown_tree_code): New decl.
|
||||
(point_and_state::point_and_state): Assert that the state is
|
||||
valid.
|
||||
* program-state.cc (program_state::program_state): Initialize
|
||||
m_valid to true.
|
||||
(program_state::operator=): Copy m_valid.
|
||||
(program_state::program_state): Likewise for move constructor.
|
||||
(program_state::print): Print m_valid.
|
||||
(program_state::dump_to_pp): Likewise.
|
||||
* program-state.h (program_state::m_valid): New field.
|
||||
* region-model.cc (region_model::get_lvalue_1): Implement the
|
||||
default case by returning a new symbolic region and calling
|
||||
the context's on_unknown_tree_code, rather than issuing an
|
||||
internal_error. Implement VIEW_CONVERT_EXPR.
|
||||
* region-model.h (region_model_context::on_unknown_tree_code): New
|
||||
vfunc.
|
||||
(test_region_model_context::on_unknown_tree_code): New.
|
||||
|
||||
2020-02-17 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* sm-malloc.cc (malloc_diagnostic::describe_state_change): For
|
||||
|
@ -684,6 +684,25 @@ impl_region_model_context::on_phi (const gphi *phi, tree rhs)
|
||||
}
|
||||
}
|
||||
|
||||
/* Implementation of region_model_context::on_unknown_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)
|
||||
{
|
||||
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)),
|
||||
loc.get_impl_location ().m_function,
|
||||
loc.get_impl_location ().m_file,
|
||||
loc.get_impl_location ().m_line);
|
||||
if (m_new_state)
|
||||
m_new_state->m_valid = false;
|
||||
}
|
||||
|
||||
/* struct point_and_state. */
|
||||
|
||||
/* Assert that this object is sane. */
|
||||
@ -1845,6 +1864,15 @@ exploded_graph::get_or_create_node (const program_point &point,
|
||||
logger->end_log_line ();
|
||||
}
|
||||
|
||||
/* Stop exploring paths for which we don't know how to effectively
|
||||
model the state. */
|
||||
if (!state.m_valid)
|
||||
{
|
||||
if (logger)
|
||||
logger->log ("invalid state; not creating node");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
auto_cfun sentinel (point.get_function ());
|
||||
|
||||
state.validate (get_ext_state ());
|
||||
|
@ -76,6 +76,9 @@ 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;
|
||||
|
||||
exploded_graph *m_eg;
|
||||
log_user m_logger;
|
||||
const exploded_node *m_enode_for_diag;
|
||||
@ -100,6 +103,9 @@ public:
|
||||
m_state (state),
|
||||
m_hash (m_point.hash () ^ m_state.hash ())
|
||||
{
|
||||
/* We shouldn't be building point_and_states and thus exploded_nodes
|
||||
for states that aren't valid. */
|
||||
gcc_assert (state.m_valid);
|
||||
}
|
||||
|
||||
hashval_t hash () const
|
||||
|
@ -573,7 +573,8 @@ sm_state_map::validate (const state_machine &sm,
|
||||
|
||||
program_state::program_state (const extrinsic_state &ext_state)
|
||||
: m_region_model (new region_model ()),
|
||||
m_checker_states (ext_state.get_num_checkers ())
|
||||
m_checker_states (ext_state.get_num_checkers ()),
|
||||
m_valid (true)
|
||||
{
|
||||
int num_states = ext_state.get_num_checkers ();
|
||||
for (int i = 0; i < num_states; i++)
|
||||
@ -584,7 +585,8 @@ program_state::program_state (const extrinsic_state &ext_state)
|
||||
|
||||
program_state::program_state (const program_state &other)
|
||||
: m_region_model (new region_model (*other.m_region_model)),
|
||||
m_checker_states (other.m_checker_states.length ())
|
||||
m_checker_states (other.m_checker_states.length ()),
|
||||
m_valid (true)
|
||||
{
|
||||
int i;
|
||||
sm_state_map *smap;
|
||||
@ -610,6 +612,8 @@ program_state::operator= (const program_state &other)
|
||||
FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
|
||||
m_checker_states.quick_push (smap->clone ());
|
||||
|
||||
m_valid = other.m_valid;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -626,6 +630,8 @@ program_state::program_state (program_state &&other)
|
||||
FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
|
||||
m_checker_states.quick_push (smap);
|
||||
other.m_checker_states.truncate (0);
|
||||
|
||||
m_valid = other.m_valid;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -693,6 +699,11 @@ program_state::print (const extrinsic_state &ext_state,
|
||||
pp_newline (pp);
|
||||
}
|
||||
}
|
||||
if (!m_valid)
|
||||
{
|
||||
pp_printf (pp, "invalid state");
|
||||
pp_newline (pp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump a multiline representation of this state to PP. */
|
||||
@ -716,6 +727,12 @@ program_state::dump_to_pp (const extrinsic_state &ext_state,
|
||||
pp_newline (pp);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_valid)
|
||||
{
|
||||
pp_printf (pp, "invalid state");
|
||||
pp_newline (pp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump a multiline representation of this state to OUTF. */
|
||||
|
@ -286,6 +286,11 @@ public:
|
||||
/* TODO: lose the pointer here (const-correctness issues?). */
|
||||
region_model *m_region_model;
|
||||
auto_delete_vec<sm_state_map> m_checker_states;
|
||||
|
||||
/* If false, then don't attempt to explore further states along this path.
|
||||
For use in "handling" lvalues for tree codes we haven't yet
|
||||
implemented. */
|
||||
bool m_valid;
|
||||
};
|
||||
|
||||
/* An abstract base class for use with for_each_state_change. */
|
||||
|
@ -4641,9 +4641,19 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
|
||||
switch (TREE_CODE (expr))
|
||||
{
|
||||
default:
|
||||
internal_error ("unhandled tree code in region_model::get_lvalue_1: %qs",
|
||||
get_tree_code_name (TREE_CODE (expr)));
|
||||
gcc_unreachable ();
|
||||
{
|
||||
/* 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;
|
||||
|
||||
case ARRAY_REF:
|
||||
{
|
||||
@ -4750,6 +4760,13 @@ region_model::get_lvalue_1 (path_var pv, region_model_context *ctxt)
|
||||
return cst_rid;
|
||||
}
|
||||
break;
|
||||
|
||||
case VIEW_CONVERT_EXPR:
|
||||
{
|
||||
tree obj = TREE_OPERAND (expr, 0);
|
||||
return get_or_create_view (get_lvalue (obj, ctxt), TREE_TYPE (expr));
|
||||
};
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1937,6 +1937,11 @@ class region_model_context
|
||||
/* Hooks for clients to be notified when a phi node is handled,
|
||||
where RHS is the pertinent argument. */
|
||||
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;
|
||||
};
|
||||
|
||||
/* A bundle of data for use when attempting to merge two region_model
|
||||
@ -2118,6 +2123,13 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void on_unknown_tree_code (path_var pv, const dump_location_t &)
|
||||
FINAL OVERRIDE
|
||||
{
|
||||
internal_error ("unhandled tree code: %qs",
|
||||
get_tree_code_name (TREE_CODE (pv.m_tree)));
|
||||
}
|
||||
|
||||
private:
|
||||
/* Implicitly delete any diagnostics in the dtor. */
|
||||
auto_delete_vec<pending_diagnostic> m_diagnostics;
|
||||
|
@ -1,3 +1,10 @@
|
||||
2020-02-17 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/93388
|
||||
* gcc.dg/analyzer/torture/20060625-1.c: New test.
|
||||
* gcc.dg/analyzer/torture/pr51628-30.c: New test.
|
||||
* gcc.dg/analyzer/torture/pr59037.c: New test.
|
||||
|
||||
2020-02-17 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
* gcc.dg/analyzer/malloc-1.c (test_48): New.
|
||||
|
1
gcc/testsuite/gcc.dg/analyzer/torture/20060625-1.c
Normal file
1
gcc/testsuite/gcc.dg/analyzer/torture/20060625-1.c
Normal file
@ -0,0 +1 @@
|
||||
#include "../../../gcc.c-torture/compile/20060625-1.c"
|
3
gcc/testsuite/gcc.dg/analyzer/torture/pr51628-30.c
Normal file
3
gcc/testsuite/gcc.dg/analyzer/torture/pr51628-30.c
Normal file
@ -0,0 +1,3 @@
|
||||
/* { dg-additional-options "-Wno-address-of-packed-member" } */
|
||||
|
||||
#include "../../../c-c++-common/pr51628-30.c"
|
1
gcc/testsuite/gcc.dg/analyzer/torture/pr59037.c
Normal file
1
gcc/testsuite/gcc.dg/analyzer/torture/pr59037.c
Normal file
@ -0,0 +1 @@
|
||||
#include "../../../c-c++-common/pr59037.c"
|
Loading…
x
Reference in New Issue
Block a user