1 /* Utility functions for the analyzer.
2 Copyright (C) 2019-2025 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
24 #include "rich-location.h"
33 /* Forward decls of common types, with indentation to show inheritance. */
39 class switch_cfg_superedge
;
40 class callgraph_superedge
;
42 class return_superedge
;
46 class constant_svalue
;
48 class poisoned_svalue
;
54 class repeated_svalue
;
55 class bits_within_svalue
;
56 class unmergeable_svalue
;
57 class placeholder_svalue
;
58 class widening_svalue
;
59 class compound_svalue
;
60 class conjured_svalue
;
61 class asm_output_svalue
;
62 class const_fn_result_svalue
;
63 typedef hash_set
<const svalue
*> svalue_set
;
66 class function_region
;
69 class symbolic_region
;
76 class bit_range_region
;
78 class region_model_manager
;
84 class region_model_context
;
85 class impl_region_model_context
;
87 class rejected_constraint
;
88 class constraint_manager
;
90 class reachable_regions
;
92 class bounded_ranges_manager
;
94 struct pending_location
;
95 class pending_diagnostic
;
97 class saved_diagnostic
;
98 struct event_loc_info
;
100 class state_change_event
;
103 class extrinsic_state
;
107 class function_point
;
109 class exploded_graph
;
112 class feasibility_problem
;
113 class exploded_cluster
;
116 class state_purge_map
;
117 class state_purge_per_ssa_name
;
118 class state_purge_per_decl
;
126 class known_function_manager
;
128 class call_summary_replay
;
129 struct per_function_data
;
130 struct interesting_t
;
134 class known_function
;
135 class builtin_known_function
;
136 class internal_known_function
;
138 /* Forward decls of functions. */
140 extern void dump_tree (pretty_printer
*pp
, tree t
);
141 extern void dump_quoted_tree (pretty_printer
*pp
, tree t
);
142 extern void print_quoted_type (pretty_printer
*pp
, tree t
);
143 extern void print_expr_for_user (pretty_printer
*pp
, tree t
);
144 extern int readability_comparator (const void *p1
, const void *p2
);
145 extern int tree_cmp (const void *p1
, const void *p2
);
146 extern tree
fixup_tree_for_diagnostic (tree
);
147 extern tree
get_diagnostic_tree_for_gassign (const gassign
*);
149 /* A tree, extended with stack frame information for locals, so that
150 we can distinguish between different values of locals within a potentially
151 recursive callstack. */
156 path_var (tree t
, int stack_depth
)
157 : m_tree (t
), m_stack_depth (stack_depth
)
159 // TODO: ignore stack depth for globals and constants
162 bool operator== (const path_var
&other
) const
164 return (m_tree
== other
.m_tree
165 && m_stack_depth
== other
.m_stack_depth
);
168 operator bool () const
170 return m_tree
!= NULL_TREE
;
173 void dump (pretty_printer
*pp
) const;
176 int m_stack_depth
; // or -1 for globals?
179 typedef offset_int bit_offset_t
;
180 typedef offset_int bit_size_t
;
181 typedef offset_int byte_offset_t
;
182 typedef offset_int byte_size_t
;
184 extern bool int_size_in_bits (const_tree type
, bit_size_t
*out
);
186 extern tree
get_field_at_bit_offset (tree record_type
, bit_offset_t bit_offset
);
188 /* The location of a region expressesd as an offset relative to a
195 : m_base_region (NULL
), m_offset (0), m_sym_offset (NULL
)
199 static region_offset
make_concrete (const region
*base_region
,
202 return region_offset (base_region
, offset
, NULL
);
204 static region_offset
make_symbolic (const region
*base_region
,
205 const svalue
*sym_offset
)
207 return region_offset (base_region
, 0, sym_offset
);
209 static region_offset
make_byte_offset (const region
*base_region
,
210 const svalue
*num_bytes_sval
);
212 const region
*get_base_region () const { return m_base_region
; }
214 bool concrete_p () const { return m_sym_offset
== NULL
; }
215 bool symbolic_p () const { return m_sym_offset
!= NULL
; }
217 bit_offset_t
get_bit_offset () const
219 gcc_assert (!symbolic_p ());
223 bool get_concrete_byte_offset (byte_offset_t
*out
) const
225 gcc_assert (!symbolic_p ());
226 if (m_offset
% BITS_PER_UNIT
== 0)
228 *out
= m_offset
/ BITS_PER_UNIT
;
234 const svalue
*get_symbolic_byte_offset () const
236 gcc_assert (symbolic_p ());
240 const svalue
&calc_symbolic_bit_offset (region_model_manager
*mgr
) const;
241 const svalue
*calc_symbolic_byte_offset (region_model_manager
*mgr
) const;
243 bool operator== (const region_offset
&other
) const
245 return (m_base_region
== other
.m_base_region
246 && m_offset
== other
.m_offset
247 && m_sym_offset
== other
.m_sym_offset
);
250 void dump_to_pp (pretty_printer
*pp
, bool) const;
251 void dump (bool) const;
254 region_offset (const region
*base_region
, bit_offset_t offset
,
255 const svalue
*sym_offset
)
256 : m_base_region (base_region
), m_offset (offset
), m_sym_offset (sym_offset
)
259 const region
*m_base_region
;
260 bit_offset_t m_offset
;
261 const svalue
*m_sym_offset
;
264 extern bool operator< (const region_offset
&, const region_offset
&);
265 extern bool operator<= (const region_offset
&, const region_offset
&);
266 extern bool operator> (const region_offset
&, const region_offset
&);
267 extern bool operator>= (const region_offset
&, const region_offset
&);
269 extern location_t
get_stmt_location (const gimple
*stmt
, function
*fun
);
271 extern bool compat_types_p (tree src_type
, tree dst_type
);
273 /* Abstract base class for simulating the behavior of known functions,
274 supplied by the core of the analyzer, or by plugins.
275 The former are typically implemented in the various kf*.cc */
280 virtual ~known_function () {}
281 virtual bool matches_call_types_p (const call_details
&cd
) const = 0;
282 virtual void impl_call_pre (const call_details
&) const
286 virtual void impl_call_post (const call_details
&) const
291 virtual const builtin_known_function
*
292 dyn_cast_builtin_kf () const { return NULL
; }
295 /* Subclass of known_function for builtin functions. */
297 class builtin_known_function
: public known_function
300 virtual enum built_in_function
builtin_code () const = 0;
301 tree
builtin_decl () const {
302 gcc_assert (builtin_code () < END_BUILTINS
);
303 return builtin_info
[builtin_code ()].decl
;
306 const builtin_known_function
*
307 dyn_cast_builtin_kf () const final override
{ return this; }
310 /* Subclass of known_function for IFN_* functions. */
312 class internal_known_function
: public known_function
315 bool matches_call_types_p (const call_details
&) const final override
317 /* Types are assumed to be correct. */
322 /* Abstract subclass of known_function that merely sets the return
323 value of the function (based on function attributes), and assumes
324 it has no side-effects. */
326 class pure_known_function_with_default_return
: public known_function
329 void impl_call_pre (const call_details
&cd
) const override
;
332 extern void register_known_functions (known_function_manager
&kfm
,
333 region_model_manager
&rmm
);
334 extern void register_known_analyzer_functions (known_function_manager
&kfm
);
335 extern void register_known_fd_functions (known_function_manager
&kfm
);
336 extern void register_known_file_functions (known_function_manager
&kfm
);
337 extern void register_known_functions_lang_cp (known_function_manager
&kfm
);
338 extern void register_varargs_builtins (known_function_manager
&kfm
);
340 /* Passed by pointer to PLUGIN_ANALYZER_INIT callbacks. */
342 class plugin_analyzer_init_iface
345 virtual void register_state_machine (std::unique_ptr
<state_machine
>) = 0;
346 virtual void register_known_function (const char *name
,
347 std::unique_ptr
<known_function
>) = 0;
348 virtual logger
*get_logger () const = 0;
351 /* An enum for describing the direction of an access to memory. */
353 enum access_direction
359 /* Abstract base class for associating custom data with an
360 exploded_edge, for handling non-standard edges such as
361 rewinding from a longjmp, signal handlers, etc.
362 Also used when "bifurcating" state: splitting the execution
363 path in non-standard ways (e.g. for simulating the various
364 outcomes of "realloc"). */
366 class custom_edge_info
369 virtual ~custom_edge_info () {}
371 /* Hook for making .dot label more readable. */
372 virtual void print (pretty_printer
*pp
) const = 0;
374 /* Hook for updating STATE when handling bifurcation. */
375 virtual bool update_state (program_state
*state
,
376 const exploded_edge
*eedge
,
377 region_model_context
*ctxt
) const;
379 /* Hook for updating MODEL within exploded_path::feasible_p
380 and when handling bifurcation. */
381 virtual bool update_model (region_model
*model
,
382 const exploded_edge
*eedge
,
383 region_model_context
*ctxt
) const = 0;
385 virtual void add_events_to_path (checker_path
*emission_path
,
386 const exploded_edge
&eedge
) const = 0;
389 /* Abstract base class for splitting state.
391 Most of the state-management code in the analyzer involves
392 modifying state objects in-place, which assumes a single outcome.
394 This class provides an escape hatch to allow for multiple outcomes
395 for such updates e.g. for modelling multiple outcomes from function
396 calls, such as the various outcomes of "realloc". */
401 virtual ~path_context () {}
403 /* Hook for clients to split state with a non-standard path. */
404 virtual void bifurcate (std::unique_ptr
<custom_edge_info
> info
) = 0;
406 /* Hook for clients to terminate the standard path. */
407 virtual void terminate_path () = 0;
409 /* Hook for clients to determine if the standard path has been
411 virtual bool terminate_path_p () const = 0;
414 extern tree
get_stashed_constant_by_name (const char *name
);
415 extern void log_stashed_constants (logger
*logger
);
417 extern FILE *get_or_create_any_logfile ();
419 extern std::unique_ptr
<json::value
>
420 tree_to_json (tree node
);
422 extern std::unique_ptr
<json::value
>
423 diagnostic_event_id_to_json (const diagnostic_event_id_t
&);
425 extern std::unique_ptr
<json::value
>
426 bit_offset_to_json (const bit_offset_t
&offset
);
428 extern std::unique_ptr
<json::value
>
429 byte_offset_to_json (const byte_offset_t
&offset
);
432 compare_constants (tree lhs_const
, enum tree_code op
, tree rhs_const
);
435 get_string_cst_size (const_tree string_cst
);
438 get_ssa_default_def (const function
&fun
, tree var
);
440 extern const svalue
*
441 strip_types (const svalue
*sval
, region_model_manager
&mgr
);
444 strip_types (const region_offset
&offset
, region_model_manager
&mgr
);
446 extern tree
remove_ssa_names (tree expr
);
450 extern bool is_special_named_call_p (const gcall
*call
, const char *funcname
,
451 unsigned int num_args
,
452 bool look_in_std
= false);
453 extern bool is_named_call_p (const_tree fndecl
, const char *funcname
);
454 extern bool is_named_call_p (const_tree fndecl
, const char *funcname
,
455 const gcall
*call
, unsigned int num_args
);
456 extern bool is_std_function_p (const_tree fndecl
);
457 extern bool is_std_named_call_p (const_tree fndecl
, const char *funcname
);
458 extern bool is_std_named_call_p (const_tree fndecl
, const char *funcname
,
459 const gcall
*call
, unsigned int num_args
);
460 extern bool is_setjmp_call_p (const gcall
*call
);
461 extern bool is_longjmp_call_p (const gcall
*call
);
462 extern bool is_placement_new_p (const gcall
*call
);
464 extern const char *get_user_facing_name (const gcall
*call
);
466 extern void register_analyzer_pass ();
468 extern label_text
make_label_text (bool can_colorize
, const char *fmt
, ...);
469 extern label_text
make_label_text_n (bool can_colorize
,
470 unsigned HOST_WIDE_INT n
,
471 const char *singular_fmt
,
472 const char *plural_fmt
, ...);
474 extern bool fndecl_has_gimple_body_p (tree fndecl
);
476 /* An RAII-style class for pushing/popping cfun within a scope.
477 Doing so ensures we get "In function " announcements
478 from the diagnostics subsystem. */
483 auto_cfun (function
*fun
) { push_cfun (fun
); }
484 ~auto_cfun () { pop_cfun (); }
487 /* A template for creating hash traits for a POD type. */
489 template <typename Type
>
490 struct pod_hash_traits
: typed_noop_remove
<Type
>
492 typedef Type value_type
;
493 typedef Type compare_type
;
494 static inline hashval_t
hash (value_type
);
495 static inline bool equal (const value_type
&existing
,
496 const value_type
&candidate
);
497 static inline void mark_deleted (Type
&);
498 static inline void mark_empty (Type
&);
499 static inline bool is_deleted (Type
);
500 static inline bool is_empty (Type
);
503 /* A hash traits class that uses member functions to implement
504 the various required ops. */
506 template <typename Type
>
507 struct member_function_hash_traits
: public typed_noop_remove
<Type
>
509 typedef Type value_type
;
510 typedef Type compare_type
;
511 static inline hashval_t
hash (value_type v
) { return v
.hash (); }
512 static inline bool equal (const value_type
&existing
,
513 const value_type
&candidate
)
515 return existing
== candidate
;
517 static inline void mark_deleted (Type
&t
) { t
.mark_deleted (); }
518 static inline void mark_empty (Type
&t
) { t
.mark_empty (); }
519 static inline bool is_deleted (Type t
) { return t
.is_deleted (); }
520 static inline bool is_empty (Type t
) { return t
.is_empty (); }
523 /* A map from T::key_t to T* for use in consolidating instances of T.
524 Owns all instances of T.
525 T::key_t should have operator== and be hashable. */
527 template <typename T
>
528 class consolidation_map
531 typedef typename
T::key_t key_t
;
532 typedef T instance_t
;
533 typedef hash_map
<key_t
, instance_t
*> inner_map_t
;
534 typedef typename
inner_map_t::iterator iterator
;
536 /* Delete all instances of T. */
538 ~consolidation_map ()
540 for (typename
inner_map_t::iterator iter
= m_inner_map
.begin ();
541 iter
!= m_inner_map
.end (); ++iter
)
542 delete (*iter
).second
;
545 /* Get the instance of T for K if one exists, or NULL. */
547 T
*get (const key_t
&k
) const
549 if (instance_t
**slot
= const_cast<inner_map_t
&> (m_inner_map
).get (k
))
554 /* Take ownership of INSTANCE. */
556 void put (const key_t
&k
, T
*instance
)
558 m_inner_map
.put (k
, instance
);
561 size_t elements () const { return m_inner_map
.elements (); }
563 iterator
begin () const { return m_inner_map
.begin (); }
564 iterator
end () const { return m_inner_map
.end (); }
567 inner_map_t m_inner_map
;
570 /* Disable -Wformat-diag; we want to be able to use pp_printf
571 for logging/dumping without complying with the rules for diagnostics. */
573 #pragma GCC diagnostic ignored "-Wformat-diag"
577 extern void sorry_no_analyzer ();
578 #endif /* #if !ENABLE_ANALYZER */
580 #endif /* GCC_ANALYZER_ANALYZER_H */