/* Classes for modeling the state of memory.
- Copyright (C) 2019-2022 Free Software Foundation, Inc.
+ Copyright (C) 2019-2024 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
This file is part of GCC.
(Zhongxing Xu, Ted Kremenek, and Jian Zhang)
http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf */
+#include "bitmap.h"
+#include "stringpool.h"
+#include "attribs.h" // for rdwr_map
+#include "selftest.h"
#include "analyzer/svalue.h"
#include "analyzer/region.h"
+#include "analyzer/known-function-manager.h"
+#include "analyzer/region-model-manager.h"
+#include "analyzer/pending-diagnostic.h"
using namespace ana;
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
void dump (bool simple) const;
+ json::object *to_json () const;
+
bool can_merge_with_p (const region_to_value_map &other,
region_to_value_map *out) const;
virtual void visit_compound_svalue (const compound_svalue *) {}
virtual void visit_conjured_svalue (const conjured_svalue *) {}
virtual void visit_asm_output_svalue (const asm_output_svalue *) {}
+ virtual void visit_const_fn_result_svalue (const const_fn_result_svalue *) {}
virtual void visit_region (const region *) {}
};
-} // namespace ana
-
-namespace ana {
-
-/* A class responsible for owning and consolidating region and svalue
- instances.
- region and svalue instances are immutable as far as clients are
- concerned, so they are provided as "const" ptrs. */
-
-class region_model_manager
-{
-public:
- region_model_manager (logger *logger = NULL);
- ~region_model_manager ();
-
- /* svalue consolidation. */
- const svalue *get_or_create_constant_svalue (tree cst_expr);
- const svalue *get_or_create_int_cst (tree type, poly_int64);
- const svalue *get_or_create_unknown_svalue (tree type);
- const svalue *get_or_create_setjmp_svalue (const setjmp_record &r,
- tree type);
- const svalue *get_or_create_poisoned_svalue (enum poison_kind kind,
- tree type);
- const svalue *get_or_create_initial_value (const region *reg);
- const svalue *get_ptr_svalue (tree ptr_type, const region *pointee);
- const svalue *get_or_create_unaryop (tree type, enum tree_code op,
- const svalue *arg);
- const svalue *get_or_create_cast (tree type, const svalue *arg);
- const svalue *get_or_create_binop (tree type,
- enum tree_code op,
- const svalue *arg0, const svalue *arg1);
- const svalue *get_or_create_sub_svalue (tree type,
- const svalue *parent_svalue,
- const region *subregion);
- const svalue *get_or_create_repeated_svalue (tree type,
- const svalue *outer_size,
- const svalue *inner_svalue);
- const svalue *get_or_create_bits_within (tree type,
- const bit_range &bits,
- const svalue *inner_svalue);
- const svalue *get_or_create_unmergeable (const svalue *arg);
- const svalue *get_or_create_widening_svalue (tree type,
- const program_point &point,
- const svalue *base_svalue,
- const svalue *iter_svalue);
- const svalue *get_or_create_compound_svalue (tree type,
- const binding_map &map);
- const svalue *get_or_create_conjured_svalue (tree type, const gimple *stmt,
- const region *id_reg);
- const svalue *
- get_or_create_asm_output_svalue (tree type,
- const gasm *asm_stmt,
- unsigned output_idx,
- const vec<const svalue *> &inputs);
-
- const svalue *maybe_get_char_from_string_cst (tree string_cst,
- tree byte_offset_cst);
-
- /* Dynamically-allocated svalue instances.
- The number of these within the analysis can grow arbitrarily.
- They are still owned by the manager. */
- const svalue *create_unique_svalue (tree type);
-
- /* region consolidation. */
- const stack_region * get_stack_region () const { return &m_stack_region; }
- const heap_region *get_heap_region () const { return &m_heap_region; }
- const code_region *get_code_region () const { return &m_code_region; }
- const globals_region *get_globals_region () const
- {
- return &m_globals_region;
- }
- const function_region *get_region_for_fndecl (tree fndecl);
- const label_region *get_region_for_label (tree label);
- const decl_region *get_region_for_global (tree expr);
- const region *get_field_region (const region *parent, tree field);
- const region *get_element_region (const region *parent,
- tree element_type,
- const svalue *index);
- const region *get_offset_region (const region *parent,
- tree type,
- const svalue *byte_offset);
- const region *get_sized_region (const region *parent,
- tree type,
- const svalue *byte_size_sval);
- const region *get_cast_region (const region *original_region,
- tree type);
- const frame_region *get_frame_region (const frame_region *calling_frame,
- function *fun);
- const region *get_symbolic_region (const svalue *sval);
- const string_region *get_region_for_string (tree string_cst);
- const region *get_bit_range (const region *parent, tree type,
- const bit_range &bits);
-
- const region *
- get_region_for_unexpected_tree_code (region_model_context *ctxt,
- tree t,
- const dump_location_t &loc);
-
- unsigned alloc_region_id () { return m_next_region_id++; }
-
- store_manager *get_store_manager () { return &m_store_mgr; }
- bounded_ranges_manager *get_range_manager () const { return m_range_mgr; }
-
- /* Dynamically-allocated region instances.
- The number of these within the analysis can grow arbitrarily.
- They are still owned by the manager. */
- const region *create_region_for_heap_alloc ();
- const region *create_region_for_alloca (const frame_region *frame);
-
- void log_stats (logger *logger, bool show_objs) const;
-
- void begin_checking_feasibility (void) { m_checking_feasibility = true; }
- void end_checking_feasibility (void) { m_checking_feasibility = false; }
-
- logger *get_logger () const { return m_logger; }
-
-private:
- bool too_complex_p (const complexity &c) const;
- bool reject_if_too_complex (svalue *sval);
-
- const svalue *maybe_fold_unaryop (tree type, enum tree_code op,
- const svalue *arg);
- const svalue *maybe_fold_binop (tree type, enum tree_code op,
- const svalue *arg0, const svalue *arg1);
- const svalue *maybe_fold_sub_svalue (tree type,
- const svalue *parent_svalue,
- const region *subregion);
- const svalue *maybe_fold_repeated_svalue (tree type,
- const svalue *outer_size,
- const svalue *inner_svalue);
- const svalue *maybe_fold_bits_within_svalue (tree type,
- const bit_range &bits,
- const svalue *inner_svalue);
- const svalue *maybe_undo_optimize_bit_field_compare (tree type,
- const compound_svalue *compound_sval,
- tree cst, const svalue *arg1);
- const svalue *maybe_fold_asm_output_svalue (tree type,
- const vec<const svalue *> &inputs);
-
- logger *m_logger;
-
- unsigned m_next_region_id;
- root_region m_root_region;
- stack_region m_stack_region;
- heap_region m_heap_region;
-
- /* svalue consolidation. */
- typedef hash_map<tree, constant_svalue *> constants_map_t;
- constants_map_t m_constants_map;
-
- typedef hash_map<tree, unknown_svalue *> unknowns_map_t;
- unknowns_map_t m_unknowns_map;
- const unknown_svalue *m_unknown_NULL;
-
- typedef hash_map<poisoned_svalue::key_t,
- poisoned_svalue *> poisoned_values_map_t;
- poisoned_values_map_t m_poisoned_values_map;
-
- typedef hash_map<setjmp_svalue::key_t,
- setjmp_svalue *> setjmp_values_map_t;
- setjmp_values_map_t m_setjmp_values_map;
-
- typedef hash_map<const region *, initial_svalue *> initial_values_map_t;
- initial_values_map_t m_initial_values_map;
-
- typedef hash_map<region_svalue::key_t, region_svalue *> pointer_values_map_t;
- pointer_values_map_t m_pointer_values_map;
-
- typedef hash_map<unaryop_svalue::key_t,
- unaryop_svalue *> unaryop_values_map_t;
- unaryop_values_map_t m_unaryop_values_map;
-
- typedef hash_map<binop_svalue::key_t, binop_svalue *> binop_values_map_t;
- binop_values_map_t m_binop_values_map;
-
- typedef hash_map<sub_svalue::key_t, sub_svalue *> sub_values_map_t;
- sub_values_map_t m_sub_values_map;
-
- typedef hash_map<repeated_svalue::key_t,
- repeated_svalue *> repeated_values_map_t;
- repeated_values_map_t m_repeated_values_map;
-
- typedef hash_map<bits_within_svalue::key_t,
- bits_within_svalue *> bits_within_values_map_t;
- bits_within_values_map_t m_bits_within_values_map;
-
- typedef hash_map<const svalue *,
- unmergeable_svalue *> unmergeable_values_map_t;
- unmergeable_values_map_t m_unmergeable_values_map;
-
- typedef hash_map<widening_svalue::key_t,
- widening_svalue */*,
- widening_svalue::key_t::hash_map_traits*/>
- widening_values_map_t;
- widening_values_map_t m_widening_values_map;
-
- typedef hash_map<compound_svalue::key_t,
- compound_svalue *> compound_values_map_t;
- compound_values_map_t m_compound_values_map;
-
- typedef hash_map<conjured_svalue::key_t,
- conjured_svalue *> conjured_values_map_t;
- conjured_values_map_t m_conjured_values_map;
-
- typedef hash_map<asm_output_svalue::key_t,
- asm_output_svalue *> asm_output_values_map_t;
- asm_output_values_map_t m_asm_output_values_map;
-
- bool m_checking_feasibility;
-
- /* "Dynamically-allocated" svalue instances.
- The number of these within the analysis can grow arbitrarily.
- They are still owned by the manager. */
- auto_delete_vec<svalue> m_managed_dynamic_svalues;
-
- /* Maximum complexity of svalues that weren't rejected. */
- complexity m_max_complexity;
-
- /* region consolidation. */
-
- code_region m_code_region;
- typedef hash_map<tree, function_region *> fndecls_map_t;
- typedef fndecls_map_t::iterator fndecls_iterator_t;
- fndecls_map_t m_fndecls_map;
-
- typedef hash_map<tree, label_region *> labels_map_t;
- typedef labels_map_t::iterator labels_iterator_t;
- labels_map_t m_labels_map;
-
- globals_region m_globals_region;
- typedef hash_map<tree, decl_region *> globals_map_t;
- typedef globals_map_t::iterator globals_iterator_t;
- globals_map_t m_globals_map;
-
- consolidation_map<field_region> m_field_regions;
- consolidation_map<element_region> m_element_regions;
- consolidation_map<offset_region> m_offset_regions;
- consolidation_map<sized_region> m_sized_regions;
- consolidation_map<cast_region> m_cast_regions;
- consolidation_map<frame_region> m_frame_regions;
- consolidation_map<symbolic_region> m_symbolic_regions;
-
- typedef hash_map<tree, string_region *> string_map_t;
- string_map_t m_string_map;
-
- consolidation_map<bit_range_region> m_bit_range_regions;
-
- store_manager m_store_mgr;
-
- bounded_ranges_manager *m_range_mgr;
-
- /* "Dynamically-allocated" region instances.
- The number of these within the analysis can grow arbitrarily.
- They are still owned by the manager. */
- auto_delete_vec<region> m_managed_dynamic_regions;
-};
-
-struct append_ssa_names_cb_data;
-
-/* Helper class for handling calls to functions with known behavior.
- Implemented in region-model-impl-calls.c. */
-
-class call_details
-{
-public:
- call_details (const gcall *call, region_model *model,
- region_model_context *ctxt);
-
- region_model_context *get_ctxt () const { return m_ctxt; }
- uncertainty_t *get_uncertainty () const;
- tree get_lhs_type () const { return m_lhs_type; }
- const region *get_lhs_region () const { return m_lhs_region; }
-
- bool maybe_set_lhs (const svalue *result) const;
+struct append_regions_cb_data;
- unsigned num_args () const;
-
- const gcall *get_call_stmt () const { return m_call; }
-
- tree get_arg_tree (unsigned idx) const;
- tree get_arg_type (unsigned idx) const;
- const svalue *get_arg_svalue (unsigned idx) const;
- const char *get_arg_string_literal (unsigned idx) const;
-
- tree get_fndecl_for_call () const;
-
- void dump_to_pp (pretty_printer *pp, bool simple) const;
- void dump (bool simple) const;
-
- const svalue *get_or_create_conjured_svalue (const region *) const;
-
-private:
- const gcall *m_call;
- region_model *m_model;
- region_model_context *m_ctxt;
- tree m_lhs_type;
- const region *m_lhs_region;
-};
+typedef void (*pop_frame_callback) (const region_model *model,
+ const region_model *prev_model,
+ const svalue *retval,
+ region_model_context *ctxt);
/* A region_model encapsulates a representation of the state of memory, with
a tree of regions, along with their associated values.
void debug () const;
+ json::object *to_json () const;
+
void validate () const;
void canonicalize ();
void
on_stmt_pre (const gimple *stmt,
- bool *out_terminate_path,
bool *out_unknown_side_effects,
region_model_context *ctxt);
const svalue *get_gassign_result (const gassign *assign,
region_model_context *ctxt);
void on_asm_stmt (const gasm *asm_stmt, region_model_context *ctxt);
- bool on_call_pre (const gcall *stmt, region_model_context *ctxt,
- bool *out_terminate_path);
+ bool on_call_pre (const gcall *stmt, region_model_context *ctxt);
void on_call_post (const gcall *stmt,
bool unknown_side_effects,
region_model_context *ctxt);
void purge_state_involving (const svalue *sval, region_model_context *ctxt);
- /* Specific handling for on_call_pre. */
- void impl_call_alloca (const call_details &cd);
- void impl_call_analyzer_describe (const gcall *call,
- region_model_context *ctxt);
- void impl_call_analyzer_dump_capacity (const gcall *call,
- region_model_context *ctxt);
- void impl_call_analyzer_dump_escaped (const gcall *call);
- void impl_call_analyzer_eval (const gcall *call,
- region_model_context *ctxt);
- void impl_call_builtin_expect (const call_details &cd);
- void impl_call_calloc (const call_details &cd);
- bool impl_call_error (const call_details &cd, unsigned min_args,
- bool *out_terminate_path);
- void impl_call_fgets (const call_details &cd);
- void impl_call_fread (const call_details &cd);
- void impl_call_free (const call_details &cd);
- void impl_call_malloc (const call_details &cd);
- void impl_call_memcpy (const call_details &cd);
- void impl_call_memset (const call_details &cd);
- void impl_call_realloc (const call_details &cd);
- void impl_call_strchr (const call_details &cd);
- void impl_call_strcpy (const call_details &cd);
- void impl_call_strlen (const call_details &cd);
- void impl_call_operator_new (const call_details &cd);
- void impl_call_operator_delete (const call_details &cd);
void impl_deallocation_call (const call_details &cd);
+ const svalue *maybe_get_copy_bounds (const region *src_reg,
+ const svalue *num_bytes_sval);
+ void update_for_int_cst_return (const call_details &cd,
+ int retval,
+ bool unmergeable);
+ void update_for_zero_return (const call_details &cd,
+ bool unmergeable);
+ void update_for_nonzero_return (const call_details &cd);
+
void handle_unrecognized_call (const gcall *call,
region_model_context *ctxt);
void get_reachable_svalues (svalue_set *out,
void handle_phi (const gphi *phi, tree lhs, tree rhs,
const region_model &old_state,
+ hash_set<const svalue *> &svals_changing_meaning,
region_model_context *ctxt);
bool maybe_update_for_edge (const superedge &edge,
const gimple *last_stmt,
region_model_context *ctxt,
- rejected_constraint **out);
+ std::unique_ptr<rejected_constraint> *out);
void update_for_gcall (const gcall *call_stmt,
region_model_context *ctxt,
region_model_context *ctxt);
const frame_region *get_current_frame () const { return m_current_frame; }
function * get_current_function () const;
- void pop_frame (const region *result_dst,
+ void pop_frame (tree result_lvalue,
const svalue **out_result,
- region_model_context *ctxt);
+ region_model_context *ctxt,
+ bool eval_return_svalue = true);
int get_stack_depth () const;
const frame_region *get_frame_at_index (int index) const;
const svalue *get_rvalue (tree expr, region_model_context *ctxt) const;
const region *deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
- region_model_context *ctxt) const;
+ region_model_context *ctxt,
+ bool add_nonnull_constraint = true) const;
const svalue *get_rvalue_for_bits (tree type,
const region *reg,
void set_value (tree lhs, tree rhs, region_model_context *ctxt);
void clobber_region (const region *reg);
void purge_region (const region *reg);
- void fill_region (const region *reg, const svalue *sval);
- void zero_fill_region (const region *reg);
+ void fill_region (const region *reg,
+ const svalue *sval,
+ region_model_context *ctxt);
+ void zero_fill_region (const region *reg,
+ region_model_context *ctxt);
+ void write_bytes (const region *dest_reg,
+ const svalue *num_bytes_sval,
+ const svalue *sval,
+ region_model_context *ctxt);
+ const svalue *read_bytes (const region *src_reg,
+ tree src_ptr_expr,
+ const svalue *num_bytes_sval,
+ region_model_context *ctxt) const;
+ void copy_bytes (const region *dest_reg,
+ const region *src_reg,
+ tree src_ptr_expr,
+ const svalue *num_bytes_sval,
+ region_model_context *ctxt);
void mark_region_as_unknown (const region *reg, uncertainty_t *uncertainty);
tristate eval_condition (const svalue *lhs,
enum tree_code op,
const svalue *rhs) const;
- tristate eval_condition_without_cm (const svalue *lhs,
- enum tree_code op,
- const svalue *rhs) const;
tristate compare_initial_and_pointer (const initial_svalue *init,
const region_svalue *ptr) const;
+ tristate symbolic_greater_than (const binop_svalue *a,
+ const svalue *b) const;
+ tristate structural_equality (const svalue *a, const svalue *b) const;
tristate eval_condition (tree lhs,
enum tree_code op,
tree rhs,
- region_model_context *ctxt);
+ region_model_context *ctxt) const;
bool add_constraint (tree lhs, enum tree_code op, tree rhs,
region_model_context *ctxt);
bool add_constraint (tree lhs, enum tree_code op, tree rhs,
region_model_context *ctxt,
- rejected_constraint **out);
+ std::unique_ptr<rejected_constraint> *out);
+
+ const region *
+ get_or_create_region_for_heap_alloc (const svalue *size_in_bytes,
+ region_model_context *ctxt,
+ bool update_state_machine = false,
+ const call_details *cd = nullptr);
- const region *create_region_for_heap_alloc (const svalue *size_in_bytes,
- region_model_context *ctxt);
const region *create_region_for_alloca (const svalue *size_in_bytes,
region_model_context *ctxt);
+ void get_referenced_base_regions (auto_bitmap &out_ids) const;
tree get_representative_tree (const svalue *sval) const;
+ tree get_representative_tree (const region *reg) const;
path_var
get_representative_path_var (const svalue *sval,
svalue_set *visited) const;
tree get_fndecl_for_call (const gcall *call,
region_model_context *ctxt);
- void get_ssa_name_regions_for_current_frame
- (auto_vec<const decl_region *> *out) const;
- static void append_ssa_names_cb (const region *base_reg,
- struct append_ssa_names_cb_data *data);
+ void get_regions_for_current_frame (auto_vec<const decl_region *> *out) const;
+ static void append_regions_cb (const region *base_reg,
+ struct append_regions_cb_data *data);
const svalue *get_store_value (const region *reg,
region_model_context *ctxt) const;
+ const svalue *get_store_bytes (const region *base_reg,
+ const byte_range &bytes,
+ region_model_context *ctxt) const;
+ const svalue *scan_for_null_terminator (const region *reg,
+ tree expr,
+ const svalue **out_sval,
+ region_model_context *ctxt) const;
bool region_exists_p (const region *reg) const;
const svalue *get_capacity (const region *reg) const;
+ bool replay_call_summary (call_summary_replay &r,
+ const region_model &summary);
+
+ void maybe_complain_about_infoleak (const region *dst_reg,
+ const svalue *copied_sval,
+ const region *src_reg,
+ region_model_context *ctxt);
+
+ void set_errno (const call_details &cd);
+
+ /* Implemented in sm-fd.cc */
+ void mark_as_valid_fd (const svalue *sval, region_model_context *ctxt);
+
/* Implemented in sm-malloc.cc */
void on_realloc_with_move (const call_details &cd,
const svalue *old_ptr_sval,
const svalue *new_ptr_sval);
- private:
+ /* Implemented in sm-malloc.cc. */
+ void
+ transition_ptr_sval_non_null (region_model_context *ctxt,
+ const svalue *new_ptr_sval);
+
+ /* Implemented in sm-taint.cc. */
+ void mark_as_tainted (const svalue *sval,
+ region_model_context *ctxt);
+
+ bool add_constraint (const svalue *lhs,
+ enum tree_code op,
+ const svalue *rhs,
+ region_model_context *ctxt);
+
+ const svalue *check_for_poison (const svalue *sval,
+ tree expr,
+ const region *src_region,
+ region_model_context *ctxt) const;
+
+ void check_region_for_write (const region *dest_reg,
+ const svalue *sval_hint,
+ region_model_context *ctxt) const;
+
+ const svalue *
+ check_for_null_terminated_string_arg (const call_details &cd,
+ unsigned idx) const;
+ const svalue *
+ check_for_null_terminated_string_arg (const call_details &cd,
+ unsigned idx,
+ bool include_terminator,
+ const svalue **out_sval) const;
+
+ const builtin_known_function *
+ get_builtin_kf (const gcall *call,
+ region_model_context *ctxt = NULL) const;
+
+ static void
+ register_pop_frame_callback (const pop_frame_callback &callback)
+ {
+ pop_frame_callbacks.safe_push (callback);
+ }
+
+ static void
+ notify_on_pop_frame (const region_model *model,
+ const region_model *prev_model,
+ const svalue *retval,
+ region_model_context *ctxt)
+ {
+ for (auto &callback : pop_frame_callbacks)
+ callback (model, prev_model, retval, ctxt);
+ }
+
+ bool called_from_main_p () const;
+
+private:
const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const;
const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const;
get_representative_path_var_1 (const region *reg,
svalue_set *visited) const;
- bool add_constraint (const svalue *lhs,
- enum tree_code op,
- const svalue *rhs,
- region_model_context *ctxt);
+ const known_function *get_known_function (tree fndecl,
+ const call_details &cd) const;
+ const known_function *get_known_function (enum internal_fn) const;
+
bool add_constraints_from_binop (const svalue *outer_lhs,
enum tree_code outer_op,
const svalue *outer_rhs,
region_model_context *ctxt);
void update_for_return_superedge (const return_superedge &return_edge,
region_model_context *ctxt);
- void update_for_call_summary (const callgraph_superedge &cg_sedge,
- region_model_context *ctxt);
bool apply_constraints_for_gcond (const cfg_superedge &edge,
const gcond *cond_stmt,
region_model_context *ctxt,
- rejected_constraint **out);
+ std::unique_ptr<rejected_constraint> *out);
bool apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
const gswitch *switch_stmt,
region_model_context *ctxt,
- rejected_constraint **out);
+ std::unique_ptr<rejected_constraint> *out);
+ bool apply_constraints_for_ggoto (const cfg_superedge &edge,
+ const ggoto *goto_stmt,
+ region_model_context *ctxt);
bool apply_constraints_for_exception (const gimple *last_stmt,
region_model_context *ctxt,
- rejected_constraint **out);
+ std::unique_ptr<rejected_constraint> *out);
int poison_any_pointers_to_descendents (const region *reg,
enum poison_kind pkind);
- void on_top_level_param (tree param, region_model_context *ctxt);
+ void on_top_level_param (tree param,
+ bool nonnull,
+ region_model_context *ctxt);
- bool called_from_main_p () const;
const svalue *get_initial_value_for_global (const region *reg) const;
- const svalue *check_for_poison (const svalue *sval,
- tree expr,
- region_model_context *ctxt) const;
const region * get_region_for_poisoned_expr (tree expr) const;
void check_dynamic_size_for_taint (enum memory_space mem_space,
const svalue *size_in_bytes,
region_model_context *ctxt) const;
+ void check_dynamic_size_for_floats (const svalue *size_in_bytes,
+ region_model_context *ctxt) const;
void check_region_for_taint (const region *reg,
enum access_direction dir,
void check_for_writable_region (const region* dest_reg,
region_model_context *ctxt) const;
- void check_region_access (const region *reg,
+ bool check_region_access (const region *reg,
enum access_direction dir,
+ const svalue *sval_hint,
region_model_context *ctxt) const;
- void check_region_for_write (const region *dest_reg,
- region_model_context *ctxt) const;
- void check_region_for_read (const region *src_reg,
+ bool check_region_for_read (const region *src_reg,
+ region_model_context *ctxt) const;
+ void check_region_size (const region *lhs_reg, const svalue *rhs_sval,
+ region_model_context *ctxt) const;
+
+ /* Implemented in bounds-checking.cc */
+ bool check_symbolic_bounds (const region *base_reg,
+ const svalue *sym_byte_offset,
+ const svalue *num_bytes_sval,
+ const svalue *capacity,
+ enum access_direction dir,
+ const svalue *sval_hint,
region_model_context *ctxt) const;
+ bool check_region_bounds (const region *reg, enum access_direction dir,
+ const svalue *sval_hint,
+ region_model_context *ctxt) const;
void check_call_args (const call_details &cd) const;
-
+ void check_call_format_attr (const call_details &cd,
+ tree format_attr) const;
+ void check_function_attr_access (const gcall *call,
+ tree callee_fndecl,
+ region_model_context *ctxt,
+ rdwr_map &rdwr_idx) const;
+ void check_function_attr_null_terminated_string_arg (const gcall *call,
+ tree callee_fndecl,
+ region_model_context *ctxt,
+ rdwr_map &rdwr_idx);
+ void check_one_function_attr_null_terminated_string_arg (const gcall *call,
+ tree callee_fndecl,
+ region_model_context *ctxt,
+ rdwr_map &rdwr_idx,
+ tree attr);
+ void check_function_attrs (const gcall *call,
+ tree callee_fndecl,
+ region_model_context *ctxt);
+
+ static auto_vec<pop_frame_callback> pop_frame_callbacks;
/* Storing this here to avoid passing it around everywhere. */
region_model_manager *const m_mgr;
{
public:
/* Hook for clients to store pending diagnostics.
- Return true if the diagnostic was stored, or false if it was deleted. */
- virtual bool warn (pending_diagnostic *d) = 0;
+ Return true if the diagnostic was stored, or false if it was deleted.
+ Optionally provide a custom stmt_finder. */
+ virtual bool warn (std::unique_ptr<pending_diagnostic> d,
+ const stmt_finder *custom_finder = NULL) = 0;
+
+ /* Hook for clients to add a note to the last previously stored
+ pending diagnostic. */
+ virtual void add_note (std::unique_ptr<pending_note> pn) = 0;
+
+ /* Hook for clients to add an event to the last previously stored
+ pending diagnostic. */
+ virtual void add_event (std::unique_ptr<checker_event> event) = 0;
/* Hook for clients to be notified when an SVAL that was reachable
in a previous state is no longer live, so that clients can emit warnings
enum tree_code op,
const svalue *rhs) = 0;
+ /* Hook for clients to be notified when the condition that
+ SVAL is within RANGES is added to the region model.
+ Similar to on_condition, but for use when handling switch statements.
+ RANGES is non-empty. */
+ virtual void on_bounded_ranges (const svalue &sval,
+ const bounded_ranges &ranges) = 0;
+
+ /* Hook for clients to be notified when a frame is popped from the stack. */
+ virtual void on_pop_frame (const frame_region *) = 0;
+
/* Hooks for clients to be notified when an unknown change happens
to SVAL (in response to a call to an unknown function). */
virtual void on_unknown_change (const svalue *sval, bool is_mutable) = 0;
/* Hook for clients to purge state involving SVAL. */
virtual void purge_state_involving (const svalue *sval) = 0;
- /* Hook for clients to split state with a non-standard path.
- Take ownership of INFO. */
- virtual void bifurcate (custom_edge_info *info) = 0;
+ /* Hook for clients to split state with a non-standard path. */
+ virtual void bifurcate (std::unique_ptr<custom_edge_info> info) = 0;
/* Hook for clients to terminate the standard path. */
virtual void terminate_path () = 0;
virtual const extrinsic_state *get_ext_state () const = 0;
- /* Hook for clients to access the "malloc" state machine in
+ /* Hook for clients to access the a specific state machine in
any underlying program_state. */
- virtual bool get_malloc_map (sm_state_map **out_smap,
- const state_machine **out_sm,
- unsigned *out_sm_idx) = 0;
- /* Likewise for the "taint" state machine. */
- virtual bool get_taint_map (sm_state_map **out_smap,
- const state_machine **out_sm,
- unsigned *out_sm_idx) = 0;
+ virtual bool
+ get_state_map_by_name (const char *name,
+ sm_state_map **out_smap,
+ const state_machine **out_sm,
+ unsigned *out_sm_idx,
+ std::unique_ptr<sm_context> *out_sm_context) = 0;
+
+ /* Precanned ways for clients to access specific state machines. */
+ bool get_fd_map (sm_state_map **out_smap,
+ const state_machine **out_sm,
+ unsigned *out_sm_idx,
+ std::unique_ptr<sm_context> *out_sm_context)
+ {
+ return get_state_map_by_name ("file-descriptor", out_smap, out_sm,
+ out_sm_idx, out_sm_context);
+ }
+ bool get_malloc_map (sm_state_map **out_smap,
+ const state_machine **out_sm,
+ unsigned *out_sm_idx)
+ {
+ return get_state_map_by_name ("malloc", out_smap, out_sm, out_sm_idx, NULL);
+ }
+ bool get_taint_map (sm_state_map **out_smap,
+ const state_machine **out_sm,
+ unsigned *out_sm_idx)
+ {
+ return get_state_map_by_name ("taint", out_smap, out_sm, out_sm_idx, NULL);
+ }
+
+ bool possibly_tainted_p (const svalue *sval);
/* Get the current statement, if any. */
virtual const gimple *get_stmt () const = 0;
+
+ virtual const exploded_graph *get_eg () const = 0;
+
+ /* Hooks for detecting infinite loops. */
+ virtual void maybe_did_work () = 0;
+ virtual bool checking_for_infinite_loop_p () const = 0;
+ virtual void on_unusable_in_infinite_loop () = 0;
};
/* A "do nothing" subclass of region_model_context. */
class noop_region_model_context : public region_model_context
{
public:
- bool warn (pending_diagnostic *) OVERRIDE { return false; }
- void on_svalue_leak (const svalue *) OVERRIDE {}
+ bool warn (std::unique_ptr<pending_diagnostic>,
+ const stmt_finder *) override { return false; }
+ void add_note (std::unique_ptr<pending_note>) override;
+ void add_event (std::unique_ptr<checker_event>) override;
+ void on_svalue_leak (const svalue *) override {}
void on_liveness_change (const svalue_set &,
- const region_model *) OVERRIDE {}
- logger *get_logger () OVERRIDE { return NULL; }
+ const region_model *) override {}
+ logger *get_logger () override { return NULL; }
void on_condition (const svalue *lhs ATTRIBUTE_UNUSED,
enum tree_code op ATTRIBUTE_UNUSED,
- const svalue *rhs ATTRIBUTE_UNUSED) OVERRIDE
+ const svalue *rhs ATTRIBUTE_UNUSED) override
+ {
+ }
+ void on_bounded_ranges (const svalue &,
+ const bounded_ranges &) override
{
}
+ void on_pop_frame (const frame_region *) override {}
void on_unknown_change (const svalue *sval ATTRIBUTE_UNUSED,
- bool is_mutable ATTRIBUTE_UNUSED) OVERRIDE
+ bool is_mutable ATTRIBUTE_UNUSED) override
{
}
void on_phi (const gphi *phi ATTRIBUTE_UNUSED,
- tree rhs ATTRIBUTE_UNUSED) OVERRIDE
+ tree rhs ATTRIBUTE_UNUSED) override
{
}
- void on_unexpected_tree_code (tree, const dump_location_t &) OVERRIDE {}
+ void on_unexpected_tree_code (tree, const dump_location_t &) override {}
- void on_escaped_function (tree) OVERRIDE {}
+ void on_escaped_function (tree) override {}
- uncertainty_t *get_uncertainty () OVERRIDE { return NULL; }
+ uncertainty_t *get_uncertainty () override { return NULL; }
- void purge_state_involving (const svalue *sval ATTRIBUTE_UNUSED) OVERRIDE {}
+ void purge_state_involving (const svalue *sval ATTRIBUTE_UNUSED) override {}
- void bifurcate (custom_edge_info *info) OVERRIDE;
- void terminate_path () OVERRIDE;
+ void bifurcate (std::unique_ptr<custom_edge_info> info) override;
+ void terminate_path () override;
- const extrinsic_state *get_ext_state () const OVERRIDE { return NULL; }
+ const extrinsic_state *get_ext_state () const override { return NULL; }
- bool get_malloc_map (sm_state_map **,
- const state_machine **,
- unsigned *) OVERRIDE
- {
- return false;
- }
- bool get_taint_map (sm_state_map **,
- const state_machine **,
- unsigned *) OVERRIDE
+ bool get_state_map_by_name (const char *,
+ sm_state_map **,
+ const state_machine **,
+ unsigned *,
+ std::unique_ptr<sm_context> *) override
{
return false;
}
- const gimple *get_stmt () const OVERRIDE { return NULL; }
+ const gimple *get_stmt () const override { return NULL; }
+ const exploded_graph *get_eg () const override { return NULL; }
+ void maybe_did_work () override {}
+ bool checking_for_infinite_loop_p () const override { return false; }
+ void on_unusable_in_infinite_loop () override {}
};
/* A subclass of region_model_context for determining if operations fail
tentative_region_model_context () : m_num_unexpected_codes (0) {}
void on_unexpected_tree_code (tree, const dump_location_t &)
- FINAL OVERRIDE
+ final override
{
m_num_unexpected_codes++;
}
int m_num_unexpected_codes;
};
+/* Subclass of region_model_context that wraps another context, allowing
+ for extra code to be added to the various hooks. */
+
+class region_model_context_decorator : public region_model_context
+{
+ public:
+ bool warn (std::unique_ptr<pending_diagnostic> d,
+ const stmt_finder *custom_finder) override
+ {
+ if (m_inner)
+ return m_inner->warn (std::move (d), custom_finder);
+ else
+ return false;
+ }
+
+ void add_note (std::unique_ptr<pending_note> pn) override
+ {
+ if (m_inner)
+ m_inner->add_note (std::move (pn));
+ }
+ void add_event (std::unique_ptr<checker_event> event) override;
+
+ void on_svalue_leak (const svalue *sval) override
+ {
+ if (m_inner)
+ m_inner->on_svalue_leak (sval);
+ }
+
+ void on_liveness_change (const svalue_set &live_svalues,
+ const region_model *model) override
+ {
+ if (m_inner)
+ m_inner->on_liveness_change (live_svalues, model);
+ }
+
+ logger *get_logger () override
+ {
+ if (m_inner)
+ return m_inner->get_logger ();
+ else
+ return nullptr;
+ }
+
+ void on_condition (const svalue *lhs,
+ enum tree_code op,
+ const svalue *rhs) override
+ {
+ if (m_inner)
+ m_inner->on_condition (lhs, op, rhs);
+ }
+
+ void on_bounded_ranges (const svalue &sval,
+ const bounded_ranges &ranges) override
+ {
+ if (m_inner)
+ m_inner->on_bounded_ranges (sval, ranges);
+ }
+
+ void on_pop_frame (const frame_region *frame_reg) override
+ {
+ if (m_inner)
+ m_inner->on_pop_frame (frame_reg);
+ }
+
+ void on_unknown_change (const svalue *sval, bool is_mutable) override
+ {
+ if (m_inner)
+ m_inner->on_unknown_change (sval, is_mutable);
+ }
+
+ void on_phi (const gphi *phi, tree rhs) override
+ {
+ if (m_inner)
+ m_inner->on_phi (phi, rhs);
+ }
+
+ void on_unexpected_tree_code (tree t,
+ const dump_location_t &loc) override
+ {
+ if (m_inner)
+ m_inner->on_unexpected_tree_code (t, loc);
+ }
+
+ void on_escaped_function (tree fndecl) override
+ {
+ if (m_inner)
+ m_inner->on_escaped_function (fndecl);
+ }
+
+ uncertainty_t *get_uncertainty () override
+ {
+ if (m_inner)
+ return m_inner->get_uncertainty ();
+ else
+ return nullptr;
+ }
+
+ void purge_state_involving (const svalue *sval) override
+ {
+ if (m_inner)
+ m_inner->purge_state_involving (sval);
+ }
+
+ void bifurcate (std::unique_ptr<custom_edge_info> info) override
+ {
+ if (m_inner)
+ m_inner->bifurcate (std::move (info));
+ }
+
+ void terminate_path () override
+ {
+ if (m_inner)
+ m_inner->terminate_path ();
+ }
+
+ const extrinsic_state *get_ext_state () const override
+ {
+ if (m_inner)
+ return m_inner->get_ext_state ();
+ else
+ return nullptr;
+ }
+
+ bool get_state_map_by_name (const char *name,
+ sm_state_map **out_smap,
+ const state_machine **out_sm,
+ unsigned *out_sm_idx,
+ std::unique_ptr<sm_context> *out_sm_context)
+ override
+ {
+ if (m_inner)
+ return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx,
+ out_sm_context);
+ else
+ return false;
+ }
+
+ const gimple *get_stmt () const override
+ {
+ if (m_inner)
+ return m_inner->get_stmt ();
+ else
+ return nullptr;
+ }
+
+ const exploded_graph *get_eg () const override
+ {
+ if (m_inner)
+ return m_inner->get_eg ();
+ else
+ return nullptr;
+ }
+
+ void maybe_did_work () override
+ {
+ if (m_inner)
+ m_inner->maybe_did_work ();
+ }
+
+ bool checking_for_infinite_loop_p () const override
+ {
+ if (m_inner)
+ return m_inner->checking_for_infinite_loop_p ();
+ return false;
+ }
+ void on_unusable_in_infinite_loop () override
+ {
+ if (m_inner)
+ m_inner->on_unusable_in_infinite_loop ();
+ }
+
+protected:
+ region_model_context_decorator (region_model_context *inner)
+ : m_inner (inner)
+ {
+ }
+
+ region_model_context *m_inner;
+};
+
+/* Subclass of region_model_context_decorator with a hook for adding
+ notes/events when saving diagnostics. */
+
+class annotating_context : public region_model_context_decorator
+{
+public:
+ bool warn (std::unique_ptr<pending_diagnostic> d,
+ const stmt_finder *custom_finder) override
+ {
+ if (m_inner)
+ if (m_inner->warn (std::move (d), custom_finder))
+ {
+ add_annotations ();
+ return true;
+ }
+ return false;
+ }
+
+ /* Hook to add new event(s)/note(s) */
+ virtual void add_annotations () = 0;
+
+protected:
+ annotating_context (region_model_context *inner)
+ : region_model_context_decorator (inner)
+ {
+ }
+};
+
/* A bundle of data for use when attempting to merge two region_model
instances to make a third. */
}
bool mergeable_svalue_p (const svalue *) const;
+ const function_point &get_function_point () const
+ {
+ return m_point.get_function_point ();
+ }
+
+ void on_widening_reuse (const widening_svalue *widening_sval);
const region_model *m_model_a;
const region_model *m_model_b;
const extrinsic_state *m_ext_state;
const program_state *m_state_a;
const program_state *m_state_b;
+
+ hash_set<const svalue *> m_svals_changing_meaning;
};
/* A record that can (optionally) be written out when
m_lhs (lhs), m_op (op), m_rhs (rhs)
{}
- void dump_to_pp (pretty_printer *pp) const FINAL OVERRIDE;
+ void dump_to_pp (pretty_printer *pp) const final override;
tree m_lhs;
enum tree_code m_op;
tree m_rhs;
};
+class rejected_default_case : public rejected_constraint
+{
+public:
+ rejected_default_case (const region_model &model)
+ : rejected_constraint (model)
+ {}
+
+ void dump_to_pp (pretty_printer *pp) const final override;
+};
+
class rejected_ranges_constraint : public rejected_constraint
{
public:
m_expr (expr), m_ranges (ranges)
{}
- void dump_to_pp (pretty_printer *pp) const FINAL OVERRIDE;
+ void dump_to_pp (pretty_printer *pp) const final override;
private:
tree m_expr;
class engine
{
public:
- engine (logger *logger = NULL);
+ engine (const supergraph *sg = NULL, logger *logger = NULL);
+ const supergraph *get_supergraph () { return m_sg; }
region_model_manager *get_model_manager () { return &m_mgr; }
+ known_function_manager *get_known_function_manager ()
+ {
+ return m_mgr.get_known_function_manager ();
+ }
void log_stats (logger *logger) const;
private:
+ const supergraph *m_sg;
region_model_manager m_mgr;
-
};
} // namespace ana
class test_region_model_context : public noop_region_model_context
{
public:
- bool warn (pending_diagnostic *d) FINAL OVERRIDE
+ bool warn (std::unique_ptr<pending_diagnostic> d,
+ const stmt_finder *) final override
{
- m_diagnostics.safe_push (d);
+ m_diagnostics.safe_push (d.release ());
return true;
}
unsigned get_num_diagnostics () const { return m_diagnostics.length (); }
void on_unexpected_tree_code (tree t, const dump_location_t &)
- FINAL OVERRIDE
+ final override
{
internal_error ("unhandled tree code: %qs",
get_tree_code_name (TREE_CODE (t)));