1 /* Classes for modeling the state of memory.
2 Copyright (C) 2019-2024 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_REGION_MODEL_H
22 #define GCC_ANALYZER_REGION_MODEL_H
24 /* Implementation of the region-based ternary model described in:
25 "A Memory Model for Static Analysis of C Programs"
26 (Zhongxing Xu, Ted Kremenek, and Jian Zhang)
27 http://lcs.ios.ac.cn/~xuzb/canalyze/memmodel.pdf */
30 #include "stringpool.h"
31 #include "attribs.h" // for rdwr_map
33 #include "analyzer/svalue.h"
34 #include "analyzer/region.h"
35 #include "analyzer/known-function-manager.h"
36 #include "analyzer/region-model-manager.h"
37 #include "analyzer/pending-diagnostic.h"
38 #include "text-art/widget.h"
39 #include "text-art/dump.h"
45 extern void add_path_var (path_var pv
, hash
&hstate
);
46 } // namespace inchash
54 one_way_id_map (int num_ids
);
55 void put (T src
, T dst
);
56 T
get_dst_for_src (T src
) const;
57 void dump_to_pp (pretty_printer
*pp
) const;
59 void update (T
*) const;
62 auto_vec
<T
> m_src_to_dst
;
65 /* class one_way_id_map. */
67 /* one_way_id_map's ctor, which populates the map with dummy null values. */
70 inline one_way_id_map
<T
>::one_way_id_map (int num_svalues
)
71 : m_src_to_dst (num_svalues
)
73 for (int i
= 0; i
< num_svalues
; i
++)
74 m_src_to_dst
.quick_push (T::null ());
77 /* Record that SRC is to be mapped to DST. */
81 one_way_id_map
<T
>::put (T src
, T dst
)
83 m_src_to_dst
[src
.as_int ()] = dst
;
86 /* Get the new value for SRC within the map. */
90 one_way_id_map
<T
>::get_dst_for_src (T src
) const
94 return m_src_to_dst
[src
.as_int ()];
97 /* Dump this map to PP. */
101 one_way_id_map
<T
>::dump_to_pp (pretty_printer
*pp
) const
103 pp_string (pp
, "src to dst: {");
106 FOR_EACH_VEC_ELT (m_src_to_dst
, i
, dst
)
109 pp_string (pp
, ", ");
110 T
src (T::from_int (i
));
112 pp_string (pp
, " -> ");
119 /* Dump this map to stderr. */
121 template <typename T
>
122 DEBUG_FUNCTION
inline void
123 one_way_id_map
<T
>::dump () const
126 pp
.set_output_stream (stderr
);
131 /* Update *ID from the old value to its new value in this map. */
133 template <typename T
>
135 one_way_id_map
<T
>::update (T
*id
) const
137 *id
= get_dst_for_src (*id
);
140 /* A mapping from region to svalue for use when tracking state. */
142 class region_to_value_map
145 typedef hash_map
<const region
*, const svalue
*> hash_map_t
;
146 typedef hash_map_t::iterator iterator
;
148 region_to_value_map () : m_hash_map () {}
149 region_to_value_map (const region_to_value_map
&other
)
150 : m_hash_map (other
.m_hash_map
) {}
151 region_to_value_map
&operator= (const region_to_value_map
&other
);
153 bool operator== (const region_to_value_map
&other
) const;
154 bool operator!= (const region_to_value_map
&other
) const
156 return !(*this == other
);
159 iterator
begin () const { return m_hash_map
.begin (); }
160 iterator
end () const { return m_hash_map
.end (); }
162 const svalue
* const *get (const region
*reg
) const
164 return const_cast <hash_map_t
&> (m_hash_map
).get (reg
);
166 void put (const region
*reg
, const svalue
*sval
)
168 m_hash_map
.put (reg
, sval
);
170 void remove (const region
*reg
)
172 m_hash_map
.remove (reg
);
175 bool is_empty () const { return m_hash_map
.is_empty (); }
177 void dump_to_pp (pretty_printer
*pp
, bool simple
, bool multiline
) const;
178 void dump (bool simple
) const;
180 json::object
*to_json () const;
182 std::unique_ptr
<text_art::tree_widget
>
183 make_dump_widget (const text_art::dump_widget_info
&dwi
) const;
185 bool can_merge_with_p (const region_to_value_map
&other
,
186 region_to_value_map
*out
) const;
188 void purge_state_involving (const svalue
*sval
);
191 hash_map_t m_hash_map
;
194 /* Various operations delete information from a region_model.
196 This struct tracks how many of each kind of entity were purged (e.g.
197 for selftests, and for debugging). */
204 m_num_equiv_classes (0),
205 m_num_constraints (0),
206 m_num_bounded_ranges_constraints (0),
207 m_num_client_items (0)
212 int m_num_equiv_classes
;
213 int m_num_constraints
;
214 int m_num_bounded_ranges_constraints
;
215 int m_num_client_items
;
218 /* A base class for visiting regions and svalues, with do-nothing
219 base implementations of the per-subclass vfuncs. */
224 virtual void visit_region_svalue (const region_svalue
*) {}
225 virtual void visit_constant_svalue (const constant_svalue
*) {}
226 virtual void visit_unknown_svalue (const unknown_svalue
*) {}
227 virtual void visit_poisoned_svalue (const poisoned_svalue
*) {}
228 virtual void visit_setjmp_svalue (const setjmp_svalue
*) {}
229 virtual void visit_initial_svalue (const initial_svalue
*) {}
230 virtual void visit_unaryop_svalue (const unaryop_svalue
*) {}
231 virtual void visit_binop_svalue (const binop_svalue
*) {}
232 virtual void visit_sub_svalue (const sub_svalue
*) {}
233 virtual void visit_repeated_svalue (const repeated_svalue
*) {}
234 virtual void visit_bits_within_svalue (const bits_within_svalue
*) {}
235 virtual void visit_unmergeable_svalue (const unmergeable_svalue
*) {}
236 virtual void visit_placeholder_svalue (const placeholder_svalue
*) {}
237 virtual void visit_widening_svalue (const widening_svalue
*) {}
238 virtual void visit_compound_svalue (const compound_svalue
*) {}
239 virtual void visit_conjured_svalue (const conjured_svalue
*) {}
240 virtual void visit_asm_output_svalue (const asm_output_svalue
*) {}
241 virtual void visit_const_fn_result_svalue (const const_fn_result_svalue
*) {}
243 virtual void visit_region (const region
*) {}
246 struct append_regions_cb_data
;
248 typedef void (*pop_frame_callback
) (const region_model
*model
,
249 const region_model
*prev_model
,
250 const svalue
*retval
,
251 region_model_context
*ctxt
);
253 /* A region_model encapsulates a representation of the state of memory, with
254 a tree of regions, along with their associated values.
255 The representation is graph-like because values can be pointers to
258 - a constraint_manager, capturing relationships between the values, and
259 - dynamic extents, mapping dynamically-allocated regions to svalues (their
265 typedef region_to_value_map dynamic_extents_t
;
267 region_model (region_model_manager
*mgr
);
268 region_model (const region_model
&other
);
270 region_model
&operator= (const region_model
&other
);
272 bool operator== (const region_model
&other
) const;
273 bool operator!= (const region_model
&other
) const
275 return !(*this == other
);
278 hashval_t
hash () const;
280 void print (pretty_printer
*pp
) const;
282 void dump_to_pp (pretty_printer
*pp
, bool simple
, bool multiline
) const;
283 void dump (FILE *fp
, bool simple
, bool multiline
) const;
284 void dump (bool simple
) const;
289 json::object
*to_json () const;
291 std::unique_ptr
<text_art::tree_widget
>
292 make_dump_widget (const text_art::dump_widget_info
&dwi
) const;
294 void validate () const;
296 void canonicalize ();
297 bool canonicalized_p () const;
300 on_stmt_pre (const gimple
*stmt
,
301 bool *out_unknown_side_effects
,
302 region_model_context
*ctxt
);
304 void on_assignment (const gassign
*stmt
, region_model_context
*ctxt
);
305 const svalue
*get_gassign_result (const gassign
*assign
,
306 region_model_context
*ctxt
);
307 void on_asm_stmt (const gasm
*asm_stmt
, region_model_context
*ctxt
);
308 bool on_call_pre (const gcall
*stmt
, region_model_context
*ctxt
);
309 void on_call_post (const gcall
*stmt
,
310 bool unknown_side_effects
,
311 region_model_context
*ctxt
);
313 void purge_state_involving (const svalue
*sval
, region_model_context
*ctxt
);
315 void impl_deallocation_call (const call_details
&cd
);
317 const svalue
*maybe_get_copy_bounds (const region
*src_reg
,
318 const svalue
*num_bytes_sval
);
319 void update_for_int_cst_return (const call_details
&cd
,
322 void update_for_zero_return (const call_details
&cd
,
324 void update_for_nonzero_return (const call_details
&cd
);
326 void handle_unrecognized_call (const gcall
*call
,
327 region_model_context
*ctxt
);
328 void get_reachable_svalues (svalue_set
*out
,
329 const svalue
*extra_sval
,
330 const uncertainty_t
*uncertainty
);
332 void on_return (const greturn
*stmt
, region_model_context
*ctxt
);
333 void on_setjmp (const gcall
*stmt
, const exploded_node
*enode
,
334 region_model_context
*ctxt
);
335 void on_longjmp (const gcall
*longjmp_call
, const gcall
*setjmp_call
,
336 int setjmp_stack_depth
, region_model_context
*ctxt
);
338 void update_for_phis (const supernode
*snode
,
339 const cfg_superedge
*last_cfg_superedge
,
340 region_model_context
*ctxt
);
342 void handle_phi (const gphi
*phi
, tree lhs
, tree rhs
,
343 const region_model
&old_state
,
344 hash_set
<const svalue
*> &svals_changing_meaning
,
345 region_model_context
*ctxt
);
347 bool maybe_update_for_edge (const superedge
&edge
,
348 const gimple
*last_stmt
,
349 region_model_context
*ctxt
,
350 std::unique_ptr
<rejected_constraint
> *out
);
352 void update_for_gcall (const gcall
*call_stmt
,
353 region_model_context
*ctxt
,
354 function
*callee
= NULL
);
356 void update_for_return_gcall (const gcall
*call_stmt
,
357 region_model_context
*ctxt
);
359 const region
*push_frame (const function
&fun
, const vec
<const svalue
*> *arg_sids
,
360 region_model_context
*ctxt
);
361 const frame_region
*get_current_frame () const { return m_current_frame
; }
362 const function
*get_current_function () const;
363 void pop_frame (tree result_lvalue
,
364 const svalue
**out_result
,
365 region_model_context
*ctxt
,
366 const gcall
*call_stmt
,
367 bool eval_return_svalue
= true);
368 int get_stack_depth () const;
369 const frame_region
*get_frame_at_index (int index
) const;
371 const region
*get_lvalue (path_var pv
, region_model_context
*ctxt
) const;
372 const region
*get_lvalue (tree expr
, region_model_context
*ctxt
) const;
373 const svalue
*get_rvalue (path_var pv
, region_model_context
*ctxt
) const;
374 const svalue
*get_rvalue (tree expr
, region_model_context
*ctxt
) const;
376 const region
*deref_rvalue (const svalue
*ptr_sval
, tree ptr_tree
,
377 region_model_context
*ctxt
,
378 bool add_nonnull_constraint
= true) const;
380 const svalue
*get_rvalue_for_bits (tree type
,
382 const bit_range
&bits
,
383 region_model_context
*ctxt
) const;
385 void set_value (const region
*lhs_reg
, const svalue
*rhs_sval
,
386 region_model_context
*ctxt
);
387 void set_value (tree lhs
, tree rhs
, region_model_context
*ctxt
);
388 void clobber_region (const region
*reg
);
389 void purge_region (const region
*reg
);
390 void fill_region (const region
*reg
,
392 region_model_context
*ctxt
);
393 void zero_fill_region (const region
*reg
,
394 region_model_context
*ctxt
);
395 void write_bytes (const region
*dest_reg
,
396 const svalue
*num_bytes_sval
,
398 region_model_context
*ctxt
);
399 const svalue
*read_bytes (const region
*src_reg
,
401 const svalue
*num_bytes_sval
,
402 region_model_context
*ctxt
) const;
403 void copy_bytes (const region
*dest_reg
,
404 const region
*src_reg
,
406 const svalue
*num_bytes_sval
,
407 region_model_context
*ctxt
);
408 void mark_region_as_unknown (const region
*reg
, uncertainty_t
*uncertainty
);
410 tristate
eval_condition (const svalue
*lhs
,
412 const svalue
*rhs
) const;
413 tristate
compare_initial_and_pointer (const initial_svalue
*init
,
414 const region_svalue
*ptr
) const;
415 tristate
symbolic_greater_than (const binop_svalue
*a
,
416 const svalue
*b
) const;
417 tristate
structural_equality (const svalue
*a
, const svalue
*b
) const;
418 tristate
eval_condition (tree lhs
,
421 region_model_context
*ctxt
) const;
422 bool add_constraint (tree lhs
, enum tree_code op
, tree rhs
,
423 region_model_context
*ctxt
);
424 bool add_constraint (tree lhs
, enum tree_code op
, tree rhs
,
425 region_model_context
*ctxt
,
426 std::unique_ptr
<rejected_constraint
> *out
);
429 get_or_create_region_for_heap_alloc (const svalue
*size_in_bytes
,
430 region_model_context
*ctxt
,
431 bool update_state_machine
= false,
432 const call_details
*cd
= nullptr);
434 const region
*create_region_for_alloca (const svalue
*size_in_bytes
,
435 region_model_context
*ctxt
);
436 void get_referenced_base_regions (auto_bitmap
&out_ids
) const;
438 tree
get_representative_tree (const svalue
*sval
,
439 logger
*logger
= nullptr) const;
440 tree
get_representative_tree (const region
*reg
,
441 logger
*logger
= nullptr) const;
443 get_representative_path_var (const svalue
*sval
,
445 logger
*logger
) const;
447 get_representative_path_var (const region
*reg
,
449 logger
*logger
) const;
452 constraint_manager
*get_constraints ()
454 return m_constraints
;
457 store
*get_store () { return &m_store
; }
458 const store
*get_store () const { return &m_store
; }
460 const dynamic_extents_t
&
461 get_dynamic_extents () const
463 return m_dynamic_extents
;
465 const svalue
*get_dynamic_extents (const region
*reg
) const;
466 void set_dynamic_extents (const region
*reg
,
467 const svalue
*size_in_bytes
,
468 region_model_context
*ctxt
);
469 void unset_dynamic_extents (const region
*reg
);
471 region_model_manager
*get_manager () const { return m_mgr
; }
472 bounded_ranges_manager
*get_range_manager () const
474 return m_mgr
->get_range_manager ();
477 void unbind_region_and_descendents (const region
*reg
,
478 enum poison_kind pkind
);
480 bool can_merge_with_p (const region_model
&other_model
,
481 const program_point
&point
,
482 region_model
*out_model
,
483 const extrinsic_state
*ext_state
= NULL
,
484 const program_state
*state_a
= NULL
,
485 const program_state
*state_b
= NULL
) const;
487 tree
get_fndecl_for_call (const gcall
*call
,
488 region_model_context
*ctxt
);
490 void get_regions_for_current_frame (auto_vec
<const decl_region
*> *out
) const;
491 static void append_regions_cb (const region
*base_reg
,
492 struct append_regions_cb_data
*data
);
494 const svalue
*get_store_value (const region
*reg
,
495 region_model_context
*ctxt
) const;
496 const svalue
*get_store_bytes (const region
*base_reg
,
497 const byte_range
&bytes
,
498 region_model_context
*ctxt
) const;
499 const svalue
*scan_for_null_terminator (const region
*reg
,
501 const svalue
**out_sval
,
502 region_model_context
*ctxt
) const;
503 const svalue
*scan_for_null_terminator_1 (const region
*reg
,
505 const svalue
**out_sval
,
506 region_model_context
*ctxt
) const;
508 bool region_exists_p (const region
*reg
) const;
510 void loop_replay_fixup (const region_model
*dst_state
);
512 const svalue
*get_capacity (const region
*reg
) const;
514 bool replay_call_summary (call_summary_replay
&r
,
515 const region_model
&summary
);
517 void maybe_complain_about_infoleak (const region
*dst_reg
,
518 const svalue
*copied_sval
,
519 const region
*src_reg
,
520 region_model_context
*ctxt
);
522 void set_errno (const call_details
&cd
);
524 /* Implemented in sm-fd.cc */
525 void mark_as_valid_fd (const svalue
*sval
, region_model_context
*ctxt
);
527 /* Implemented in sm-malloc.cc */
528 void on_realloc_with_move (const call_details
&cd
,
529 const svalue
*old_ptr_sval
,
530 const svalue
*new_ptr_sval
);
532 /* Implemented in sm-malloc.cc. */
534 transition_ptr_sval_non_null (region_model_context
*ctxt
,
535 const svalue
*new_ptr_sval
);
537 /* Implemented in sm-taint.cc. */
538 void mark_as_tainted (const svalue
*sval
,
539 region_model_context
*ctxt
);
541 bool add_constraint (const svalue
*lhs
,
544 region_model_context
*ctxt
);
546 const svalue
*check_for_poison (const svalue
*sval
,
548 const region
*src_region
,
549 region_model_context
*ctxt
) const;
551 void check_region_for_write (const region
*dest_reg
,
552 const svalue
*sval_hint
,
553 region_model_context
*ctxt
) const;
556 check_for_null_terminated_string_arg (const call_details
&cd
,
559 check_for_null_terminated_string_arg (const call_details
&cd
,
561 bool include_terminator
,
562 const svalue
**out_sval
) const;
564 const builtin_known_function
*
565 get_builtin_kf (const gcall
*call
,
566 region_model_context
*ctxt
= NULL
) const;
569 register_pop_frame_callback (const pop_frame_callback
&callback
)
571 pop_frame_callbacks
.safe_push (callback
);
575 notify_on_pop_frame (const region_model
*model
,
576 const region_model
*prev_model
,
577 const svalue
*retval
,
578 region_model_context
*ctxt
)
580 for (auto &callback
: pop_frame_callbacks
)
581 callback (model
, prev_model
, retval
, ctxt
);
584 bool called_from_main_p () const;
587 const region
*get_lvalue_1 (path_var pv
, region_model_context
*ctxt
) const;
588 const svalue
*get_rvalue_1 (path_var pv
, region_model_context
*ctxt
) const;
591 get_representative_path_var_1 (const svalue
*sval
,
593 logger
*logger
) const;
595 get_representative_path_var_1 (const region
*reg
,
597 logger
*logger
) const;
599 const known_function
*get_known_function (tree fndecl
,
600 const call_details
&cd
) const;
601 const known_function
*get_known_function (enum internal_fn
) const;
603 bool add_constraints_from_binop (const svalue
*outer_lhs
,
604 enum tree_code outer_op
,
605 const svalue
*outer_rhs
,
607 region_model_context
*ctxt
);
609 void update_for_call_superedge (const call_superedge
&call_edge
,
610 region_model_context
*ctxt
);
611 void update_for_return_superedge (const return_superedge
&return_edge
,
612 region_model_context
*ctxt
);
613 bool apply_constraints_for_gcond (const cfg_superedge
&edge
,
614 const gcond
*cond_stmt
,
615 region_model_context
*ctxt
,
616 std::unique_ptr
<rejected_constraint
> *out
);
617 bool apply_constraints_for_gswitch (const switch_cfg_superedge
&edge
,
618 const gswitch
*switch_stmt
,
619 region_model_context
*ctxt
,
620 std::unique_ptr
<rejected_constraint
> *out
);
621 bool apply_constraints_for_ggoto (const cfg_superedge
&edge
,
622 const ggoto
*goto_stmt
,
623 region_model_context
*ctxt
);
624 bool apply_constraints_for_exception (const gimple
*last_stmt
,
625 region_model_context
*ctxt
,
626 std::unique_ptr
<rejected_constraint
> *out
);
628 int poison_any_pointers_to_descendents (const region
*reg
,
629 enum poison_kind pkind
);
631 void on_top_level_param (tree param
,
633 region_model_context
*ctxt
);
635 const svalue
*get_initial_value_for_global (const region
*reg
) const;
637 const region
* get_region_for_poisoned_expr (tree expr
) const;
639 void check_dynamic_size_for_taint (enum memory_space mem_space
,
640 const svalue
*size_in_bytes
,
641 region_model_context
*ctxt
) const;
642 void check_dynamic_size_for_floats (const svalue
*size_in_bytes
,
643 region_model_context
*ctxt
) const;
645 void check_region_for_taint (const region
*reg
,
646 enum access_direction dir
,
647 region_model_context
*ctxt
) const;
649 void check_for_writable_region (const region
* dest_reg
,
650 region_model_context
*ctxt
) const;
651 bool check_region_access (const region
*reg
,
652 enum access_direction dir
,
653 const svalue
*sval_hint
,
654 region_model_context
*ctxt
) const;
655 bool check_region_for_read (const region
*src_reg
,
656 region_model_context
*ctxt
) const;
657 void check_region_size (const region
*lhs_reg
, const svalue
*rhs_sval
,
658 region_model_context
*ctxt
) const;
660 /* Implemented in bounds-checking.cc */
661 bool check_symbolic_bounds (const region
*base_reg
,
662 const svalue
*sym_byte_offset
,
663 const svalue
*num_bytes_sval
,
664 const svalue
*capacity
,
665 enum access_direction dir
,
666 const svalue
*sval_hint
,
667 region_model_context
*ctxt
) const;
668 bool check_region_bounds (const region
*reg
, enum access_direction dir
,
669 const svalue
*sval_hint
,
670 region_model_context
*ctxt
) const;
672 void check_call_args (const call_details
&cd
) const;
673 void check_call_format_attr (const call_details
&cd
,
674 tree format_attr
) const;
675 void check_function_attr_access (const gcall
*call
,
677 region_model_context
*ctxt
,
678 rdwr_map
&rdwr_idx
) const;
679 void check_function_attr_null_terminated_string_arg (const gcall
*call
,
681 region_model_context
*ctxt
,
683 void check_one_function_attr_null_terminated_string_arg (const gcall
*call
,
685 region_model_context
*ctxt
,
688 void check_function_attrs (const gcall
*call
,
690 region_model_context
*ctxt
);
692 static auto_vec
<pop_frame_callback
> pop_frame_callbacks
;
693 /* Storing this here to avoid passing it around everywhere. */
694 region_model_manager
*const m_mgr
;
698 constraint_manager
*m_constraints
; // TODO: embed, rather than dynalloc?
700 const frame_region
*m_current_frame
;
702 /* Map from base region to size in bytes, for tracking the sizes of
703 dynamically-allocated regions.
704 This is part of the region_model rather than the region to allow for
705 memory regions to be resized (e.g. by realloc). */
706 dynamic_extents_t m_dynamic_extents
;
709 /* Some region_model activity could lead to warnings (e.g. attempts to use an
710 uninitialized value). This abstract base class encapsulates an interface
711 for the region model to use when emitting such warnings.
713 Having this as an abstract base class allows us to support the various
714 operations needed by program_state in the analyzer within region_model,
715 whilst keeping them somewhat modularized. */
717 class region_model_context
720 /* Hook for clients to store pending diagnostics.
721 Return true if the diagnostic was stored, or false if it was deleted.
722 Optionally provide a custom stmt_finder. */
723 virtual bool warn (std::unique_ptr
<pending_diagnostic
> d
,
724 const stmt_finder
*custom_finder
= NULL
) = 0;
726 /* Hook for clients to add a note to the last previously stored
727 pending diagnostic. */
728 virtual void add_note (std::unique_ptr
<pending_note
> pn
) = 0;
730 /* Hook for clients to add an event to the last previously stored
731 pending diagnostic. */
732 virtual void add_event (std::unique_ptr
<checker_event
> event
) = 0;
734 /* Hook for clients to be notified when an SVAL that was reachable
735 in a previous state is no longer live, so that clients can emit warnings
737 virtual void on_svalue_leak (const svalue
*sval
) = 0;
739 /* Hook for clients to be notified when the set of explicitly live
740 svalues changes, so that they can purge state relating to dead
742 virtual void on_liveness_change (const svalue_set
&live_svalues
,
743 const region_model
*model
) = 0;
745 virtual logger
*get_logger () = 0;
747 /* Hook for clients to be notified when the condition
748 "LHS OP RHS" is added to the region model.
749 This exists so that state machines can detect tests on edges,
750 and use them to trigger sm-state transitions (e.g. transitions due
751 to ptrs becoming known to be NULL or non-NULL, rather than just
753 virtual void on_condition (const svalue
*lhs
,
755 const svalue
*rhs
) = 0;
757 /* Hook for clients to be notified when the condition that
758 SVAL is within RANGES is added to the region model.
759 Similar to on_condition, but for use when handling switch statements.
760 RANGES is non-empty. */
761 virtual void on_bounded_ranges (const svalue
&sval
,
762 const bounded_ranges
&ranges
) = 0;
764 /* Hook for clients to be notified when a frame is popped from the stack. */
765 virtual void on_pop_frame (const frame_region
*) = 0;
767 /* Hooks for clients to be notified when an unknown change happens
768 to SVAL (in response to a call to an unknown function). */
769 virtual void on_unknown_change (const svalue
*sval
, bool is_mutable
) = 0;
771 /* Hooks for clients to be notified when a phi node is handled,
772 where RHS is the pertinent argument. */
773 virtual void on_phi (const gphi
*phi
, tree rhs
) = 0;
775 /* Hooks for clients to be notified when the region model doesn't
776 know how to handle the tree code of T at LOC. */
777 virtual void on_unexpected_tree_code (tree t
,
778 const dump_location_t
&loc
) = 0;
780 /* Hook for clients to be notified when a function_decl escapes. */
781 virtual void on_escaped_function (tree fndecl
) = 0;
783 virtual uncertainty_t
*get_uncertainty () = 0;
785 /* Hook for clients to purge state involving SVAL. */
786 virtual void purge_state_involving (const svalue
*sval
) = 0;
788 /* Hook for clients to split state with a non-standard path. */
789 virtual void bifurcate (std::unique_ptr
<custom_edge_info
> info
) = 0;
791 /* Hook for clients to terminate the standard path. */
792 virtual void terminate_path () = 0;
794 virtual const extrinsic_state
*get_ext_state () const = 0;
796 /* Hook for clients to access the a specific state machine in
797 any underlying program_state. */
799 get_state_map_by_name (const char *name
,
800 sm_state_map
**out_smap
,
801 const state_machine
**out_sm
,
802 unsigned *out_sm_idx
,
803 std::unique_ptr
<sm_context
> *out_sm_context
) = 0;
805 /* Precanned ways for clients to access specific state machines. */
806 bool get_fd_map (sm_state_map
**out_smap
,
807 const state_machine
**out_sm
,
808 unsigned *out_sm_idx
,
809 std::unique_ptr
<sm_context
> *out_sm_context
)
811 return get_state_map_by_name ("file-descriptor", out_smap
, out_sm
,
812 out_sm_idx
, out_sm_context
);
814 bool get_malloc_map (sm_state_map
**out_smap
,
815 const state_machine
**out_sm
,
816 unsigned *out_sm_idx
)
818 return get_state_map_by_name ("malloc", out_smap
, out_sm
, out_sm_idx
, NULL
);
820 bool get_taint_map (sm_state_map
**out_smap
,
821 const state_machine
**out_sm
,
822 unsigned *out_sm_idx
)
824 return get_state_map_by_name ("taint", out_smap
, out_sm
, out_sm_idx
, NULL
);
827 bool possibly_tainted_p (const svalue
*sval
);
829 /* Get the current statement, if any. */
830 virtual const gimple
*get_stmt () const = 0;
832 virtual const exploded_graph
*get_eg () const = 0;
834 /* Hooks for detecting infinite loops. */
835 virtual void maybe_did_work () = 0;
836 virtual bool checking_for_infinite_loop_p () const = 0;
837 virtual void on_unusable_in_infinite_loop () = 0;
840 /* A "do nothing" subclass of region_model_context. */
842 class noop_region_model_context
: public region_model_context
845 bool warn (std::unique_ptr
<pending_diagnostic
>,
846 const stmt_finder
*) override
{ return false; }
847 void add_note (std::unique_ptr
<pending_note
>) override
;
848 void add_event (std::unique_ptr
<checker_event
>) override
;
849 void on_svalue_leak (const svalue
*) override
{}
850 void on_liveness_change (const svalue_set
&,
851 const region_model
*) override
{}
852 logger
*get_logger () override
{ return NULL
; }
853 void on_condition (const svalue
*lhs ATTRIBUTE_UNUSED
,
854 enum tree_code op ATTRIBUTE_UNUSED
,
855 const svalue
*rhs ATTRIBUTE_UNUSED
) override
858 void on_bounded_ranges (const svalue
&,
859 const bounded_ranges
&) override
862 void on_pop_frame (const frame_region
*) override
{}
863 void on_unknown_change (const svalue
*sval ATTRIBUTE_UNUSED
,
864 bool is_mutable ATTRIBUTE_UNUSED
) override
867 void on_phi (const gphi
*phi ATTRIBUTE_UNUSED
,
868 tree rhs ATTRIBUTE_UNUSED
) override
871 void on_unexpected_tree_code (tree
, const dump_location_t
&) override
{}
873 void on_escaped_function (tree
) override
{}
875 uncertainty_t
*get_uncertainty () override
{ return NULL
; }
877 void purge_state_involving (const svalue
*sval ATTRIBUTE_UNUSED
) override
{}
879 void bifurcate (std::unique_ptr
<custom_edge_info
> info
) override
;
880 void terminate_path () override
;
882 const extrinsic_state
*get_ext_state () const override
{ return NULL
; }
884 bool get_state_map_by_name (const char *,
886 const state_machine
**,
888 std::unique_ptr
<sm_context
> *) override
893 const gimple
*get_stmt () const override
{ return NULL
; }
894 const exploded_graph
*get_eg () const override
{ return NULL
; }
895 void maybe_did_work () override
{}
896 bool checking_for_infinite_loop_p () const override
{ return false; }
897 void on_unusable_in_infinite_loop () override
{}
900 /* A subclass of region_model_context for determining if operations fail
901 e.g. "can we generate a region for the lvalue of EXPR?". */
903 class tentative_region_model_context
: public noop_region_model_context
906 tentative_region_model_context () : m_num_unexpected_codes (0) {}
908 void on_unexpected_tree_code (tree
, const dump_location_t
&)
911 m_num_unexpected_codes
++;
914 bool had_errors_p () const { return m_num_unexpected_codes
> 0; }
917 int m_num_unexpected_codes
;
920 /* Subclass of region_model_context that wraps another context, allowing
921 for extra code to be added to the various hooks. */
923 class region_model_context_decorator
: public region_model_context
926 bool warn (std::unique_ptr
<pending_diagnostic
> d
,
927 const stmt_finder
*custom_finder
) override
930 return m_inner
->warn (std::move (d
), custom_finder
);
935 void add_note (std::unique_ptr
<pending_note
> pn
) override
938 m_inner
->add_note (std::move (pn
));
940 void add_event (std::unique_ptr
<checker_event
> event
) override
;
942 void on_svalue_leak (const svalue
*sval
) override
945 m_inner
->on_svalue_leak (sval
);
948 void on_liveness_change (const svalue_set
&live_svalues
,
949 const region_model
*model
) override
952 m_inner
->on_liveness_change (live_svalues
, model
);
955 logger
*get_logger () override
958 return m_inner
->get_logger ();
963 void on_condition (const svalue
*lhs
,
965 const svalue
*rhs
) override
968 m_inner
->on_condition (lhs
, op
, rhs
);
971 void on_bounded_ranges (const svalue
&sval
,
972 const bounded_ranges
&ranges
) override
975 m_inner
->on_bounded_ranges (sval
, ranges
);
978 void on_pop_frame (const frame_region
*frame_reg
) override
981 m_inner
->on_pop_frame (frame_reg
);
984 void on_unknown_change (const svalue
*sval
, bool is_mutable
) override
987 m_inner
->on_unknown_change (sval
, is_mutable
);
990 void on_phi (const gphi
*phi
, tree rhs
) override
993 m_inner
->on_phi (phi
, rhs
);
996 void on_unexpected_tree_code (tree t
,
997 const dump_location_t
&loc
) override
1000 m_inner
->on_unexpected_tree_code (t
, loc
);
1003 void on_escaped_function (tree fndecl
) override
1006 m_inner
->on_escaped_function (fndecl
);
1009 uncertainty_t
*get_uncertainty () override
1012 return m_inner
->get_uncertainty ();
1017 void purge_state_involving (const svalue
*sval
) override
1020 m_inner
->purge_state_involving (sval
);
1023 void bifurcate (std::unique_ptr
<custom_edge_info
> info
) override
1026 m_inner
->bifurcate (std::move (info
));
1029 void terminate_path () override
1032 m_inner
->terminate_path ();
1035 const extrinsic_state
*get_ext_state () const override
1038 return m_inner
->get_ext_state ();
1043 bool get_state_map_by_name (const char *name
,
1044 sm_state_map
**out_smap
,
1045 const state_machine
**out_sm
,
1046 unsigned *out_sm_idx
,
1047 std::unique_ptr
<sm_context
> *out_sm_context
)
1051 return m_inner
->get_state_map_by_name (name
, out_smap
, out_sm
, out_sm_idx
,
1057 const gimple
*get_stmt () const override
1060 return m_inner
->get_stmt ();
1065 const exploded_graph
*get_eg () const override
1068 return m_inner
->get_eg ();
1073 void maybe_did_work () override
1076 m_inner
->maybe_did_work ();
1079 bool checking_for_infinite_loop_p () const override
1082 return m_inner
->checking_for_infinite_loop_p ();
1085 void on_unusable_in_infinite_loop () override
1088 m_inner
->on_unusable_in_infinite_loop ();
1092 region_model_context_decorator (region_model_context
*inner
)
1097 region_model_context
*m_inner
;
1100 /* Subclass of region_model_context_decorator with a hook for adding
1101 notes/events when saving diagnostics. */
1103 class annotating_context
: public region_model_context_decorator
1106 bool warn (std::unique_ptr
<pending_diagnostic
> d
,
1107 const stmt_finder
*custom_finder
) override
1110 if (m_inner
->warn (std::move (d
), custom_finder
))
1118 /* Hook to add new event(s)/note(s) */
1119 virtual void add_annotations () = 0;
1122 annotating_context (region_model_context
*inner
)
1123 : region_model_context_decorator (inner
)
1128 /* A bundle of data for use when attempting to merge two region_model
1129 instances to make a third. */
1133 model_merger (const region_model
*model_a
,
1134 const region_model
*model_b
,
1135 const program_point
&point
,
1136 region_model
*merged_model
,
1137 const extrinsic_state
*ext_state
,
1138 const program_state
*state_a
,
1139 const program_state
*state_b
)
1140 : m_model_a (model_a
), m_model_b (model_b
),
1142 m_merged_model (merged_model
),
1143 m_ext_state (ext_state
),
1144 m_state_a (state_a
), m_state_b (state_b
)
1148 void dump_to_pp (pretty_printer
*pp
, bool simple
) const;
1149 void dump (FILE *fp
, bool simple
) const;
1150 void dump (bool simple
) const;
1152 region_model_manager
*get_manager () const
1154 return m_model_a
->get_manager ();
1157 bool mergeable_svalue_p (const svalue
*) const;
1158 const function_point
&get_function_point () const
1160 return m_point
.get_function_point ();
1163 void on_widening_reuse (const widening_svalue
*widening_sval
);
1165 const region_model
*m_model_a
;
1166 const region_model
*m_model_b
;
1167 const program_point
&m_point
;
1168 region_model
*m_merged_model
;
1170 const extrinsic_state
*m_ext_state
;
1171 const program_state
*m_state_a
;
1172 const program_state
*m_state_b
;
1174 hash_set
<const svalue
*> m_svals_changing_meaning
;
1177 /* A record that can (optionally) be written out when
1178 region_model::add_constraint fails. */
1180 class rejected_constraint
1183 virtual ~rejected_constraint () {}
1184 virtual void dump_to_pp (pretty_printer
*pp
) const = 0;
1186 const region_model
&get_model () const { return m_model
; }
1189 rejected_constraint (const region_model
&model
)
1193 region_model m_model
;
1196 class rejected_op_constraint
: public rejected_constraint
1199 rejected_op_constraint (const region_model
&model
,
1200 tree lhs
, enum tree_code op
, tree rhs
)
1201 : rejected_constraint (model
),
1202 m_lhs (lhs
), m_op (op
), m_rhs (rhs
)
1205 void dump_to_pp (pretty_printer
*pp
) const final override
;
1208 enum tree_code m_op
;
1212 class rejected_default_case
: public rejected_constraint
1215 rejected_default_case (const region_model
&model
)
1216 : rejected_constraint (model
)
1219 void dump_to_pp (pretty_printer
*pp
) const final override
;
1222 class rejected_ranges_constraint
: public rejected_constraint
1225 rejected_ranges_constraint (const region_model
&model
,
1226 tree expr
, const bounded_ranges
*ranges
)
1227 : rejected_constraint (model
),
1228 m_expr (expr
), m_ranges (ranges
)
1231 void dump_to_pp (pretty_printer
*pp
) const final override
;
1235 const bounded_ranges
*m_ranges
;
1238 /* A bundle of state. */
1243 engine (const supergraph
*sg
= NULL
, logger
*logger
= NULL
);
1244 const supergraph
*get_supergraph () { return m_sg
; }
1245 region_model_manager
*get_model_manager () { return &m_mgr
; }
1246 known_function_manager
*get_known_function_manager ()
1248 return m_mgr
.get_known_function_manager ();
1251 void log_stats (logger
*logger
) const;
1254 const supergraph
*m_sg
;
1255 region_model_manager m_mgr
;
1260 extern void debug (const region_model
&rmodel
);
1266 namespace selftest
{
1268 using namespace ::selftest
;
1270 /* An implementation of region_model_context for use in selftests, which
1271 stores any pending_diagnostic instances passed to it. */
1273 class test_region_model_context
: public noop_region_model_context
1276 bool warn (std::unique_ptr
<pending_diagnostic
> d
,
1277 const stmt_finder
*) final override
1279 m_diagnostics
.safe_push (d
.release ());
1283 unsigned get_num_diagnostics () const { return m_diagnostics
.length (); }
1285 void on_unexpected_tree_code (tree t
, const dump_location_t
&)
1288 internal_error ("unhandled tree code: %qs",
1289 get_tree_code_name (TREE_CODE (t
)));
1293 /* Implicitly delete any diagnostics in the dtor. */
1294 auto_delete_vec
<pending_diagnostic
> m_diagnostics
;
1297 /* Attempt to add the constraint (LHS OP RHS) to MODEL.
1298 Verify that MODEL remains satisfiable. */
1300 #define ADD_SAT_CONSTRAINT(MODEL, LHS, OP, RHS) \
1301 SELFTEST_BEGIN_STMT \
1302 bool sat = (MODEL).add_constraint (LHS, OP, RHS, NULL); \
1303 ASSERT_TRUE (sat); \
1306 /* Attempt to add the constraint (LHS OP RHS) to MODEL.
1307 Verify that the result is not satisfiable. */
1309 #define ADD_UNSAT_CONSTRAINT(MODEL, LHS, OP, RHS) \
1310 SELFTEST_BEGIN_STMT \
1311 bool sat = (MODEL).add_constraint (LHS, OP, RHS, NULL); \
1312 ASSERT_FALSE (sat); \
1315 /* Implementation detail of the ASSERT_CONDITION_* macros. */
1317 void assert_condition (const location
&loc
,
1318 region_model
&model
,
1319 const svalue
*lhs
, tree_code op
, const svalue
*rhs
,
1322 void assert_condition (const location
&loc
,
1323 region_model
&model
,
1324 tree lhs
, tree_code op
, tree rhs
,
1327 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1330 #define ASSERT_CONDITION_TRUE(REGION_MODEL, LHS, OP, RHS) \
1331 SELFTEST_BEGIN_STMT \
1332 assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS, \
1333 tristate (tristate::TS_TRUE)); \
1336 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1339 #define ASSERT_CONDITION_FALSE(REGION_MODEL, LHS, OP, RHS) \
1340 SELFTEST_BEGIN_STMT \
1341 assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS, \
1342 tristate (tristate::TS_FALSE)); \
1345 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1348 #define ASSERT_CONDITION_UNKNOWN(REGION_MODEL, LHS, OP, RHS) \
1349 SELFTEST_BEGIN_STMT \
1350 assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS, \
1351 tristate (tristate::TS_UNKNOWN)); \
1354 } /* end of namespace selftest. */
1356 #endif /* #if CHECKING_P */
1360 #endif /* GCC_ANALYZER_REGION_MODEL_H */