aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/common.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/analyzer/common.h')
-rw-r--r--gcc/analyzer/common.h603
1 files changed, 603 insertions, 0 deletions
diff --git a/gcc/analyzer/common.h b/gcc/analyzer/common.h
new file mode 100644
index 0000000..cb03004
--- /dev/null
+++ b/gcc/analyzer/common.h
@@ -0,0 +1,603 @@
+/* Base header for the analyzer, plus utility functions.
+ Copyright (C) 2019-2025 Free Software Foundation, Inc.
+ Contributed by David Malcolm <dmalcolm@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+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/>. */
+
+#ifndef GCC_ANALYZER_COMMON_H
+#define GCC_ANALYZER_COMMON_H
+
+#include "config.h"
+#define INCLUDE_VECTOR
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "options.h"
+#include "bitmap.h"
+#include "diagnostic-core.h"
+#include "diagnostic-path.h"
+#include "rich-location.h"
+#include "function.h"
+#include "json.h"
+#include "tristate.h"
+
+class graphviz_out;
+
+namespace ana {
+
+/* Forward decls of common types, with indentation to show inheritance. */
+
+class supergraph;
+class supernode;
+class superedge;
+ class cfg_superedge;
+ class switch_cfg_superedge;
+ class eh_dispatch_cfg_superedge;
+ class eh_dispatch_try_cfg_superedge;
+ class eh_dispatch_allowed_cfg_superedge;
+ class callgraph_superedge;
+ class call_superedge;
+ class return_superedge;
+
+class svalue;
+ class region_svalue;
+ class constant_svalue;
+ class unknown_svalue;
+ class poisoned_svalue;
+ class setjmp_svalue;
+ class initial_svalue;
+ class unaryop_svalue;
+ class binop_svalue;
+ class sub_svalue;
+ class repeated_svalue;
+ class bits_within_svalue;
+ class unmergeable_svalue;
+ class placeholder_svalue;
+ class widening_svalue;
+ class compound_svalue;
+ class conjured_svalue;
+ class asm_output_svalue;
+ class const_fn_result_svalue;
+typedef hash_set<const svalue *> svalue_set;
+class region;
+ class frame_region;
+ class function_region;
+ class label_region;
+ class decl_region;
+ class symbolic_region;
+ class element_region;
+ class offset_region;
+ class sized_region;
+ class cast_region;
+ class field_region;
+ class string_region;
+ class bit_range_region;
+ class var_arg_region;
+class region_model_manager;
+class conjured_purge;
+struct model_merger;
+class store_manager;
+class store;
+class region_model;
+class region_model_context;
+ class impl_region_model_context;
+class call_details;
+class rejected_constraint;
+class constraint_manager;
+class equiv_class;
+class reachable_regions;
+class bounded_ranges;
+class bounded_ranges_manager;
+
+struct pending_location;
+class pending_diagnostic;
+class pending_note;
+class saved_diagnostic;
+struct event_loc_info;
+class checker_event;
+ class state_change_event;
+ class warning_event;
+class checker_path;
+class extrinsic_state;
+class sm_state_map;
+class stmt_finder;
+class program_point;
+class function_point;
+class program_state;
+class exploded_graph;
+class exploded_node;
+class exploded_edge;
+class feasibility_problem;
+class exploded_cluster;
+class exploded_path;
+class analysis_plan;
+class state_purge_map;
+class state_purge_per_ssa_name;
+class state_purge_per_decl;
+class state_change;
+class rewind_info_t;
+
+class engine;
+class state_machine;
+class logger;
+class visitor;
+class known_function_manager;
+class call_summary;
+class call_summary_replay;
+struct per_function_data;
+struct interesting_t;
+
+class feasible_node;
+
+class known_function;
+ class builtin_known_function;
+ class internal_known_function;
+
+/* Forward decls of functions. */
+
+extern void dump_tree (pretty_printer *pp, tree t);
+extern void dump_quoted_tree (pretty_printer *pp, tree t);
+extern void print_quoted_type (pretty_printer *pp, tree t);
+extern void print_expr_for_user (pretty_printer *pp, tree t);
+extern int readability_comparator (const void *p1, const void *p2);
+extern int tree_cmp (const void *p1, const void *p2);
+extern tree fixup_tree_for_diagnostic (tree);
+extern tree get_diagnostic_tree_for_gassign (const gassign *);
+
+/* A tree, extended with stack frame information for locals, so that
+ we can distinguish between different values of locals within a potentially
+ recursive callstack. */
+
+class path_var
+{
+public:
+ path_var (tree t, int stack_depth)
+ : m_tree (t), m_stack_depth (stack_depth)
+ {
+ // TODO: ignore stack depth for globals and constants
+ }
+
+ bool operator== (const path_var &other) const
+ {
+ return (m_tree == other.m_tree
+ && m_stack_depth == other.m_stack_depth);
+ }
+
+ operator bool () const
+ {
+ return m_tree != NULL_TREE;
+ }
+
+ void dump (pretty_printer *pp) const;
+
+ tree m_tree;
+ int m_stack_depth; // or -1 for globals?
+};
+
+typedef offset_int bit_offset_t;
+typedef offset_int bit_size_t;
+typedef offset_int byte_offset_t;
+typedef offset_int byte_size_t;
+
+extern bool int_size_in_bits (const_tree type, bit_size_t *out);
+
+extern tree get_field_at_bit_offset (tree record_type, bit_offset_t bit_offset);
+
+/* The location of a region expressesd as an offset relative to a
+ base region. */
+
+class region_offset
+{
+public:
+ region_offset ()
+ : m_base_region (NULL), m_offset (0), m_sym_offset (NULL)
+ {
+ }
+
+ static region_offset make_concrete (const region *base_region,
+ bit_offset_t offset)
+ {
+ return region_offset (base_region, offset, NULL);
+ }
+ static region_offset make_symbolic (const region *base_region,
+ const svalue *sym_offset)
+ {
+ return region_offset (base_region, 0, sym_offset);
+ }
+ static region_offset make_byte_offset (const region *base_region,
+ const svalue *num_bytes_sval);
+
+ const region *get_base_region () const { return m_base_region; }
+
+ bool concrete_p () const { return m_sym_offset == NULL; }
+ bool symbolic_p () const { return m_sym_offset != NULL; }
+
+ bit_offset_t get_bit_offset () const
+ {
+ gcc_assert (!symbolic_p ());
+ return m_offset;
+ }
+
+ bool get_concrete_byte_offset (byte_offset_t *out) const
+ {
+ gcc_assert (!symbolic_p ());
+ if (m_offset % BITS_PER_UNIT == 0)
+ {
+ *out = m_offset / BITS_PER_UNIT;
+ return true;
+ }
+ return false;
+ }
+
+ const svalue *get_symbolic_byte_offset () const
+ {
+ gcc_assert (symbolic_p ());
+ return m_sym_offset;
+ }
+
+ const svalue &calc_symbolic_bit_offset (region_model_manager *mgr) const;
+ const svalue *calc_symbolic_byte_offset (region_model_manager *mgr) const;
+
+ bool operator== (const region_offset &other) const
+ {
+ return (m_base_region == other.m_base_region
+ && m_offset == other.m_offset
+ && m_sym_offset == other.m_sym_offset);
+ }
+
+ void dump_to_pp (pretty_printer *pp, bool) const;
+ void dump (bool) const;
+
+private:
+ region_offset (const region *base_region, bit_offset_t offset,
+ const svalue *sym_offset)
+ : m_base_region (base_region), m_offset (offset), m_sym_offset (sym_offset)
+ {}
+
+ const region *m_base_region;
+ bit_offset_t m_offset;
+ const svalue *m_sym_offset;
+};
+
+extern bool operator< (const region_offset &, const region_offset &);
+extern bool operator<= (const region_offset &, const region_offset &);
+extern bool operator> (const region_offset &, const region_offset &);
+extern bool operator>= (const region_offset &, const region_offset &);
+
+extern location_t get_stmt_location (const gimple *stmt, function *fun);
+
+extern bool compat_types_p (tree src_type, tree dst_type);
+
+/* Abstract base class for simulating the behavior of known functions,
+ supplied by the core of the analyzer, or by plugins.
+ The former are typically implemented in the various kf*.cc */
+
+class known_function
+{
+public:
+ virtual ~known_function () {}
+ virtual bool matches_call_types_p (const call_details &cd) const = 0;
+ virtual void impl_call_pre (const call_details &) const
+ {
+ return;
+ }
+ virtual void impl_call_post (const call_details &) const
+ {
+ return;
+ }
+
+ virtual const builtin_known_function *
+ dyn_cast_builtin_kf () const { return NULL; }
+};
+
+/* Subclass of known_function for builtin functions. */
+
+class builtin_known_function : public known_function
+{
+public:
+ virtual enum built_in_function builtin_code () const = 0;
+ tree builtin_decl () const {
+ gcc_assert (builtin_code () < END_BUILTINS);
+ return builtin_info[builtin_code ()].decl;
+ }
+
+ const builtin_known_function *
+ dyn_cast_builtin_kf () const final override { return this; }
+};
+
+/* Subclass of known_function for IFN_* functions. */
+
+class internal_known_function : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &) const final override
+ {
+ /* Types are assumed to be correct. */
+ return true;
+ }
+};
+
+/* Abstract subclass of known_function that merely sets the return
+ value of the function (based on function attributes), and assumes
+ it has no side-effects. */
+
+class pure_known_function_with_default_return : public known_function
+{
+public:
+ void impl_call_pre (const call_details &cd) const override;
+};
+
+extern void register_known_functions (known_function_manager &kfm,
+ region_model_manager &rmm);
+extern void register_known_analyzer_functions (known_function_manager &kfm);
+extern void register_known_fd_functions (known_function_manager &kfm);
+extern void register_known_file_functions (known_function_manager &kfm);
+extern void register_known_functions_lang_cp (known_function_manager &kfm);
+extern void register_varargs_builtins (known_function_manager &kfm);
+
+/* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks. */
+
+class plugin_analyzer_init_iface
+{
+public:
+ virtual void register_state_machine (std::unique_ptr<state_machine>) = 0;
+ virtual void register_known_function (const char *name,
+ std::unique_ptr<known_function>) = 0;
+ virtual logger *get_logger () const = 0;
+};
+
+/* An enum for describing the direction of an access to memory. */
+
+enum class access_direction
+{
+ read,
+ write
+};
+
+/* Abstract base class for associating custom data with an
+ exploded_edge, for handling non-standard edges such as
+ rewinding from a longjmp, signal handlers, etc.
+ Also used when "bifurcating" state: splitting the execution
+ path in non-standard ways (e.g. for simulating the various
+ outcomes of "realloc"). */
+
+class custom_edge_info
+{
+public:
+ virtual ~custom_edge_info () {}
+
+ /* Hook for making .dot label more readable. */
+ virtual void print (pretty_printer *pp) const = 0;
+
+ /* Hook for updating STATE when handling bifurcation. */
+ virtual bool update_state (program_state *state,
+ const exploded_edge *eedge,
+ region_model_context *ctxt) const;
+
+ /* Hook for updating MODEL within exploded_path::feasible_p
+ and when handling bifurcation. */
+ virtual bool update_model (region_model *model,
+ const exploded_edge *eedge,
+ region_model_context *ctxt) const = 0;
+
+ virtual void add_events_to_path (checker_path *emission_path,
+ const exploded_edge &eedge) const = 0;
+
+ virtual exploded_node *create_enode (exploded_graph &eg,
+ const program_point &point,
+ program_state &&state,
+ exploded_node *enode_for_diag,
+ region_model_context *ctxt) const;
+};
+
+/* Abstract base class for splitting state.
+
+ Most of the state-management code in the analyzer involves
+ modifying state objects in-place, which assumes a single outcome.
+
+ This class provides an escape hatch to allow for multiple outcomes
+ for such updates e.g. for modelling multiple outcomes from function
+ calls, such as the various outcomes of "realloc". */
+
+class path_context
+{
+public:
+ virtual ~path_context () {}
+
+ /* 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;
+
+ /* Hook for clients to determine if the standard path has been
+ terminated. */
+ virtual bool terminate_path_p () const = 0;
+};
+
+extern tree get_stashed_constant_by_name (const char *name);
+extern void log_stashed_constants (logger *logger);
+
+extern FILE *get_or_create_any_logfile ();
+
+extern std::unique_ptr<json::value>
+tree_to_json (tree node);
+
+extern std::unique_ptr<json::value>
+diagnostic_event_id_to_json (const diagnostic_event_id_t &);
+
+extern std::unique_ptr<json::value>
+bit_offset_to_json (const bit_offset_t &offset);
+
+extern std::unique_ptr<json::value>
+byte_offset_to_json (const byte_offset_t &offset);
+
+extern tristate
+compare_constants (tree lhs_const, enum tree_code op, tree rhs_const);
+
+extern tree
+get_string_cst_size (const_tree string_cst);
+
+extern tree
+get_ssa_default_def (const function &fun, tree var);
+
+extern const svalue *
+strip_types (const svalue *sval, region_model_manager &mgr);
+
+extern region_offset
+strip_types (const region_offset &offset, region_model_manager &mgr);
+
+extern tree remove_ssa_names (tree expr);
+
+} // namespace ana
+
+extern bool is_special_named_call_p (const gcall &call, const char *funcname,
+ unsigned int num_args,
+ bool look_in_std = false);
+extern bool is_named_call_p (const_tree fndecl, const char *funcname);
+extern bool is_named_call_p (const_tree fndecl, const char *funcname,
+ const gcall &call, unsigned int num_args);
+extern bool is_std_function_p (const_tree fndecl);
+extern bool is_std_named_call_p (const_tree fndecl, const char *funcname);
+extern bool is_std_named_call_p (const_tree fndecl, const char *funcname,
+ const gcall &call, unsigned int num_args);
+extern bool is_setjmp_call_p (const gcall &call);
+extern bool is_longjmp_call_p (const gcall &call);
+extern bool is_placement_new_p (const gcall &call);
+extern bool is_cxa_throw_p (const gcall &call);
+extern bool is_cxa_rethrow_p (const gcall &call);
+
+extern const char *get_user_facing_name (const gcall &call);
+
+extern void register_analyzer_pass ();
+
+extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
+extern label_text make_label_text_n (bool can_colorize,
+ unsigned HOST_WIDE_INT n,
+ const char *singular_fmt,
+ const char *plural_fmt, ...);
+
+extern bool fndecl_has_gimple_body_p (tree fndecl);
+
+/* An RAII-style class for pushing/popping cfun within a scope.
+ Doing so ensures we get "In function " announcements
+ from the diagnostics subsystem. */
+
+class auto_cfun
+{
+public:
+ auto_cfun (function *fun) { push_cfun (fun); }
+ ~auto_cfun () { pop_cfun (); }
+};
+
+/* A template for creating hash traits for a POD type. */
+
+template <typename Type>
+struct pod_hash_traits : typed_noop_remove<Type>
+{
+ typedef Type value_type;
+ typedef Type compare_type;
+ static inline hashval_t hash (value_type);
+ static inline bool equal (const value_type &existing,
+ const value_type &candidate);
+ static inline void mark_deleted (Type &);
+ static inline void mark_empty (Type &);
+ static inline bool is_deleted (Type);
+ static inline bool is_empty (Type);
+};
+
+/* A hash traits class that uses member functions to implement
+ the various required ops. */
+
+template <typename Type>
+struct member_function_hash_traits : public typed_noop_remove<Type>
+{
+ typedef Type value_type;
+ typedef Type compare_type;
+ static inline hashval_t hash (value_type v) { return v.hash (); }
+ static inline bool equal (const value_type &existing,
+ const value_type &candidate)
+ {
+ return existing == candidate;
+ }
+ static inline void mark_deleted (Type &t) { t.mark_deleted (); }
+ static inline void mark_empty (Type &t) { t.mark_empty (); }
+ static inline bool is_deleted (Type t) { return t.is_deleted (); }
+ static inline bool is_empty (Type t) { return t.is_empty (); }
+};
+
+/* A map from T::key_t to T* for use in consolidating instances of T.
+ Owns all instances of T.
+ T::key_t should have operator== and be hashable. */
+
+template <typename T>
+class consolidation_map
+{
+public:
+ typedef typename T::key_t key_t;
+ typedef T instance_t;
+ typedef hash_map<key_t, instance_t *> inner_map_t;
+ typedef typename inner_map_t::iterator iterator;
+
+ /* Delete all instances of T. */
+
+ ~consolidation_map ()
+ {
+ for (typename inner_map_t::iterator iter = m_inner_map.begin ();
+ iter != m_inner_map.end (); ++iter)
+ delete (*iter).second;
+ }
+
+ /* Get the instance of T for K if one exists, or NULL. */
+
+ T *get (const key_t &k) const
+ {
+ if (instance_t **slot = const_cast<inner_map_t &> (m_inner_map).get (k))
+ return *slot;
+ return NULL;
+ }
+
+ /* Take ownership of INSTANCE. */
+
+ void put (const key_t &k, T *instance)
+ {
+ m_inner_map.put (k, instance);
+ }
+
+ size_t elements () const { return m_inner_map.elements (); }
+
+ iterator begin () const { return m_inner_map.begin (); }
+ iterator end () const { return m_inner_map.end (); }
+
+private:
+ inner_map_t m_inner_map;
+};
+
+/* Disable -Wformat-diag; we want to be able to use pp_printf
+ for logging/dumping without complying with the rules for diagnostics. */
+#if __GNUC__ >= 10
+#pragma GCC diagnostic ignored "-Wformat-diag"
+#endif
+
+#if !ENABLE_ANALYZER
+extern void sorry_no_analyzer ();
+#endif /* #if !ENABLE_ANALYZER */
+
+#endif /* GCC_ANALYZER_COMMON_H */