1 /* Utility functions for the analyzer.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef GCC_ANALYZER_ANALYZER_H
22 #define GCC_ANALYZER_ANALYZER_H
32 /* Forward decls of common types, with indentation to show inheritance. */
38 class switch_cfg_superedge;
39 class callgraph_superedge;
41 class return_superedge;
45 class constant_svalue;
47 class poisoned_svalue;
53 class repeated_svalue;
54 class bits_within_svalue;
55 class unmergeable_svalue;
56 class placeholder_svalue;
57 class widening_svalue;
58 class compound_svalue;
59 class conjured_svalue;
60 class asm_output_svalue;
61 class const_fn_result_svalue;
62 typedef hash_set<const svalue *> svalue_set;
65 class function_region;
68 class symbolic_region;
75 class bit_range_region;
77 class region_model_manager;
83 class region_model_context;
84 class impl_region_model_context;
86 class rejected_constraint;
87 class constraint_manager;
89 class reachable_regions;
91 class bounded_ranges_manager;
93 class pending_diagnostic;
95 class state_change_event;
97 class extrinsic_state;
101 class function_point;
103 class exploded_graph;
106 class feasibility_problem;
107 class exploded_cluster;
110 class state_purge_map;
111 class state_purge_per_ssa_name;
112 class state_purge_per_decl;
120 class known_function_manager;
122 class call_summary_replay;
123 struct per_function_data;
124 struct interesting_t;
126 /* Forward decls of functions. */
128 extern void dump_tree (pretty_printer *pp, tree t);
129 extern void dump_quoted_tree (pretty_printer *pp, tree t);
130 extern void print_quoted_type (pretty_printer *pp, tree t);
131 extern int readability_comparator (const void *p1, const void *p2);
132 extern int tree_cmp (const void *p1, const void *p2);
133 extern tree fixup_tree_for_diagnostic (tree);
134 extern tree get_diagnostic_tree_for_gassign (const gassign *);
136 /* A tree, extended with stack frame information for locals, so that
137 we can distinguish between different values of locals within a potentially
138 recursive callstack. */
143 path_var (tree t, int stack_depth)
144 : m_tree (t), m_stack_depth (stack_depth)
146 // TODO: ignore stack depth for globals and constants
149 bool operator== (const path_var &other) const
151 return (m_tree == other.m_tree
152 && m_stack_depth == other.m_stack_depth);
155 operator bool () const
157 return m_tree != NULL_TREE;
160 void dump (pretty_printer *pp) const;
163 int m_stack_depth; // or -1 for globals?
166 typedef offset_int bit_offset_t;
167 typedef offset_int bit_size_t;
168 typedef offset_int byte_offset_t;
169 typedef offset_int byte_size_t;
171 extern bool int_size_in_bits (const_tree type, bit_size_t *out);
173 extern tree get_field_at_bit_offset (tree record_type, bit_offset_t bit_offset);
175 /* The location of a region expressesd as an offset relative to a
181 static region_offset make_concrete (const region *base_region,
184 return region_offset (base_region, offset, NULL);
186 static region_offset make_symbolic (const region *base_region,
187 const svalue *sym_offset)
189 return region_offset (base_region, 0, sym_offset);
192 const region *get_base_region () const { return m_base_region; }
194 bool symbolic_p () const { return m_sym_offset != NULL; }
196 bit_offset_t get_bit_offset () const
198 gcc_assert (!symbolic_p ());
202 const svalue *get_symbolic_byte_offset () const
204 gcc_assert (symbolic_p ());
208 bool operator== (const region_offset &other) const
210 return (m_base_region == other.m_base_region
211 && m_offset == other.m_offset
212 && m_sym_offset == other.m_sym_offset);
216 region_offset (const region *base_region, bit_offset_t offset,
217 const svalue *sym_offset)
218 : m_base_region (base_region), m_offset (offset), m_sym_offset (sym_offset)
221 const region *m_base_region;
222 bit_offset_t m_offset;
223 const svalue *m_sym_offset;
226 extern location_t get_stmt_location (const gimple *stmt, function *fun);
228 extern bool compat_types_p (tree src_type, tree dst_type);
230 /* Abstract base class for simulating the behavior of known functions,
231 supplied by the core of the analyzer, or by plugins. */
236 virtual ~known_function () {}
237 virtual bool matches_call_types_p (const call_details &cd) const = 0;
238 virtual void impl_call_pre (const call_details &) const
242 virtual void impl_call_post (const call_details &) const
248 /* Subclass of known_function for IFN_* functions. */
250 class internal_known_function : public known_function
253 bool matches_call_types_p (const call_details &) const final override
255 /* Types are assumed to be correct. */
260 extern void register_known_functions (known_function_manager &mgr);
261 extern void register_known_fd_functions (known_function_manager &kfm);
262 extern void register_known_file_functions (known_function_manager &kfm);
263 extern void register_varargs_builtins (known_function_manager &kfm);
265 /* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks. */
267 class plugin_analyzer_init_iface
270 virtual void register_state_machine (std::unique_ptr<state_machine>) = 0;
271 virtual void register_known_function (const char *name,
272 std::unique_ptr<known_function>) = 0;
273 virtual logger *get_logger () const = 0;
276 /* An enum for describing the direction of an access to memory. */
278 enum access_direction
284 /* Abstract base class for associating custom data with an
285 exploded_edge, for handling non-standard edges such as
286 rewinding from a longjmp, signal handlers, etc.
287 Also used when "bifurcating" state: splitting the execution
288 path in non-standard ways (e.g. for simulating the various
289 outcomes of "realloc"). */
291 class custom_edge_info
294 virtual ~custom_edge_info () {}
296 /* Hook for making .dot label more readable. */
297 virtual void print (pretty_printer *pp) const = 0;
299 /* Hook for updating STATE when handling bifurcation. */
300 virtual bool update_state (program_state *state,
301 const exploded_edge *eedge,
302 region_model_context *ctxt) const;
304 /* Hook for updating MODEL within exploded_path::feasible_p
305 and when handling bifurcation. */
306 virtual bool update_model (region_model *model,
307 const exploded_edge *eedge,
308 region_model_context *ctxt) const = 0;
310 virtual void add_events_to_path (checker_path *emission_path,
311 const exploded_edge &eedge) const = 0;
314 /* Abstract base class for splitting state.
316 Most of the state-management code in the analyzer involves
317 modifying state objects in-place, which assumes a single outcome.
319 This class provides an escape hatch to allow for multiple outcomes
320 for such updates e.g. for modelling multiple outcomes from function
321 calls, such as the various outcomes of "realloc". */
326 virtual ~path_context () {}
328 /* Hook for clients to split state with a non-standard path. */
329 virtual void bifurcate (std::unique_ptr<custom_edge_info> info) = 0;
331 /* Hook for clients to terminate the standard path. */
332 virtual void terminate_path () = 0;
334 /* Hook for clients to determine if the standard path has been
336 virtual bool terminate_path_p () const = 0;
339 extern tree get_stashed_constant_by_name (const char *name);
340 extern void log_stashed_constants (logger *logger);
342 extern FILE *get_or_create_any_logfile ();
346 extern bool is_special_named_call_p (const gcall *call, const char *funcname,
347 unsigned int num_args);
348 extern bool is_named_call_p (const_tree fndecl, const char *funcname);
349 extern bool is_named_call_p (const_tree fndecl, const char *funcname,
350 const gcall *call, unsigned int num_args);
351 extern bool is_std_named_call_p (const_tree fndecl, const char *funcname);
352 extern bool is_std_named_call_p (const_tree fndecl, const char *funcname,
353 const gcall *call, unsigned int num_args);
354 extern bool is_setjmp_call_p (const gcall *call);
355 extern bool is_longjmp_call_p (const gcall *call);
357 extern const char *get_user_facing_name (const gcall *call);
359 extern void register_analyzer_pass ();
361 extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
362 extern label_text make_label_text_n (bool can_colorize,
363 unsigned HOST_WIDE_INT n,
364 const char *singular_fmt,
365 const char *plural_fmt, ...);
367 extern bool fndecl_has_gimple_body_p (tree fndecl);
369 /* An RAII-style class for pushing/popping cfun within a scope.
370 Doing so ensures we get "In function " announcements
371 from the diagnostics subsystem. */
376 auto_cfun (function *fun) { push_cfun (fun); }
377 ~auto_cfun () { pop_cfun (); }
380 /* A template for creating hash traits for a POD type. */
382 template <typename Type>
383 struct pod_hash_traits : typed_noop_remove<Type>
385 typedef Type value_type;
386 typedef Type compare_type;
387 static inline hashval_t hash (value_type);
388 static inline bool equal (const value_type &existing,
389 const value_type &candidate);
390 static inline void mark_deleted (Type &);
391 static inline void mark_empty (Type &);
392 static inline bool is_deleted (Type);
393 static inline bool is_empty (Type);
396 /* A hash traits class that uses member functions to implement
397 the various required ops. */
399 template <typename Type>
400 struct member_function_hash_traits : public typed_noop_remove<Type>
402 typedef Type value_type;
403 typedef Type compare_type;
404 static inline hashval_t hash (value_type v) { return v.hash (); }
405 static inline bool equal (const value_type &existing,
406 const value_type &candidate)
408 return existing == candidate;
410 static inline void mark_deleted (Type &t) { t.mark_deleted (); }
411 static inline void mark_empty (Type &t) { t.mark_empty (); }
412 static inline bool is_deleted (Type t) { return t.is_deleted (); }
413 static inline bool is_empty (Type t) { return t.is_empty (); }
416 /* A map from T::key_t to T* for use in consolidating instances of T.
417 Owns all instances of T.
418 T::key_t should have operator== and be hashable. */
420 template <typename T>
421 class consolidation_map
424 typedef typename T::key_t key_t;
425 typedef T instance_t;
426 typedef hash_map<key_t, instance_t *> inner_map_t;
427 typedef typename inner_map_t::iterator iterator;
429 /* Delete all instances of T. */
431 ~consolidation_map ()
433 for (typename inner_map_t::iterator iter = m_inner_map.begin ();
434 iter != m_inner_map.end (); ++iter)
435 delete (*iter).second;
438 /* Get the instance of T for K if one exists, or NULL. */
440 T *get (const key_t &k) const
442 if (instance_t **slot = const_cast<inner_map_t &> (m_inner_map).get (k))
447 /* Take ownership of INSTANCE. */
449 void put (const key_t &k, T *instance)
451 m_inner_map.put (k, instance);
454 size_t elements () const { return m_inner_map.elements (); }
456 iterator begin () const { return m_inner_map.begin (); }
457 iterator end () const { return m_inner_map.end (); }
460 inner_map_t m_inner_map;
463 /* Disable -Wformat-diag; we want to be able to use pp_printf
464 for logging/dumping without complying with the rules for diagnostics. */
466 #pragma GCC diagnostic ignored "-Wformat-diag"
470 extern void sorry_no_analyzer ();
471 #endif /* #if !ENABLE_ANALYZER */
473 #endif /* GCC_ANALYZER_ANALYZER_H */