+2020-02-03 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/93544
+ * diagnostic-manager.cc
+ (diagnostic_manager::prune_for_sm_diagnostic): Bulletproof
+ against bad choices due to bad paths.
+ * engine.cc (impl_region_model_context::on_phi): New.
+ * exploded-graph.h (impl_region_model_context::on_phi): New decl.
+ * region-model.cc (region_model::on_longjmp): Likewise.
+ (region_model::handle_phi): Add phi param. Call the ctxt's on_phi
+ vfunc.
+ (region_model::update_for_phis): Pass phi to handle_phi.
+ * region-model.h (region_model::handle_phi): Add phi param.
+ (region_model_context::on_phi): New vfunc.
+ (test_region_model_context::on_phi): New.
+ * sm-malloc.cc (malloc_state_machine::on_phi): New.
+ (malloc_state_machine::on_zero_assignment): New.
+ * sm.h (state_machine::on_phi): New vfunc.
+
2020-02-03 David Malcolm <dmalcolm@redhat.com>
* engine.cc (supernode_cluster::dump_dot): Show BB index as
pp_gimple_stmt_1 (&pp, phi, 0, (dump_flags_t)0);
log (" phi: %s", pp_formatted_text (&pp));
}
+ /* If we've chosen a bad exploded_path, then the
+ phi arg might be a constant. Fail gracefully for
+ this case. */
+ if (CONSTANT_CLASS_P (var))
+ {
+ log ("new var is a constant (bad path?);"
+ " setting var to NULL");
+ var = NULL;
+ }
}
}
}
}
+/* Implementation of region_model_context::on_phi vfunc.
+ Notify all state machines about the phi, which could lead to
+ state transitions. */
+
+void
+impl_region_model_context::on_phi (const gphi *phi, tree rhs)
+{
+ int sm_idx;
+ sm_state_map *smap;
+ FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
+ {
+ const state_machine &sm = m_ext_state.get_sm (sm_idx);
+ impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
+ m_old_state, m_new_state,
+ m_change,
+ m_old_state->m_checker_states[sm_idx],
+ m_new_state->m_checker_states[sm_idx]);
+ sm.on_phi (&sm_ctxt, m_enode_for_diag->get_supernode (), phi, rhs);
+ }
+}
+
/* struct point_and_state. */
/* Assert that this object is sane. */
void on_unknown_change (svalue_id sid ATTRIBUTE_UNUSED) FINAL OVERRIDE;
+ void on_phi (const gphi *phi, tree rhs) FINAL OVERRIDE;
+
exploded_graph *m_eg;
log_user m_logger;
const exploded_node *m_enode_for_diag;
where RHS is for the appropriate edge. */
void
-region_model::handle_phi (tree lhs, tree rhs, bool is_back_edge,
+region_model::handle_phi (const gphi *phi,
+ tree lhs, tree rhs, bool is_back_edge,
region_model_context *ctxt)
{
/* For now, don't bother tracking the .MEM SSA names. */
}
else
set_value (get_lvalue (lhs, ctxt), rhs_sid, ctxt);
+
+ if (ctxt)
+ ctxt->on_phi (phi, rhs);
}
/* Implementation of region_model::get_lvalue; the latter adds type-checking.
/* Update next_state based on phi. */
bool is_back_edge = last_cfg_superedge->back_edge_p ();
- handle_phi (lhs, src, is_back_edge, ctxt);
+ handle_phi (phi, lhs, src, is_back_edge, ctxt);
}
}
const cfg_superedge *last_cfg_superedge,
region_model_context *ctxt);
- void handle_phi (tree lhs, tree rhs, bool is_back_edge,
+ void handle_phi (const gphi *phi,
+ tree lhs, tree rhs, bool is_back_edge,
region_model_context *ctxt);
bool maybe_update_for_edge (const superedge &edge,
/* Hooks for clients to be notified when an unknown change happens
to SID (in response to a call to an unknown function). */
virtual void on_unknown_change (svalue_id sid) = 0;
+
+ /* 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;
};
/* A bundle of data for use when attempting to merge two region_model
{
}
+ void on_phi (const gphi *phi ATTRIBUTE_UNUSED,
+ tree rhs ATTRIBUTE_UNUSED) FINAL OVERRIDE
+ {
+ }
+
private:
/* Implicitly delete any diagnostics in the dtor. */
auto_delete_vec<pending_diagnostic> m_diagnostics;
const supernode *node,
const gimple *stmt) const FINAL OVERRIDE;
+ void on_phi (sm_context *sm_ctxt,
+ const supernode *node,
+ const gphi *phi,
+ tree rhs) const FINAL OVERRIDE;
+
void on_condition (sm_context *sm_ctxt,
const supernode *node,
const gimple *stmt,
/* Stop state, for pointers we don't want to track any more. */
state_t m_stop;
+
+private:
+ void on_zero_assignment (sm_context *sm_ctxt,
+ const supernode *node,
+ const gimple *stmt,
+ tree lhs) const;
};
/* Class for diagnostics relating to malloc_state_machine. */
}
if (tree lhs = is_zero_assignment (stmt))
- {
- if (any_pointer_p (lhs))
- {
- sm_ctxt->on_transition (node, stmt, lhs, m_start, m_null);
- sm_ctxt->on_transition (node, stmt, lhs, m_unchecked, m_null);
- sm_ctxt->on_transition (node, stmt, lhs, m_nonnull, m_null);
- sm_ctxt->on_transition (node, stmt, lhs, m_freed, m_null);
- }
- }
+ if (any_pointer_p (lhs))
+ on_zero_assignment (sm_ctxt, node, stmt,lhs);
if (const gassign *assign_stmt = dyn_cast <const gassign *> (stmt))
{
return false;
}
+/* Implementation of state_machine::on_phi vfunc for malloc_state_machine. */
+
+void
+malloc_state_machine::on_phi (sm_context *sm_ctxt,
+ const supernode *node,
+ const gphi *phi,
+ tree rhs) const
+{
+ if (zerop (rhs))
+ {
+ tree lhs = gimple_phi_result (phi);
+ on_zero_assignment (sm_ctxt, node, phi, lhs);
+ }
+}
+
/* Implementation of state_machine::on_condition vfunc for malloc_state_machine.
Potentially transition state 'unchecked' to 'nonnull' or to 'null'. */
return new malloc_leak (*this, var);
}
+/* Shared logic for handling GIMPLE_ASSIGNs and GIMPLE_PHIs that
+ assign zero to LHS. */
+
+void
+malloc_state_machine::on_zero_assignment (sm_context *sm_ctxt,
+ const supernode *node,
+ const gimple *stmt,
+ tree lhs) const
+{
+ sm_ctxt->on_transition (node, stmt, lhs, m_start, m_null);
+ sm_ctxt->on_transition (node, stmt, lhs, m_unchecked, m_null);
+ sm_ctxt->on_transition (node, stmt, lhs, m_nonnull, m_null);
+ sm_ctxt->on_transition (node, stmt, lhs, m_freed, m_null);
+}
+
} // anonymous namespace
/* Internal interface to this file. */
const supernode *node,
const gimple *stmt) const = 0;
+ virtual void on_phi (sm_context *sm_ctxt ATTRIBUTE_UNUSED,
+ const supernode *node ATTRIBUTE_UNUSED,
+ const gphi *phi ATTRIBUTE_UNUSED,
+ tree rhs ATTRIBUTE_UNUSED) const
+ {
+ }
+
virtual void on_condition (sm_context *sm_ctxt,
const supernode *node,
const gimple *stmt,
+2020-02-03 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/93544
+ * gcc.dg/analyzer/torture/pr93544.c: New test.
+
2020-02-03 David Malcolm <dmalcolm@redhat.com>
PR analyzer/93546
--- /dev/null
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */
+
+int ja;
+
+int *
+qd (void);
+
+void
+lk (void)
+{
+ int *bs, *dx;
+
+ bs = dx = !!ja ? qd () : 0; /* { dg-message "following 'true' branch" } */
+
+ __builtin_free (dx);
+ __builtin_free (bs); /* { dg-warning "double-'free'" } */
+}