diff options
Diffstat (limited to 'gcc/analyzer/varargs.cc')
-rw-r--r-- | gcc/analyzer/varargs.cc | 164 |
1 files changed, 87 insertions, 77 deletions
diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc index 0cacc9b..1fdfd34 100644 --- a/gcc/analyzer/varargs.cc +++ b/gcc/analyzer/varargs.cc @@ -18,18 +18,8 @@ You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ -#include "config.h" -#define INCLUDE_VECTOR -#include "system.h" -#include "coretypes.h" -#include "make-unique.h" -#include "tree.h" -#include "function.h" -#include "basic-block.h" -#include "gimple.h" -#include "diagnostic-core.h" -#include "diagnostic-path.h" -#include "analyzer/analyzer.h" +#include "analyzer/common.h" + #include "analyzer/analyzer-logging.h" #include "analyzer/sm.h" #include "analyzer/pending-diagnostic.h" @@ -167,10 +157,10 @@ get_va_list_diag_arg (tree va_list_tree) static const svalue * get_va_copy_arg (const region_model *model, region_model_context *ctxt, - const gcall *call, + const gcall &call, unsigned arg_idx) { - tree arg = gimple_call_arg (call, arg_idx); + tree arg = gimple_call_arg (&call, arg_idx); const svalue *arg_sval = model->get_rvalue (arg, ctxt); if (const svalue *cast = arg_sval->maybe_undo_cast ()) arg_sval = cast; @@ -215,7 +205,11 @@ public: { return s != m_started; } - std::unique_ptr<pending_diagnostic> on_leak (tree var) const final override; + + std::unique_ptr<pending_diagnostic> + on_leak (tree var, + const program_state *old_state, + const program_state *new_state) const final override; /* State for a va_list that is the result of a va_start or va_copy. */ state_t m_started; @@ -225,16 +219,16 @@ public: private: void on_va_start (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void on_va_copy (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void on_va_arg (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void on_va_end (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const; + const gcall &call) const; void check_for_ended_va_list (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, const svalue *arg, const char *usage_fnname) const; }; @@ -256,10 +250,12 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node, const gimple *stmt) const { - if (const gcall *call = dyn_cast <const gcall *> (stmt)) + if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt)) { - if (gimple_call_internal_p (call) - && gimple_call_internal_fn (call) == IFN_VA_ARG) + const gcall &call = *call_stmt; + + if (gimple_call_internal_p (call_stmt) + && gimple_call_internal_fn (call_stmt) == IFN_VA_ARG) { on_va_arg (sm_ctxt, node, call); return false; @@ -267,7 +263,7 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt, if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call)) if (fndecl_built_in_p (callee_fndecl, BUILT_IN_NORMAL) - && gimple_builtin_call_types_compatible_p (call, callee_fndecl)) + && gimple_builtin_call_types_compatible_p (&call, callee_fndecl)) switch (DECL_UNCHECKED_FUNCTION_CODE (callee_fndecl)) { default: @@ -293,24 +289,24 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt, IDX to CALL. */ static const svalue * -get_stateful_arg (sm_context &sm_ctxt, const gcall *call, unsigned arg_idx) +get_stateful_arg (sm_context &sm_ctxt, const gcall &call, unsigned arg_idx) { - tree ap = gimple_call_arg (call, arg_idx); + tree ap = gimple_call_arg (&call, arg_idx); if (ap && POINTER_TYPE_P (TREE_TYPE (ap))) { if (const program_state *new_state = sm_ctxt.get_new_program_state ()) { const region_model *new_model = new_state->m_region_model; - const svalue *ptr_sval = new_model->get_rvalue (ap, NULL); - const region *reg = new_model->deref_rvalue (ptr_sval, ap, NULL); - const svalue *impl_sval = new_model->get_store_value (reg, NULL); + const svalue *ptr_sval = new_model->get_rvalue (ap, nullptr); + const region *reg = new_model->deref_rvalue (ptr_sval, ap, nullptr); + const svalue *impl_sval = new_model->get_store_value (reg, nullptr); if (const svalue *cast = impl_sval->maybe_undo_cast ()) impl_sval = cast; return impl_sval; } } - return NULL; + return nullptr; } /* Abstract class for diagnostics relating to va_list_state_machine. */ @@ -338,17 +334,17 @@ public: return false; } - diagnostic_event::meaning + diagnostics::paths::event::meaning get_meaning_for_state_change (const evdesc::state_change &change) const final override { if (change.m_new_state == m_sm.m_started) - return diagnostic_event::meaning (diagnostic_event::VERB_acquire, - diagnostic_event::NOUN_resource); + return diagnostics::paths::event::meaning (diagnostics::paths::event::verb::acquire, + diagnostics::paths::event::noun::resource); if (change.m_new_state == m_sm.m_ended) - return diagnostic_event::meaning (diagnostic_event::VERB_release, - diagnostic_event::NOUN_resource); - return diagnostic_event::meaning (); + return diagnostics::paths::event::meaning (diagnostics::paths::event::verb::release, + diagnostics::paths::event::noun::resource); + return diagnostics::paths::event::meaning (); } protected: @@ -374,7 +370,7 @@ protected: return "va_end"; } } - return NULL; + return nullptr; } const va_list_state_machine &m_sm; @@ -456,7 +452,7 @@ public: } private: - diagnostic_event_id_t m_va_end_event; + diagnostics::paths::event_id_t m_va_end_event; const char *m_usage_fnname; }; @@ -468,10 +464,14 @@ class va_list_leak : public va_list_sm_diagnostic { public: va_list_leak (const va_list_state_machine &sm, - const svalue *ap_sval, tree ap_tree) + const svalue *ap_sval, tree ap_tree, + const program_state *final_state) : va_list_sm_diagnostic (sm, ap_sval, ap_tree), - m_start_event_fnname (NULL) + m_start_event_fnname (nullptr), + m_final_state () { + if (final_state) + m_final_state = std::make_unique<program_state> (*final_state); } int get_controlling_option () const final override @@ -532,9 +532,16 @@ public: return true; } + const program_state * + get_final_state () const final override + { + return m_final_state.get (); + } + private: - diagnostic_event_id_t m_start_event; + diagnostics::paths::event_id_t m_start_event; const char *m_start_event_fnname; + std::unique_ptr<program_state> m_final_state; }; /* Update state machine for a "va_start" call. */ @@ -542,14 +549,14 @@ private: void va_list_state_machine::on_va_start (sm_context &sm_ctxt, const supernode *, - const gcall *call) const + const gcall &call) const { const svalue *arg = get_stateful_arg (sm_ctxt, call, 0); if (arg) { /* Transition from start state to "started". */ - if (sm_ctxt.get_state (call, arg) == m_start) - sm_ctxt.set_next_state (call, arg, m_started); + if (sm_ctxt.get_state (&call, arg) == m_start) + sm_ctxt.set_next_state (&call, arg, m_started); } } @@ -558,32 +565,32 @@ va_list_state_machine::on_va_start (sm_context &sm_ctxt, void va_list_state_machine::check_for_ended_va_list (sm_context &sm_ctxt, const supernode *node, - const gcall *call, + const gcall &call, const svalue *arg, const char *usage_fnname) const { - if (sm_ctxt.get_state (call, arg) == m_ended) - sm_ctxt.warn (node, call, arg, - make_unique<va_list_use_after_va_end> + if (sm_ctxt.get_state (&call, arg) == m_ended) + sm_ctxt.warn (node, &call, arg, + std::make_unique<va_list_use_after_va_end> (*this, arg, NULL_TREE, usage_fnname)); } /* Get the svalue with associated va_list_state_machine state for ARG_IDX of CALL to va_copy, if SM_CTXT supports this, - or NULL otherwise. */ + or nullptr otherwise. */ static const svalue * get_stateful_va_copy_arg (sm_context &sm_ctxt, - const gcall *call, + const gcall &call, unsigned arg_idx) { if (const program_state *new_state = sm_ctxt.get_new_program_state ()) { const region_model *new_model = new_state->m_region_model; - const svalue *arg = get_va_copy_arg (new_model, NULL, call, arg_idx); + const svalue *arg = get_va_copy_arg (new_model, nullptr, call, arg_idx); return arg; } - return NULL; + return nullptr; } /* Update state machine for a "va_copy" call. */ @@ -591,7 +598,7 @@ get_stateful_va_copy_arg (sm_context &sm_ctxt, void va_list_state_machine::on_va_copy (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const + const gcall &call) const { const svalue *src_arg = get_stateful_va_copy_arg (sm_ctxt, call, 1); if (src_arg) @@ -601,8 +608,8 @@ va_list_state_machine::on_va_copy (sm_context &sm_ctxt, if (dst_arg) { /* Transition from start state to "started". */ - if (sm_ctxt.get_state (call, dst_arg) == m_start) - sm_ctxt.set_next_state (call, dst_arg, m_started); + if (sm_ctxt.get_state (&call, dst_arg) == m_start) + sm_ctxt.set_next_state (&call, dst_arg, m_started); } } @@ -611,7 +618,7 @@ va_list_state_machine::on_va_copy (sm_context &sm_ctxt, void va_list_state_machine::on_va_arg (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const + const gcall &call) const { const svalue *arg = get_stateful_arg (sm_ctxt, call, 0); if (arg) @@ -623,15 +630,15 @@ va_list_state_machine::on_va_arg (sm_context &sm_ctxt, void va_list_state_machine::on_va_end (sm_context &sm_ctxt, const supernode *node, - const gcall *call) const + const gcall &call) const { const svalue *arg = get_stateful_arg (sm_ctxt, call, 0); if (arg) { - state_t s = sm_ctxt.get_state (call, arg); + state_t s = sm_ctxt.get_state (&call, arg); /* Transition from "started" to "ended". */ if (s == m_started) - sm_ctxt.set_next_state (call, arg, m_ended); + sm_ctxt.set_next_state (&call, arg, m_ended); else if (s == m_ended) check_for_ended_va_list (sm_ctxt, node, call, arg, "va_end"); } @@ -641,19 +648,21 @@ va_list_state_machine::on_va_end (sm_context &sm_ctxt, (for complaining about leaks of values in state 'started'). */ std::unique_ptr<pending_diagnostic> -va_list_state_machine::on_leak (tree var) const +va_list_state_machine::on_leak (tree var, + const program_state *, + const program_state *new_state) const { - return make_unique<va_list_leak> (*this, nullptr, var); + return std::make_unique<va_list_leak> (*this, nullptr, var, new_state); } } // anonymous namespace /* Internal interface to this file. */ -state_machine * +std::unique_ptr<state_machine> make_va_list_state_machine (logger *logger) { - return new va_list_state_machine (logger); + return std::make_unique<va_list_state_machine> (logger); } /* Handler for "__builtin_va_start". */ @@ -731,7 +740,7 @@ kf_va_copy::impl_call_pre (const call_details &cd) const in_va_list = model->check_for_poison (in_va_list, get_va_list_diag_arg (cd.get_arg_tree (1)), - NULL, + nullptr, cd.get_ctxt ()); const region *out_dst_reg @@ -757,13 +766,13 @@ kf_va_copy::impl_call_pre (const call_details &cd) const static int get_num_variadic_arguments (tree callee_fndecl, - const gcall *call_stmt) + const gcall &call_stmt) { int num_positional = 0; for (tree iter_parm = DECL_ARGUMENTS (callee_fndecl); iter_parm; iter_parm = DECL_CHAIN (iter_parm)) num_positional++; - return gimple_call_num_args (call_stmt) - num_positional; + return gimple_call_num_args (&call_stmt) - num_positional; } /* An abstract subclass of pending_diagnostic for diagnostics relating @@ -817,12 +826,12 @@ public: const program_point &src_point = src_node->get_point (); const int src_stack_depth = src_point.get_stack_depth (); const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt (); - const gcall *call_stmt = as_a <const gcall *> (last_stmt); + const gcall &call_stmt = *as_a <const gcall *> (last_stmt); int num_variadic_arguments = get_num_variadic_arguments (dst_node->get_function ()->decl, call_stmt); emission_path->add_event - (make_unique<va_arg_call_event> + (std::make_unique<va_arg_call_event> (eedge, event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION, src_point.get_fndecl (), @@ -1011,14 +1020,14 @@ va_arg_compatible_types_p (tree lhs_type, tree arg_type, const svalue &arg_sval) } /* If AP_SVAL is a pointer to a var_arg_region, return that var_arg_region. - Otherwise return NULL. */ + Otherwise return nullptr. */ static const var_arg_region * maybe_get_var_arg_region (const svalue *ap_sval) { if (const region *reg = ap_sval->maybe_get_region ()) return reg->dyn_cast_var_arg_region (); - return NULL; + return nullptr; } /* Handler for "__builtin_va_arg". */ @@ -1078,7 +1087,7 @@ kf_va_arg::impl_call_pre (const call_details &cd) const else { if (ctxt) - ctxt->warn (make_unique <va_arg_type_mismatch> + ctxt->warn (std::make_unique <va_arg_type_mismatch> (va_list_tree, arg_reg, lhs_type, @@ -1089,8 +1098,9 @@ kf_va_arg::impl_call_pre (const call_details &cd) const else { if (ctxt) - ctxt->warn (make_unique <va_list_exhausted> (va_list_tree, - arg_reg)); + ctxt->warn + (std::make_unique <va_list_exhausted> (va_list_tree, + arg_reg)); saw_problem = true; } } @@ -1139,10 +1149,10 @@ public: void register_varargs_builtins (known_function_manager &kfm) { - kfm.add (BUILT_IN_VA_START, make_unique<kf_va_start> ()); - kfm.add (BUILT_IN_VA_COPY, make_unique<kf_va_copy> ()); - kfm.add (IFN_VA_ARG, make_unique<kf_va_arg> ()); - kfm.add (BUILT_IN_VA_END, make_unique<kf_va_end> ()); + kfm.add (BUILT_IN_VA_START, std::make_unique<kf_va_start> ()); + kfm.add (BUILT_IN_VA_COPY, std::make_unique<kf_va_copy> ()); + kfm.add (IFN_VA_ARG, std::make_unique<kf_va_arg> ()); + kfm.add (BUILT_IN_VA_END, std::make_unique<kf_va_end> ()); } } // namespace ana |