1 /* Classes for modeling the state of memory.
2 Copyright (C) 2019-2023 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 */
31 #include "analyzer/svalue.h"
32 #include "analyzer/region.h"
33 #include "analyzer/known-function-manager.h"
34 #include "analyzer/region-model-manager.h"
35 #include "analyzer/pending-diagnostic.h"
41 extern void add_path_var (path_var pv
, hash
&hstate
);
42 } // namespace inchash
50 one_way_id_map (int num_ids
);
51 void put (T src
, T dst
);
52 T
get_dst_for_src (T src
) const;
53 void dump_to_pp (pretty_printer
*pp
) const;
55 void update (T
*) const;
58 auto_vec
<T
> m_src_to_dst
;
61 /* class one_way_id_map. */
63 /* one_way_id_map's ctor, which populates the map with dummy null values. */
66 inline one_way_id_map
<T
>::one_way_id_map (int num_svalues
)
67 : m_src_to_dst (num_svalues
)
69 for (int i
= 0; i
< num_svalues
; i
++)
70 m_src_to_dst
.quick_push (T::null ());
73 /* Record that SRC is to be mapped to DST. */
77 one_way_id_map
<T
>::put (T src
, T dst
)
79 m_src_to_dst
[src
.as_int ()] = dst
;
82 /* Get the new value for SRC within the map. */
86 one_way_id_map
<T
>::get_dst_for_src (T src
) const
90 return m_src_to_dst
[src
.as_int ()];
93 /* Dump this map to PP. */
97 one_way_id_map
<T
>::dump_to_pp (pretty_printer
*pp
) const
99 pp_string (pp
, "src to dst: {");
102 FOR_EACH_VEC_ELT (m_src_to_dst
, i
, dst
)
105 pp_string (pp
, ", ");
106 T
src (T::from_int (i
));
108 pp_string (pp
, " -> ");
115 /* Dump this map to stderr. */
117 template <typename T
>
118 DEBUG_FUNCTION
inline void
119 one_way_id_map
<T
>::dump () const
122 pp
.buffer
->stream
= stderr
;
127 /* Update *ID from the old value to its new value in this map. */
129 template <typename T
>
131 one_way_id_map
<T
>::update (T
*id
) const
133 *id
= get_dst_for_src (*id
);
136 /* A mapping from region to svalue for use when tracking state. */
138 class region_to_value_map
141 typedef hash_map
<const region
*, const svalue
*> hash_map_t
;
142 typedef hash_map_t::iterator iterator
;
144 region_to_value_map () : m_hash_map () {}
145 region_to_value_map (const region_to_value_map
&other
)
146 : m_hash_map (other
.m_hash_map
) {}
147 region_to_value_map
&operator= (const region_to_value_map
&other
);
149 bool operator== (const region_to_value_map
&other
) const;
150 bool operator!= (const region_to_value_map
&other
) const
152 return !(*this == other
);
155 iterator
begin () const { return m_hash_map
.begin (); }
156 iterator
end () const { return m_hash_map
.end (); }
158 const svalue
* const *get (const region
*reg
) const
160 return const_cast <hash_map_t
&> (m_hash_map
).get (reg
);
162 void put (const region
*reg
, const svalue
*sval
)
164 m_hash_map
.put (reg
, sval
);
166 void remove (const region
*reg
)
168 m_hash_map
.remove (reg
);
171 bool is_empty () const { return m_hash_map
.is_empty (); }
173 void dump_to_pp (pretty_printer
*pp
, bool simple
, bool multiline
) const;
174 void dump (bool simple
) const;
176 bool can_merge_with_p (const region_to_value_map
&other
,
177 region_to_value_map
*out
) const;
179 void purge_state_involving (const svalue
*sval
);
182 hash_map_t m_hash_map
;
185 /* Various operations delete information from a region_model.
187 This struct tracks how many of each kind of entity were purged (e.g.
188 for selftests, and for debugging). */
195 m_num_equiv_classes (0),
196 m_num_constraints (0),
197 m_num_bounded_ranges_constraints (0),
198 m_num_client_items (0)
203 int m_num_equiv_classes
;
204 int m_num_constraints
;
205 int m_num_bounded_ranges_constraints
;
206 int m_num_client_items
;
209 /* A base class for visiting regions and svalues, with do-nothing
210 base implementations of the per-subclass vfuncs. */
215 virtual void visit_region_svalue (const region_svalue
*) {}
216 virtual void visit_constant_svalue (const constant_svalue
*) {}
217 virtual void visit_unknown_svalue (const unknown_svalue
*) {}
218 virtual void visit_poisoned_svalue (const poisoned_svalue
*) {}
219 virtual void visit_setjmp_svalue (const setjmp_svalue
*) {}
220 virtual void visit_initial_svalue (const initial_svalue
*) {}
221 virtual void visit_unaryop_svalue (const unaryop_svalue
*) {}
222 virtual void visit_binop_svalue (const binop_svalue
*) {}
223 virtual void visit_sub_svalue (const sub_svalue
*) {}
224 virtual void visit_repeated_svalue (const repeated_svalue
*) {}
225 virtual void visit_bits_within_svalue (const bits_within_svalue
*) {}
226 virtual void visit_unmergeable_svalue (const unmergeable_svalue
*) {}
227 virtual void visit_placeholder_svalue (const placeholder_svalue
*) {}
228 virtual void visit_widening_svalue (const widening_svalue
*) {}
229 virtual void visit_compound_svalue (const compound_svalue
*) {}
230 virtual void visit_conjured_svalue (const conjured_svalue
*) {}
231 virtual void visit_asm_output_svalue (const asm_output_svalue
*) {}
232 virtual void visit_const_fn_result_svalue (const const_fn_result_svalue
*) {}
234 virtual void visit_region (const region
*) {}
237 struct append_regions_cb_data
;
239 typedef void (*pop_frame_callback
) (const region_model
*model
,
240 const region_model
*prev_model
,
241 const svalue
*retval
,
242 region_model_context
*ctxt
);
244 /* A region_model encapsulates a representation of the state of memory, with
245 a tree of regions, along with their associated values.
246 The representation is graph-like because values can be pointers to
249 - a constraint_manager, capturing relationships between the values, and
250 - dynamic extents, mapping dynamically-allocated regions to svalues (their
256 typedef region_to_value_map dynamic_extents_t
;
258 region_model (region_model_manager
*mgr
);
259 region_model (const region_model
&other
);
261 region_model
&operator= (const region_model
&other
);
263 bool operator== (const region_model
&other
) const;
264 bool operator!= (const region_model
&other
) const
266 return !(*this == other
);
269 hashval_t
hash () const;
271 void print (pretty_printer
*pp
) const;
273 void dump_to_pp (pretty_printer
*pp
, bool simple
, bool multiline
) const;
274 void dump (FILE *fp
, bool simple
, bool multiline
) const;
275 void dump (bool simple
) const;
279 void validate () const;
281 void canonicalize ();
282 bool canonicalized_p () const;
285 on_stmt_pre (const gimple
*stmt
,
286 bool *out_unknown_side_effects
,
287 region_model_context
*ctxt
);
289 void on_assignment (const gassign
*stmt
, region_model_context
*ctxt
);
290 const svalue
*get_gassign_result (const gassign
*assign
,
291 region_model_context
*ctxt
);
292 void on_asm_stmt (const gasm
*asm_stmt
, region_model_context
*ctxt
);
293 bool on_call_pre (const gcall
*stmt
, region_model_context
*ctxt
);
294 void on_call_post (const gcall
*stmt
,
295 bool unknown_side_effects
,
296 region_model_context
*ctxt
);
298 void purge_state_involving (const svalue
*sval
, region_model_context
*ctxt
);
300 void impl_deallocation_call (const call_details
&cd
);
302 const svalue
*maybe_get_copy_bounds (const region
*src_reg
,
303 const svalue
*num_bytes_sval
);
304 void update_for_int_cst_return (const call_details
&cd
,
307 void update_for_zero_return (const call_details
&cd
,
309 void update_for_nonzero_return (const call_details
&cd
);
311 void handle_unrecognized_call (const gcall
*call
,
312 region_model_context
*ctxt
);
313 void get_reachable_svalues (svalue_set
*out
,
314 const svalue
*extra_sval
,
315 const uncertainty_t
*uncertainty
);
317 void on_return (const greturn
*stmt
, region_model_context
*ctxt
);
318 void on_setjmp (const gcall
*stmt
, const exploded_node
*enode
,
319 region_model_context
*ctxt
);
320 void on_longjmp (const gcall
*longjmp_call
, const gcall
*setjmp_call
,
321 int setjmp_stack_depth
, region_model_context
*ctxt
);
323 void update_for_phis (const supernode
*snode
,
324 const cfg_superedge
*last_cfg_superedge
,
325 region_model_context
*ctxt
);
327 void handle_phi (const gphi
*phi
, tree lhs
, tree rhs
,
328 const region_model
&old_state
,
329 region_model_context
*ctxt
);
331 bool maybe_update_for_edge (const superedge
&edge
,
332 const gimple
*last_stmt
,
333 region_model_context
*ctxt
,
334 rejected_constraint
**out
);
336 void update_for_gcall (const gcall
*call_stmt
,
337 region_model_context
*ctxt
,
338 function
*callee
= NULL
);
340 void update_for_return_gcall (const gcall
*call_stmt
,
341 region_model_context
*ctxt
);
343 const region
*push_frame (function
*fun
, const vec
<const svalue
*> *arg_sids
,
344 region_model_context
*ctxt
);
345 const frame_region
*get_current_frame () const { return m_current_frame
; }
346 function
* get_current_function () const;
347 void pop_frame (tree result_lvalue
,
348 const svalue
**out_result
,
349 region_model_context
*ctxt
,
350 bool eval_return_svalue
= true);
351 int get_stack_depth () const;
352 const frame_region
*get_frame_at_index (int index
) const;
354 const region
*get_lvalue (path_var pv
, region_model_context
*ctxt
) const;
355 const region
*get_lvalue (tree expr
, region_model_context
*ctxt
) const;
356 const svalue
*get_rvalue (path_var pv
, region_model_context
*ctxt
) const;
357 const svalue
*get_rvalue (tree expr
, region_model_context
*ctxt
) const;
359 const region
*deref_rvalue (const svalue
*ptr_sval
, tree ptr_tree
,
360 region_model_context
*ctxt
,
361 bool add_nonnull_constraint
= true) const;
363 const svalue
*get_rvalue_for_bits (tree type
,
365 const bit_range
&bits
,
366 region_model_context
*ctxt
) const;
368 void set_value (const region
*lhs_reg
, const svalue
*rhs_sval
,
369 region_model_context
*ctxt
);
370 void set_value (tree lhs
, tree rhs
, region_model_context
*ctxt
);
371 void clobber_region (const region
*reg
);
372 void purge_region (const region
*reg
);
373 void fill_region (const region
*reg
,
375 region_model_context
*ctxt
);
376 void zero_fill_region (const region
*reg
,
377 region_model_context
*ctxt
);
378 void write_bytes (const region
*dest_reg
,
379 const svalue
*num_bytes_sval
,
381 region_model_context
*ctxt
);
382 const svalue
*read_bytes (const region
*src_reg
,
384 const svalue
*num_bytes_sval
,
385 region_model_context
*ctxt
) const;
386 void copy_bytes (const region
*dest_reg
,
387 const region
*src_reg
,
389 const svalue
*num_bytes_sval
,
390 region_model_context
*ctxt
);
391 void mark_region_as_unknown (const region
*reg
, uncertainty_t
*uncertainty
);
393 tristate
eval_condition (const svalue
*lhs
,
395 const svalue
*rhs
) const;
396 tristate
compare_initial_and_pointer (const initial_svalue
*init
,
397 const region_svalue
*ptr
) const;
398 tristate
symbolic_greater_than (const binop_svalue
*a
,
399 const svalue
*b
) const;
400 tristate
structural_equality (const svalue
*a
, const svalue
*b
) const;
401 tristate
eval_condition (tree lhs
,
404 region_model_context
*ctxt
) const;
405 bool add_constraint (tree lhs
, enum tree_code op
, tree rhs
,
406 region_model_context
*ctxt
);
407 bool add_constraint (tree lhs
, enum tree_code op
, tree rhs
,
408 region_model_context
*ctxt
,
409 rejected_constraint
**out
);
412 get_or_create_region_for_heap_alloc (const svalue
*size_in_bytes
,
413 region_model_context
*ctxt
,
414 bool update_state_machine
= false,
415 const call_details
*cd
= nullptr);
417 const region
*create_region_for_alloca (const svalue
*size_in_bytes
,
418 region_model_context
*ctxt
);
419 void get_referenced_base_regions (auto_bitmap
&out_ids
) const;
421 tree
get_representative_tree (const svalue
*sval
) const;
422 tree
get_representative_tree (const region
*reg
) const;
424 get_representative_path_var (const svalue
*sval
,
425 svalue_set
*visited
) const;
427 get_representative_path_var (const region
*reg
,
428 svalue_set
*visited
) const;
431 constraint_manager
*get_constraints ()
433 return m_constraints
;
436 store
*get_store () { return &m_store
; }
437 const store
*get_store () const { return &m_store
; }
439 const dynamic_extents_t
&
440 get_dynamic_extents () const
442 return m_dynamic_extents
;
444 const svalue
*get_dynamic_extents (const region
*reg
) const;
445 void set_dynamic_extents (const region
*reg
,
446 const svalue
*size_in_bytes
,
447 region_model_context
*ctxt
);
448 void unset_dynamic_extents (const region
*reg
);
450 region_model_manager
*get_manager () const { return m_mgr
; }
451 bounded_ranges_manager
*get_range_manager () const
453 return m_mgr
->get_range_manager ();
456 void unbind_region_and_descendents (const region
*reg
,
457 enum poison_kind pkind
);
459 bool can_merge_with_p (const region_model
&other_model
,
460 const program_point
&point
,
461 region_model
*out_model
,
462 const extrinsic_state
*ext_state
= NULL
,
463 const program_state
*state_a
= NULL
,
464 const program_state
*state_b
= NULL
) const;
466 tree
get_fndecl_for_call (const gcall
*call
,
467 region_model_context
*ctxt
);
469 void get_regions_for_current_frame (auto_vec
<const decl_region
*> *out
) const;
470 static void append_regions_cb (const region
*base_reg
,
471 struct append_regions_cb_data
*data
);
473 const svalue
*get_store_value (const region
*reg
,
474 region_model_context
*ctxt
) const;
475 const svalue
*get_store_bytes (const region
*base_reg
,
476 const byte_range
&bytes
,
477 region_model_context
*ctxt
) const;
478 const svalue
*scan_for_null_terminator (const region
*reg
,
480 const svalue
**out_sval
,
481 region_model_context
*ctxt
) const;
483 bool region_exists_p (const region
*reg
) const;
485 void loop_replay_fixup (const region_model
*dst_state
);
487 const svalue
*get_capacity (const region
*reg
) const;
489 bool replay_call_summary (call_summary_replay
&r
,
490 const region_model
&summary
);
492 void maybe_complain_about_infoleak (const region
*dst_reg
,
493 const svalue
*copied_sval
,
494 const region
*src_reg
,
495 region_model_context
*ctxt
);
497 void set_errno (const call_details
&cd
);
499 /* Implemented in sm-fd.cc */
500 void mark_as_valid_fd (const svalue
*sval
, region_model_context
*ctxt
);
502 /* Implemented in sm-malloc.cc */
503 void on_realloc_with_move (const call_details
&cd
,
504 const svalue
*old_ptr_sval
,
505 const svalue
*new_ptr_sval
);
507 /* Implemented in sm-malloc.cc. */
509 transition_ptr_sval_non_null (region_model_context
*ctxt
,
510 const svalue
*new_ptr_sval
);
512 /* Implemented in sm-taint.cc. */
513 void mark_as_tainted (const svalue
*sval
,
514 region_model_context
*ctxt
);
516 bool add_constraint (const svalue
*lhs
,
519 region_model_context
*ctxt
);
521 const svalue
*check_for_poison (const svalue
*sval
,
523 const region
*src_region
,
524 region_model_context
*ctxt
) const;
526 void check_region_for_write (const region
*dest_reg
,
527 const svalue
*sval_hint
,
528 region_model_context
*ctxt
) const;
531 check_for_null_terminated_string_arg (const call_details
&cd
,
534 check_for_null_terminated_string_arg (const call_details
&cd
,
536 bool include_terminator
,
537 const svalue
**out_sval
);
539 const builtin_known_function
*
540 get_builtin_kf (const gcall
*call
,
541 region_model_context
*ctxt
= NULL
) const;
544 register_pop_frame_callback (const pop_frame_callback
&callback
)
546 pop_frame_callbacks
.safe_push (callback
);
550 notify_on_pop_frame (const region_model
*model
,
551 const region_model
*prev_model
,
552 const svalue
*retval
,
553 region_model_context
*ctxt
)
555 for (auto &callback
: pop_frame_callbacks
)
556 callback (model
, prev_model
, retval
, ctxt
);
560 const region
*get_lvalue_1 (path_var pv
, region_model_context
*ctxt
) const;
561 const svalue
*get_rvalue_1 (path_var pv
, region_model_context
*ctxt
) const;
564 get_representative_path_var_1 (const svalue
*sval
,
565 svalue_set
*visited
) const;
567 get_representative_path_var_1 (const region
*reg
,
568 svalue_set
*visited
) const;
570 const known_function
*get_known_function (tree fndecl
,
571 const call_details
&cd
) const;
572 const known_function
*get_known_function (enum internal_fn
) const;
574 bool add_constraints_from_binop (const svalue
*outer_lhs
,
575 enum tree_code outer_op
,
576 const svalue
*outer_rhs
,
578 region_model_context
*ctxt
);
580 void update_for_call_superedge (const call_superedge
&call_edge
,
581 region_model_context
*ctxt
);
582 void update_for_return_superedge (const return_superedge
&return_edge
,
583 region_model_context
*ctxt
);
584 bool apply_constraints_for_gcond (const cfg_superedge
&edge
,
585 const gcond
*cond_stmt
,
586 region_model_context
*ctxt
,
587 rejected_constraint
**out
);
588 bool apply_constraints_for_gswitch (const switch_cfg_superedge
&edge
,
589 const gswitch
*switch_stmt
,
590 region_model_context
*ctxt
,
591 rejected_constraint
**out
);
592 bool apply_constraints_for_ggoto (const cfg_superedge
&edge
,
593 const ggoto
*goto_stmt
,
594 region_model_context
*ctxt
);
595 bool apply_constraints_for_exception (const gimple
*last_stmt
,
596 region_model_context
*ctxt
,
597 rejected_constraint
**out
);
599 int poison_any_pointers_to_descendents (const region
*reg
,
600 enum poison_kind pkind
);
602 void on_top_level_param (tree param
,
604 region_model_context
*ctxt
);
606 bool called_from_main_p () const;
607 const svalue
*get_initial_value_for_global (const region
*reg
) const;
609 const region
* get_region_for_poisoned_expr (tree expr
) const;
611 void check_dynamic_size_for_taint (enum memory_space mem_space
,
612 const svalue
*size_in_bytes
,
613 region_model_context
*ctxt
) const;
614 void check_dynamic_size_for_floats (const svalue
*size_in_bytes
,
615 region_model_context
*ctxt
) const;
617 void check_region_for_taint (const region
*reg
,
618 enum access_direction dir
,
619 region_model_context
*ctxt
) const;
621 void check_for_writable_region (const region
* dest_reg
,
622 region_model_context
*ctxt
) const;
623 bool check_region_access (const region
*reg
,
624 enum access_direction dir
,
625 const svalue
*sval_hint
,
626 region_model_context
*ctxt
) const;
627 bool check_region_for_read (const region
*src_reg
,
628 region_model_context
*ctxt
) const;
629 void check_region_size (const region
*lhs_reg
, const svalue
*rhs_sval
,
630 region_model_context
*ctxt
) const;
632 /* Implemented in bounds-checking.cc */
633 bool check_symbolic_bounds (const region
*base_reg
,
634 const svalue
*sym_byte_offset
,
635 const svalue
*num_bytes_sval
,
636 const svalue
*capacity
,
637 enum access_direction dir
,
638 const svalue
*sval_hint
,
639 region_model_context
*ctxt
) const;
640 bool check_region_bounds (const region
*reg
, enum access_direction dir
,
641 const svalue
*sval_hint
,
642 region_model_context
*ctxt
) const;
644 void check_call_args (const call_details
&cd
) const;
645 void check_call_format_attr (const call_details
&cd
,
646 tree format_attr
) const;
647 void check_external_function_for_access_attr (const gcall
*call
,
649 region_model_context
*ctxt
) const;
651 static auto_vec
<pop_frame_callback
> pop_frame_callbacks
;
652 /* Storing this here to avoid passing it around everywhere. */
653 region_model_manager
*const m_mgr
;
657 constraint_manager
*m_constraints
; // TODO: embed, rather than dynalloc?
659 const frame_region
*m_current_frame
;
661 /* Map from base region to size in bytes, for tracking the sizes of
662 dynamically-allocated regions.
663 This is part of the region_model rather than the region to allow for
664 memory regions to be resized (e.g. by realloc). */
665 dynamic_extents_t m_dynamic_extents
;
668 /* Some region_model activity could lead to warnings (e.g. attempts to use an
669 uninitialized value). This abstract base class encapsulates an interface
670 for the region model to use when emitting such warnings.
672 Having this as an abstract base class allows us to support the various
673 operations needed by program_state in the analyzer within region_model,
674 whilst keeping them somewhat modularized. */
676 class region_model_context
679 /* Hook for clients to store pending diagnostics.
680 Return true if the diagnostic was stored, or false if it was deleted.
681 Optionally provide a custom stmt_finder. */
682 virtual bool warn (std::unique_ptr
<pending_diagnostic
> d
,
683 const stmt_finder
*custom_finder
= NULL
) = 0;
685 /* Hook for clients to add a note to the last previously stored
686 pending diagnostic. */
687 virtual void add_note (std::unique_ptr
<pending_note
> pn
) = 0;
689 /* Hook for clients to add an event to the last previously stored
690 pending diagnostic. */
691 virtual void add_event (std::unique_ptr
<checker_event
> event
) = 0;
693 /* Hook for clients to be notified when an SVAL that was reachable
694 in a previous state is no longer live, so that clients can emit warnings
696 virtual void on_svalue_leak (const svalue
*sval
) = 0;
698 /* Hook for clients to be notified when the set of explicitly live
699 svalues changes, so that they can purge state relating to dead
701 virtual void on_liveness_change (const svalue_set
&live_svalues
,
702 const region_model
*model
) = 0;
704 virtual logger
*get_logger () = 0;
706 /* Hook for clients to be notified when the condition
707 "LHS OP RHS" is added to the region model.
708 This exists so that state machines can detect tests on edges,
709 and use them to trigger sm-state transitions (e.g. transitions due
710 to ptrs becoming known to be NULL or non-NULL, rather than just
712 virtual void on_condition (const svalue
*lhs
,
714 const svalue
*rhs
) = 0;
716 /* Hook for clients to be notified when the condition that
717 SVAL is within RANGES is added to the region model.
718 Similar to on_condition, but for use when handling switch statements.
719 RANGES is non-empty. */
720 virtual void on_bounded_ranges (const svalue
&sval
,
721 const bounded_ranges
&ranges
) = 0;
723 /* Hook for clients to be notified when a frame is popped from the stack. */
724 virtual void on_pop_frame (const frame_region
*) = 0;
726 /* Hooks for clients to be notified when an unknown change happens
727 to SVAL (in response to a call to an unknown function). */
728 virtual void on_unknown_change (const svalue
*sval
, bool is_mutable
) = 0;
730 /* Hooks for clients to be notified when a phi node is handled,
731 where RHS is the pertinent argument. */
732 virtual void on_phi (const gphi
*phi
, tree rhs
) = 0;
734 /* Hooks for clients to be notified when the region model doesn't
735 know how to handle the tree code of T at LOC. */
736 virtual void on_unexpected_tree_code (tree t
,
737 const dump_location_t
&loc
) = 0;
739 /* Hook for clients to be notified when a function_decl escapes. */
740 virtual void on_escaped_function (tree fndecl
) = 0;
742 virtual uncertainty_t
*get_uncertainty () = 0;
744 /* Hook for clients to purge state involving SVAL. */
745 virtual void purge_state_involving (const svalue
*sval
) = 0;
747 /* Hook for clients to split state with a non-standard path. */
748 virtual void bifurcate (std::unique_ptr
<custom_edge_info
> info
) = 0;
750 /* Hook for clients to terminate the standard path. */
751 virtual void terminate_path () = 0;
753 virtual const extrinsic_state
*get_ext_state () const = 0;
755 /* Hook for clients to access the a specific state machine in
756 any underlying program_state. */
758 get_state_map_by_name (const char *name
,
759 sm_state_map
**out_smap
,
760 const state_machine
**out_sm
,
761 unsigned *out_sm_idx
,
762 std::unique_ptr
<sm_context
> *out_sm_context
) = 0;
764 /* Precanned ways for clients to access specific state machines. */
765 bool get_fd_map (sm_state_map
**out_smap
,
766 const state_machine
**out_sm
,
767 unsigned *out_sm_idx
,
768 std::unique_ptr
<sm_context
> *out_sm_context
)
770 return get_state_map_by_name ("file-descriptor", out_smap
, out_sm
,
771 out_sm_idx
, out_sm_context
);
773 bool get_malloc_map (sm_state_map
**out_smap
,
774 const state_machine
**out_sm
,
775 unsigned *out_sm_idx
)
777 return get_state_map_by_name ("malloc", out_smap
, out_sm
, out_sm_idx
, NULL
);
779 bool get_taint_map (sm_state_map
**out_smap
,
780 const state_machine
**out_sm
,
781 unsigned *out_sm_idx
)
783 return get_state_map_by_name ("taint", out_smap
, out_sm
, out_sm_idx
, NULL
);
786 bool possibly_tainted_p (const svalue
*sval
);
788 /* Get the current statement, if any. */
789 virtual const gimple
*get_stmt () const = 0;
791 virtual const exploded_graph
*get_eg () const = 0;
794 /* A "do nothing" subclass of region_model_context. */
796 class noop_region_model_context
: public region_model_context
799 bool warn (std::unique_ptr
<pending_diagnostic
>,
800 const stmt_finder
*) override
{ return false; }
801 void add_note (std::unique_ptr
<pending_note
>) override
;
802 void add_event (std::unique_ptr
<checker_event
>) override
;
803 void on_svalue_leak (const svalue
*) override
{}
804 void on_liveness_change (const svalue_set
&,
805 const region_model
*) override
{}
806 logger
*get_logger () override
{ return NULL
; }
807 void on_condition (const svalue
*lhs ATTRIBUTE_UNUSED
,
808 enum tree_code op ATTRIBUTE_UNUSED
,
809 const svalue
*rhs ATTRIBUTE_UNUSED
) override
812 void on_bounded_ranges (const svalue
&,
813 const bounded_ranges
&) override
816 void on_pop_frame (const frame_region
*) override
{}
817 void on_unknown_change (const svalue
*sval ATTRIBUTE_UNUSED
,
818 bool is_mutable ATTRIBUTE_UNUSED
) override
821 void on_phi (const gphi
*phi ATTRIBUTE_UNUSED
,
822 tree rhs ATTRIBUTE_UNUSED
) override
825 void on_unexpected_tree_code (tree
, const dump_location_t
&) override
{}
827 void on_escaped_function (tree
) override
{}
829 uncertainty_t
*get_uncertainty () override
{ return NULL
; }
831 void purge_state_involving (const svalue
*sval ATTRIBUTE_UNUSED
) override
{}
833 void bifurcate (std::unique_ptr
<custom_edge_info
> info
) override
;
834 void terminate_path () override
;
836 const extrinsic_state
*get_ext_state () const override
{ return NULL
; }
838 bool get_state_map_by_name (const char *,
840 const state_machine
**,
842 std::unique_ptr
<sm_context
> *) override
847 const gimple
*get_stmt () const override
{ return NULL
; }
848 const exploded_graph
*get_eg () const override
{ return NULL
; }
851 /* A subclass of region_model_context for determining if operations fail
852 e.g. "can we generate a region for the lvalue of EXPR?". */
854 class tentative_region_model_context
: public noop_region_model_context
857 tentative_region_model_context () : m_num_unexpected_codes (0) {}
859 void on_unexpected_tree_code (tree
, const dump_location_t
&)
862 m_num_unexpected_codes
++;
865 bool had_errors_p () const { return m_num_unexpected_codes
> 0; }
868 int m_num_unexpected_codes
;
871 /* Subclass of region_model_context that wraps another context, allowing
872 for extra code to be added to the various hooks. */
874 class region_model_context_decorator
: public region_model_context
877 bool warn (std::unique_ptr
<pending_diagnostic
> d
,
878 const stmt_finder
*custom_finder
)
881 return m_inner
->warn (std::move (d
), custom_finder
);
886 void add_note (std::unique_ptr
<pending_note
> pn
) override
889 m_inner
->add_note (std::move (pn
));
891 void add_event (std::unique_ptr
<checker_event
> event
) override
;
893 void on_svalue_leak (const svalue
*sval
) override
896 m_inner
->on_svalue_leak (sval
);
899 void on_liveness_change (const svalue_set
&live_svalues
,
900 const region_model
*model
) override
903 m_inner
->on_liveness_change (live_svalues
, model
);
906 logger
*get_logger () override
909 return m_inner
->get_logger ();
914 void on_condition (const svalue
*lhs
,
916 const svalue
*rhs
) override
919 m_inner
->on_condition (lhs
, op
, rhs
);
922 void on_bounded_ranges (const svalue
&sval
,
923 const bounded_ranges
&ranges
) override
926 m_inner
->on_bounded_ranges (sval
, ranges
);
929 void on_pop_frame (const frame_region
*frame_reg
) override
932 m_inner
->on_pop_frame (frame_reg
);
935 void on_unknown_change (const svalue
*sval
, bool is_mutable
) override
938 m_inner
->on_unknown_change (sval
, is_mutable
);
941 void on_phi (const gphi
*phi
, tree rhs
) override
944 m_inner
->on_phi (phi
, rhs
);
947 void on_unexpected_tree_code (tree t
,
948 const dump_location_t
&loc
) override
951 m_inner
->on_unexpected_tree_code (t
, loc
);
954 void on_escaped_function (tree fndecl
) override
957 m_inner
->on_escaped_function (fndecl
);
960 uncertainty_t
*get_uncertainty () override
963 return m_inner
->get_uncertainty ();
968 void purge_state_involving (const svalue
*sval
) override
971 m_inner
->purge_state_involving (sval
);
974 void bifurcate (std::unique_ptr
<custom_edge_info
> info
) override
977 m_inner
->bifurcate (std::move (info
));
980 void terminate_path () override
983 m_inner
->terminate_path ();
986 const extrinsic_state
*get_ext_state () const override
989 return m_inner
->get_ext_state ();
994 bool get_state_map_by_name (const char *name
,
995 sm_state_map
**out_smap
,
996 const state_machine
**out_sm
,
997 unsigned *out_sm_idx
,
998 std::unique_ptr
<sm_context
> *out_sm_context
)
1002 return m_inner
->get_state_map_by_name (name
, out_smap
, out_sm
, out_sm_idx
,
1008 const gimple
*get_stmt () const override
1011 return m_inner
->get_stmt ();
1016 const exploded_graph
*get_eg () const override
1019 return m_inner
->get_eg ();
1025 region_model_context_decorator (region_model_context
*inner
)
1030 region_model_context
*m_inner
;
1033 /* Subclass of region_model_context_decorator with a hook for adding
1034 notes/events when saving diagnostics. */
1036 class annotating_context
: public region_model_context_decorator
1039 bool warn (std::unique_ptr
<pending_diagnostic
> d
,
1040 const stmt_finder
*custom_finder
) override
1043 if (m_inner
->warn (std::move (d
), custom_finder
))
1051 /* Hook to add new event(s)/note(s) */
1052 virtual void add_annotations () = 0;
1055 annotating_context (region_model_context
*inner
)
1056 : region_model_context_decorator (inner
)
1061 /* A bundle of data for use when attempting to merge two region_model
1062 instances to make a third. */
1066 model_merger (const region_model
*model_a
,
1067 const region_model
*model_b
,
1068 const program_point
&point
,
1069 region_model
*merged_model
,
1070 const extrinsic_state
*ext_state
,
1071 const program_state
*state_a
,
1072 const program_state
*state_b
)
1073 : m_model_a (model_a
), m_model_b (model_b
),
1075 m_merged_model (merged_model
),
1076 m_ext_state (ext_state
),
1077 m_state_a (state_a
), m_state_b (state_b
)
1081 void dump_to_pp (pretty_printer
*pp
, bool simple
) const;
1082 void dump (FILE *fp
, bool simple
) const;
1083 void dump (bool simple
) const;
1085 region_model_manager
*get_manager () const
1087 return m_model_a
->get_manager ();
1090 bool mergeable_svalue_p (const svalue
*) const;
1091 const function_point
&get_function_point () const
1093 return m_point
.get_function_point ();
1096 const region_model
*m_model_a
;
1097 const region_model
*m_model_b
;
1098 const program_point
&m_point
;
1099 region_model
*m_merged_model
;
1101 const extrinsic_state
*m_ext_state
;
1102 const program_state
*m_state_a
;
1103 const program_state
*m_state_b
;
1106 /* A record that can (optionally) be written out when
1107 region_model::add_constraint fails. */
1109 class rejected_constraint
1112 virtual ~rejected_constraint () {}
1113 virtual void dump_to_pp (pretty_printer
*pp
) const = 0;
1115 const region_model
&get_model () const { return m_model
; }
1118 rejected_constraint (const region_model
&model
)
1122 region_model m_model
;
1125 class rejected_op_constraint
: public rejected_constraint
1128 rejected_op_constraint (const region_model
&model
,
1129 tree lhs
, enum tree_code op
, tree rhs
)
1130 : rejected_constraint (model
),
1131 m_lhs (lhs
), m_op (op
), m_rhs (rhs
)
1134 void dump_to_pp (pretty_printer
*pp
) const final override
;
1137 enum tree_code m_op
;
1141 class rejected_default_case
: public rejected_constraint
1144 rejected_default_case (const region_model
&model
)
1145 : rejected_constraint (model
)
1148 void dump_to_pp (pretty_printer
*pp
) const final override
;
1151 class rejected_ranges_constraint
: public rejected_constraint
1154 rejected_ranges_constraint (const region_model
&model
,
1155 tree expr
, const bounded_ranges
*ranges
)
1156 : rejected_constraint (model
),
1157 m_expr (expr
), m_ranges (ranges
)
1160 void dump_to_pp (pretty_printer
*pp
) const final override
;
1164 const bounded_ranges
*m_ranges
;
1167 /* A bundle of state. */
1172 engine (const supergraph
*sg
= NULL
, logger
*logger
= NULL
);
1173 const supergraph
*get_supergraph () { return m_sg
; }
1174 region_model_manager
*get_model_manager () { return &m_mgr
; }
1175 known_function_manager
*get_known_function_manager ()
1177 return m_mgr
.get_known_function_manager ();
1180 void log_stats (logger
*logger
) const;
1183 const supergraph
*m_sg
;
1184 region_model_manager m_mgr
;
1189 extern void debug (const region_model
&rmodel
);
1195 namespace selftest
{
1197 using namespace ::selftest
;
1199 /* An implementation of region_model_context for use in selftests, which
1200 stores any pending_diagnostic instances passed to it. */
1202 class test_region_model_context
: public noop_region_model_context
1205 bool warn (std::unique_ptr
<pending_diagnostic
> d
,
1206 const stmt_finder
*) final override
1208 m_diagnostics
.safe_push (d
.release ());
1212 unsigned get_num_diagnostics () const { return m_diagnostics
.length (); }
1214 void on_unexpected_tree_code (tree t
, const dump_location_t
&)
1217 internal_error ("unhandled tree code: %qs",
1218 get_tree_code_name (TREE_CODE (t
)));
1222 /* Implicitly delete any diagnostics in the dtor. */
1223 auto_delete_vec
<pending_diagnostic
> m_diagnostics
;
1226 /* Attempt to add the constraint (LHS OP RHS) to MODEL.
1227 Verify that MODEL remains satisfiable. */
1229 #define ADD_SAT_CONSTRAINT(MODEL, LHS, OP, RHS) \
1230 SELFTEST_BEGIN_STMT \
1231 bool sat = (MODEL).add_constraint (LHS, OP, RHS, NULL); \
1232 ASSERT_TRUE (sat); \
1235 /* Attempt to add the constraint (LHS OP RHS) to MODEL.
1236 Verify that the result is not satisfiable. */
1238 #define ADD_UNSAT_CONSTRAINT(MODEL, LHS, OP, RHS) \
1239 SELFTEST_BEGIN_STMT \
1240 bool sat = (MODEL).add_constraint (LHS, OP, RHS, NULL); \
1241 ASSERT_FALSE (sat); \
1244 /* Implementation detail of the ASSERT_CONDITION_* macros. */
1246 void assert_condition (const location
&loc
,
1247 region_model
&model
,
1248 const svalue
*lhs
, tree_code op
, const svalue
*rhs
,
1251 void assert_condition (const location
&loc
,
1252 region_model
&model
,
1253 tree lhs
, tree_code op
, tree rhs
,
1256 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1259 #define ASSERT_CONDITION_TRUE(REGION_MODEL, LHS, OP, RHS) \
1260 SELFTEST_BEGIN_STMT \
1261 assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS, \
1262 tristate (tristate::TS_TRUE)); \
1265 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1268 #define ASSERT_CONDITION_FALSE(REGION_MODEL, LHS, OP, RHS) \
1269 SELFTEST_BEGIN_STMT \
1270 assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS, \
1271 tristate (tristate::TS_FALSE)); \
1274 /* Assert that REGION_MODEL evaluates the condition "LHS OP RHS"
1277 #define ASSERT_CONDITION_UNKNOWN(REGION_MODEL, LHS, OP, RHS) \
1278 SELFTEST_BEGIN_STMT \
1279 assert_condition (SELFTEST_LOCATION, REGION_MODEL, LHS, OP, RHS, \
1280 tristate (tristate::TS_UNKNOWN)); \
1283 } /* end of namespace selftest. */
1285 #endif /* #if CHECKING_P */
1289 #endif /* GCC_ANALYZER_REGION_MODEL_H */