analyzer: eliminate sm_context::warn_for_state in favor of a new 'warn' vfunc

This patch is yet more preliminary work towards generalizing sm-malloc.cc
beyond just malloc/free.

It eliminates sm_context::warn_for_state in terms of a new sm_context::warn
vfunc, guarded by sm_context::get_state calls.

gcc/analyzer/ChangeLog:
	* diagnostic-manager.cc
	(null_assignment_sm_context::warn_for_state): Replace with...
	(null_assignment_sm_context::warn): ...this.
	* engine.cc (impl_sm_context::warn_for_state): Replace with...
	(impl_sm_context::warn): ...this.
	* sm-file.cc (fileptr_state_machine::on_stmt): Replace
	warn_for_state and on_transition calls with a get_state
	test guarding warn and set_next_state calls.
	* sm-malloc.cc (malloc_state_machine::on_stmt): Likewise.
	* sm-pattern-test.cc (pattern_test_state_machine::on_condition):
	Replace warn_for_state call with warn call.
	* sm-sensitive.cc
	(sensitive_state_machine::warn_for_any_exposure): Replace
	warn_for_state call with a get_state test guarding a warn call.
	* sm-signal.cc (signal_state_machine::on_stmt): Likewise.
	* sm-taint.cc (taint_state_machine::on_stmt):  Replace
	warn_for_state and on_transition calls with a get_state
	test guarding warn and set_next_state calls.
	* sm.h (sm_context::warn_for_state): Replace with...
	(sm_context::warn): ...this.
This commit is contained in:
David Malcolm 2020-08-28 10:10:38 -04:00
parent 6d9ca8c860
commit 25ef215abb
9 changed files with 108 additions and 88 deletions

View File

@ -808,9 +808,8 @@ struct null_assignment_sm_context : public sm_context
*m_new_state));
}
void warn_for_state (const supernode *, const gimple *,
tree, state_machine::state_t,
pending_diagnostic *d) FINAL OVERRIDE
void warn (const supernode *, const gimple *,
tree, pending_diagnostic *d) FINAL OVERRIDE
{
delete d;
}

View File

