/* 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"
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;
-/* 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 *get_model () const { return m_model; }
- region_model_manager *get_manager () const;
- region_model_context *get_ctxt () const { return m_ctxt; }
- logger *get_logger () const;
-
- 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;
-
- 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_analyzer_get_unknown_ptr (const call_details &cd);
- void impl_call_builtin_expect (const call_details &cd);
- void impl_call_calloc (const call_details &cd);
- void impl_call_errno_location (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_pipe (const call_details &cd);
- void impl_call_putenv (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);
- /* Implemented in varargs.cc. */
- void impl_call_va_start (const call_details &cd);
- void impl_call_va_copy (const call_details &cd);
- void impl_call_va_arg (const call_details &cd);
- void impl_call_va_end (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,
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,
function * get_current_function () const;
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,
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;
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;
- 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);
const svalue *old_ptr_sval,
const svalue *new_ptr_sval);
+ /* 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);
- private:
+ 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;
- const known_function *get_known_function (tree fndecl) const;
+ 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_constraint (const svalue *lhs,
- enum tree_code op,
- const svalue *rhs,
- region_model_context *ctxt);
bool add_constraints_from_binop (const svalue *outer_lhs,
enum tree_code outer_op,
const svalue *outer_rhs,
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,
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;
- void check_symbolic_bounds (const region *base_reg,
+
+ /* 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;
- void check_region_bounds (const region *reg, enum access_direction dir,
+ 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_external_function_for_access_attr (const gcall *call,
- tree callee_fndecl,
- region_model_context *ctxt) 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 (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. */
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
about leaks. */
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 access the a specific state machine in
any underlying program_state. */
- virtual bool get_state_map_by_name (const char *name,
- 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)
+ 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_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);
+ 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);
+ 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 (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 {}
void on_liveness_change (const svalue_set &,
const region_model *) override {}
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 get_state_map_by_name (const char *,
sm_state_map **,
const state_machine **,
- unsigned *) override
+ unsigned *,
+ std::unique_ptr<sm_context> *) override
{
return false;
}
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
{
- return m_inner->warn (std::move (d));
+ 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
{
- m_inner->add_note (std::move (pn));
+ 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
{
- m_inner->on_svalue_leak (sval);
+ if (m_inner)
+ m_inner->on_svalue_leak (sval);
}
void on_liveness_change (const svalue_set &live_svalues,
const region_model *model) override
{
- m_inner->on_liveness_change (live_svalues, model);
+ if (m_inner)
+ m_inner->on_liveness_change (live_svalues, model);
}
logger *get_logger () override
{
- return m_inner->get_logger ();
+ 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
{
- m_inner->on_condition (lhs, op, rhs);
+ if (m_inner)
+ m_inner->on_condition (lhs, op, rhs);
}
void on_bounded_ranges (const svalue &sval,
const bounded_ranges &ranges) override
{
- m_inner->on_bounded_ranges (sval, ranges);
+ 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
{
- m_inner->on_unknown_change (sval, is_mutable);
+ if (m_inner)
+ m_inner->on_unknown_change (sval, is_mutable);
}
void on_phi (const gphi *phi, tree rhs) override
{
- m_inner->on_phi (phi, rhs);
+ if (m_inner)
+ m_inner->on_phi (phi, rhs);
}
void on_unexpected_tree_code (tree t,
const dump_location_t &loc) override
{
- m_inner->on_unexpected_tree_code (t, loc);
+ if (m_inner)
+ m_inner->on_unexpected_tree_code (t, loc);
}
void on_escaped_function (tree fndecl) override
{
- m_inner->on_escaped_function (fndecl);
+ if (m_inner)
+ m_inner->on_escaped_function (fndecl);
}
uncertainty_t *get_uncertainty () override
{
- return m_inner->get_uncertainty ();
+ if (m_inner)
+ return m_inner->get_uncertainty ();
+ else
+ return nullptr;
}
void purge_state_involving (const svalue *sval) override
{
- m_inner->purge_state_involving (sval);
+ if (m_inner)
+ m_inner->purge_state_involving (sval);
}
void bifurcate (std::unique_ptr<custom_edge_info> info) override
{
- m_inner->bifurcate (std::move (info));
+ if (m_inner)
+ m_inner->bifurcate (std::move (info));
}
void terminate_path () override
{
- m_inner->terminate_path ();
+ if (m_inner)
+ m_inner->terminate_path ();
}
const extrinsic_state *get_ext_state () const override
{
- return m_inner->get_ext_state ();
+ 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) override
+ unsigned *out_sm_idx,
+ std::unique_ptr<sm_context> *out_sm_context)
+ override
{
- return m_inner->get_state_map_by_name (name, out_smap, out_sm, out_sm_idx);
+ 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
{
- return m_inner->get_stmt ();
+ 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)
{
- gcc_assert (m_inner);
}
region_model_context *m_inner;
};
-/* Subclass of region_model_context_decorator that adds a note
- when saving diagnostics. */
+/* Subclass of region_model_context_decorator with a hook for adding
+ notes/events when saving diagnostics. */
-class note_adding_context : public region_model_context_decorator
+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->warn (std::move (d)))
- {
- add_note (make_note ());
- return true;
- }
- else
- return false;
+ if (m_inner)
+ if (m_inner->warn (std::move (d), custom_finder))
+ {
+ add_annotations ();
+ return true;
+ }
+ return false;
}
- /* Hook to make the new note. */
- virtual std::unique_ptr<pending_note> make_note () = 0;
+ /* Hook to add new event(s)/note(s) */
+ virtual void add_annotations () = 0;
protected:
- note_adding_context (region_model_context *inner)
+ annotating_context (region_model_context *inner)
: region_model_context_decorator (inner)
{
}
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
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:
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;