/* Classes for modeling the state of memory.
- Copyright (C) 2019-2023 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.
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"
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;
struct append_regions_cb_data;
+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.
The representation is graph-like because values can be pointers to
void debug () const;
+ json::object *to_json () const;
+
void validate () const;
void canonicalize ();
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,
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,
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,
const svalue *get_capacity (const region *reg) const;
- const svalue *get_string_size (const svalue *sval) const;
- const svalue *get_string_size (const region *reg) const;
-
bool replay_call_summary (call_summary_replay &r,
const region_model &summary);
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,
- const svalue **out_sval = nullptr);
+ 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;
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);
bool nonnull,
region_model_context *ctxt);
- bool called_from_main_p () const;
const svalue *get_initial_value_for_global (const region *reg) const;
const region * get_region_for_poisoned_expr (tree expr) 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_external_function_for_access_attr (const gcall *call,
- tree callee_fndecl,
- region_model_context *ctxt) 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 (std::unique_ptr<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. */
/* 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 (std::unique_ptr<pending_diagnostic>) override { return false; }
+ 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 {}
}
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
class region_model_context_decorator : public region_model_context
{
public:
- bool warn (std::unique_ptr<pending_diagnostic> d) override
+ bool warn (std::unique_ptr<pending_diagnostic> d,
+ const stmt_finder *custom_finder) override
{
if (m_inner)
- return m_inner->warn (std::move (d));
+ return m_inner->warn (std::move (d), custom_finder);
else
return false;
}
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)
class annotating_context : public region_model_context_decorator
{
public:
- bool warn (std::unique_ptr<pending_diagnostic> d) override
+ bool warn (std::unique_ptr<pending_diagnostic> d,
+ const stmt_finder *custom_finder) override
{
if (m_inner)
- if (m_inner->warn (std::move (d)))
+ if (m_inner->warn (std::move (d), custom_finder))
{
add_annotations ();
return true;
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 program_point &m_point;
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
class test_region_model_context : public noop_region_model_context
{
public:
- bool warn (std::unique_ptr<pending_diagnostic> d) final override
+ bool warn (std::unique_ptr<pending_diagnostic> d,
+ const stmt_finder *) final override
{
m_diagnostics.safe_push (d.release ());
return true;