@ -254,35 +254,23 @@ public:
to, origin_new_sval, m_eg.get_ext_state ());
}
void warn_for_state (const supernode *snode, const gimple *stmt,
tree var, state_machine::state_t state,
pending_diagnostic *d) FINAL OVERRIDE
void warn (const supernode *snode, const gimple *stmt,
tree var, pending_diagnostic *d) FINAL OVERRIDE
{
LOG_FUNC (get_logger ());
gcc_assert (d); // take ownership
impl_region_model_context old_ctxt
(m_eg, m_enode_for_diag, m_old_state, m_new_state, NULL);
state_machine::state_t current;
if (var)
{
const svalue *var_old_sval
= m_old_state->m_region_model->get_rvalue (var, &old_ctxt);
current = m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ());
}
else
current = m_old_smap->get_global_state ();
if (state == current)
{
const svalue *var_old_sval
= m_old_state->m_region_model->get_rvalue (var, &old_ctxt);
m_eg.get_diagnostic_manager ().add_diagnostic
(&m_sm, m_enode_for_diag, snode, stmt, m_stmt_finder,
var, var_old_sval, state, d);
}
else
delete d;
const svalue *var_old_sval
= m_old_state->m_region_model->get_rvalue (var, &old_ctxt);
state_machine::state_t current
= (var
? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
: m_old_smap->get_global_state ());
m_eg.get_diagnostic_manager ().add_diagnostic
(&m_sm, m_enode_for_diag, snode, stmt, m_stmt_finder,
var, var_old_sval, current, d);
}
/* Hook for picking more readable trees for SSA names of temporaries,

View File

@ -344,9 +344,12 @@ fileptr_state_machine::on_stmt (sm_context *sm_ctxt,
sm_ctxt->on_transition (node, stmt , arg, m_nonnull, m_closed);
sm_ctxt->warn_for_state (node, stmt, arg, m_closed,
new double_fclose (*this, diag_arg));
sm_ctxt->on_transition (node, stmt, arg, m_closed, m_stop);
if (sm_ctxt->get_state (stmt, arg) == m_closed)
{
sm_ctxt->warn (node, stmt, arg,
new double_fclose (*this, diag_arg));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
return true;
}

View File

@ -716,14 +716,20 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt,
we don't want to complain about double-free of NULL. */
/* freed -> stop, with warning. */
sm_ctxt->warn_for_state (node, stmt, arg, m_freed,
new double_free (*this, diag_arg));
sm_ctxt->on_transition (node, stmt, arg, m_freed, m_stop);
if (sm_ctxt->get_state (stmt, arg) == m_freed)
{
sm_ctxt->warn (node, stmt, arg,
new double_free (*this, diag_arg));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
/* non-heap -> stop, with warning. */
sm_ctxt->warn_for_state (node, stmt, arg, m_non_heap,
new free_of_non_heap (*this, diag_arg));
sm_ctxt->on_transition (node, stmt, arg, m_non_heap, m_stop);
if (sm_ctxt->get_state (stmt, arg) == m_non_heap)
{
sm_ctxt->warn (node, stmt, arg,
new free_of_non_heap (*this, diag_arg));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
return true;
}
@ -744,17 +750,23 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt,
|| bitmap_bit_p (nonnull_args, i))
{
tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
sm_ctxt->warn_for_state
(node, stmt, arg, m_unchecked,
new possible_null_arg (*this, diag_arg, callee_fndecl,
i));
sm_ctxt->on_transition (node, stmt, arg, m_unchecked,
m_nonnull);
sm_ctxt->warn_for_state
(node, stmt, arg, m_null,
new null_arg (*this, diag_arg, callee_fndecl, i));
sm_ctxt->on_transition (node, stmt, arg, m_null, m_stop);
state_t state = sm_ctxt->get_state (stmt, arg);
/* Can't use a switch as the states are non-const. */
if (state == m_unchecked)
{
sm_ctxt->warn (node, stmt, arg,
new possible_null_arg (*this, diag_arg,
callee_fndecl,
i));
sm_ctxt->set_next_state (stmt, arg, m_nonnull);
}
else if (state == m_null)
{
sm_ctxt->warn (node, stmt, arg,
new null_arg (*this, diag_arg,
callee_fndecl, i));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
}
}
BITMAP_FREE (nonnull_args);
@ -800,17 +812,26 @@ malloc_state_machine::on_stmt (sm_context *sm_ctxt,
tree arg = TREE_OPERAND (op, 0);
tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
sm_ctxt->warn_for_state (node, stmt, arg, m_unchecked,
new possible_null_deref (*this, diag_arg));
sm_ctxt->on_transition (node, stmt, arg, m_unchecked, m_nonnull);
sm_ctxt->warn_for_state (node, stmt, arg, m_null,
new null_deref (*this, diag_arg));
sm_ctxt->on_transition (node, stmt, arg, m_null, m_stop);
sm_ctxt->warn_for_state (node, stmt, arg, m_freed,
new use_after_free (*this, diag_arg));
sm_ctxt->on_transition (node, stmt, arg, m_freed, m_stop);
state_t state = sm_ctxt->get_state (stmt, arg);
/* Can't use a switch as the states are non-const. */
if (state == m_unchecked)
{
sm_ctxt->warn (node, stmt, arg,
new possible_null_deref (*this, diag_arg));
sm_ctxt->set_next_state (stmt, arg, m_nonnull);
}
else if (state == m_null)
{
sm_ctxt->warn (node, stmt, arg,
new null_deref (*this, diag_arg));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
else if (state == m_freed)
{
sm_ctxt->warn (node, stmt, arg,
new use_after_free (*this, diag_arg));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
}
}
return false;

View File

@ -128,7 +128,7 @@ pattern_test_state_machine::on_condition (sm_context *sm_ctxt,
return;
pending_diagnostic *diag = new pattern_match (lhs, op, rhs);
sm_ctxt->warn_for_state (node, stmt, lhs, m_start, diag);
sm_ctxt->warn (node, stmt, lhs, diag);
}
bool

View File

@ -174,8 +174,9 @@ sensitive_state_machine::warn_for_any_exposure (sm_context *sm_ctxt,
tree arg) const
{
tree diag_arg = sm_ctxt->get_diagnostic_tree (arg);
sm_ctxt->warn_for_state (node, stmt, arg, m_sensitive,
new exposure_through_output_file (*this, diag_arg));
if (sm_ctxt->get_state (stmt, arg) == m_sensitive)
sm_ctxt->warn (node, stmt, arg,
new exposure_through_output_file (*this, diag_arg));
}
/* Implementation of state_machine::on_stmt vfunc for

View File

@ -346,9 +346,10 @@ signal_state_machine::on_stmt (sm_context *sm_ctxt,
if (const gcall *call = dyn_cast <const gcall *> (stmt))
if (tree callee_fndecl = sm_ctxt->get_fndecl_for_call (call))
if (signal_unsafe_p (callee_fndecl))
sm_ctxt->warn_for_state (node, stmt, NULL_TREE, m_in_signal_handler,
new signal_unsafe_call (*this, call,
callee_fndecl));
if (sm_ctxt->get_global_state () == m_in_signal_handler)
sm_ctxt->warn (node, stmt, NULL_TREE,
new signal_unsafe_call (*this, call,
callee_fndecl));
}
return false;

View File

@ -233,27 +233,36 @@ taint_state_machine::on_stmt (sm_context *sm_ctxt,
if (INTEGRAL_TYPE_P (TREE_TYPE (arg)))
is_unsigned = TYPE_UNSIGNED (TREE_TYPE (arg));
/* Complain about missing bounds. */
sm_ctxt->warn_for_state
(node, stmt, arg, m_tainted,
new tainted_array_index (*this, diag_arg,
is_unsigned
? BOUNDS_LOWER : BOUNDS_NONE));
sm_ctxt->on_transition (node, stmt, arg, m_tainted, m_stop);
/* Complain about missing upper bound. */
sm_ctxt->warn_for_state (node, stmt, arg, m_has_lb,
new tainted_array_index (*this, diag_arg,
BOUNDS_LOWER));
sm_ctxt->on_transition (node, stmt, arg, m_has_lb, m_stop);
/* Complain about missing lower bound. */
if (!is_unsigned)
state_t state = sm_ctxt->get_state (stmt, arg);
/* Can't use a switch as the states are non-const. */
if (state == m_tainted)
{
sm_ctxt->warn_for_state (node, stmt, arg, m_has_ub,
new tainted_array_index (*this, diag_arg,
BOUNDS_UPPER));
sm_ctxt->on_transition (node, stmt, arg, m_has_ub, m_stop);
/* Complain about missing bounds. */
pending_diagnostic *d
= new tainted_array_index (*this, diag_arg,
is_unsigned
? BOUNDS_LOWER : BOUNDS_NONE);
sm_ctxt->warn (node, stmt, arg, d);
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
else if (state == m_has_lb)
{
/* Complain about missing upper bound. */
sm_ctxt->warn (node, stmt, arg,
new tainted_array_index (*this, diag_arg,
BOUNDS_LOWER));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
else if (state == m_has_ub)
{
/* Complain about missing lower bound. */
if (!is_unsigned)
{
sm_ctxt->warn (node, stmt, arg,
new tainted_array_index (*this, diag_arg,
BOUNDS_UPPER));
sm_ctxt->set_next_state (stmt, arg, m_stop);
}
}
}
}

View File

@ -198,11 +198,9 @@ public:
}
/* Called by state_machine in response to pattern matches:
issue a diagnostic D if VAR is in state STATE, using NODE and STMT
for location information. */
virtual void warn_for_state (const supernode *node, const gimple *stmt,
tree var, state_machine::state_t state,
pending_diagnostic *d) = 0;
issue a diagnostic D using NODE and STMT for location information. */
virtual void warn (const supernode *node, const gimple *stmt,
tree var, pending_diagnostic *d) = 0;
/* For use when generating trees when creating pending_diagnostics, so that
rather than e.g.