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/>. */
22 #define INCLUDE_MEMORY
23 #define INCLUDE_ALGORITHM
25 #include "coretypes.h"
26 #include "make-unique.h"
29 #include "basic-block.h"
31 #include "gimple-iterator.h"
32 #include "diagnostic-core.h"
37 #include "stringpool.h"
40 #include "fold-const.h"
41 #include "tree-pretty-print.h"
42 #include "diagnostic-color.h"
45 #include "analyzer/analyzer.h"
46 #include "analyzer/analyzer-logging.h"
47 #include "ordered-hash-map.h"
51 #include "analyzer/supergraph.h"
53 #include "analyzer/call-string.h"
54 #include "analyzer/program-point.h"
55 #include "analyzer/store.h"
56 #include "analyzer/region-model.h"
57 #include "analyzer/constraint-manager.h"
58 #include "diagnostic-event-id.h"
59 #include "analyzer/sm.h"
60 #include "diagnostic-event-id.h"
61 #include "analyzer/sm.h"
62 #include "analyzer/pending-diagnostic.h"
63 #include "analyzer/region-model-reachability.h"
64 #include "analyzer/analyzer-selftests.h"
65 #include "analyzer/program-state.h"
66 #include "analyzer/call-summary.h"
67 #include "stor-layout.h"
69 #include "tree-object-size.h"
70 #include "gimple-ssa.h"
71 #include "tree-phinodes.h"
72 #include "tree-ssa-operands.h"
73 #include "ssa-iterators.h"
76 #include "gcc-rich-location.h"
77 #include "analyzer/checker-event.h"
78 #include "analyzer/checker-path.h"
79 #include "analyzer/feasible-graph.h"
80 #include "analyzer/record-layout.h"
81 #include "diagnostic-format-sarif.h"
87 auto_vec
<pop_frame_callback
> region_model::pop_frame_callbacks
;
89 /* Dump T to PP in language-independent form, for debugging/logging/dumping
93 dump_tree (pretty_printer
*pp
, tree t
)
95 dump_generic_node (pp
, t
, 0, TDF_SLIM
, 0);
98 /* Dump T to PP in language-independent form in quotes, for
99 debugging/logging/dumping purposes. */
102 dump_quoted_tree (pretty_printer
*pp
, tree t
)
104 pp_begin_quote (pp
, pp_show_color (pp
));
106 pp_end_quote (pp
, pp_show_color (pp
));
109 /* Equivalent to pp_printf (pp, "%qT", t), to avoid nesting pp_printf
110 calls within other pp_printf calls.
112 default_tree_printer handles 'T' and some other codes by calling
113 dump_generic_node (pp, t, 0, TDF_SLIM, 0);
114 dump_generic_node calls pp_printf in various places, leading to
117 Ideally pp_printf could be made to be reentrant, but in the meantime
118 this function provides a workaround. */
121 print_quoted_type (pretty_printer
*pp
, tree t
)
123 pp_begin_quote (pp
, pp_show_color (pp
));
124 dump_generic_node (pp
, t
, 0, TDF_SLIM
, 0);
125 pp_end_quote (pp
, pp_show_color (pp
));
128 /* class region_to_value_map. */
130 /* Assignment operator for region_to_value_map. */
132 region_to_value_map
&
133 region_to_value_map::operator= (const region_to_value_map
&other
)
136 for (auto iter
: other
.m_hash_map
)
138 const region
*reg
= iter
.first
;
139 const svalue
*sval
= iter
.second
;
140 m_hash_map
.put (reg
, sval
);
145 /* Equality operator for region_to_value_map. */
148 region_to_value_map::operator== (const region_to_value_map
&other
) const
150 if (m_hash_map
.elements () != other
.m_hash_map
.elements ())
153 for (auto iter
: *this)
155 const region
*reg
= iter
.first
;
156 const svalue
*sval
= iter
.second
;
157 const svalue
* const *other_slot
= other
.get (reg
);
158 if (other_slot
== NULL
)
160 if (sval
!= *other_slot
)
167 /* Dump this object to PP. */
170 region_to_value_map::dump_to_pp (pretty_printer
*pp
, bool simple
,
171 bool multiline
) const
173 auto_vec
<const region
*> regs
;
174 for (iterator iter
= begin (); iter
!= end (); ++iter
)
175 regs
.safe_push ((*iter
).first
);
176 regs
.qsort (region::cmp_ptr_ptr
);
180 pp_string (pp
, " {");
183 FOR_EACH_VEC_ELT (regs
, i
, reg
)
188 pp_string (pp
, ", ");
189 reg
->dump_to_pp (pp
, simple
);
190 pp_string (pp
, ": ");
191 const svalue
*sval
= *get (reg
);
192 sval
->dump_to_pp (pp
, true);
200 /* Dump this object to stderr. */
203 region_to_value_map::dump (bool simple
) const
206 pp_format_decoder (&pp
) = default_tree_printer
;
207 pp_show_color (&pp
) = pp_show_color (global_dc
->printer
);
208 pp
.buffer
->stream
= stderr
;
209 dump_to_pp (&pp
, simple
, true);
215 /* Attempt to merge THIS with OTHER, writing the result
218 For now, write (region, value) mappings that are in common between THIS
219 and OTHER to OUT, effectively taking the intersection.
221 Reject merger of different values. */
224 region_to_value_map::can_merge_with_p (const region_to_value_map
&other
,
225 region_to_value_map
*out
) const
227 for (auto iter
: *this)
229 const region
*iter_reg
= iter
.first
;
230 const svalue
*iter_sval
= iter
.second
;
231 const svalue
* const * other_slot
= other
.get (iter_reg
);
234 if (iter_sval
== *other_slot
)
235 out
->put (iter_reg
, iter_sval
);
243 /* Purge any state involving SVAL. */
246 region_to_value_map::purge_state_involving (const svalue
*sval
)
248 auto_vec
<const region
*> to_purge
;
249 for (auto iter
: *this)
251 const region
*iter_reg
= iter
.first
;
252 const svalue
*iter_sval
= iter
.second
;
253 if (iter_reg
->involves_p (sval
) || iter_sval
->involves_p (sval
))
254 to_purge
.safe_push (iter_reg
);
256 for (auto iter
: to_purge
)
257 m_hash_map
.remove (iter
);
260 /* class region_model. */
262 /* Ctor for region_model: construct an "empty" model. */
264 region_model::region_model (region_model_manager
*mgr
)
265 : m_mgr (mgr
), m_store (), m_current_frame (NULL
),
268 m_constraints
= new constraint_manager (mgr
);
271 /* region_model's copy ctor. */
273 region_model::region_model (const region_model
&other
)
274 : m_mgr (other
.m_mgr
), m_store (other
.m_store
),
275 m_constraints (new constraint_manager (*other
.m_constraints
)),
276 m_current_frame (other
.m_current_frame
),
277 m_dynamic_extents (other
.m_dynamic_extents
)
281 /* region_model's dtor. */
283 region_model::~region_model ()
285 delete m_constraints
;
288 /* region_model's assignment operator. */
291 region_model::operator= (const region_model
&other
)
293 /* m_mgr is const. */
294 gcc_assert (m_mgr
== other
.m_mgr
);
296 m_store
= other
.m_store
;
298 delete m_constraints
;
299 m_constraints
= new constraint_manager (*other
.m_constraints
);
301 m_current_frame
= other
.m_current_frame
;
303 m_dynamic_extents
= other
.m_dynamic_extents
;
308 /* Equality operator for region_model.
310 Amongst other things this directly compares the stores and the constraint
311 managers, so for this to be meaningful both this and OTHER should
312 have been canonicalized. */
315 region_model::operator== (const region_model
&other
) const
317 /* We can only compare instances that use the same manager. */
318 gcc_assert (m_mgr
== other
.m_mgr
);
320 if (m_store
!= other
.m_store
)
323 if (*m_constraints
!= *other
.m_constraints
)
326 if (m_current_frame
!= other
.m_current_frame
)
329 if (m_dynamic_extents
!= other
.m_dynamic_extents
)
332 gcc_checking_assert (hash () == other
.hash ());
337 /* Generate a hash value for this region_model. */
340 region_model::hash () const
342 hashval_t result
= m_store
.hash ();
343 result
^= m_constraints
->hash ();
347 /* Dump a representation of this model to PP, showing the
348 stack, the store, and any constraints.
349 Use SIMPLE to control how svalues and regions are printed. */
352 region_model::dump_to_pp (pretty_printer
*pp
, bool simple
,
353 bool multiline
) const
356 pp_printf (pp
, "stack depth: %i", get_stack_depth ());
360 pp_string (pp
, " {");
361 for (const frame_region
*iter_frame
= m_current_frame
; iter_frame
;
362 iter_frame
= iter_frame
->get_calling_frame ())
366 else if (iter_frame
!= m_current_frame
)
367 pp_string (pp
, ", ");
368 pp_printf (pp
, "frame (index %i): ", iter_frame
->get_index ());
369 iter_frame
->dump_to_pp (pp
, simple
);
378 pp_string (pp
, ", {");
379 m_store
.dump_to_pp (pp
, simple
, multiline
,
380 m_mgr
->get_store_manager ());
384 /* Dump constraints. */
385 pp_string (pp
, "constraint_manager:");
389 pp_string (pp
, " {");
390 m_constraints
->dump_to_pp (pp
, multiline
);
394 /* Dump sizes of dynamic regions, if any are known. */
395 if (!m_dynamic_extents
.is_empty ())
397 pp_string (pp
, "dynamic_extents:");
398 m_dynamic_extents
.dump_to_pp (pp
, simple
, multiline
);
402 /* Dump a representation of this model to FILE. */
405 region_model::dump (FILE *fp
, bool simple
, bool multiline
) const
408 pp_format_decoder (&pp
) = default_tree_printer
;
409 pp_show_color (&pp
) = pp_show_color (global_dc
->printer
);
410 pp
.buffer
->stream
= fp
;
411 dump_to_pp (&pp
, simple
, multiline
);
416 /* Dump a multiline representation of this model to stderr. */
419 region_model::dump (bool simple
) const
421 dump (stderr
, simple
, true);
424 /* Dump a multiline representation of this model to stderr. */
427 region_model::debug () const
432 /* Assert that this object is valid. */
435 region_model::validate () const
440 /* Canonicalize the store and constraints, to maximize the chance of
441 equality between region_model instances. */
444 region_model::canonicalize ()
446 m_store
.canonicalize (m_mgr
->get_store_manager ());
447 m_constraints
->canonicalize ();
450 /* Return true if this region_model is in canonical form. */
453 region_model::canonicalized_p () const
455 region_model
copy (*this);
456 copy
.canonicalize ();
457 return *this == copy
;
460 /* See the comment for store::loop_replay_fixup. */
463 region_model::loop_replay_fixup (const region_model
*dst_state
)
465 m_store
.loop_replay_fixup (dst_state
->get_store (), m_mgr
);
468 /* A subclass of pending_diagnostic for complaining about uses of
471 class poisoned_value_diagnostic
472 : public pending_diagnostic_subclass
<poisoned_value_diagnostic
>
475 poisoned_value_diagnostic (tree expr
, enum poison_kind pkind
,
476 const region
*src_region
,
478 : m_expr (expr
), m_pkind (pkind
),
479 m_src_region (src_region
),
480 m_check_expr (check_expr
)
483 const char *get_kind () const final override
{ return "poisoned_value_diagnostic"; }
485 bool use_of_uninit_p () const final override
487 return m_pkind
== POISON_KIND_UNINIT
;
490 bool operator== (const poisoned_value_diagnostic
&other
) const
492 return (m_expr
== other
.m_expr
493 && m_pkind
== other
.m_pkind
494 && m_src_region
== other
.m_src_region
);
497 int get_controlling_option () const final override
503 case POISON_KIND_UNINIT
:
504 return OPT_Wanalyzer_use_of_uninitialized_value
;
505 case POISON_KIND_FREED
:
506 case POISON_KIND_DELETED
:
507 return OPT_Wanalyzer_use_after_free
;
508 case POISON_KIND_POPPED_STACK
:
509 return OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame
;
513 bool terminate_path_p () const final override
{ return true; }
515 bool emit (diagnostic_emission_context
&ctxt
) final override
521 case POISON_KIND_UNINIT
:
523 ctxt
.add_cwe (457); /* "CWE-457: Use of Uninitialized Variable". */
524 return ctxt
.warn ("use of uninitialized value %qE",
528 case POISON_KIND_FREED
:
530 ctxt
.add_cwe (416); /* "CWE-416: Use After Free". */
531 return ctxt
.warn ("use after %<free%> of %qE",
535 case POISON_KIND_DELETED
:
537 ctxt
.add_cwe (416); /* "CWE-416: Use After Free". */
538 return ctxt
.warn ("use after %<delete%> of %qE",
542 case POISON_KIND_POPPED_STACK
:
544 /* TODO: which CWE? */
546 ("dereferencing pointer %qE to within stale stack frame",
553 label_text
describe_final_event (const evdesc::final_event
&ev
) final override
559 case POISON_KIND_UNINIT
:
560 return ev
.formatted_print ("use of uninitialized value %qE here",
562 case POISON_KIND_FREED
:
563 return ev
.formatted_print ("use after %<free%> of %qE here",
565 case POISON_KIND_DELETED
:
566 return ev
.formatted_print ("use after %<delete%> of %qE here",
568 case POISON_KIND_POPPED_STACK
:
569 return ev
.formatted_print
570 ("dereferencing pointer %qE to within stale stack frame",
575 void mark_interesting_stuff (interesting_t
*interest
) final override
578 interest
->add_region_creation (m_src_region
);
581 /* Attempt to suppress false positives.
582 Reject paths where the value of the underlying region isn't poisoned.
583 This can happen due to state merging when exploring the exploded graph,
584 where the more precise analysis during feasibility analysis finds that
585 the region is in fact valid.
586 To do this we need to get the value from the fgraph. Unfortunately
587 we can't simply query the state of m_src_region (from the enode),
588 since it might be a different region in the fnode state (e.g. with
589 heap-allocated regions, the numbering could be different).
590 Hence we access m_check_expr, if available. */
592 bool check_valid_fpath_p (const feasible_node
&fnode
,
593 const gimple
*emission_stmt
)
599 /* We've reached the enode, but not necessarily the right function_point.
600 Try to get the state at the correct stmt. */
601 region_model
emission_model (fnode
.get_model ().get_manager());
602 if (!fnode
.get_state_at_stmt (emission_stmt
, &emission_model
))
603 /* Couldn't get state; accept this diagnostic. */
606 const svalue
*fsval
= emission_model
.get_rvalue (m_check_expr
, NULL
);
607 /* Check to see if the expr is also poisoned in FNODE (and in the
609 const poisoned_svalue
* fspval
= fsval
->dyn_cast_poisoned_svalue ();
612 if (fspval
->get_poison_kind () != m_pkind
)
619 enum poison_kind m_pkind
;
620 const region
*m_src_region
;
624 /* A subclass of pending_diagnostic for complaining about shifts
625 by negative counts. */
627 class shift_count_negative_diagnostic
628 : public pending_diagnostic_subclass
<shift_count_negative_diagnostic
>
631 shift_count_negative_diagnostic (const gassign
*assign
, tree count_cst
)
632 : m_assign (assign
), m_count_cst (count_cst
)
635 const char *get_kind () const final override
637 return "shift_count_negative_diagnostic";
640 bool operator== (const shift_count_negative_diagnostic
&other
) const
642 return (m_assign
== other
.m_assign
643 && same_tree_p (m_count_cst
, other
.m_count_cst
));
646 int get_controlling_option () const final override
648 return OPT_Wanalyzer_shift_count_negative
;
651 bool emit (diagnostic_emission_context
&ctxt
) final override
653 return ctxt
.warn ("shift by negative count (%qE)", m_count_cst
);
656 label_text
describe_final_event (const evdesc::final_event
&ev
) final override
658 return ev
.formatted_print ("shift by negative amount here (%qE)", m_count_cst
);
662 const gassign
*m_assign
;
666 /* A subclass of pending_diagnostic for complaining about shifts
667 by counts >= the width of the operand type. */
669 class shift_count_overflow_diagnostic
670 : public pending_diagnostic_subclass
<shift_count_overflow_diagnostic
>
673 shift_count_overflow_diagnostic (const gassign
*assign
,
674 int operand_precision
,
676 : m_assign (assign
), m_operand_precision (operand_precision
),
677 m_count_cst (count_cst
)
680 const char *get_kind () const final override
682 return "shift_count_overflow_diagnostic";
685 bool operator== (const shift_count_overflow_diagnostic
&other
) const
687 return (m_assign
== other
.m_assign
688 && m_operand_precision
== other
.m_operand_precision
689 && same_tree_p (m_count_cst
, other
.m_count_cst
));
692 int get_controlling_option () const final override
694 return OPT_Wanalyzer_shift_count_overflow
;
697 bool emit (diagnostic_emission_context
&ctxt
) final override
699 return ctxt
.warn ("shift by count (%qE) >= precision of type (%qi)",
700 m_count_cst
, m_operand_precision
);
703 label_text
describe_final_event (const evdesc::final_event
&ev
) final override
705 return ev
.formatted_print ("shift by count %qE here", m_count_cst
);
709 const gassign
*m_assign
;
710 int m_operand_precision
;
714 /* If ASSIGN is a stmt that can be modelled via
715 set_value (lhs_reg, SVALUE, CTXT)
716 for some SVALUE, get the SVALUE.
717 Otherwise return NULL. */
720 region_model::get_gassign_result (const gassign
*assign
,
721 region_model_context
*ctxt
)
723 tree lhs
= gimple_assign_lhs (assign
);
725 if (gimple_has_volatile_ops (assign
)
726 && !gimple_clobber_p (assign
))
728 conjured_purge
p (this, ctxt
);
729 return m_mgr
->get_or_create_conjured_svalue (TREE_TYPE (lhs
),
731 get_lvalue (lhs
, ctxt
),
735 tree rhs1
= gimple_assign_rhs1 (assign
);
736 enum tree_code op
= gimple_assign_rhs_code (assign
);
742 case POINTER_PLUS_EXPR
:
744 /* e.g. "_1 = a_10(D) + 12;" */
746 tree offset
= gimple_assign_rhs2 (assign
);
748 const svalue
*ptr_sval
= get_rvalue (ptr
, ctxt
);
749 const svalue
*offset_sval
= get_rvalue (offset
, ctxt
);
750 /* Quoting tree.def, "the second operand [of a POINTER_PLUS_EXPR]
751 is an integer of type sizetype". */
752 offset_sval
= m_mgr
->get_or_create_cast (size_type_node
, offset_sval
);
754 const svalue
*sval_binop
755 = m_mgr
->get_or_create_binop (TREE_TYPE (lhs
), op
,
756 ptr_sval
, offset_sval
);
761 case POINTER_DIFF_EXPR
:
763 /* e.g. "_1 = p_2(D) - q_3(D);". */
764 tree rhs2
= gimple_assign_rhs2 (assign
);
765 const svalue
*rhs1_sval
= get_rvalue (rhs1
, ctxt
);
766 const svalue
*rhs2_sval
= get_rvalue (rhs2
, ctxt
);
768 // TODO: perhaps fold to zero if they're known to be equal?
770 const svalue
*sval_binop
771 = m_mgr
->get_or_create_binop (TREE_TYPE (lhs
), op
,
772 rhs1_sval
, rhs2_sval
);
777 /* Assignments of the form
778 set_value (lvalue (LHS), rvalue (EXPR))
780 We already have the lvalue for the LHS above, as "lhs_reg". */
781 case ADDR_EXPR
: /* LHS = &RHS; */
783 case COMPONENT_REF
: /* LHS = op0.op1; */
790 case SSA_NAME
: /* LHS = VAR; */
791 case VAR_DECL
: /* LHS = VAR; */
792 case PARM_DECL
:/* LHS = VAR; */
795 return get_rvalue (rhs1
, ctxt
);
805 case VIEW_CONVERT_EXPR
:
808 const svalue
*rhs_sval
= get_rvalue (rhs1
, ctxt
);
809 const svalue
*sval_unaryop
810 = m_mgr
->get_or_create_unaryop (TREE_TYPE (lhs
), op
, rhs_sval
);
823 tree rhs2
= gimple_assign_rhs2 (assign
);
825 const svalue
*rhs1_sval
= get_rvalue (rhs1
, ctxt
);
826 const svalue
*rhs2_sval
= get_rvalue (rhs2
, ctxt
);
828 if (TREE_TYPE (lhs
) == boolean_type_node
)
830 /* Consider constraints between svalues. */
831 tristate t
= eval_condition (rhs1_sval
, op
, rhs2_sval
);
833 return m_mgr
->get_or_create_constant_svalue
834 (t
.is_true () ? boolean_true_node
: boolean_false_node
);
837 /* Otherwise, generate a symbolic binary op. */
838 const svalue
*sval_binop
839 = m_mgr
->get_or_create_binop (TREE_TYPE (lhs
), op
,
840 rhs1_sval
, rhs2_sval
);
848 case MULT_HIGHPART_EXPR
:
871 tree rhs2
= gimple_assign_rhs2 (assign
);
873 const svalue
*rhs1_sval
= get_rvalue (rhs1
, ctxt
);
874 const svalue
*rhs2_sval
= get_rvalue (rhs2
, ctxt
);
876 if (ctxt
&& (op
== LSHIFT_EXPR
|| op
== RSHIFT_EXPR
))
878 /* "INT34-C. Do not shift an expression by a negative number of bits
879 or by greater than or equal to the number of bits that exist in
881 if (const tree rhs2_cst
= rhs2_sval
->maybe_get_constant ())
882 if (TREE_CODE (rhs2_cst
) == INTEGER_CST
883 && INTEGRAL_TYPE_P (TREE_TYPE (rhs1
)))
885 if (tree_int_cst_sgn (rhs2_cst
) < 0)
887 (make_unique
<shift_count_negative_diagnostic
>
889 else if (compare_tree_int (rhs2_cst
,
890 TYPE_PRECISION (TREE_TYPE (rhs1
)))
893 (make_unique
<shift_count_overflow_diagnostic
>
895 int (TYPE_PRECISION (TREE_TYPE (rhs1
))),
900 const svalue
*sval_binop
901 = m_mgr
->get_or_create_binop (TREE_TYPE (lhs
), op
,
902 rhs1_sval
, rhs2_sval
);
906 /* Vector expressions. In theory we could implement these elementwise,
907 but for now, simply return unknown values. */
908 case VEC_DUPLICATE_EXPR
:
909 case VEC_SERIES_EXPR
:
912 case VEC_WIDEN_MULT_HI_EXPR
:
913 case VEC_WIDEN_MULT_LO_EXPR
:
914 case VEC_WIDEN_MULT_EVEN_EXPR
:
915 case VEC_WIDEN_MULT_ODD_EXPR
:
916 case VEC_UNPACK_HI_EXPR
:
917 case VEC_UNPACK_LO_EXPR
:
918 case VEC_UNPACK_FLOAT_HI_EXPR
:
919 case VEC_UNPACK_FLOAT_LO_EXPR
:
920 case VEC_UNPACK_FIX_TRUNC_HI_EXPR
:
921 case VEC_UNPACK_FIX_TRUNC_LO_EXPR
:
922 case VEC_PACK_TRUNC_EXPR
:
923 case VEC_PACK_SAT_EXPR
:
924 case VEC_PACK_FIX_TRUNC_EXPR
:
925 case VEC_PACK_FLOAT_EXPR
:
926 case VEC_WIDEN_LSHIFT_HI_EXPR
:
927 case VEC_WIDEN_LSHIFT_LO_EXPR
:
928 return m_mgr
->get_or_create_unknown_svalue (TREE_TYPE (lhs
));
932 /* Workaround for discarding certain false positives from
933 -Wanalyzer-use-of-uninitialized-value
935 ((A OR-IF B) OR-IF C)
937 ((A AND-IF B) AND-IF C)
938 where evaluating B is redundant, but could involve simple accesses of
939 uninitialized locals.
941 When optimization is turned on the FE can immediately fold compound
942 conditionals. Specifically, c_parser_condition parses this condition:
943 ((A OR-IF B) OR-IF C)
944 and calls c_fully_fold on the condition.
945 Within c_fully_fold, fold_truth_andor is called, which bails when
946 optimization is off, but if any optimization is turned on can convert the
947 ((A OR-IF B) OR-IF C)
950 for sufficiently simple B
951 i.e. the inner OR-IF becomes an OR.
952 At gimplification time the inner OR becomes BIT_IOR_EXPR (in gimplify_expr),
953 giving this for the inner condition:
956 thus effectively synthesizing a redundant access of B when optimization
957 is turned on, when compared to:
958 if (A) goto L1; else goto L4;
959 L1: if (B) goto L2; else goto L4;
960 L2: if (C) goto L3; else goto L4;
961 for the unoptimized case.
963 Return true if CTXT appears to be handling such a short-circuitable stmt,
964 such as the def-stmt for B for the:
966 case above, for the case where A is true and thus B would have been
967 short-circuited without optimization, using MODEL for the value of A. */
970 within_short_circuited_stmt_p (const region_model
*model
,
971 const gassign
*assign_stmt
)
973 /* We must have an assignment to a temporary of _Bool type. */
974 tree lhs
= gimple_assign_lhs (assign_stmt
);
975 if (TREE_TYPE (lhs
) != boolean_type_node
)
977 if (TREE_CODE (lhs
) != SSA_NAME
)
979 if (SSA_NAME_VAR (lhs
) != NULL_TREE
)
982 /* The temporary bool must be used exactly once: as the second arg of
983 a BIT_IOR_EXPR or BIT_AND_EXPR. */
984 use_operand_p use_op
;
986 if (!single_imm_use (lhs
, &use_op
, &use_stmt
))
988 const gassign
*use_assign
= dyn_cast
<const gassign
*> (use_stmt
);
991 enum tree_code op
= gimple_assign_rhs_code (use_assign
);
992 if (!(op
== BIT_IOR_EXPR
||op
== BIT_AND_EXPR
))
994 if (!(gimple_assign_rhs1 (use_assign
) != lhs
995 && gimple_assign_rhs2 (use_assign
) == lhs
))
998 /* The first arg of the bitwise stmt must have a known value in MODEL
999 that implies that the value of the second arg doesn't matter, i.e.
1000 1 for bitwise or, 0 for bitwise and. */
1001 tree other_arg
= gimple_assign_rhs1 (use_assign
);
1002 /* Use a NULL ctxt here to avoid generating warnings. */
1003 const svalue
*other_arg_sval
= model
->get_rvalue (other_arg
, NULL
);
1004 tree other_arg_cst
= other_arg_sval
->maybe_get_constant ();
1012 if (zerop (other_arg_cst
))
1016 if (!zerop (other_arg_cst
))
1021 /* All tests passed. We appear to be in a stmt that generates a boolean
1022 temporary with a value that won't matter. */
1026 /* Workaround for discarding certain false positives from
1027 -Wanalyzer-use-of-uninitialized-value
1028 seen with -ftrivial-auto-var-init=.
1030 -ftrivial-auto-var-init= will generate calls to IFN_DEFERRED_INIT.
1032 If the address of the var is taken, gimplification will give us
1035 _1 = .DEFERRED_INIT (4, 2, &"len"[0]);
1038 The result of DEFERRED_INIT will be an uninit value; we don't
1039 want to emit a false positive for "len = _1;"
1041 Return true if ASSIGN_STMT is such a stmt. */
1044 due_to_ifn_deferred_init_p (const gassign
*assign_stmt
)
1047 /* We must have an assignment to a decl from an SSA name that's the
1048 result of a IFN_DEFERRED_INIT call. */
1049 if (gimple_assign_rhs_code (assign_stmt
) != SSA_NAME
)
1051 tree lhs
= gimple_assign_lhs (assign_stmt
);
1052 if (TREE_CODE (lhs
) != VAR_DECL
)
1054 tree rhs
= gimple_assign_rhs1 (assign_stmt
);
1055 if (TREE_CODE (rhs
) != SSA_NAME
)
1057 const gimple
*def_stmt
= SSA_NAME_DEF_STMT (rhs
);
1058 const gcall
*call
= dyn_cast
<const gcall
*> (def_stmt
);
1061 if (gimple_call_internal_p (call
)
1062 && gimple_call_internal_fn (call
) == IFN_DEFERRED_INIT
)
1067 /* Check for SVAL being poisoned, adding a warning to CTXT.
1068 Return SVAL, or, if a warning is added, another value, to avoid
1069 repeatedly complaining about the same poisoned value in followup code.
1070 SRC_REGION is a hint about where SVAL came from, and can be NULL. */
1073 region_model::check_for_poison (const svalue
*sval
,
1075 const region
*src_region
,
1076 region_model_context
*ctxt
) const
1081 if (const poisoned_svalue
*poisoned_sval
= sval
->dyn_cast_poisoned_svalue ())
1083 enum poison_kind pkind
= poisoned_sval
->get_poison_kind ();
1085 /* Ignore uninitialized uses of empty types; there's nothing
1087 if (pkind
== POISON_KIND_UNINIT
1088 && sval
->get_type ()
1089 && is_empty_type (sval
->get_type ()))
1092 if (pkind
== POISON_KIND_UNINIT
)
1093 if (const gimple
*curr_stmt
= ctxt
->get_stmt ())
1094 if (const gassign
*assign_stmt
1095 = dyn_cast
<const gassign
*> (curr_stmt
))
1097 /* Special case to avoid certain false positives. */
1098 if (within_short_circuited_stmt_p (this, assign_stmt
))
1101 /* Special case to avoid false positive on
1102 -ftrivial-auto-var-init=. */
1103 if (due_to_ifn_deferred_init_p (assign_stmt
))
1107 /* If we have an SSA name for a temporary, we don't want to print
1109 Poisoned values are shared by type, and so we can't reconstruct
1110 the tree other than via the def stmts, using
1111 fixup_tree_for_diagnostic. */
1112 tree diag_arg
= fixup_tree_for_diagnostic (expr
);
1113 if (src_region
== NULL
&& pkind
== POISON_KIND_UNINIT
)
1114 src_region
= get_region_for_poisoned_expr (expr
);
1116 /* Can we reliably get the poisoned value from "expr"?
1117 This is for use by poisoned_value_diagnostic::check_valid_fpath_p.
1118 Unfortunately, we might not have a reliable value for EXPR.
1119 Hence we only query its value now, and only use it if we get the
1120 poisoned value back again. */
1121 tree check_expr
= expr
;
1122 const svalue
*foo_sval
= get_rvalue (expr
, NULL
);
1123 if (foo_sval
== sval
)
1127 if (ctxt
->warn (make_unique
<poisoned_value_diagnostic
> (diag_arg
,
1132 /* We only want to report use of a poisoned value at the first
1133 place it gets used; return an unknown value to avoid generating
1134 a chain of followup warnings. */
1135 sval
= m_mgr
->get_or_create_unknown_svalue (sval
->get_type ());
1144 /* Attempt to get a region for describing EXPR, the source of region of
1145 a poisoned_svalue for use in a poisoned_value_diagnostic.
1146 Return NULL if there is no good region to use. */
1149 region_model::get_region_for_poisoned_expr (tree expr
) const
1151 if (TREE_CODE (expr
) == SSA_NAME
)
1153 tree decl
= SSA_NAME_VAR (expr
);
1154 if (decl
&& DECL_P (decl
))
1159 return get_lvalue (expr
, NULL
);
1162 /* Update this model for the ASSIGN stmt, using CTXT to report any
1166 region_model::on_assignment (const gassign
*assign
, region_model_context
*ctxt
)
1168 tree lhs
= gimple_assign_lhs (assign
);
1169 tree rhs1
= gimple_assign_rhs1 (assign
);
1171 const region
*lhs_reg
= get_lvalue (lhs
, ctxt
);
1173 /* Any writes other than to the stack are treated
1174 as externally visible. */
1177 enum memory_space memspace
= lhs_reg
->get_memory_space ();
1178 if (memspace
!= MEMSPACE_STACK
)
1179 ctxt
->maybe_did_work ();
1182 /* Most assignments are handled by:
1183 set_value (lhs_reg, SVALUE, CTXT)
1185 if (const svalue
*sval
= get_gassign_result (assign
, ctxt
))
1187 tree expr
= get_diagnostic_tree_for_gassign (assign
);
1188 check_for_poison (sval
, expr
, NULL
, ctxt
);
1189 set_value (lhs_reg
, sval
, ctxt
);
1193 enum tree_code op
= gimple_assign_rhs_code (assign
);
1199 sorry_at (assign
->location
, "unhandled assignment op: %qs",
1200 get_tree_code_name (op
));
1201 const svalue
*unknown_sval
1202 = m_mgr
->get_or_create_unknown_svalue (TREE_TYPE (lhs
));
1203 set_value (lhs_reg
, unknown_sval
, ctxt
);
1209 if (TREE_CLOBBER_P (rhs1
))
1211 /* e.g. "x ={v} {CLOBBER};" */
1212 clobber_region (lhs_reg
);
1216 /* Any CONSTRUCTOR that survives to this point is either
1217 just a zero-init of everything, or a vector. */
1218 if (!CONSTRUCTOR_NO_CLEARING (rhs1
))
1219 zero_fill_region (lhs_reg
, ctxt
);
1223 FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (rhs1
), ix
, index
, val
)
1225 gcc_assert (TREE_CODE (TREE_TYPE (rhs1
)) == VECTOR_TYPE
);
1227 index
= build_int_cst (integer_type_node
, ix
);
1228 gcc_assert (TREE_CODE (index
) == INTEGER_CST
);
1229 const svalue
*index_sval
1230 = m_mgr
->get_or_create_constant_svalue (index
);
1231 gcc_assert (index_sval
);
1232 const region
*sub_reg
1233 = m_mgr
->get_element_region (lhs_reg
,
1236 const svalue
*val_sval
= get_rvalue (val
, ctxt
);
1237 set_value (sub_reg
, val_sval
, ctxt
);
1245 /* e.g. "struct s2 x = {{'A', 'B', 'C', 'D'}};". */
1246 const svalue
*rhs_sval
= get_rvalue (rhs1
, ctxt
);
1247 m_store
.set_value (m_mgr
->get_store_manager(), lhs_reg
, rhs_sval
,
1248 ctxt
? ctxt
->get_uncertainty () : NULL
);
1254 /* Handle the pre-sm-state part of STMT, modifying this object in-place.
1255 Write true to *OUT_UNKNOWN_SIDE_EFFECTS if the stmt has unknown
1259 region_model::on_stmt_pre (const gimple
*stmt
,
1260 bool *out_unknown_side_effects
,
1261 region_model_context
*ctxt
)
1263 switch (gimple_code (stmt
))
1266 /* No-op for now. */
1271 const gassign
*assign
= as_a
<const gassign
*> (stmt
);
1272 on_assignment (assign
, ctxt
);
1278 const gasm
*asm_stmt
= as_a
<const gasm
*> (stmt
);
1279 on_asm_stmt (asm_stmt
, ctxt
);
1281 ctxt
->maybe_did_work ();
1287 /* Track whether we have a gcall to a function that's not recognized by
1288 anything, for which we don't have a function body, or for which we
1289 don't know the fndecl. */
1290 const gcall
*call
= as_a
<const gcall
*> (stmt
);
1291 *out_unknown_side_effects
= on_call_pre (call
, ctxt
);
1297 const greturn
*return_
= as_a
<const greturn
*> (stmt
);
1298 on_return (return_
, ctxt
);
1304 /* Given a call CD with function attribute FORMAT_ATTR, check that the
1305 format arg to the call is a valid null-terminated string. */
1308 region_model::check_call_format_attr (const call_details
&cd
,
1309 tree format_attr
) const
1311 /* We assume that FORMAT_ATTR has already been validated. */
1313 /* arg0 of the attribute should be kind of format strings
1314 that this function expects (e.g. "printf"). */
1315 const tree arg0_tree_list
= TREE_VALUE (format_attr
);
1316 if (!arg0_tree_list
)
1319 /* arg1 of the attribute should be the 1-based parameter index
1320 to treat as the format string. */
1321 const tree arg1_tree_list
= TREE_CHAIN (arg0_tree_list
);
1322 if (!arg1_tree_list
)
1324 const tree arg1_value
= TREE_VALUE (arg1_tree_list
);
1328 unsigned format_arg_idx
= TREE_INT_CST_LOW (arg1_value
) - 1;
1329 if (cd
.num_args () <= format_arg_idx
)
1332 /* Subclass of annotating_context that
1333 adds a note about the format attr to any saved diagnostics. */
1334 class annotating_ctxt
: public annotating_context
1337 annotating_ctxt (const call_details
&cd
,
1338 unsigned fmt_param_idx
)
1339 : annotating_context (cd
.get_ctxt ()),
1341 m_fmt_param_idx (fmt_param_idx
)
1344 void add_annotations () final override
1346 class reason_format_attr
1347 : public pending_note_subclass
<reason_format_attr
>
1350 reason_format_attr (const call_arg_details
&arg_details
)
1351 : m_arg_details (arg_details
)
1355 const char *get_kind () const final override
1357 return "reason_format_attr";
1360 void emit () const final override
1362 inform (DECL_SOURCE_LOCATION (m_arg_details
.m_called_fndecl
),
1363 "parameter %i of %qD marked as a format string"
1364 " via %qs attribute",
1365 m_arg_details
.m_arg_idx
+ 1, m_arg_details
.m_called_fndecl
,
1369 bool operator== (const reason_format_attr
&other
) const
1371 return m_arg_details
== other
.m_arg_details
;
1375 call_arg_details m_arg_details
;
1378 call_arg_details
arg_details (m_cd
, m_fmt_param_idx
);
1379 add_note (make_unique
<reason_format_attr
> (arg_details
));
1382 const call_details
&m_cd
;
1383 unsigned m_fmt_param_idx
;
1386 annotating_ctxt
my_ctxt (cd
, format_arg_idx
);
1387 call_details
my_cd (cd
, &my_ctxt
);
1388 my_cd
.check_for_null_terminated_string_arg (format_arg_idx
);
1391 /* Ensure that all arguments at the call described by CD are checked
1392 for poisoned values, by calling get_rvalue on each argument.
1394 Check that calls to functions with "format" attribute have valid
1395 null-terminated strings for their format argument. */
1398 region_model::check_call_args (const call_details
&cd
) const
1400 for (unsigned arg_idx
= 0; arg_idx
< cd
.num_args (); arg_idx
++)
1401 cd
.get_arg_svalue (arg_idx
);
1403 /* Handle attribute "format". */
1404 if (tree format_attr
= cd
.lookup_function_attribute ("format"))
1405 check_call_format_attr (cd
, format_attr
);
1408 /* Update this model for an outcome of a call that returns a specific
1410 If UNMERGEABLE, then make the result unmergeable, e.g. to prevent
1411 the state-merger code from merging success and failure outcomes. */
1414 region_model::update_for_int_cst_return (const call_details
&cd
,
1418 if (!cd
.get_lhs_type ())
1420 if (TREE_CODE (cd
.get_lhs_type ()) != INTEGER_TYPE
)
1422 const svalue
*result
1423 = m_mgr
->get_or_create_int_cst (cd
.get_lhs_type (), retval
);
1425 result
= m_mgr
->get_or_create_unmergeable (result
);
1426 set_value (cd
.get_lhs_region (), result
, cd
.get_ctxt ());
1429 /* Update this model for an outcome of a call that returns zero.
1430 If UNMERGEABLE, then make the result unmergeable, e.g. to prevent
1431 the state-merger code from merging success and failure outcomes. */
1434 region_model::update_for_zero_return (const call_details
&cd
,
1437 update_for_int_cst_return (cd
, 0, unmergeable
);
1440 /* Update this model for an outcome of a call that returns non-zero.
1441 Specifically, assign an svalue to the LHS, and add a constraint that
1442 that svalue is non-zero. */
1445 region_model::update_for_nonzero_return (const call_details
&cd
)
1447 if (!cd
.get_lhs_type ())
1449 if (TREE_CODE (cd
.get_lhs_type ()) != INTEGER_TYPE
)
1451 cd
.set_any_lhs_with_defaults ();
1453 = m_mgr
->get_or_create_int_cst (cd
.get_lhs_type (), 0);
1454 const svalue
*result
1455 = get_store_value (cd
.get_lhs_region (), cd
.get_ctxt ());
1456 add_constraint (result
, NE_EXPR
, zero
, cd
.get_ctxt ());
1459 /* Subroutine of region_model::maybe_get_copy_bounds.
1460 The Linux kernel commonly uses
1461 min_t([unsigned] long, VAR, sizeof(T));
1462 to set an upper bound on the size of a copy_to_user.
1463 Attempt to simplify such sizes by trying to get the upper bound as a
1465 Return the simplified svalue if possible, or NULL otherwise. */
1467 static const svalue
*
1468 maybe_simplify_upper_bound (const svalue
*num_bytes_sval
,
1469 region_model_manager
*mgr
)
1471 tree type
= num_bytes_sval
->get_type ();
1472 while (const svalue
*raw
= num_bytes_sval
->maybe_undo_cast ())
1473 num_bytes_sval
= raw
;
1474 if (const binop_svalue
*binop_sval
= num_bytes_sval
->dyn_cast_binop_svalue ())
1475 if (binop_sval
->get_op () == MIN_EXPR
)
1476 if (binop_sval
->get_arg1 ()->get_kind () == SK_CONSTANT
)
1478 return mgr
->get_or_create_cast (type
, binop_sval
->get_arg1 ());
1479 /* TODO: we might want to also capture the constraint
1480 when recording the diagnostic, or note that we're using
1486 /* Attempt to get an upper bound for the size of a copy when simulating a
1489 NUM_BYTES_SVAL is the symbolic value for the size of the copy.
1490 Use it if it's constant, otherwise try to simplify it. Failing
1491 that, use the size of SRC_REG if constant.
1493 Return a symbolic value for an upper limit on the number of bytes
1494 copied, or NULL if no such value could be determined. */
1497 region_model::maybe_get_copy_bounds (const region
*src_reg
,
1498 const svalue
*num_bytes_sval
)
1500 if (num_bytes_sval
->maybe_get_constant ())
1501 return num_bytes_sval
;
1503 if (const svalue
*simplified
1504 = maybe_simplify_upper_bound (num_bytes_sval
, m_mgr
))
1505 num_bytes_sval
= simplified
;
1507 if (num_bytes_sval
->maybe_get_constant ())
1508 return num_bytes_sval
;
1510 /* For now, try just guessing the size as the capacity of the
1511 base region of the src.
1512 This is a hack; we might get too large a value. */
1513 const region
*src_base_reg
= src_reg
->get_base_region ();
1514 num_bytes_sval
= get_capacity (src_base_reg
);
1516 if (num_bytes_sval
->maybe_get_constant ())
1517 return num_bytes_sval
;
1519 /* Non-constant: give up. */
1523 /* Get any known_function for FNDECL for call CD.
1525 The call must match all assumptions made by the known_function (such as
1526 e.g. "argument 1's type must be a pointer type").
1528 Return NULL if no known_function is found, or it does not match the
1531 const known_function
*
1532 region_model::get_known_function (tree fndecl
, const call_details
&cd
) const
1534 known_function_manager
*known_fn_mgr
= m_mgr
->get_known_function_manager ();
1535 return known_fn_mgr
->get_match (fndecl
, cd
);
1538 /* Get any known_function for IFN, or NULL. */
1540 const known_function
*
1541 region_model::get_known_function (enum internal_fn ifn
) const
1543 known_function_manager
*known_fn_mgr
= m_mgr
->get_known_function_manager ();
1544 return known_fn_mgr
->get_internal_fn (ifn
);
1547 /* Get any builtin_known_function for CALL and emit any warning to CTXT
1550 The call must match all assumptions made by the known_function (such as
1551 e.g. "argument 1's type must be a pointer type").
1553 Return NULL if no builtin_known_function is found, or it does
1554 not match the assumption(s).
1556 Internally calls get_known_function to find a known_function and cast it
1557 to a builtin_known_function.
1559 For instance, calloc is a C builtin, defined in gcc/builtins.def
1560 by the DEF_LIB_BUILTIN macro. Such builtins are recognized by the
1561 analyzer by their name, so that even in C++ or if the user redeclares
1562 them but mismatch their signature, they are still recognized as builtins.
1564 Cases when a supposed builtin is not flagged as one by the FE:
1566 The C++ FE does not recognize calloc as a builtin if it has not been
1567 included from a standard header, but the C FE does. Hence in C++ if
1568 CALL comes from a calloc and stdlib is not included,
1569 gcc/tree.h:fndecl_built_in_p (CALL) would be false.
1571 In C code, a __SIZE_TYPE__ calloc (__SIZE_TYPE__, __SIZE_TYPE__) user
1572 declaration has obviously a mismatching signature from the standard, and
1573 its function_decl tree won't be unified by
1574 gcc/c-decl.cc:match_builtin_function_types.
1576 Yet in both cases the analyzer should treat the calls as a builtin calloc
1577 so that extra attributes unspecified by the standard but added by GCC
1578 (e.g. sprintf attributes in gcc/builtins.def), useful for the detection of
1579 dangerous behavior, are indeed processed.
1581 Therefore for those cases when a "builtin flag" is not added by the FE,
1582 builtins' kf are derived from builtin_known_function, whose method
1583 builtin_known_function::builtin_decl returns the builtin's
1584 function_decl tree as defined in gcc/builtins.def, with all the extra
1587 const builtin_known_function
*
1588 region_model::get_builtin_kf (const gcall
*call
,
1589 region_model_context
*ctxt
/* = NULL */) const
1591 region_model
*mut_this
= const_cast <region_model
*> (this);
1592 tree callee_fndecl
= mut_this
->get_fndecl_for_call (call
, ctxt
);
1593 if (! callee_fndecl
)
1596 call_details
cd (call
, mut_this
, ctxt
);
1597 if (const known_function
*kf
= get_known_function (callee_fndecl
, cd
))
1598 return kf
->dyn_cast_builtin_kf ();
1603 /* Update this model for the CALL stmt, using CTXT to report any
1604 diagnostics - the first half.
1606 Updates to the region_model that should be made *before* sm-states
1607 are updated are done here; other updates to the region_model are done
1608 in region_model::on_call_post.
1610 Return true if the function call has unknown side effects (it wasn't
1611 recognized and we don't have a body for it, or are unable to tell which
1615 region_model::on_call_pre (const gcall
*call
, region_model_context
*ctxt
)
1617 call_details
cd (call
, this, ctxt
);
1619 /* Special-case for IFN_DEFERRED_INIT.
1620 We want to report uninitialized variables with -fanalyzer (treating
1621 -ftrivial-auto-var-init= as purely a mitigation feature).
1622 Handle IFN_DEFERRED_INIT by treating it as no-op: don't touch the
1623 lhs of the call, so that it is still uninitialized from the point of
1624 view of the analyzer. */
1625 if (gimple_call_internal_p (call
)
1626 && gimple_call_internal_fn (call
) == IFN_DEFERRED_INIT
)
1627 return false; /* No side effects. */
1629 /* Get svalues for all of the arguments at the callsite, to ensure that we
1630 complain about any uninitialized arguments. This might lead to
1631 duplicates if any of the handling below also looks up the svalues,
1632 but the deduplication code should deal with that. */
1634 check_call_args (cd
);
1636 tree callee_fndecl
= get_fndecl_for_call (call
, ctxt
);
1638 if (gimple_call_internal_p (call
))
1639 if (const known_function
*kf
1640 = get_known_function (gimple_call_internal_fn (call
)))
1642 kf
->impl_call_pre (cd
);
1643 return false; /* No further side effects. */
1648 cd
.set_any_lhs_with_defaults ();
1649 return true; /* Unknown side effects. */
1652 if (const known_function
*kf
= get_known_function (callee_fndecl
, cd
))
1654 kf
->impl_call_pre (cd
);
1655 return false; /* No further side effects. */
1658 cd
.set_any_lhs_with_defaults ();
1660 const int callee_fndecl_flags
= flags_from_decl_or_type (callee_fndecl
);
1661 if (callee_fndecl_flags
& (ECF_CONST
| ECF_PURE
))
1662 return false; /* No side effects. */
1664 if (fndecl_built_in_p (callee_fndecl
))
1665 return true; /* Unknown side effects. */
1667 if (!fndecl_has_gimple_body_p (callee_fndecl
))
1668 return true; /* Unknown side effects. */
1670 return false; /* No side effects. */
1673 /* Update this model for the CALL stmt, using CTXT to report any
1674 diagnostics - the second half.
1676 Updates to the region_model that should be made *after* sm-states
1677 are updated are done here; other updates to the region_model are done
1678 in region_model::on_call_pre.
1680 If UNKNOWN_SIDE_EFFECTS is true, also call handle_unrecognized_call
1684 region_model::on_call_post (const gcall
*call
,
1685 bool unknown_side_effects
,
1686 region_model_context
*ctxt
)
1688 if (tree callee_fndecl
= get_fndecl_for_call (call
, ctxt
))
1690 call_details
cd (call
, this, ctxt
);
1691 if (const known_function
*kf
= get_known_function (callee_fndecl
, cd
))
1693 kf
->impl_call_post (cd
);
1696 /* Was this fndecl referenced by
1697 __attribute__((malloc(FOO)))? */
1698 if (lookup_attribute ("*dealloc", DECL_ATTRIBUTES (callee_fndecl
)))
1700 impl_deallocation_call (cd
);
1705 if (unknown_side_effects
)
1707 handle_unrecognized_call (call
, ctxt
);
1709 ctxt
->maybe_did_work ();
1713 /* Purge state involving SVAL from this region_model, using CTXT
1714 (if non-NULL) to purge other state in a program_state.
1716 For example, if we're at the def-stmt of an SSA name, then we need to
1717 purge any state for svalues that involve that SSA name. This avoids
1718 false positives in loops, since a symbolic value referring to the
1719 SSA name will be referring to the previous value of that SSA name.
1722 while ((e = hashmap_iter_next(&iter))) {
1723 struct oid2strbuf *e_strbuf = (struct oid2strbuf *)e;
1724 free (e_strbuf->value);
1726 at the def-stmt of e_8:
1727 e_8 = hashmap_iter_next (&iter);
1728 we should purge the "freed" state of:
1729 INIT_VAL(CAST_REG(‘struct oid2strbuf’, (*INIT_VAL(e_8))).value)
1730 which is the "e_strbuf->value" value from the previous iteration,
1731 or we will erroneously report a double-free - the "e_8" within it
1732 refers to the previous value. */
1735 region_model::purge_state_involving (const svalue
*sval
,
1736 region_model_context
*ctxt
)
1738 if (!sval
->can_have_associated_state_p ())
1740 m_store
.purge_state_involving (sval
, m_mgr
);
1741 m_constraints
->purge_state_involving (sval
);
1742 m_dynamic_extents
.purge_state_involving (sval
);
1744 ctxt
->purge_state_involving (sval
);
1747 /* A pending_note subclass for adding a note about an
1748 __attribute__((access, ...)) to a diagnostic. */
1750 class reason_attr_access
: public pending_note_subclass
<reason_attr_access
>
1753 reason_attr_access (tree callee_fndecl
, const attr_access
&access
)
1754 : m_callee_fndecl (callee_fndecl
),
1755 m_ptr_argno (access
.ptrarg
),
1756 m_access_str (TREE_STRING_POINTER (access
.to_external_string ()))
1760 const char *get_kind () const final override
{ return "reason_attr_access"; }
1762 void emit () const final override
1764 inform (DECL_SOURCE_LOCATION (m_callee_fndecl
),
1765 "parameter %i of %qD marked with attribute %qs",
1766 m_ptr_argno
+ 1, m_callee_fndecl
, m_access_str
);
1769 bool operator== (const reason_attr_access
&other
) const
1771 return (m_callee_fndecl
== other
.m_callee_fndecl
1772 && m_ptr_argno
== other
.m_ptr_argno
1773 && !strcmp (m_access_str
, other
.m_access_str
));
1777 tree m_callee_fndecl
;
1778 unsigned m_ptr_argno
;
1779 const char *m_access_str
;
1782 /* Check CALL a call to external function CALLEE_FNDECL based on
1783 any __attribute__ ((access, ....) on the latter, complaining to
1784 CTXT about any issues.
1786 Currently we merely call check_region_for_write on any regions
1787 pointed to by arguments marked with a "write_only" or "read_write"
1791 region_model::check_function_attr_access (const gcall
*call
,
1793 region_model_context
*ctxt
,
1794 rdwr_map
&rdwr_idx
) const
1797 gcc_assert (callee_fndecl
);
1800 tree fntype
= TREE_TYPE (callee_fndecl
);
1801 gcc_assert (fntype
);
1805 for (tree iter
= TYPE_ARG_TYPES (fntype
); iter
;
1806 iter
= TREE_CHAIN (iter
), ++argno
)
1808 const attr_access
* access
= rdwr_idx
.get (argno
);
1812 /* Ignore any duplicate entry in the map for the size argument. */
1813 if (access
->ptrarg
!= argno
)
1816 if (access
->mode
== access_write_only
1817 || access
->mode
== access_read_write
)
1819 /* Subclass of annotating_context that
1820 adds a note about the attr access to any saved diagnostics. */
1821 class annotating_ctxt
: public annotating_context
1824 annotating_ctxt (tree callee_fndecl
,
1825 const attr_access
&access
,
1826 region_model_context
*ctxt
)
1827 : annotating_context (ctxt
),
1828 m_callee_fndecl (callee_fndecl
),
1832 void add_annotations () final override
1834 add_note (make_unique
<reason_attr_access
>
1835 (m_callee_fndecl
, m_access
));
1838 tree m_callee_fndecl
;
1839 const attr_access
&m_access
;
1842 /* Use this ctxt below so that any diagnostics get the
1843 note added to them. */
1844 annotating_ctxt
my_ctxt (callee_fndecl
, *access
, ctxt
);
1846 tree ptr_tree
= gimple_call_arg (call
, access
->ptrarg
);
1847 const svalue
*ptr_sval
= get_rvalue (ptr_tree
, &my_ctxt
);
1848 const region
*reg
= deref_rvalue (ptr_sval
, ptr_tree
, &my_ctxt
);
1849 check_region_for_write (reg
, nullptr, &my_ctxt
);
1850 /* We don't use the size arg for now. */
1855 /* Subroutine of region_model::check_function_attr_null_terminated_string_arg,
1856 checking one instance of __attribute__((null_terminated_string_arg)). */
1860 check_one_function_attr_null_terminated_string_arg (const gcall
*call
,
1862 region_model_context
*ctxt
,
1867 gcc_assert (callee_fndecl
);
1871 tree arg
= TREE_VALUE (attr
);
1875 /* Convert from 1-based to 0-based index. */
1876 unsigned int arg_idx
= TREE_INT_CST_LOW (TREE_VALUE (arg
)) - 1;
1878 /* If there's also an "access" attribute on the ptr param
1879 for reading with a size param specified, then that size
1880 limits the size of the possible read from the pointer. */
1881 if (const attr_access
* access
= rdwr_idx
.get (arg_idx
))
1882 if ((access
->mode
== access_read_only
1883 || access
->mode
== access_read_write
)
1884 && access
->sizarg
!= UINT_MAX
)
1886 call_details
cd_checked (call
, this, ctxt
);
1887 const svalue
*limit_sval
1888 = cd_checked
.get_arg_svalue (access
->sizarg
);
1889 const svalue
*ptr_sval
1890 = cd_checked
.get_arg_svalue (arg_idx
);
1891 /* Try reading all of the bytes expressed by the size param,
1892 but without emitting warnings (via a null context). */
1893 const svalue
*limited_sval
1894 = read_bytes (deref_rvalue (ptr_sval
, NULL_TREE
, nullptr),
1898 if (limited_sval
->get_kind () == SK_POISONED
)
1900 /* Reading up to the truncation limit caused issues.
1901 Assume that the string is meant to be terminated
1902 before then, so perform a *checked* check for the
1904 check_for_null_terminated_string_arg (cd_checked
,
1909 /* Reading up to the truncation limit seems OK; repeat
1910 the read, but with checking enabled. */
1911 read_bytes (deref_rvalue (ptr_sval
, NULL_TREE
, ctxt
),
1919 /* Otherwise, we don't have an access-attribute limiting the read.
1920 Simulate a read up to the null terminator (if any). */
1922 call_details
cd (call
, this, ctxt
);
1923 check_for_null_terminated_string_arg (cd
, arg_idx
);
1926 /* Check CALL a call to external function CALLEE_FNDECL for any uses
1927 of __attribute__ ((null_terminated_string_arg)), compaining
1928 to CTXT about any issues.
1930 Use RDWR_IDX for tracking uses of __attribute__ ((access, ....). */
1934 check_function_attr_null_terminated_string_arg (const gcall
*call
,
1936 region_model_context
*ctxt
,
1940 gcc_assert (callee_fndecl
);
1943 tree fntype
= TREE_TYPE (callee_fndecl
);
1944 gcc_assert (fntype
);
1946 /* A function declaration can specify multiple attribute
1947 null_terminated_string_arg, each with one argument. */
1948 for (tree attr
= TYPE_ATTRIBUTES (fntype
); attr
; attr
= TREE_CHAIN (attr
))
1950 attr
= lookup_attribute ("null_terminated_string_arg", attr
);
1954 check_one_function_attr_null_terminated_string_arg (call
, callee_fndecl
,
1960 /* Check CALL a call to external function CALLEE_FNDECL for any
1961 function attributes, complaining to CTXT about any issues. */
1964 region_model::check_function_attrs (const gcall
*call
,
1966 region_model_context
*ctxt
)
1969 gcc_assert (callee_fndecl
);
1972 tree fntype
= TREE_TYPE (callee_fndecl
);
1976 if (!TYPE_ATTRIBUTES (fntype
))
1979 /* Initialize a map of attribute access specifications for arguments
1980 to the function call. */
1982 init_attr_rdwr_indices (&rdwr_idx
, TYPE_ATTRIBUTES (fntype
));
1984 check_function_attr_access (call
, callee_fndecl
, ctxt
, rdwr_idx
);
1985 check_function_attr_null_terminated_string_arg (call
, callee_fndecl
,
1989 /* Handle a call CALL to a function with unknown behavior.
1991 Traverse the regions in this model, determining what regions are
1992 reachable from pointer arguments to CALL and from global variables,
1995 Set all reachable regions to new unknown values and purge sm-state
1996 from their values, and from values that point to them. */
1999 region_model::handle_unrecognized_call (const gcall
*call
,
2000 region_model_context
*ctxt
)
2002 tree fndecl
= get_fndecl_for_call (call
, ctxt
);
2005 check_function_attrs (call
, fndecl
, ctxt
);
2007 reachable_regions
reachable_regs (this);
2009 /* Determine the reachable regions and their mutability. */
2011 /* Add globals and regions that already escaped in previous
2013 m_store
.for_each_cluster (reachable_regions::init_cluster_cb
,
2016 /* Params that are pointers. */
2017 tree iter_param_types
= NULL_TREE
;
2019 iter_param_types
= TYPE_ARG_TYPES (TREE_TYPE (fndecl
));
2020 for (unsigned arg_idx
= 0; arg_idx
< gimple_call_num_args (call
); arg_idx
++)
2022 /* Track expected param type, where available. */
2023 tree param_type
= NULL_TREE
;
2024 if (iter_param_types
)
2026 param_type
= TREE_VALUE (iter_param_types
);
2027 gcc_assert (param_type
);
2028 iter_param_types
= TREE_CHAIN (iter_param_types
);
2031 tree parm
= gimple_call_arg (call
, arg_idx
);
2032 const svalue
*parm_sval
= get_rvalue (parm
, ctxt
);
2033 reachable_regs
.handle_parm (parm_sval
, param_type
);
2037 uncertainty_t
*uncertainty
= ctxt
? ctxt
->get_uncertainty () : NULL
;
2039 /* Purge sm-state for the svalues that were reachable,
2040 both in non-mutable and mutable form. */
2041 for (svalue_set::iterator iter
2042 = reachable_regs
.begin_reachable_svals ();
2043 iter
!= reachable_regs
.end_reachable_svals (); ++iter
)
2045 const svalue
*sval
= (*iter
);
2047 ctxt
->on_unknown_change (sval
, false);
2049 for (svalue_set::iterator iter
2050 = reachable_regs
.begin_mutable_svals ();
2051 iter
!= reachable_regs
.end_mutable_svals (); ++iter
)
2053 const svalue
*sval
= (*iter
);
2055 ctxt
->on_unknown_change (sval
, true);
2057 uncertainty
->on_mutable_sval_at_unknown_call (sval
);
2060 /* Mark any clusters that have escaped. */
2061 reachable_regs
.mark_escaped_clusters (ctxt
);
2063 /* Update bindings for all clusters that have escaped, whether above,
2065 m_store
.on_unknown_fncall (call
, m_mgr
->get_store_manager (),
2066 conjured_purge (this, ctxt
));
2068 /* Purge dynamic extents from any regions that have escaped mutably:
2069 realloc could have been called on them. */
2070 for (hash_set
<const region
*>::iterator
2071 iter
= reachable_regs
.begin_mutable_base_regs ();
2072 iter
!= reachable_regs
.end_mutable_base_regs ();
2075 const region
*base_reg
= (*iter
);
2076 unset_dynamic_extents (base_reg
);
2080 /* Traverse the regions in this model, determining what regions are
2081 reachable from the store and populating *OUT.
2083 If EXTRA_SVAL is non-NULL, treat it as an additional "root"
2084 for reachability (for handling return values from functions when
2085 analyzing return of the only function on the stack).
2087 If UNCERTAINTY is non-NULL, treat any svalues that were recorded
2088 within it as being maybe-bound as additional "roots" for reachability.
2090 Find svalues that haven't leaked. */
2093 region_model::get_reachable_svalues (svalue_set
*out
,
2094 const svalue
*extra_sval
,
2095 const uncertainty_t
*uncertainty
)
2097 reachable_regions
reachable_regs (this);
2099 /* Add globals and regions that already escaped in previous
2101 m_store
.for_each_cluster (reachable_regions::init_cluster_cb
,
2105 reachable_regs
.handle_sval (extra_sval
);
2108 for (uncertainty_t::iterator iter
2109 = uncertainty
->begin_maybe_bound_svals ();
2110 iter
!= uncertainty
->end_maybe_bound_svals (); ++iter
)
2111 reachable_regs
.handle_sval (*iter
);
2113 /* Get regions for locals that have explicitly bound values. */
2114 for (store::cluster_map_t::iterator iter
= m_store
.begin ();
2115 iter
!= m_store
.end (); ++iter
)
2117 const region
*base_reg
= (*iter
).first
;
2118 if (const region
*parent
= base_reg
->get_parent_region ())
2119 if (parent
->get_kind () == RK_FRAME
)
2120 reachable_regs
.add (base_reg
, false);
2123 /* Populate *OUT based on the values that were reachable. */
2124 for (svalue_set::iterator iter
2125 = reachable_regs
.begin_reachable_svals ();
2126 iter
!= reachable_regs
.end_reachable_svals (); ++iter
)
2130 /* Update this model for the RETURN_STMT, using CTXT to report any
2134 region_model::on_return (const greturn
*return_stmt
, region_model_context
*ctxt
)
2136 tree callee
= get_current_function ()->decl
;
2137 tree lhs
= DECL_RESULT (callee
);
2138 tree rhs
= gimple_return_retval (return_stmt
);
2142 const svalue
*sval
= get_rvalue (rhs
, ctxt
);
2143 const region
*ret_reg
= get_lvalue (lhs
, ctxt
);
2144 set_value (ret_reg
, sval
, ctxt
);
2148 /* Update this model for a call and return of setjmp/sigsetjmp at CALL within
2149 ENODE, using CTXT to report any diagnostics.
2151 This is for the initial direct invocation of setjmp/sigsetjmp (which returns
2152 0), as opposed to any second return due to longjmp/sigsetjmp. */
2155 region_model::on_setjmp (const gcall
*call
, const exploded_node
*enode
,
2156 region_model_context
*ctxt
)
2158 const svalue
*buf_ptr
= get_rvalue (gimple_call_arg (call
, 0), ctxt
);
2159 const region
*buf_reg
= deref_rvalue (buf_ptr
, gimple_call_arg (call
, 0),
2162 /* Create a setjmp_svalue for this call and store it in BUF_REG's
2166 setjmp_record
r (enode
, call
);
2168 = m_mgr
->get_or_create_setjmp_svalue (r
, buf_reg
->get_type ());
2169 set_value (buf_reg
, sval
, ctxt
);
2172 /* Direct calls to setjmp return 0. */
2173 if (tree lhs
= gimple_call_lhs (call
))
2175 const svalue
*new_sval
2176 = m_mgr
->get_or_create_int_cst (TREE_TYPE (lhs
), 0);
2177 const region
*lhs_reg
= get_lvalue (lhs
, ctxt
);
2178 set_value (lhs_reg
, new_sval
, ctxt
);
2182 /* Update this region_model for rewinding from a "longjmp" at LONGJMP_CALL
2183 to a "setjmp" at SETJMP_CALL where the final stack depth should be
2184 SETJMP_STACK_DEPTH. Pop any stack frames. Leak detection is *not*
2185 done, and should be done by the caller. */
2188 region_model::on_longjmp (const gcall
*longjmp_call
, const gcall
*setjmp_call
,
2189 int setjmp_stack_depth
, region_model_context
*ctxt
)
2191 /* Evaluate the val, using the frame of the "longjmp". */
2192 tree fake_retval
= gimple_call_arg (longjmp_call
, 1);
2193 const svalue
*fake_retval_sval
= get_rvalue (fake_retval
, ctxt
);
2195 /* Pop any frames until we reach the stack depth of the function where
2196 setjmp was called. */
2197 gcc_assert (get_stack_depth () >= setjmp_stack_depth
);
2198 while (get_stack_depth () > setjmp_stack_depth
)
2199 pop_frame (NULL
, NULL
, ctxt
, false);
2201 gcc_assert (get_stack_depth () == setjmp_stack_depth
);
2203 /* Assign to LHS of "setjmp" in new_state. */
2204 if (tree lhs
= gimple_call_lhs (setjmp_call
))
2206 /* Passing 0 as the val to longjmp leads to setjmp returning 1. */
2207 const svalue
*zero_sval
2208 = m_mgr
->get_or_create_int_cst (TREE_TYPE (fake_retval
), 0);
2209 tristate eq_zero
= eval_condition (fake_retval_sval
, EQ_EXPR
, zero_sval
);
2210 /* If we have 0, use 1. */
2211 if (eq_zero
.is_true ())
2213 const svalue
*one_sval
2214 = m_mgr
->get_or_create_int_cst (TREE_TYPE (fake_retval
), 1);
2215 fake_retval_sval
= one_sval
;
2219 /* Otherwise note that the value is nonzero. */
2220 m_constraints
->add_constraint (fake_retval_sval
, NE_EXPR
, zero_sval
);
2223 /* Decorate the return value from setjmp as being unmergeable,
2224 so that we don't attempt to merge states with it as zero
2225 with states in which it's nonzero, leading to a clean distinction
2226 in the exploded_graph betweeen the first return and the second
2228 fake_retval_sval
= m_mgr
->get_or_create_unmergeable (fake_retval_sval
);
2230 const region
*lhs_reg
= get_lvalue (lhs
, ctxt
);
2231 set_value (lhs_reg
, fake_retval_sval
, ctxt
);
2235 /* Update this region_model for a phi stmt of the form
2236 LHS = PHI <...RHS...>.
2237 where RHS is for the appropriate edge.
2238 Get state from OLD_STATE so that all of the phi stmts for a basic block
2239 are effectively handled simultaneously. */
2242 region_model::handle_phi (const gphi
*phi
,
2244 const region_model
&old_state
,
2245 hash_set
<const svalue
*> &svals_changing_meaning
,
2246 region_model_context
*ctxt
)
2248 /* For now, don't bother tracking the .MEM SSA names. */
2249 if (tree var
= SSA_NAME_VAR (lhs
))
2250 if (TREE_CODE (var
) == VAR_DECL
)
2251 if (VAR_DECL_IS_VIRTUAL_OPERAND (var
))
2254 const svalue
*src_sval
= old_state
.get_rvalue (rhs
, ctxt
);
2255 const region
*dst_reg
= old_state
.get_lvalue (lhs
, ctxt
);
2257 const svalue
*sval
= old_state
.get_rvalue (lhs
, nullptr);
2258 if (sval
->get_kind () == SK_WIDENING
)
2259 svals_changing_meaning
.add (sval
);
2261 set_value (dst_reg
, src_sval
, ctxt
);
2264 ctxt
->on_phi (phi
, rhs
);
2267 /* Implementation of region_model::get_lvalue; the latter adds type-checking.
2269 Get the id of the region for PV within this region_model,
2270 emitting any diagnostics to CTXT. */
2273 region_model::get_lvalue_1 (path_var pv
, region_model_context
*ctxt
) const
2275 tree expr
= pv
.m_tree
;
2279 switch (TREE_CODE (expr
))
2282 return m_mgr
->get_region_for_unexpected_tree_code (ctxt
, expr
,
2283 dump_location_t ());
2287 tree array
= TREE_OPERAND (expr
, 0);
2288 tree index
= TREE_OPERAND (expr
, 1);
2290 const region
*array_reg
= get_lvalue (array
, ctxt
);
2291 const svalue
*index_sval
= get_rvalue (index
, ctxt
);
2292 return m_mgr
->get_element_region (array_reg
,
2293 TREE_TYPE (TREE_TYPE (array
)),
2300 tree inner_expr
= TREE_OPERAND (expr
, 0);
2301 const region
*inner_reg
= get_lvalue (inner_expr
, ctxt
);
2302 tree num_bits
= TREE_OPERAND (expr
, 1);
2303 tree first_bit_offset
= TREE_OPERAND (expr
, 2);
2304 gcc_assert (TREE_CODE (num_bits
) == INTEGER_CST
);
2305 gcc_assert (TREE_CODE (first_bit_offset
) == INTEGER_CST
);
2306 bit_range
bits (TREE_INT_CST_LOW (first_bit_offset
),
2307 TREE_INT_CST_LOW (num_bits
));
2308 return m_mgr
->get_bit_range (inner_reg
, TREE_TYPE (expr
), bits
);
2314 tree ptr
= TREE_OPERAND (expr
, 0);
2315 tree offset
= TREE_OPERAND (expr
, 1);
2316 const svalue
*ptr_sval
= get_rvalue (ptr
, ctxt
);
2317 const svalue
*offset_sval
= get_rvalue (offset
, ctxt
);
2318 const region
*star_ptr
= deref_rvalue (ptr_sval
, ptr
, ctxt
);
2319 return m_mgr
->get_offset_region (star_ptr
,
2326 return m_mgr
->get_region_for_fndecl (expr
);
2329 return m_mgr
->get_region_for_label (expr
);
2332 /* Handle globals. */
2333 if (is_global_var (expr
))
2334 return m_mgr
->get_region_for_global (expr
);
2342 gcc_assert (TREE_CODE (expr
) == SSA_NAME
2343 || TREE_CODE (expr
) == PARM_DECL
2345 || TREE_CODE (expr
) == RESULT_DECL
);
2347 int stack_index
= pv
.m_stack_depth
;
2348 const frame_region
*frame
= get_frame_at_index (stack_index
);
2350 return frame
->get_region_for_local (m_mgr
, expr
, ctxt
);
2356 tree obj
= TREE_OPERAND (expr
, 0);
2357 tree field
= TREE_OPERAND (expr
, 1);
2358 const region
*obj_reg
= get_lvalue (obj
, ctxt
);
2359 return m_mgr
->get_field_region (obj_reg
, field
);
2364 return m_mgr
->get_region_for_string (expr
);
2368 /* Assert that SRC_TYPE can be converted to DST_TYPE as a no-op. */
2371 assert_compat_types (tree src_type
, tree dst_type
)
2373 if (src_type
&& dst_type
&& !VOID_TYPE_P (dst_type
))
2376 if (!(useless_type_conversion_p (src_type
, dst_type
)))
2377 internal_error ("incompatible types: %qT and %qT", src_type
, dst_type
);
2382 /* Return true if SRC_TYPE can be converted to DST_TYPE as a no-op. */
2385 compat_types_p (tree src_type
, tree dst_type
)
2387 if (src_type
&& dst_type
&& !VOID_TYPE_P (dst_type
))
2388 if (!(useless_type_conversion_p (src_type
, dst_type
)))
2393 /* Get the region for PV within this region_model,
2394 emitting any diagnostics to CTXT. */
2397 region_model::get_lvalue (path_var pv
, region_model_context
*ctxt
) const
2399 if (pv
.m_tree
== NULL_TREE
)
2402 const region
*result_reg
= get_lvalue_1 (pv
, ctxt
);
2403 assert_compat_types (result_reg
->get_type (), TREE_TYPE (pv
.m_tree
));
2407 /* Get the region for EXPR within this region_model (assuming the most
2408 recent stack frame if it's a local). */
2411 region_model::get_lvalue (tree expr
, region_model_context
*ctxt
) const
2413 return get_lvalue (path_var (expr
, get_stack_depth () - 1), ctxt
);
2416 /* Implementation of region_model::get_rvalue; the latter adds type-checking.
2418 Get the value of PV within this region_model,
2419 emitting any diagnostics to CTXT. */
2422 region_model::get_rvalue_1 (path_var pv
, region_model_context
*ctxt
) const
2424 gcc_assert (pv
.m_tree
);
2426 switch (TREE_CODE (pv
.m_tree
))
2429 return m_mgr
->get_or_create_unknown_svalue (TREE_TYPE (pv
.m_tree
));
2434 tree expr
= pv
.m_tree
;
2435 tree op0
= TREE_OPERAND (expr
, 0);
2436 const region
*expr_reg
= get_lvalue (op0
, ctxt
);
2437 return m_mgr
->get_ptr_svalue (TREE_TYPE (expr
), expr_reg
);
2443 tree expr
= pv
.m_tree
;
2444 tree op0
= TREE_OPERAND (expr
, 0);
2445 const region
*reg
= get_lvalue (op0
, ctxt
);
2446 tree num_bits
= TREE_OPERAND (expr
, 1);
2447 tree first_bit_offset
= TREE_OPERAND (expr
, 2);
2448 gcc_assert (TREE_CODE (num_bits
) == INTEGER_CST
);
2449 gcc_assert (TREE_CODE (first_bit_offset
) == INTEGER_CST
);
2450 bit_range
bits (TREE_INT_CST_LOW (first_bit_offset
),
2451 TREE_INT_CST_LOW (num_bits
));
2452 return get_rvalue_for_bits (TREE_TYPE (expr
), reg
, bits
, ctxt
);
2456 if (DECL_HARD_REGISTER (pv
.m_tree
))
2458 /* If it has a hard register, it doesn't have a memory region
2459 and can't be referred to as an lvalue. */
2460 return m_mgr
->get_or_create_unknown_svalue (TREE_TYPE (pv
.m_tree
));
2468 const region
*reg
= get_lvalue (pv
, ctxt
);
2469 return get_store_value (reg
, ctxt
);
2474 case VIEW_CONVERT_EXPR
:
2476 tree expr
= pv
.m_tree
;
2477 tree arg
= TREE_OPERAND (expr
, 0);
2478 const svalue
*arg_sval
= get_rvalue (arg
, ctxt
);
2479 const svalue
*sval_unaryop
2480 = m_mgr
->get_or_create_unaryop (TREE_TYPE (expr
), TREE_CODE (expr
),
2482 return sval_unaryop
;
2490 return m_mgr
->get_or_create_constant_svalue (pv
.m_tree
);
2492 case POINTER_PLUS_EXPR
:
2494 tree expr
= pv
.m_tree
;
2495 tree ptr
= TREE_OPERAND (expr
, 0);
2496 tree offset
= TREE_OPERAND (expr
, 1);
2497 const svalue
*ptr_sval
= get_rvalue (ptr
, ctxt
);
2498 const svalue
*offset_sval
= get_rvalue (offset
, ctxt
);
2499 const svalue
*sval_binop
2500 = m_mgr
->get_or_create_binop (TREE_TYPE (expr
), POINTER_PLUS_EXPR
,
2501 ptr_sval
, offset_sval
);
2512 tree expr
= pv
.m_tree
;
2513 tree arg0
= TREE_OPERAND (expr
, 0);
2514 tree arg1
= TREE_OPERAND (expr
, 1);
2515 const svalue
*arg0_sval
= get_rvalue (arg0
, ctxt
);
2516 const svalue
*arg1_sval
= get_rvalue (arg1
, ctxt
);
2517 const svalue
*sval_binop
2518 = m_mgr
->get_or_create_binop (TREE_TYPE (expr
), TREE_CODE (expr
),
2519 arg0_sval
, arg1_sval
);
2526 const region
*ref_reg
= get_lvalue (pv
, ctxt
);
2527 return get_store_value (ref_reg
, ctxt
);
2531 tree expr
= OBJ_TYPE_REF_EXPR (pv
.m_tree
);
2532 return get_rvalue (expr
, ctxt
);
2537 /* Get the value of PV within this region_model,
2538 emitting any diagnostics to CTXT. */
2541 region_model::get_rvalue (path_var pv
, region_model_context
*ctxt
) const
2543 if (pv
.m_tree
== NULL_TREE
)
2546 const svalue
*result_sval
= get_rvalue_1 (pv
, ctxt
);
2548 assert_compat_types (result_sval
->get_type (), TREE_TYPE (pv
.m_tree
));
2550 result_sval
= check_for_poison (result_sval
, pv
.m_tree
, NULL
, ctxt
);
2555 /* Get the value of EXPR within this region_model (assuming the most
2556 recent stack frame if it's a local). */
2559 region_model::get_rvalue (tree expr
, region_model_context
*ctxt
) const
2561 return get_rvalue (path_var (expr
, get_stack_depth () - 1), ctxt
);
2564 /* Return true if this model is on a path with "main" as the entrypoint
2565 (as opposed to one in which we're merely analyzing a subset of the
2566 path through the code). */
2569 region_model::called_from_main_p () const
2571 if (!m_current_frame
)
2573 /* Determine if the oldest stack frame in this model is for "main". */
2574 const frame_region
*frame0
= get_frame_at_index (0);
2575 gcc_assert (frame0
);
2576 return id_equal (DECL_NAME (frame0
->get_function ()->decl
), "main");
2579 /* Subroutine of region_model::get_store_value for when REG is (or is within)
2580 a global variable that hasn't been touched since the start of this path
2581 (or was implicitly touched due to a call to an unknown function). */
2584 region_model::get_initial_value_for_global (const region
*reg
) const
2586 /* Get the decl that REG is for (or is within). */
2587 const decl_region
*base_reg
2588 = reg
->get_base_region ()->dyn_cast_decl_region ();
2589 gcc_assert (base_reg
);
2590 tree decl
= base_reg
->get_decl ();
2592 /* Special-case: to avoid having to explicitly update all previously
2593 untracked globals when calling an unknown fn, they implicitly have
2594 an unknown value if an unknown call has occurred, unless this is
2595 static to-this-TU and hasn't escaped. Globals that have escaped
2596 are explicitly tracked, so we shouldn't hit this case for them. */
2597 if (m_store
.called_unknown_fn_p ()
2598 && TREE_PUBLIC (decl
)
2599 && !TREE_READONLY (decl
))
2600 return m_mgr
->get_or_create_unknown_svalue (reg
->get_type ());
2602 /* If we are on a path from the entrypoint from "main" and we have a
2603 global decl defined in this TU that hasn't been touched yet, then
2604 the initial value of REG can be taken from the initialization value
2606 if (called_from_main_p () || TREE_READONLY (decl
))
2607 return reg
->get_initial_value_at_main (m_mgr
);
2609 /* Otherwise, return INIT_VAL(REG). */
2610 return m_mgr
->get_or_create_initial_value (reg
);
2613 /* Get a value for REG, looking it up in the store, or otherwise falling
2614 back to "initial" or "unknown" values.
2615 Use CTXT to report any warnings associated with reading from REG. */
2618 region_model::get_store_value (const region
*reg
,
2619 region_model_context
*ctxt
) const
2621 /* Getting the value of an empty region gives an unknown_svalue. */
2622 if (reg
->empty_p ())
2623 return m_mgr
->get_or_create_unknown_svalue (reg
->get_type ());
2625 bool check_poisoned
= true;
2626 if (check_region_for_read (reg
, ctxt
))
2627 check_poisoned
= false;
2629 /* Special-case: handle var_decls in the constant pool. */
2630 if (const decl_region
*decl_reg
= reg
->dyn_cast_decl_region ())
2631 if (const svalue
*sval
= decl_reg
->maybe_get_constant_value (m_mgr
))
2635 = m_store
.get_any_binding (m_mgr
->get_store_manager (), reg
);
2638 if (reg
->get_type ())
2639 sval
= m_mgr
->get_or_create_cast (reg
->get_type (), sval
);
2643 /* Special-case: read at a constant index within a STRING_CST. */
2644 if (const offset_region
*offset_reg
= reg
->dyn_cast_offset_region ())
2645 if (tree byte_offset_cst
2646 = offset_reg
->get_byte_offset ()->maybe_get_constant ())
2647 if (const string_region
*str_reg
2648 = reg
->get_parent_region ()->dyn_cast_string_region ())
2650 tree string_cst
= str_reg
->get_string_cst ();
2651 if (const svalue
*char_sval
2652 = m_mgr
->maybe_get_char_from_string_cst (string_cst
,
2654 return m_mgr
->get_or_create_cast (reg
->get_type (), char_sval
);
2657 /* Special-case: read the initial char of a STRING_CST. */
2658 if (const cast_region
*cast_reg
= reg
->dyn_cast_cast_region ())
2659 if (const string_region
*str_reg
2660 = cast_reg
->get_original_region ()->dyn_cast_string_region ())
2662 tree string_cst
= str_reg
->get_string_cst ();
2663 tree byte_offset_cst
= build_int_cst (integer_type_node
, 0);
2664 if (const svalue
*char_sval
2665 = m_mgr
->maybe_get_char_from_string_cst (string_cst
,
2667 return m_mgr
->get_or_create_cast (reg
->get_type (), char_sval
);
2670 /* Otherwise we implicitly have the initial value of the region
2671 (if the cluster had been touched, binding_cluster::get_any_binding,
2672 would have returned UNKNOWN, and we would already have returned
2675 /* Handle globals. */
2676 if (reg
->get_base_region ()->get_parent_region ()->get_kind ()
2678 return get_initial_value_for_global (reg
);
2680 return m_mgr
->get_or_create_initial_value (reg
, check_poisoned
);
2683 /* Return false if REG does not exist, true if it may do.
2684 This is for detecting regions within the stack that don't exist anymore
2685 after frames are popped. */
2688 region_model::region_exists_p (const region
*reg
) const
2690 /* If within a stack frame, check that the stack frame is live. */
2691 if (const frame_region
*enclosing_frame
= reg
->maybe_get_frame_region ())
2693 /* Check that the current frame is the enclosing frame, or is called
2695 for (const frame_region
*iter_frame
= get_current_frame (); iter_frame
;
2696 iter_frame
= iter_frame
->get_calling_frame ())
2697 if (iter_frame
== enclosing_frame
)
2705 /* Get a region for referencing PTR_SVAL, creating a region if need be, and
2706 potentially generating warnings via CTXT.
2707 PTR_SVAL must be of pointer type.
2708 PTR_TREE if non-NULL can be used when emitting diagnostics. */
2711 region_model::deref_rvalue (const svalue
*ptr_sval
, tree ptr_tree
,
2712 region_model_context
*ctxt
,
2713 bool add_nonnull_constraint
) const
2715 gcc_assert (ptr_sval
);
2716 gcc_assert (POINTER_TYPE_P (ptr_sval
->get_type ()));
2718 /* If we're dereferencing PTR_SVAL, assume that it is non-NULL; add this
2719 as a constraint. This suppresses false positives from
2720 -Wanalyzer-null-dereference for the case where we later have an
2721 if (PTR_SVAL) that would occur if we considered the false branch
2722 and transitioned the malloc state machine from start->null. */
2723 if (add_nonnull_constraint
)
2725 tree null_ptr_cst
= build_int_cst (ptr_sval
->get_type (), 0);
2726 const svalue
*null_ptr
2727 = m_mgr
->get_or_create_constant_svalue (null_ptr_cst
);
2728 m_constraints
->add_constraint (ptr_sval
, NE_EXPR
, null_ptr
);
2731 switch (ptr_sval
->get_kind ())
2738 const region_svalue
*region_sval
2739 = as_a
<const region_svalue
*> (ptr_sval
);
2740 return region_sval
->get_pointee ();
2745 const binop_svalue
*binop_sval
2746 = as_a
<const binop_svalue
*> (ptr_sval
);
2747 switch (binop_sval
->get_op ())
2749 case POINTER_PLUS_EXPR
:
2751 /* If we have a symbolic value expressing pointer arithmentic,
2752 try to convert it to a suitable region. */
2753 const region
*parent_region
2754 = deref_rvalue (binop_sval
->get_arg0 (), NULL_TREE
, ctxt
);
2755 const svalue
*offset
= binop_sval
->get_arg1 ();
2756 tree type
= TREE_TYPE (ptr_sval
->get_type ());
2757 return m_mgr
->get_offset_region (parent_region
, type
, offset
);
2769 tree ptr
= get_representative_tree (ptr_sval
);
2770 /* If we can't get a representative tree for PTR_SVAL
2771 (e.g. if it hasn't been bound into the store), then
2772 fall back on PTR_TREE, if non-NULL. */
2777 const poisoned_svalue
*poisoned_sval
2778 = as_a
<const poisoned_svalue
*> (ptr_sval
);
2779 enum poison_kind pkind
= poisoned_sval
->get_poison_kind ();
2780 ctxt
->warn (::make_unique
<poisoned_value_diagnostic
>
2781 (ptr
, pkind
, nullptr, nullptr));
2788 return m_mgr
->get_symbolic_region (ptr_sval
);
2791 /* Attempt to get BITS within any value of REG, as TYPE.
2792 In particular, extract values from compound_svalues for the case
2793 where there's a concrete binding at BITS.
2794 Return an unknown svalue if we can't handle the given case.
2795 Use CTXT to report any warnings associated with reading from REG. */
2798 region_model::get_rvalue_for_bits (tree type
,
2800 const bit_range
&bits
,
2801 region_model_context
*ctxt
) const
2803 const svalue
*sval
= get_store_value (reg
, ctxt
);
2804 return m_mgr
->get_or_create_bits_within (type
, bits
, sval
);
2807 /* A subclass of pending_diagnostic for complaining about writes to
2808 constant regions of memory. */
2810 class write_to_const_diagnostic
2811 : public pending_diagnostic_subclass
<write_to_const_diagnostic
>
2814 write_to_const_diagnostic (const region
*reg
, tree decl
)
2815 : m_reg (reg
), m_decl (decl
)
2818 const char *get_kind () const final override
2820 return "write_to_const_diagnostic";
2823 bool operator== (const write_to_const_diagnostic
&other
) const
2825 return (m_reg
== other
.m_reg
2826 && m_decl
== other
.m_decl
);
2829 int get_controlling_option () const final override
2831 return OPT_Wanalyzer_write_to_const
;
2834 bool emit (diagnostic_emission_context
&ctxt
) final override
2836 auto_diagnostic_group d
;
2838 switch (m_reg
->get_kind ())
2841 warned
= ctxt
.warn ("write to %<const%> object %qE", m_decl
);
2844 warned
= ctxt
.warn ("write to function %qE", m_decl
);
2847 warned
= ctxt
.warn ("write to label %qE", m_decl
);
2851 inform (DECL_SOURCE_LOCATION (m_decl
), "declared here");
2855 label_text
describe_final_event (const evdesc::final_event
&ev
) final override
2857 switch (m_reg
->get_kind ())
2860 return ev
.formatted_print ("write to %<const%> object %qE here", m_decl
);
2862 return ev
.formatted_print ("write to function %qE here", m_decl
);
2864 return ev
.formatted_print ("write to label %qE here", m_decl
);
2869 const region
*m_reg
;
2873 /* A subclass of pending_diagnostic for complaining about writes to
2876 class write_to_string_literal_diagnostic
2877 : public pending_diagnostic_subclass
<write_to_string_literal_diagnostic
>
2880 write_to_string_literal_diagnostic (const region
*reg
)
2884 const char *get_kind () const final override
2886 return "write_to_string_literal_diagnostic";
2889 bool operator== (const write_to_string_literal_diagnostic
&other
) const
2891 return m_reg
== other
.m_reg
;
2894 int get_controlling_option () const final override
2896 return OPT_Wanalyzer_write_to_string_literal
;
2899 bool emit (diagnostic_emission_context
&ctxt
) final override
2901 return ctxt
.warn ("write to string literal");
2902 /* Ideally we would show the location of the STRING_CST as well,
2903 but it is not available at this point. */
2906 label_text
describe_final_event (const evdesc::final_event
&ev
) final override
2908 return ev
.formatted_print ("write to string literal here");
2912 const region
*m_reg
;
2915 /* Use CTXT to warn If DEST_REG is a region that shouldn't be written to. */
2918 region_model::check_for_writable_region (const region
* dest_reg
,
2919 region_model_context
*ctxt
) const
2921 /* Fail gracefully if CTXT is NULL. */
2925 const region
*base_reg
= dest_reg
->get_base_region ();
2926 switch (base_reg
->get_kind ())
2932 const function_region
*func_reg
= as_a
<const function_region
*> (base_reg
);
2933 tree fndecl
= func_reg
->get_fndecl ();
2934 ctxt
->warn (make_unique
<write_to_const_diagnostic
>
2935 (func_reg
, fndecl
));
2940 const label_region
*label_reg
= as_a
<const label_region
*> (base_reg
);
2941 tree label
= label_reg
->get_label ();
2942 ctxt
->warn (make_unique
<write_to_const_diagnostic
>
2943 (label_reg
, label
));
2948 const decl_region
*decl_reg
= as_a
<const decl_region
*> (base_reg
);
2949 tree decl
= decl_reg
->get_decl ();
2950 /* Warn about writes to const globals.
2951 Don't warn for writes to const locals, and params in particular,
2952 since we would warn in push_frame when setting them up (e.g the
2953 "this" param is "T* const"). */
2954 if (TREE_READONLY (decl
)
2955 && is_global_var (decl
))
2956 ctxt
->warn (make_unique
<write_to_const_diagnostic
> (dest_reg
, decl
));
2960 ctxt
->warn (make_unique
<write_to_string_literal_diagnostic
> (dest_reg
));
2965 /* Get the capacity of REG in bytes. */
2968 region_model::get_capacity (const region
*reg
) const
2970 switch (reg
->get_kind ())
2976 const decl_region
*decl_reg
= as_a
<const decl_region
*> (reg
);
2977 tree decl
= decl_reg
->get_decl ();
2978 if (TREE_CODE (decl
) == SSA_NAME
)
2980 tree type
= TREE_TYPE (decl
);
2981 tree size
= TYPE_SIZE (type
);
2982 return get_rvalue (size
, NULL
);
2986 tree size
= decl_init_size (decl
, false);
2988 return get_rvalue (size
, NULL
);
2993 /* Look through sized regions to get at the capacity
2994 of the underlying regions. */
2995 return get_capacity (reg
->get_parent_region ());
2998 /* "Capacity" here means "size". */
2999 const string_region
*string_reg
= as_a
<const string_region
*> (reg
);
3000 tree string_cst
= string_reg
->get_string_cst ();
3001 return m_mgr
->get_or_create_int_cst (size_type_node
,
3002 TREE_STRING_LENGTH (string_cst
));
3007 if (const svalue
*recorded
= get_dynamic_extents (reg
))
3010 return m_mgr
->get_or_create_unknown_svalue (sizetype
);
3013 /* If CTXT is non-NULL, use it to warn about any problems accessing REG,
3014 using DIR to determine if this access is a read or write.
3015 Return TRUE if an OOB access was detected.
3016 If SVAL_HINT is non-NULL, use it as a hint in diagnostics
3017 about the value that would be written to REG. */
3020 region_model::check_region_access (const region
*reg
,
3021 enum access_direction dir
,
3022 const svalue
*sval_hint
,
3023 region_model_context
*ctxt
) const
3025 /* Fail gracefully if CTXT is NULL. */
3029 bool oob_access_detected
= false;
3030 check_region_for_taint (reg
, dir
, ctxt
);
3031 if (!check_region_bounds (reg
, dir
, sval_hint
, ctxt
))
3032 oob_access_detected
= true;
3039 /* Currently a no-op. */
3042 check_for_writable_region (reg
, ctxt
);
3045 return oob_access_detected
;
3048 /* If CTXT is non-NULL, use it to warn about any problems writing to REG. */
3051 region_model::check_region_for_write (const region
*dest_reg
,
3052 const svalue
*sval_hint
,
3053 region_model_context
*ctxt
) const
3055 check_region_access (dest_reg
, DIR_WRITE
, sval_hint
, ctxt
);
3058 /* If CTXT is non-NULL, use it to warn about any problems reading from REG.
3059 Returns TRUE if an OOB read was detected. */
3062 region_model::check_region_for_read (const region
*src_reg
,
3063 region_model_context
*ctxt
) const
3065 return check_region_access (src_reg
, DIR_READ
, NULL
, ctxt
);
3068 /* Concrete subclass for casts of pointers that lead to trailing bytes. */
3070 class dubious_allocation_size
3071 : public pending_diagnostic_subclass
<dubious_allocation_size
>
3074 dubious_allocation_size (const region
*lhs
, const region
*rhs
,
3076 : m_lhs (lhs
), m_rhs (rhs
), m_expr (NULL_TREE
), m_stmt (stmt
),
3077 m_has_allocation_event (false)
3080 dubious_allocation_size (const region
*lhs
, const region
*rhs
,
3081 tree expr
, const gimple
*stmt
)
3082 : m_lhs (lhs
), m_rhs (rhs
), m_expr (expr
), m_stmt (stmt
),
3083 m_has_allocation_event (false)
3086 const char *get_kind () const final override
3088 return "dubious_allocation_size";
3091 bool operator== (const dubious_allocation_size
&other
) const
3093 return (m_stmt
== other
.m_stmt
3094 && pending_diagnostic::same_tree_p (m_expr
, other
.m_expr
));
3097 int get_controlling_option () const final override
3099 return OPT_Wanalyzer_allocation_size
;
3102 bool emit (diagnostic_emission_context
&ctxt
) final override
3106 return ctxt
.warn ("allocated buffer size is not a multiple"
3107 " of the pointee's size");
3110 label_text
describe_final_event (const evdesc::final_event
&ev
) final
3113 tree pointee_type
= TREE_TYPE (m_lhs
->get_type ());
3114 if (m_has_allocation_event
)
3115 return ev
.formatted_print ("assigned to %qT here;"
3116 " %<sizeof (%T)%> is %qE",
3117 m_lhs
->get_type (), pointee_type
,
3118 size_in_bytes (pointee_type
));
3119 /* Fallback: Typically, we should always see an allocation_event
3123 if (TREE_CODE (m_expr
) == INTEGER_CST
)
3124 return ev
.formatted_print ("allocated %E bytes and assigned to"
3125 " %qT here; %<sizeof (%T)%> is %qE",
3126 m_expr
, m_lhs
->get_type (), pointee_type
,
3127 size_in_bytes (pointee_type
));
3129 return ev
.formatted_print ("allocated %qE bytes and assigned to"
3130 " %qT here; %<sizeof (%T)%> is %qE",
3131 m_expr
, m_lhs
->get_type (), pointee_type
,
3132 size_in_bytes (pointee_type
));
3135 return ev
.formatted_print ("allocated and assigned to %qT here;"
3136 " %<sizeof (%T)%> is %qE",
3137 m_lhs
->get_type (), pointee_type
,
3138 size_in_bytes (pointee_type
));
3142 add_region_creation_events (const region
*,
3144 const event_loc_info
&loc_info
,
3145 checker_path
&emission_path
) final override
3147 emission_path
.add_event
3148 (make_unique
<region_creation_event_allocation_size
> (capacity
, loc_info
));
3150 m_has_allocation_event
= true;
3153 void mark_interesting_stuff (interesting_t
*interest
) final override
3155 interest
->add_region_creation (m_rhs
);
3159 const region
*m_lhs
;
3160 const region
*m_rhs
;
3162 const gimple
*m_stmt
;
3163 bool m_has_allocation_event
;
3166 /* Return true on dubious allocation sizes for constant sizes. */
3169 capacity_compatible_with_type (tree cst
, tree pointee_size_tree
,
3172 gcc_assert (TREE_CODE (cst
) == INTEGER_CST
);
3173 gcc_assert (TREE_CODE (pointee_size_tree
) == INTEGER_CST
);
3175 unsigned HOST_WIDE_INT pointee_size
= TREE_INT_CST_LOW (pointee_size_tree
);
3176 unsigned HOST_WIDE_INT alloc_size
= TREE_INT_CST_LOW (cst
);
3179 return alloc_size
== 0 || alloc_size
>= pointee_size
;
3180 return alloc_size
% pointee_size
== 0;
3184 capacity_compatible_with_type (tree cst
, tree pointee_size_tree
)
3186 return capacity_compatible_with_type (cst
, pointee_size_tree
, false);
3189 /* Checks whether SVAL could be a multiple of SIZE_CST.
3191 It works by visiting all svalues inside SVAL until it reaches
3192 atomic nodes. From those, it goes back up again and adds each
3193 node that is not a multiple of SIZE_CST to the RESULT_SET. */
3195 class size_visitor
: public visitor
3198 size_visitor (tree size_cst
, const svalue
*root_sval
, constraint_manager
*cm
)
3199 : m_size_cst (size_cst
), m_root_sval (root_sval
), m_cm (cm
)
3201 m_root_sval
->accept (this);
3204 bool is_dubious_capacity ()
3206 return result_set
.contains (m_root_sval
);
3209 void visit_constant_svalue (const constant_svalue
*sval
) final override
3211 check_constant (sval
->get_constant (), sval
);
3214 void visit_unaryop_svalue (const unaryop_svalue
*sval
) final override
3216 if (CONVERT_EXPR_CODE_P (sval
->get_op ())
3217 && result_set
.contains (sval
->get_arg ()))
3218 result_set
.add (sval
);
3221 void visit_binop_svalue (const binop_svalue
*sval
) final override
3223 const svalue
*arg0
= sval
->get_arg0 ();
3224 const svalue
*arg1
= sval
->get_arg1 ();
3226 switch (sval
->get_op ())
3229 if (result_set
.contains (arg0
) && result_set
.contains (arg1
))
3230 result_set
.add (sval
);
3234 if (result_set
.contains (arg0
) || result_set
.contains (arg1
))
3235 result_set
.add (sval
);
3242 void visit_unmergeable_svalue (const unmergeable_svalue
*sval
) final override
3244 if (result_set
.contains (sval
->get_arg ()))
3245 result_set
.add (sval
);
3248 void visit_widening_svalue (const widening_svalue
*sval
) final override
3250 const svalue
*base
= sval
->get_base_svalue ();
3251 const svalue
*iter
= sval
->get_iter_svalue ();
3253 if (result_set
.contains (base
) || result_set
.contains (iter
))
3254 result_set
.add (sval
);
3257 void visit_initial_svalue (const initial_svalue
*sval
) final override
3259 equiv_class_id id
= equiv_class_id::null ();
3260 if (m_cm
->get_equiv_class_by_svalue (sval
, &id
))
3262 if (tree cst
= id
.get_obj (*m_cm
).get_any_constant ())
3263 check_constant (cst
, sval
);
3265 else if (!m_cm
->sval_constrained_p (sval
))
3267 result_set
.add (sval
);
3271 void visit_conjured_svalue (const conjured_svalue
*sval
) final override
3273 equiv_class_id id
= equiv_class_id::null ();
3274 if (m_cm
->get_equiv_class_by_svalue (sval
, &id
))
3275 if (tree cst
= id
.get_obj (*m_cm
).get_any_constant ())
3276 check_constant (cst
, sval
);
3280 void check_constant (tree cst
, const svalue
*sval
)
3282 switch (TREE_CODE (cst
))
3285 /* Assume all unhandled operands are compatible. */
3288 if (!capacity_compatible_with_type (cst
, m_size_cst
))
3289 result_set
.add (sval
);
3295 const svalue
*m_root_sval
;
3296 constraint_manager
*m_cm
;
3297 svalue_set result_set
; /* Used as a mapping of svalue*->bool. */
3300 /* Return true if a struct or union either uses the inheritance pattern,
3301 where the first field is a base struct, or the flexible array member
3302 pattern, where the last field is an array without a specified size. */
3305 struct_or_union_with_inheritance_p (tree struc
)
3307 tree iter
= TYPE_FIELDS (struc
);
3308 if (iter
== NULL_TREE
)
3310 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (iter
)))
3314 while (iter
!= NULL_TREE
)
3317 iter
= DECL_CHAIN (iter
);
3320 if (last_field
!= NULL_TREE
3321 && TREE_CODE (TREE_TYPE (last_field
)) == ARRAY_TYPE
)
3327 /* Return true if the lhs and rhs of an assignment have different types. */
3330 is_any_cast_p (const gimple
*stmt
)
3332 if (const gassign
*assign
= dyn_cast
<const gassign
*> (stmt
))
3333 return gimple_assign_cast_p (assign
)
3334 || !pending_diagnostic::same_tree_p (
3335 TREE_TYPE (gimple_assign_lhs (assign
)),
3336 TREE_TYPE (gimple_assign_rhs1 (assign
)));
3337 else if (const gcall
*call
= dyn_cast
<const gcall
*> (stmt
))
3339 tree lhs
= gimple_call_lhs (call
);
3340 return lhs
!= NULL_TREE
&& !pending_diagnostic::same_tree_p (
3341 TREE_TYPE (gimple_call_lhs (call
)),
3342 gimple_call_return_type (call
));
3348 /* On pointer assignments, check whether the buffer size of
3349 RHS_SVAL is compatible with the type of the LHS_REG.
3350 Use a non-null CTXT to report allocation size warnings. */
3353 region_model::check_region_size (const region
*lhs_reg
, const svalue
*rhs_sval
,
3354 region_model_context
*ctxt
) const
3356 if (!ctxt
|| ctxt
->get_stmt () == NULL
)
3358 /* Only report warnings on assignments that actually change the type. */
3359 if (!is_any_cast_p (ctxt
->get_stmt ()))
3362 tree pointer_type
= lhs_reg
->get_type ();
3363 if (pointer_type
== NULL_TREE
|| !POINTER_TYPE_P (pointer_type
))
3366 tree pointee_type
= TREE_TYPE (pointer_type
);
3367 /* Make sure that the type on the left-hand size actually has a size. */
3368 if (pointee_type
== NULL_TREE
|| VOID_TYPE_P (pointee_type
)
3369 || TYPE_SIZE_UNIT (pointee_type
) == NULL_TREE
)
3372 /* Bail out early on pointers to structs where we can
3373 not deduce whether the buffer size is compatible. */
3374 bool is_struct
= RECORD_OR_UNION_TYPE_P (pointee_type
);
3375 if (is_struct
&& struct_or_union_with_inheritance_p (pointee_type
))
3378 tree pointee_size_tree
= size_in_bytes (pointee_type
);
3379 /* We give up if the type size is not known at compile-time or the
3380 type size is always compatible regardless of the buffer size. */
3381 if (TREE_CODE (pointee_size_tree
) != INTEGER_CST
3382 || integer_zerop (pointee_size_tree
)
3383 || integer_onep (pointee_size_tree
))
3386 const region
*rhs_reg
= deref_rvalue (rhs_sval
, NULL_TREE
, ctxt
, false);
3387 const svalue
*capacity
= get_capacity (rhs_reg
);
3388 switch (capacity
->get_kind ())
3390 case svalue_kind::SK_CONSTANT
:
3392 const constant_svalue
*cst_cap_sval
3393 = as_a
<const constant_svalue
*> (capacity
);
3394 tree cst_cap
= cst_cap_sval
->get_constant ();
3395 if (TREE_CODE (cst_cap
) == INTEGER_CST
3396 && !capacity_compatible_with_type (cst_cap
, pointee_size_tree
,
3398 ctxt
->warn (make_unique
<dubious_allocation_size
> (lhs_reg
, rhs_reg
,
3400 ctxt
->get_stmt ()));
3407 size_visitor
v (pointee_size_tree
, capacity
, m_constraints
);
3408 if (v
.is_dubious_capacity ())
3410 tree expr
= get_representative_tree (capacity
);
3411 ctxt
->warn (make_unique
<dubious_allocation_size
> (lhs_reg
,
3414 ctxt
->get_stmt ()));
3422 /* Set the value of the region given by LHS_REG to the value given
3424 Use CTXT to report any warnings associated with writing to LHS_REG. */
3427 region_model::set_value (const region
*lhs_reg
, const svalue
*rhs_sval
,
3428 region_model_context
*ctxt
)
3430 gcc_assert (lhs_reg
);
3431 gcc_assert (rhs_sval
);
3433 /* Setting the value of an empty region is a no-op. */
3434 if (lhs_reg
->empty_p ())
3437 check_region_size (lhs_reg
, rhs_sval
, ctxt
);
3439 check_region_for_write (lhs_reg
, rhs_sval
, ctxt
);
3441 m_store
.set_value (m_mgr
->get_store_manager(), lhs_reg
, rhs_sval
,
3442 ctxt
? ctxt
->get_uncertainty () : NULL
);
3445 /* Set the value of the region given by LHS to the value given by RHS. */
3448 region_model::set_value (tree lhs
, tree rhs
, region_model_context
*ctxt
)
3450 const region
*lhs_reg
= get_lvalue (lhs
, ctxt
);
3451 const svalue
*rhs_sval
= get_rvalue (rhs
, ctxt
);
3452 gcc_assert (lhs_reg
);
3453 gcc_assert (rhs_sval
);
3454 set_value (lhs_reg
, rhs_sval
, ctxt
);
3457 /* Issue a note specifying that a particular function parameter is expected
3458 to be a valid null-terminated string. */
3461 inform_about_expected_null_terminated_string_arg (const call_arg_details
&ad
)
3463 // TODO: ideally we'd underline the param here
3464 inform (DECL_SOURCE_LOCATION (ad
.m_called_fndecl
),
3465 "argument %d of %qD must be a pointer to a null-terminated string",
3466 ad
.m_arg_idx
+ 1, ad
.m_called_fndecl
);
3469 /* A binding of a specific svalue at a concrete byte range. */
3474 : m_byte_range (0, 0), m_sval (nullptr)
3478 fragment (const byte_range
&bytes
, const svalue
*sval
)
3479 : m_byte_range (bytes
), m_sval (sval
)
3483 static int cmp_ptrs (const void *p1
, const void *p2
)
3485 const fragment
*f1
= (const fragment
*)p1
;
3486 const fragment
*f2
= (const fragment
*)p2
;
3487 return byte_range::cmp (f1
->m_byte_range
, f2
->m_byte_range
);
3490 /* Determine if there is a zero terminator somewhere in the
3491 bytes of this fragment, starting at START_READ_OFFSET (which
3492 is absolute to the start of the cluster as a whole), and stopping
3493 at the end of this fragment.
3496 - true if there definitely is a zero byte, writing to *OUT_BYTES_READ
3497 the number of bytes from that would be read, including the zero byte.
3498 - false if there definitely isn't a zero byte
3499 - unknown if we don't know. */
3500 tristate
has_null_terminator (byte_offset_t start_read_offset
,
3501 byte_offset_t
*out_bytes_read
) const
3503 byte_offset_t rel_start_read_offset
3504 = start_read_offset
- m_byte_range
.get_start_byte_offset ();
3505 gcc_assert (rel_start_read_offset
>= 0);
3506 byte_offset_t available_bytes
3507 = (m_byte_range
.get_next_byte_offset () - start_read_offset
);
3508 gcc_assert (available_bytes
>= 0);
3510 if (rel_start_read_offset
> INT_MAX
)
3511 return tristate::TS_UNKNOWN
;
3512 HOST_WIDE_INT rel_start_read_offset_hwi
= rel_start_read_offset
.slow ();
3514 if (available_bytes
> INT_MAX
)
3515 return tristate::TS_UNKNOWN
;
3516 HOST_WIDE_INT available_bytes_hwi
= available_bytes
.slow ();
3518 switch (m_sval
->get_kind ())
3523 = as_a
<const constant_svalue
*> (m_sval
)->get_constant ();
3524 switch (TREE_CODE (cst
))
3527 return string_cst_has_null_terminator (cst
,
3528 rel_start_read_offset_hwi
,
3529 available_bytes_hwi
,
3532 if (rel_start_read_offset_hwi
== 0
3533 && integer_onep (TYPE_SIZE_UNIT (TREE_TYPE (cst
))))
3535 /* Model accesses to the initial byte of a 1-byte
3539 *out_bytes_read
= 1;
3540 return tristate (true);
3544 *out_bytes_read
= available_bytes
;
3545 return tristate (false);
3548 /* Treat any other access to an INTEGER_CST as unknown. */
3549 return tristate::TS_UNKNOWN
;
3560 const initial_svalue
*initial_sval
= (const initial_svalue
*)m_sval
;
3561 const region
*reg
= initial_sval
->get_region ();
3562 if (const string_region
*string_reg
= reg
->dyn_cast_string_region ())
3564 tree string_cst
= string_reg
->get_string_cst ();
3565 return string_cst_has_null_terminator (string_cst
,
3566 rel_start_read_offset_hwi
,
3567 available_bytes_hwi
,
3570 return tristate::TS_UNKNOWN
;
3574 case SK_BITS_WITHIN
:
3576 const bits_within_svalue
*bits_within_sval
3577 = (const bits_within_svalue
*)m_sval
;
3578 byte_range
bytes (0, 0);
3579 if (bits_within_sval
->get_bits ().as_byte_range (&bytes
))
3581 const svalue
*inner_sval
= bits_within_sval
->get_inner_svalue ();
3582 fragment
f (byte_range
3583 (start_read_offset
- bytes
.get_start_bit_offset (),
3584 std::max
<byte_size_t
> (bytes
.m_size_in_bytes
,
3587 return f
.has_null_terminator (start_read_offset
, out_bytes_read
);
3593 // TODO: it may be possible to handle other cases here.
3596 return tristate::TS_UNKNOWN
;
3600 string_cst_has_null_terminator (tree string_cst
,
3601 HOST_WIDE_INT rel_start_read_offset_hwi
,
3602 HOST_WIDE_INT available_bytes_hwi
,
3603 byte_offset_t
*out_bytes_read
)
3605 /* Look for the first 0 byte within STRING_CST
3606 from START_READ_OFFSET onwards. */
3607 const HOST_WIDE_INT num_bytes_to_search
3608 = std::min
<HOST_WIDE_INT
> ((TREE_STRING_LENGTH (string_cst
)
3609 - rel_start_read_offset_hwi
),
3610 available_bytes_hwi
);
3611 const char *start
= (TREE_STRING_POINTER (string_cst
)
3612 + rel_start_read_offset_hwi
);
3613 if (num_bytes_to_search
>= 0)
3614 if (const void *p
= memchr (start
, 0,
3615 num_bytes_to_search
))
3617 *out_bytes_read
= (const char *)p
- start
+ 1;
3618 return tristate (true);
3621 *out_bytes_read
= available_bytes_hwi
;
3622 return tristate (false);
3625 byte_range m_byte_range
;
3626 const svalue
*m_sval
;
3629 /* A frozen copy of a single base region's binding_cluster within a store,
3630 optimized for traversal of the concrete parts in byte order.
3631 This only captures concrete bindings, and is an implementation detail
3632 of region_model::scan_for_null_terminator. */
3634 class iterable_cluster
3637 iterable_cluster (const binding_cluster
*cluster
)
3641 for (auto iter
: *cluster
)
3643 const binding_key
*key
= iter
.first
;
3644 const svalue
*sval
= iter
.second
;
3646 if (const concrete_binding
*concrete_key
3647 = key
->dyn_cast_concrete_binding ())
3649 byte_range
fragment_bytes (0, 0);
3650 if (concrete_key
->get_byte_range (&fragment_bytes
))
3651 m_fragments
.safe_push (fragment (fragment_bytes
, sval
));
3654 m_symbolic_bindings
.safe_push (key
);
3656 m_fragments
.qsort (fragment::cmp_ptrs
);
3660 get_fragment_for_byte (byte_offset_t byte
, fragment
*out_frag
) const
3662 /* TODO: binary search rather than linear. */
3664 for (iter_idx
= 0; iter_idx
< m_fragments
.length (); iter_idx
++)
3666 if (m_fragments
[iter_idx
].m_byte_range
.contains_p (byte
))
3668 *out_frag
= m_fragments
[iter_idx
];
3675 bool has_symbolic_bindings_p () const
3677 return !m_symbolic_bindings
.is_empty ();
3681 auto_vec
<fragment
> m_fragments
;
3682 auto_vec
<const binding_key
*> m_symbolic_bindings
;
3685 /* Simulate reading the bytes at BYTES from BASE_REG.
3686 Complain to CTXT about any issues with the read e.g. out-of-bounds. */
3689 region_model::get_store_bytes (const region
*base_reg
,
3690 const byte_range
&bytes
,
3691 region_model_context
*ctxt
) const
3693 /* Shortcut reading all of a string_region. */
3694 if (bytes
.get_start_byte_offset () == 0)
3695 if (const string_region
*string_reg
= base_reg
->dyn_cast_string_region ())
3696 if (bytes
.m_size_in_bytes
3697 == TREE_STRING_LENGTH (string_reg
->get_string_cst ()))
3698 return m_mgr
->get_or_create_initial_value (base_reg
);
3700 const svalue
*index_sval
3701 = m_mgr
->get_or_create_int_cst (size_type_node
,
3702 bytes
.get_start_byte_offset ());
3703 const region
*offset_reg
= m_mgr
->get_offset_region (base_reg
,
3706 const svalue
*byte_size_sval
3707 = m_mgr
->get_or_create_int_cst (size_type_node
, bytes
.m_size_in_bytes
);
3708 const region
*read_reg
= m_mgr
->get_sized_region (offset_reg
,
3712 /* Simulate reading those bytes from the store. */
3713 const svalue
*sval
= get_store_value (read_reg
, ctxt
);
3718 get_tree_for_byte_offset (tree ptr_expr
, byte_offset_t byte_offset
)
3720 gcc_assert (ptr_expr
);
3721 return fold_build2 (MEM_REF
,
3723 ptr_expr
, wide_int_to_tree (size_type_node
, byte_offset
));
3726 /* Simulate a series of reads of REG until we find a 0 byte
3727 (equivalent to calling strlen).
3729 Complain to CTXT and return NULL if:
3730 - the buffer pointed to isn't null-terminated
3731 - the buffer pointed to has any uninitalized bytes before any 0-terminator
3732 - any of the reads aren't within the bounds of the underlying base region
3734 Otherwise, return a svalue for the number of bytes read (strlen + 1),
3735 and, if OUT_SVAL is non-NULL, write to *OUT_SVAL with an svalue
3736 representing the content of REG up to and including the terminator.
3741 Get offset for first byte to read.
3742 Find the binding (if any) that contains it.
3743 Find the size in bits of that binding.
3744 Round to the nearest byte (which way???)
3745 Or maybe give up if we have a partial binding there.
3746 Get the svalue from the binding.
3747 Determine the strlen (if any) of that svalue.
3748 Does it have a 0-terminator within it?
3749 If so, we have a partial read up to and including that terminator
3750 Read those bytes from the store; add to the result in the correct place.
3752 If not, we have a full read of that svalue
3753 Read those bytes from the store; add to the result in the correct place.
3754 Update read/write offsets
3762 region_model::scan_for_null_terminator (const region
*reg
,
3764 const svalue
**out_sval
,
3765 region_model_context
*ctxt
) const
3767 store_manager
*store_mgr
= m_mgr
->get_store_manager ();
3769 region_offset offset
= reg
->get_offset (m_mgr
);
3770 if (offset
.symbolic_p ())
3773 *out_sval
= get_store_value (reg
, nullptr);
3774 return m_mgr
->get_or_create_unknown_svalue (size_type_node
);
3776 byte_offset_t src_byte_offset
;
3777 if (!offset
.get_concrete_byte_offset (&src_byte_offset
))
3780 *out_sval
= get_store_value (reg
, nullptr);
3781 return m_mgr
->get_or_create_unknown_svalue (size_type_node
);
3783 const byte_offset_t initial_src_byte_offset
= src_byte_offset
;
3784 byte_offset_t dst_byte_offset
= 0;
3786 const region
*base_reg
= reg
->get_base_region ();
3788 if (const string_region
*str_reg
= base_reg
->dyn_cast_string_region ())
3790 tree string_cst
= str_reg
->get_string_cst ();
3791 if (const void *p
= memchr (TREE_STRING_POINTER (string_cst
),
3793 TREE_STRING_LENGTH (string_cst
)))
3795 size_t num_bytes_read
3796 = (const char *)p
- TREE_STRING_POINTER (string_cst
) + 1;
3797 /* Simulate the read. */
3798 byte_range
bytes_to_read (0, num_bytes_read
);
3799 const svalue
*sval
= get_store_bytes (reg
, bytes_to_read
, ctxt
);
3802 return m_mgr
->get_or_create_int_cst (size_type_node
,
3807 const binding_cluster
*cluster
= m_store
.get_cluster (base_reg
);
3808 iterable_cluster
c (cluster
);
3814 if (c
.get_fragment_for_byte (src_byte_offset
, &f
))
3816 byte_offset_t fragment_bytes_read
;
3817 tristate is_terminated
3818 = f
.has_null_terminator (src_byte_offset
, &fragment_bytes_read
);
3819 if (is_terminated
.is_unknown ())
3822 *out_sval
= get_store_value (reg
, nullptr);
3823 return m_mgr
->get_or_create_unknown_svalue (size_type_node
);
3826 /* Simulate reading those bytes from the store. */
3827 byte_range
bytes_to_read (src_byte_offset
, fragment_bytes_read
);
3828 const svalue
*sval
= get_store_bytes (base_reg
, bytes_to_read
, ctxt
);
3829 check_for_poison (sval
, expr
, nullptr, ctxt
);
3833 byte_range
bytes_to_write (dst_byte_offset
, fragment_bytes_read
);
3834 const binding_key
*key
3835 = store_mgr
->get_concrete_binding (bytes_to_write
);
3836 result
.put (key
, sval
);
3839 src_byte_offset
+= fragment_bytes_read
;
3840 dst_byte_offset
+= fragment_bytes_read
;
3842 if (is_terminated
.is_true ())
3845 *out_sval
= m_mgr
->get_or_create_compound_svalue (NULL_TREE
,
3847 return m_mgr
->get_or_create_int_cst (size_type_node
,
3855 /* No binding for this base_region, or no binding at src_byte_offset
3856 (or a symbolic binding). */
3858 if (c
.has_symbolic_bindings_p ())
3861 *out_sval
= get_store_value (reg
, nullptr);
3862 return m_mgr
->get_or_create_unknown_svalue (size_type_node
);
3865 /* TODO: the various special-cases seen in
3866 region_model::get_store_value. */
3868 /* Simulate reading from this byte, then give up. */
3869 byte_range
bytes_to_read (src_byte_offset
, 1);
3870 const svalue
*sval
= get_store_bytes (base_reg
, bytes_to_read
, ctxt
);
3873 ? get_tree_for_byte_offset (expr
,
3874 src_byte_offset
- initial_src_byte_offset
)
3876 check_for_poison (sval
, byte_expr
, nullptr, ctxt
);
3877 if (base_reg
->can_have_initial_svalue_p ())
3880 *out_sval
= get_store_value (reg
, nullptr);
3881 return m_mgr
->get_or_create_unknown_svalue (size_type_node
);
3887 /* Check that argument ARG_IDX (0-based) to the call described by CD
3888 is a pointer to a valid null-terminated string.
3890 Simulate scanning through the buffer, reading until we find a 0 byte
3891 (equivalent to calling strlen).
3893 Complain and return NULL if:
3894 - the buffer pointed to isn't null-terminated
3895 - the buffer pointed to has any uninitalized bytes before any 0-terminator
3896 - any of the reads aren't within the bounds of the underlying base region
3898 Otherwise, return a svalue for strlen of the buffer (*not* including
3899 the null terminator).
3901 TODO: we should also complain if:
3902 - the pointer is NULL (or could be). */
3905 region_model::check_for_null_terminated_string_arg (const call_details
&cd
,
3906 unsigned arg_idx
) const
3908 return check_for_null_terminated_string_arg (cd
,
3910 false, /* include_terminator */
3911 nullptr); // out_sval
3915 /* Check that argument ARG_IDX (0-based) to the call described by CD
3916 is a pointer to a valid null-terminated string.
3918 Simulate scanning through the buffer, reading until we find a 0 byte
3919 (equivalent to calling strlen).
3921 Complain and return NULL if:
3922 - the buffer pointed to isn't null-terminated
3923 - the buffer pointed to has any uninitalized bytes before any 0-terminator
3924 - any of the reads aren't within the bounds of the underlying base region
3926 Otherwise, return a svalue. This will be the number of bytes read
3927 (including the null terminator) if INCLUDE_TERMINATOR is true, or strlen
3928 of the buffer (not including the null terminator) if it is false.
3930 Also, when returning an svalue, if OUT_SVAL is non-NULL, write to
3931 *OUT_SVAL with an svalue representing the content of the buffer up to
3932 and including the terminator.
3934 TODO: we should also complain if:
3935 - the pointer is NULL (or could be). */
3938 region_model::check_for_null_terminated_string_arg (const call_details
&cd
,
3940 bool include_terminator
,
3941 const svalue
**out_sval
) const
3943 class null_terminator_check_event
: public custom_event
3946 null_terminator_check_event (const event_loc_info
&loc_info
,
3947 const call_arg_details
&arg_details
)
3948 : custom_event (loc_info
),
3949 m_arg_details (arg_details
)
3953 label_text
get_desc (bool can_colorize
) const final override
3955 if (m_arg_details
.m_arg_expr
)
3956 return make_label_text (can_colorize
,
3957 "while looking for null terminator"
3958 " for argument %i (%qE) of %qD...",
3959 m_arg_details
.m_arg_idx
+ 1,
3960 m_arg_details
.m_arg_expr
,
3961 m_arg_details
.m_called_fndecl
);
3963 return make_label_text (can_colorize
,
3964 "while looking for null terminator"
3965 " for argument %i of %qD...",
3966 m_arg_details
.m_arg_idx
+ 1,
3967 m_arg_details
.m_called_fndecl
);
3971 const call_arg_details m_arg_details
;
3974 class null_terminator_check_decl_note
3975 : public pending_note_subclass
<null_terminator_check_decl_note
>
3978 null_terminator_check_decl_note (const call_arg_details
&arg_details
)
3979 : m_arg_details (arg_details
)
3983 const char *get_kind () const final override
3985 return "null_terminator_check_decl_note";
3988 void emit () const final override
3990 inform_about_expected_null_terminated_string_arg (m_arg_details
);
3993 bool operator== (const null_terminator_check_decl_note
&other
) const
3995 return m_arg_details
== other
.m_arg_details
;
3999 const call_arg_details m_arg_details
;
4002 /* Subclass of decorated_region_model_context that
4003 adds the above event and note to any saved diagnostics. */
4004 class annotating_ctxt
: public annotating_context
4007 annotating_ctxt (const call_details
&cd
,
4009 : annotating_context (cd
.get_ctxt ()),
4014 void add_annotations () final override
4016 call_arg_details
arg_details (m_cd
, m_arg_idx
);
4017 event_loc_info
loc_info (m_cd
.get_location (),
4018 m_cd
.get_model ()->get_current_function ()->decl
,
4019 m_cd
.get_model ()->get_stack_depth ());
4021 add_event (make_unique
<null_terminator_check_event
> (loc_info
,
4023 add_note (make_unique
<null_terminator_check_decl_note
> (arg_details
));
4026 const call_details
&m_cd
;
4030 /* Use this ctxt below so that any diagnostics that get added
4032 annotating_ctxt
my_ctxt (cd
, arg_idx
);
4034 const svalue
*arg_sval
= cd
.get_arg_svalue (arg_idx
);
4035 const region
*buf_reg
4036 = deref_rvalue (arg_sval
, cd
.get_arg_tree (arg_idx
), &my_ctxt
);
4038 if (const svalue
*num_bytes_read_sval
4039 = scan_for_null_terminator (buf_reg
,
4040 cd
.get_arg_tree (arg_idx
),
4044 if (include_terminator
)
4045 return num_bytes_read_sval
;
4048 /* strlen is (bytes_read - 1). */
4049 const svalue
*one
= m_mgr
->get_or_create_int_cst (size_type_node
, 1);
4050 return m_mgr
->get_or_create_binop (size_type_node
,
4052 num_bytes_read_sval
,
4060 /* Remove all bindings overlapping REG within the store. */
4063 region_model::clobber_region (const region
*reg
)
4065 m_store
.clobber_region (m_mgr
->get_store_manager(), reg
);
4068 /* Remove any bindings for REG within the store. */
4071 region_model::purge_region (const region
*reg
)
4073 m_store
.purge_region (m_mgr
->get_store_manager(), reg
);
4076 /* Fill REG with SVAL.
4077 Use CTXT to report any warnings associated with the write
4078 (e.g. out-of-bounds). */
4081 region_model::fill_region (const region
*reg
,
4083 region_model_context
*ctxt
)
4085 check_region_for_write (reg
, nullptr, ctxt
);
4086 m_store
.fill_region (m_mgr
->get_store_manager(), reg
, sval
);
4090 Use CTXT to report any warnings associated with the write
4091 (e.g. out-of-bounds). */
4094 region_model::zero_fill_region (const region
*reg
,
4095 region_model_context
*ctxt
)
4097 check_region_for_write (reg
, nullptr, ctxt
);
4098 m_store
.zero_fill_region (m_mgr
->get_store_manager(), reg
);
4101 /* Copy NUM_BYTES_SVAL of SVAL to DEST_REG.
4102 Use CTXT to report any warnings associated with the copy
4103 (e.g. out-of-bounds writes). */
4106 region_model::write_bytes (const region
*dest_reg
,
4107 const svalue
*num_bytes_sval
,
4109 region_model_context
*ctxt
)
4111 const region
*sized_dest_reg
4112 = m_mgr
->get_sized_region (dest_reg
, NULL_TREE
, num_bytes_sval
);
4113 set_value (sized_dest_reg
, sval
, ctxt
);
4116 /* Read NUM_BYTES_SVAL from SRC_REG.
4117 Use CTXT to report any warnings associated with the copy
4118 (e.g. out-of-bounds reads, copying of uninitialized values, etc). */
4121 region_model::read_bytes (const region
*src_reg
,
4123 const svalue
*num_bytes_sval
,
4124 region_model_context
*ctxt
) const
4126 if (num_bytes_sval
->get_kind () == SK_UNKNOWN
)
4127 return m_mgr
->get_or_create_unknown_svalue (NULL_TREE
);
4128 const region
*sized_src_reg
4129 = m_mgr
->get_sized_region (src_reg
, NULL_TREE
, num_bytes_sval
);
4130 const svalue
*src_contents_sval
= get_store_value (sized_src_reg
, ctxt
);
4131 check_for_poison (src_contents_sval
, src_ptr_expr
,
4132 sized_src_reg
, ctxt
);
4133 return src_contents_sval
;
4136 /* Copy NUM_BYTES_SVAL bytes from SRC_REG to DEST_REG.
4137 Use CTXT to report any warnings associated with the copy
4138 (e.g. out-of-bounds reads/writes, copying of uninitialized values,
4142 region_model::copy_bytes (const region
*dest_reg
,
4143 const region
*src_reg
,
4145 const svalue
*num_bytes_sval
,
4146 region_model_context
*ctxt
)
4148 const svalue
*data_sval
4149 = read_bytes (src_reg
, src_ptr_expr
, num_bytes_sval
, ctxt
);
4150 write_bytes (dest_reg
, num_bytes_sval
, data_sval
, ctxt
);
4153 /* Mark REG as having unknown content. */
4156 region_model::mark_region_as_unknown (const region
*reg
,
4157 uncertainty_t
*uncertainty
)
4159 svalue_set maybe_live_values
;
4160 m_store
.mark_region_as_unknown (m_mgr
->get_store_manager(), reg
,
4161 uncertainty
, &maybe_live_values
);
4162 m_store
.on_maybe_live_values (maybe_live_values
);
4165 /* Determine what is known about the condition "LHS_SVAL OP RHS_SVAL" within
4169 region_model::eval_condition (const svalue
*lhs
,
4171 const svalue
*rhs
) const
4176 /* For now, make no attempt to capture constraints on floating-point
4178 if ((lhs
->get_type () && FLOAT_TYPE_P (lhs
->get_type ()))
4179 || (rhs
->get_type () && FLOAT_TYPE_P (rhs
->get_type ())))
4180 return tristate::unknown ();
4182 /* See what we know based on the values. */
4184 /* Unwrap any unmergeable values. */
4185 lhs
= lhs
->unwrap_any_unmergeable ();
4186 rhs
= rhs
->unwrap_any_unmergeable ();
4190 /* If we have the same svalue, then we have equality
4191 (apart from NaN-handling).
4192 TODO: should this definitely be the case for poisoned values? */
4193 /* Poisoned and unknown values are "unknowable". */
4194 if (lhs
->get_kind () == SK_POISONED
4195 || lhs
->get_kind () == SK_UNKNOWN
)
4196 return tristate::TS_UNKNOWN
;
4203 return tristate::TS_TRUE
;
4208 return tristate::TS_FALSE
;
4211 /* For other ops, use the logic below. */
4216 /* If we have a pair of region_svalues, compare them. */
4217 if (const region_svalue
*lhs_ptr
= lhs
->dyn_cast_region_svalue ())
4218 if (const region_svalue
*rhs_ptr
= rhs
->dyn_cast_region_svalue ())
4220 tristate res
= region_svalue::eval_condition (lhs_ptr
, op
, rhs_ptr
);
4221 if (res
.is_known ())
4223 /* Otherwise, only known through constraints. */
4226 if (const constant_svalue
*cst_lhs
= lhs
->dyn_cast_constant_svalue ())
4228 /* If we have a pair of constants, compare them. */
4229 if (const constant_svalue
*cst_rhs
= rhs
->dyn_cast_constant_svalue ())
4230 return constant_svalue::eval_condition (cst_lhs
, op
, cst_rhs
);
4233 /* When we have one constant, put it on the RHS. */
4234 std::swap (lhs
, rhs
);
4235 op
= swap_tree_comparison (op
);
4238 gcc_assert (lhs
->get_kind () != SK_CONSTANT
);
4240 /* Handle comparison against zero. */
4241 if (const constant_svalue
*cst_rhs
= rhs
->dyn_cast_constant_svalue ())
4242 if (zerop (cst_rhs
->get_constant ()))
4244 if (const region_svalue
*ptr
= lhs
->dyn_cast_region_svalue ())
4246 /* A region_svalue is a non-NULL pointer, except in certain
4247 special cases (see the comment for region::non_null_p). */
4248 const region
*pointee
= ptr
->get_pointee ();
4249 if (pointee
->non_null_p ())
4259 return tristate::TS_FALSE
;
4264 return tristate::TS_TRUE
;
4268 else if (const binop_svalue
*binop
= lhs
->dyn_cast_binop_svalue ())
4270 /* Treat offsets from a non-NULL pointer as being non-NULL. This
4271 isn't strictly true, in that eventually ptr++ will wrap
4272 around and be NULL, but it won't occur in practise and thus
4273 can be used to suppress effectively false positives that we
4274 shouldn't warn for. */
4275 if (binop
->get_op () == POINTER_PLUS_EXPR
)
4277 tristate lhs_ts
= eval_condition (binop
->get_arg0 (), op
, rhs
);
4278 if (lhs_ts
.is_known ())
4282 else if (const unaryop_svalue
*unaryop
4283 = lhs
->dyn_cast_unaryop_svalue ())
4285 if (unaryop
->get_op () == NEGATE_EXPR
)
4287 /* e.g. "-X <= 0" is equivalent to X >= 0". */
4288 tristate lhs_ts
= eval_condition (unaryop
->get_arg (),
4289 swap_tree_comparison (op
),
4291 if (lhs_ts
.is_known ())
4297 /* Handle rejection of equality for comparisons of the initial values of
4298 "external" values (such as params) with the address of locals. */
4299 if (const initial_svalue
*init_lhs
= lhs
->dyn_cast_initial_svalue ())
4300 if (const region_svalue
*rhs_ptr
= rhs
->dyn_cast_region_svalue ())
4302 tristate res
= compare_initial_and_pointer (init_lhs
, rhs_ptr
);
4303 if (res
.is_known ())
4306 if (const initial_svalue
*init_rhs
= rhs
->dyn_cast_initial_svalue ())
4307 if (const region_svalue
*lhs_ptr
= lhs
->dyn_cast_region_svalue ())
4309 tristate res
= compare_initial_and_pointer (init_rhs
, lhs_ptr
);
4310 if (res
.is_known ())
4314 if (const widening_svalue
*widen_lhs
= lhs
->dyn_cast_widening_svalue ())
4315 if (tree rhs_cst
= rhs
->maybe_get_constant ())
4317 tristate res
= widen_lhs
->eval_condition_without_cm (op
, rhs_cst
);
4318 if (res
.is_known ())
4322 /* Handle comparisons between two svalues with more than one operand. */
4323 if (const binop_svalue
*binop
= lhs
->dyn_cast_binop_svalue ())
4331 /* TODO: binops can be equal even if they are not structurally
4332 equal in case of commutative operators. */
4333 tristate res
= structural_equality (lhs
, rhs
);
4340 tristate res
= structural_equality (lhs
, rhs
);
4347 tristate res
= structural_equality (lhs
, rhs
);
4350 res
= symbolic_greater_than (binop
, rhs
);
4357 tristate res
= symbolic_greater_than (binop
, rhs
);
4365 /* Attempt to unwrap cast if there is one, and the types match. */
4366 tree lhs_type
= lhs
->get_type ();
4367 tree rhs_type
= rhs
->get_type ();
4368 if (lhs_type
&& rhs_type
)
4370 const unaryop_svalue
*lhs_un_op
= dyn_cast
<const unaryop_svalue
*> (lhs
);
4371 const unaryop_svalue
*rhs_un_op
= dyn_cast
<const unaryop_svalue
*> (rhs
);
4372 if (lhs_un_op
&& CONVERT_EXPR_CODE_P (lhs_un_op
->get_op ())
4373 && rhs_un_op
&& CONVERT_EXPR_CODE_P (rhs_un_op
->get_op ())
4374 && lhs_type
== rhs_type
)
4375 return eval_condition (lhs_un_op
->get_arg (),
4377 rhs_un_op
->get_arg ());
4379 else if (lhs_un_op
&& CONVERT_EXPR_CODE_P (lhs_un_op
->get_op ())
4380 && lhs_type
== rhs_type
)
4381 return eval_condition (lhs_un_op
->get_arg (), op
, rhs
);
4383 else if (rhs_un_op
&& CONVERT_EXPR_CODE_P (rhs_un_op
->get_op ())
4384 && lhs_type
== rhs_type
)
4385 return eval_condition (lhs
, op
, rhs_un_op
->get_arg ());
4388 /* Otherwise, try constraints.
4389 Cast to const to ensure we don't change the constraint_manager as we
4390 do this (e.g. by creating equivalence classes). */
4391 const constraint_manager
*constraints
= m_constraints
;
4392 return constraints
->eval_condition (lhs
, op
, rhs
);
4395 /* Subroutine of region_model::eval_condition, for rejecting
4396 equality of INIT_VAL(PARM) with &LOCAL. */
4399 region_model::compare_initial_and_pointer (const initial_svalue
*init
,
4400 const region_svalue
*ptr
) const
4402 const region
*pointee
= ptr
->get_pointee ();
4404 /* If we have a pointer to something within a stack frame, it can't be the
4405 initial value of a param. */
4406 if (pointee
->maybe_get_frame_region ())
4407 if (init
->initial_value_of_param_p ())
4408 return tristate::TS_FALSE
;
4410 return tristate::TS_UNKNOWN
;
4413 /* Return true if SVAL is definitely positive. */
4416 is_positive_svalue (const svalue
*sval
)
4418 if (tree cst
= sval
->maybe_get_constant ())
4419 return !zerop (cst
) && get_range_pos_neg (cst
) == 1;
4420 tree type
= sval
->get_type ();
4423 /* Consider a binary operation size_t + int. The analyzer wraps the int in
4424 an unaryop_svalue, converting it to a size_t, but in the dynamic execution
4425 the result is smaller than the first operand. Thus, we have to look if
4426 the argument of the unaryop_svalue is also positive. */
4427 if (const unaryop_svalue
*un_op
= dyn_cast
<const unaryop_svalue
*> (sval
))
4428 return CONVERT_EXPR_CODE_P (un_op
->get_op ()) && TYPE_UNSIGNED (type
)
4429 && is_positive_svalue (un_op
->get_arg ());
4430 return TYPE_UNSIGNED (type
);
4433 /* Return true if A is definitely larger than B.
4435 Limitation: does not account for integer overflows and does not try to
4436 return false, so it can not be used negated. */
4439 region_model::symbolic_greater_than (const binop_svalue
*bin_a
,
4440 const svalue
*b
) const
4442 if (bin_a
->get_op () == PLUS_EXPR
|| bin_a
->get_op () == MULT_EXPR
)
4444 /* Eliminate the right-hand side of both svalues. */
4445 if (const binop_svalue
*bin_b
= dyn_cast
<const binop_svalue
*> (b
))
4446 if (bin_a
->get_op () == bin_b
->get_op ()
4447 && eval_condition (bin_a
->get_arg1 (),
4449 bin_b
->get_arg1 ()).is_true ()
4450 && eval_condition (bin_a
->get_arg0 (),
4452 bin_b
->get_arg0 ()).is_true ())
4453 return tristate (tristate::TS_TRUE
);
4455 /* Otherwise, try to remove a positive offset or factor from BIN_A. */
4456 if (is_positive_svalue (bin_a
->get_arg1 ())
4457 && eval_condition (bin_a
->get_arg0 (),
4458 GE_EXPR
, b
).is_true ())
4459 return tristate (tristate::TS_TRUE
);
4461 return tristate::unknown ();
4464 /* Return true if A and B are equal structurally.
4466 Structural equality means that A and B are equal if the svalues A and B have
4467 the same nodes at the same positions in the tree and the leafs are equal.
4468 Equality for conjured_svalues and initial_svalues is determined by comparing
4469 the pointers while constants are compared by value. That behavior is useful
4470 to check for binaryop_svlaues that evaluate to the same concrete value but
4471 might use one operand with a different type but the same constant value.
4474 binop_svalue (mult_expr,
4475 initial_svalue (‘size_t’, decl_region (..., 'some_var')),
4476 constant_svalue (‘size_t’, 4))
4478 binop_svalue (mult_expr,
4479 initial_svalue (‘size_t’, decl_region (..., 'some_var'),
4480 constant_svalue (‘sizetype’, 4))
4481 are structurally equal. A concrete C code example, where this occurs, can
4482 be found in test7 of out-of-bounds-5.c. */
4485 region_model::structural_equality (const svalue
*a
, const svalue
*b
) const
4487 /* If A and B are referentially equal, they are also structurally equal. */
4489 return tristate (tristate::TS_TRUE
);
4491 switch (a
->get_kind ())
4494 return tristate::unknown ();
4495 /* SK_CONJURED and SK_INITIAL are already handled
4496 by the referential equality above. */
4499 tree a_cst
= a
->maybe_get_constant ();
4500 tree b_cst
= b
->maybe_get_constant ();
4502 return tristate (tree_int_cst_equal (a_cst
, b_cst
));
4504 return tristate (tristate::TS_FALSE
);
4507 const unaryop_svalue
*un_a
= as_a
<const unaryop_svalue
*> (a
);
4508 if (const unaryop_svalue
*un_b
= dyn_cast
<const unaryop_svalue
*> (b
))
4509 return tristate (pending_diagnostic::same_tree_p (un_a
->get_type (),
4511 && un_a
->get_op () == un_b
->get_op ()
4512 && structural_equality (un_a
->get_arg (),
4515 return tristate (tristate::TS_FALSE
);
4518 const binop_svalue
*bin_a
= as_a
<const binop_svalue
*> (a
);
4519 if (const binop_svalue
*bin_b
= dyn_cast
<const binop_svalue
*> (b
))
4520 return tristate (bin_a
->get_op () == bin_b
->get_op ()
4521 && structural_equality (bin_a
->get_arg0 (),
4523 && structural_equality (bin_a
->get_arg1 (),
4524 bin_b
->get_arg1 ()));
4526 return tristate (tristate::TS_FALSE
);
4530 /* Handle various constraints of the form:
4531 LHS: ((bool)INNER_LHS INNER_OP INNER_RHS))
4535 LHS: CAST([long]int, ((bool)INNER_LHS INNER_OP INNER_RHS))
4538 by adding constraints for INNER_LHS INNEROP INNER_RHS.
4540 Return true if this function can fully handle the constraint; if
4541 so, add the implied constraint(s) and write true to *OUT if they
4542 are consistent with existing constraints, or write false to *OUT
4543 if they contradicts existing constraints.
4545 Return false for cases that this function doeesn't know how to handle.
4547 For example, if we're checking a stored conditional, we'll have
4549 LHS: CAST(long int, (&HEAP_ALLOCATED_REGION(8)!=(int *)0B))
4552 which this function can turn into an add_constraint of:
4553 (&HEAP_ALLOCATED_REGION(8) != (int *)0B)
4555 Similarly, optimized && and || conditionals lead to e.g.
4557 becoming gimple like this:
4561 On the "_3 is false" branch we can have constraints of the form:
4562 ((&HEAP_ALLOCATED_REGION(8)!=(int *)0B)
4563 | (&HEAP_ALLOCATED_REGION(10)!=(int *)0B))
4565 which implies that both _1 and _2 are false,
4566 which this function can turn into a pair of add_constraints of
4567 (&HEAP_ALLOCATED_REGION(8)!=(int *)0B)
4569 (&HEAP_ALLOCATED_REGION(10)!=(int *)0B). */
4572 region_model::add_constraints_from_binop (const svalue
*outer_lhs
,
4573 enum tree_code outer_op
,
4574 const svalue
*outer_rhs
,
4576 region_model_context
*ctxt
)
4578 while (const svalue
*cast
= outer_lhs
->maybe_undo_cast ())
4580 const binop_svalue
*binop_sval
= outer_lhs
->dyn_cast_binop_svalue ();
4583 if (!outer_rhs
->all_zeroes_p ())
4586 const svalue
*inner_lhs
= binop_sval
->get_arg0 ();
4587 enum tree_code inner_op
= binop_sval
->get_op ();
4588 const svalue
*inner_rhs
= binop_sval
->get_arg1 ();
4590 if (outer_op
!= NE_EXPR
&& outer_op
!= EQ_EXPR
)
4594 - "OUTER_LHS != false" (i.e. OUTER is true), or
4595 - "OUTER_LHS == false" (i.e. OUTER is false). */
4596 bool is_true
= outer_op
== NE_EXPR
;
4610 /* ...and "(inner_lhs OP inner_rhs) == 0"
4611 then (inner_lhs OP inner_rhs) must have the same
4612 logical value as LHS. */
4614 inner_op
= invert_tree_comparison (inner_op
, false /* honor_nans */);
4615 *out
= add_constraint (inner_lhs
, inner_op
, inner_rhs
, ctxt
);
4623 /* ...and "(inner_lhs & inner_rhs) != 0"
4624 then both inner_lhs and inner_rhs must be true. */
4625 const svalue
*false_sval
4626 = m_mgr
->get_or_create_constant_svalue (boolean_false_node
);
4627 bool sat1
= add_constraint (inner_lhs
, NE_EXPR
, false_sval
, ctxt
);
4628 bool sat2
= add_constraint (inner_rhs
, NE_EXPR
, false_sval
, ctxt
);
4629 *out
= sat1
&& sat2
;
4637 /* ...and "(inner_lhs | inner_rhs) == 0"
4638 i.e. "(inner_lhs | inner_rhs)" is false
4639 then both inner_lhs and inner_rhs must be false. */
4640 const svalue
*false_sval
4641 = m_mgr
->get_or_create_constant_svalue (boolean_false_node
);
4642 bool sat1
= add_constraint (inner_lhs
, EQ_EXPR
, false_sval
, ctxt
);
4643 bool sat2
= add_constraint (inner_rhs
, EQ_EXPR
, false_sval
, ctxt
);
4644 *out
= sat1
&& sat2
;
4651 /* Attempt to add the constraint "LHS OP RHS" to this region_model.
4652 If it is consistent with existing constraints, add it, and return true.
4653 Return false if it contradicts existing constraints.
4654 Use CTXT for reporting any diagnostics associated with the accesses. */
4657 region_model::add_constraint (tree lhs
, enum tree_code op
, tree rhs
,
4658 region_model_context
*ctxt
)
4660 /* For now, make no attempt to capture constraints on floating-point
4662 if (FLOAT_TYPE_P (TREE_TYPE (lhs
)) || FLOAT_TYPE_P (TREE_TYPE (rhs
)))
4665 const svalue
*lhs_sval
= get_rvalue (lhs
, ctxt
);
4666 const svalue
*rhs_sval
= get_rvalue (rhs
, ctxt
);
4668 return add_constraint (lhs_sval
, op
, rhs_sval
, ctxt
);
4672 unusable_in_infinite_loop_constraint_p (const svalue
*sval
)
4674 if (sval
->get_kind () == SK_WIDENING
)
4679 /* Attempt to add the constraint "LHS OP RHS" to this region_model.
4680 If it is consistent with existing constraints, add it, and return true.
4681 Return false if it contradicts existing constraints.
4682 Use CTXT for reporting any diagnostics associated with the accesses. */
4685 region_model::add_constraint (const svalue
*lhs
,
4688 region_model_context
*ctxt
)
4690 const bool checking_for_infinite_loop
4691 = ctxt
? ctxt
->checking_for_infinite_loop_p () : false;
4693 if (checking_for_infinite_loop
)
4695 if (unusable_in_infinite_loop_constraint_p (lhs
)
4696 || unusable_in_infinite_loop_constraint_p (rhs
))
4699 ctxt
->on_unusable_in_infinite_loop ();
4704 tristate t_cond
= eval_condition (lhs
, op
, rhs
);
4706 /* If we already have the condition, do nothing. */
4707 if (t_cond
.is_true ())
4710 /* Reject a constraint that would contradict existing knowledge, as
4712 if (t_cond
.is_false ())
4715 if (checking_for_infinite_loop
)
4717 /* Here, we don't have a definite true/false value, so bail out
4718 when checking for infinite loops. */
4720 ctxt
->on_unusable_in_infinite_loop ();
4725 if (add_constraints_from_binop (lhs
, op
, rhs
, &out
, ctxt
))
4728 /* Attempt to store the constraint. */
4729 if (!m_constraints
->add_constraint (lhs
, op
, rhs
))
4732 /* Notify the context, if any. This exists so that the state machines
4733 in a program_state can be notified about the condition, and so can
4734 set sm-state for e.g. unchecked->checked, both for cfg-edges, and
4735 when synthesizing constraints as above. */
4737 ctxt
->on_condition (lhs
, op
, rhs
);
4739 /* If we have ®ION == NULL, then drop dynamic extents for REGION (for
4740 the case where REGION is heap-allocated and thus could be NULL). */
4741 if (tree rhs_cst
= rhs
->maybe_get_constant ())
4742 if (op
== EQ_EXPR
&& zerop (rhs_cst
))
4743 if (const region_svalue
*region_sval
= lhs
->dyn_cast_region_svalue ())
4744 unset_dynamic_extents (region_sval
->get_pointee ());
4749 /* As above, but when returning false, if OUT is non-NULL, write a
4750 new rejected_constraint to *OUT. */
4753 region_model::add_constraint (tree lhs
, enum tree_code op
, tree rhs
,
4754 region_model_context
*ctxt
,
4755 std::unique_ptr
<rejected_constraint
> *out
)
4757 bool sat
= add_constraint (lhs
, op
, rhs
, ctxt
);
4759 *out
= make_unique
<rejected_op_constraint
> (*this, lhs
, op
, rhs
);
4763 /* Determine what is known about the condition "LHS OP RHS" within
4765 Use CTXT for reporting any diagnostics associated with the accesses. */
4768 region_model::eval_condition (tree lhs
,
4771 region_model_context
*ctxt
) const
4773 /* For now, make no attempt to model constraints on floating-point
4775 if (FLOAT_TYPE_P (TREE_TYPE (lhs
)) || FLOAT_TYPE_P (TREE_TYPE (rhs
)))
4776 return tristate::unknown ();
4778 return eval_condition (get_rvalue (lhs
, ctxt
), op
, get_rvalue (rhs
, ctxt
));
4781 /* Implementation of region_model::get_representative_path_var.
4782 Attempt to return a path_var that represents SVAL, or return NULL_TREE.
4783 Use VISITED to prevent infinite mutual recursion with the overload for
4787 region_model::get_representative_path_var_1 (const svalue
*sval
,
4788 svalue_set
*visited
) const
4792 /* Prevent infinite recursion. */
4793 if (visited
->contains (sval
))
4795 if (sval
->get_kind () == SK_CONSTANT
)
4796 return path_var (sval
->maybe_get_constant (), 0);
4798 return path_var (NULL_TREE
, 0);
4800 visited
->add (sval
);
4802 /* Handle casts by recursion into get_representative_path_var. */
4803 if (const svalue
*cast_sval
= sval
->maybe_undo_cast ())
4805 path_var result
= get_representative_path_var (cast_sval
, visited
);
4806 tree orig_type
= sval
->get_type ();
4807 /* If necessary, wrap the result in a cast. */
4808 if (result
.m_tree
&& orig_type
)
4809 result
.m_tree
= build1 (NOP_EXPR
, orig_type
, result
.m_tree
);
4813 auto_vec
<path_var
> pvs
;
4814 m_store
.get_representative_path_vars (this, visited
, sval
, &pvs
);
4816 if (tree cst
= sval
->maybe_get_constant ())
4817 pvs
.safe_push (path_var (cst
, 0));
4819 /* Handle string literals and various other pointers. */
4820 if (const region_svalue
*ptr_sval
= sval
->dyn_cast_region_svalue ())
4822 const region
*reg
= ptr_sval
->get_pointee ();
4823 if (path_var pv
= get_representative_path_var (reg
, visited
))
4824 return path_var (build1 (ADDR_EXPR
,
4830 /* If we have a sub_svalue, look for ways to represent the parent. */
4831 if (const sub_svalue
*sub_sval
= sval
->dyn_cast_sub_svalue ())
4833 const svalue
*parent_sval
= sub_sval
->get_parent ();
4834 const region
*subreg
= sub_sval
->get_subregion ();
4835 if (path_var parent_pv
4836 = get_representative_path_var (parent_sval
, visited
))
4837 if (const field_region
*field_reg
= subreg
->dyn_cast_field_region ())
4838 return path_var (build3 (COMPONENT_REF
,
4841 field_reg
->get_field (),
4843 parent_pv
.m_stack_depth
);
4846 /* Handle binops. */
4847 if (const binop_svalue
*binop_sval
= sval
->dyn_cast_binop_svalue ())
4849 = get_representative_path_var (binop_sval
->get_arg0 (), visited
))
4851 = get_representative_path_var (binop_sval
->get_arg1 (), visited
))
4852 return path_var (build2 (binop_sval
->get_op (),
4854 lhs_pv
.m_tree
, rhs_pv
.m_tree
),
4855 lhs_pv
.m_stack_depth
);
4857 if (pvs
.length () < 1)
4858 return path_var (NULL_TREE
, 0);
4860 pvs
.qsort (readability_comparator
);
4864 /* Attempt to return a path_var that represents SVAL, or return NULL_TREE.
4865 Use VISITED to prevent infinite mutual recursion with the overload for
4868 This function defers to get_representative_path_var_1 to do the work;
4869 it adds verification that get_representative_path_var_1 returned a tree
4870 of the correct type. */
4873 region_model::get_representative_path_var (const svalue
*sval
,
4874 svalue_set
*visited
) const
4877 return path_var (NULL_TREE
, 0);
4879 tree orig_type
= sval
->get_type ();
4881 path_var result
= get_representative_path_var_1 (sval
, visited
);
4883 /* Verify that the result has the same type as SVAL, if any. */
4884 if (result
.m_tree
&& orig_type
)
4885 gcc_assert (TREE_TYPE (result
.m_tree
) == orig_type
);
4890 /* Attempt to return a tree that represents SVAL, or return NULL_TREE.
4892 Strip off any top-level cast, to avoid messages like
4893 double-free of '(void *)ptr'
4894 from analyzer diagnostics. */
4897 region_model::get_representative_tree (const svalue
*sval
) const
4900 tree expr
= get_representative_path_var (sval
, &visited
).m_tree
;
4902 /* Strip off any top-level cast. */
4903 if (expr
&& TREE_CODE (expr
) == NOP_EXPR
)
4904 expr
= TREE_OPERAND (expr
, 0);
4906 return fixup_tree_for_diagnostic (expr
);
4910 region_model::get_representative_tree (const region
*reg
) const
4913 tree expr
= get_representative_path_var (reg
, &visited
).m_tree
;
4915 /* Strip off any top-level cast. */
4916 if (expr
&& TREE_CODE (expr
) == NOP_EXPR
)
4917 expr
= TREE_OPERAND (expr
, 0);
4919 return fixup_tree_for_diagnostic (expr
);
4922 /* Implementation of region_model::get_representative_path_var.
4924 Attempt to return a path_var that represents REG, or return
4926 For example, a region for a field of a local would be a path_var
4927 wrapping a COMPONENT_REF.
4928 Use VISITED to prevent infinite mutual recursion with the overload for
4932 region_model::get_representative_path_var_1 (const region
*reg
,
4933 svalue_set
*visited
) const
4935 switch (reg
->get_kind ())
4945 case RK_THREAD_LOCAL
:
4947 /* Regions that represent memory spaces are not expressible as trees. */
4948 return path_var (NULL_TREE
, 0);
4952 const function_region
*function_reg
4953 = as_a
<const function_region
*> (reg
);
4954 return path_var (function_reg
->get_fndecl (), 0);
4958 const label_region
*label_reg
= as_a
<const label_region
*> (reg
);
4959 return path_var (label_reg
->get_label (), 0);
4964 const symbolic_region
*symbolic_reg
4965 = as_a
<const symbolic_region
*> (reg
);
4966 const svalue
*pointer
= symbolic_reg
->get_pointer ();
4967 path_var pointer_pv
= get_representative_path_var (pointer
, visited
);
4969 return path_var (NULL_TREE
, 0);
4970 tree offset
= build_int_cst (pointer
->get_type (), 0);
4971 return path_var (build2 (MEM_REF
,
4975 pointer_pv
.m_stack_depth
);
4979 const decl_region
*decl_reg
= as_a
<const decl_region
*> (reg
);
4980 return path_var (decl_reg
->get_decl (), decl_reg
->get_stack_depth ());
4984 const field_region
*field_reg
= as_a
<const field_region
*> (reg
);
4986 = get_representative_path_var (reg
->get_parent_region (), visited
);
4988 return path_var (NULL_TREE
, 0);
4989 return path_var (build3 (COMPONENT_REF
,
4992 field_reg
->get_field (),
4994 parent_pv
.m_stack_depth
);
4999 const element_region
*element_reg
5000 = as_a
<const element_region
*> (reg
);
5002 = get_representative_path_var (reg
->get_parent_region (), visited
);
5004 return path_var (NULL_TREE
, 0);
5006 = get_representative_path_var (element_reg
->get_index (), visited
);
5008 return path_var (NULL_TREE
, 0);
5009 return path_var (build4 (ARRAY_REF
,
5011 parent_pv
.m_tree
, index_pv
.m_tree
,
5012 NULL_TREE
, NULL_TREE
),
5013 parent_pv
.m_stack_depth
);
5018 const offset_region
*offset_reg
5019 = as_a
<const offset_region
*> (reg
);
5021 = get_representative_path_var (reg
->get_parent_region (), visited
);
5023 return path_var (NULL_TREE
, 0);
5025 = get_representative_path_var (offset_reg
->get_byte_offset (),
5027 if (!offset_pv
|| TREE_CODE (offset_pv
.m_tree
) != INTEGER_CST
)
5028 return path_var (NULL_TREE
, 0);
5029 tree addr_parent
= build1 (ADDR_EXPR
,
5030 build_pointer_type (reg
->get_type ()),
5032 return path_var (build2 (MEM_REF
,
5034 addr_parent
, offset_pv
.m_tree
),
5035 parent_pv
.m_stack_depth
);
5039 return path_var (NULL_TREE
, 0);
5044 = get_representative_path_var (reg
->get_parent_region (), visited
);
5046 return path_var (NULL_TREE
, 0);
5047 return path_var (build1 (NOP_EXPR
,
5050 parent_pv
.m_stack_depth
);
5053 case RK_HEAP_ALLOCATED
:
5055 /* No good way to express heap-allocated/alloca regions as trees. */
5056 return path_var (NULL_TREE
, 0);
5060 const string_region
*string_reg
= as_a
<const string_region
*> (reg
);
5061 return path_var (string_reg
->get_string_cst (), 0);
5068 return path_var (NULL_TREE
, 0);
5072 /* Attempt to return a path_var that represents REG, or return
5074 For example, a region for a field of a local would be a path_var
5075 wrapping a COMPONENT_REF.
5076 Use VISITED to prevent infinite mutual recursion with the overload for
5079 This function defers to get_representative_path_var_1 to do the work;
5080 it adds verification that get_representative_path_var_1 returned a tree
5081 of the correct type. */
5084 region_model::get_representative_path_var (const region
*reg
,
5085 svalue_set
*visited
) const
5087 path_var result
= get_representative_path_var_1 (reg
, visited
);
5089 /* Verify that the result has the same type as REG, if any. */
5090 if (result
.m_tree
&& reg
->get_type ())
5091 gcc_assert (TREE_TYPE (result
.m_tree
) == reg
->get_type ());
5096 /* Update this model for any phis in SNODE, assuming we came from
5097 LAST_CFG_SUPEREDGE. */
5100 region_model::update_for_phis (const supernode
*snode
,
5101 const cfg_superedge
*last_cfg_superedge
,
5102 region_model_context
*ctxt
)
5104 gcc_assert (last_cfg_superedge
);
5106 /* Copy this state and pass it to handle_phi so that all of the phi stmts
5107 are effectively handled simultaneously. */
5108 const region_model
old_state (*this);
5110 hash_set
<const svalue
*> svals_changing_meaning
;
5112 for (gphi_iterator gpi
= const_cast<supernode
*>(snode
)->start_phis ();
5113 !gsi_end_p (gpi
); gsi_next (&gpi
))
5115 gphi
*phi
= gpi
.phi ();
5117 tree src
= last_cfg_superedge
->get_phi_arg (phi
);
5118 tree lhs
= gimple_phi_result (phi
);
5120 /* Update next_state based on phi and old_state. */
5121 handle_phi (phi
, lhs
, src
, old_state
, svals_changing_meaning
, ctxt
);
5124 for (auto iter
: svals_changing_meaning
)
5125 m_constraints
->purge_state_involving (iter
);
5128 /* Attempt to update this model for taking EDGE (where the last statement
5129 was LAST_STMT), returning true if the edge can be taken, false
5131 When returning false, if OUT is non-NULL, write a new rejected_constraint
5134 For CFG superedges where LAST_STMT is a conditional or a switch
5135 statement, attempt to add the relevant conditions for EDGE to this
5136 model, returning true if they are feasible, or false if they are
5139 For call superedges, push frame information and store arguments
5142 For return superedges, pop frame information and store return
5143 values into any lhs.
5145 Rejection of call/return superedges happens elsewhere, in
5146 program_point::on_edge (i.e. based on program point, rather
5147 than program state). */
5150 region_model::maybe_update_for_edge (const superedge
&edge
,
5151 const gimple
*last_stmt
,
5152 region_model_context
*ctxt
,
5153 std::unique_ptr
<rejected_constraint
> *out
)
5155 /* Handle frame updates for interprocedural edges. */
5156 switch (edge
.m_kind
)
5161 case SUPEREDGE_CALL
:
5163 const call_superedge
*call_edge
= as_a
<const call_superedge
*> (&edge
);
5164 update_for_call_superedge (*call_edge
, ctxt
);
5168 case SUPEREDGE_RETURN
:
5170 const return_superedge
*return_edge
5171 = as_a
<const return_superedge
*> (&edge
);
5172 update_for_return_superedge (*return_edge
, ctxt
);
5176 case SUPEREDGE_INTRAPROCEDURAL_CALL
:
5177 /* This is a no-op for call summaries; we should already
5178 have handled the effect of the call summary at the call stmt. */
5182 if (last_stmt
== NULL
)
5185 /* Apply any constraints for conditionals/switch/computed-goto statements. */
5187 if (const gcond
*cond_stmt
= dyn_cast
<const gcond
*> (last_stmt
))
5189 const cfg_superedge
*cfg_sedge
= as_a
<const cfg_superedge
*> (&edge
);
5190 return apply_constraints_for_gcond (*cfg_sedge
, cond_stmt
, ctxt
, out
);
5193 if (const gswitch
*switch_stmt
= dyn_cast
<const gswitch
*> (last_stmt
))
5195 const switch_cfg_superedge
*switch_sedge
5196 = as_a
<const switch_cfg_superedge
*> (&edge
);
5197 return apply_constraints_for_gswitch (*switch_sedge
, switch_stmt
,
5201 if (const ggoto
*goto_stmt
= dyn_cast
<const ggoto
*> (last_stmt
))
5203 const cfg_superedge
*cfg_sedge
= as_a
<const cfg_superedge
*> (&edge
);
5204 return apply_constraints_for_ggoto (*cfg_sedge
, goto_stmt
, ctxt
);
5207 /* Apply any constraints due to an exception being thrown. */
5208 if (const cfg_superedge
*cfg_sedge
= dyn_cast
<const cfg_superedge
*> (&edge
))
5209 if (cfg_sedge
->get_flags () & EDGE_EH
)
5210 return apply_constraints_for_exception (last_stmt
, ctxt
, out
);
5215 /* Push a new frame_region on to the stack region.
5216 Populate the frame_region with child regions for the function call's
5217 parameters, using values from the arguments at the callsite in the
5221 region_model::update_for_gcall (const gcall
*call_stmt
,
5222 region_model_context
*ctxt
,
5225 /* Build a vec of argument svalues, using the current top
5226 frame for resolving tree expressions. */
5227 auto_vec
<const svalue
*> arg_svals (gimple_call_num_args (call_stmt
));
5229 for (unsigned i
= 0; i
< gimple_call_num_args (call_stmt
); i
++)
5231 tree arg
= gimple_call_arg (call_stmt
, i
);
5232 arg_svals
.quick_push (get_rvalue (arg
, ctxt
));
5237 /* Get the function * from the gcall. */
5238 tree fn_decl
= get_fndecl_for_call (call_stmt
,ctxt
);
5239 callee
= DECL_STRUCT_FUNCTION (fn_decl
);
5242 push_frame (callee
, &arg_svals
, ctxt
);
5245 /* Pop the top-most frame_region from the stack, and copy the return
5246 region's values (if any) into the region for the lvalue of the LHS of
5247 the call (if any). */
5250 region_model::update_for_return_gcall (const gcall
*call_stmt
,
5251 region_model_context
*ctxt
)
5253 /* Get the lvalue for the result of the call, passing it to pop_frame,
5254 so that pop_frame can determine the region with respect to the
5256 tree lhs
= gimple_call_lhs (call_stmt
);
5257 pop_frame (lhs
, NULL
, ctxt
);
5260 /* Extract calling information from the superedge and update the model for the
5264 region_model::update_for_call_superedge (const call_superedge
&call_edge
,
5265 region_model_context
*ctxt
)
5267 const gcall
*call_stmt
= call_edge
.get_call_stmt ();
5268 update_for_gcall (call_stmt
, ctxt
, call_edge
.get_callee_function ());
5271 /* Extract calling information from the return superedge and update the model
5272 for the returning call */
5275 region_model::update_for_return_superedge (const return_superedge
&return_edge
,
5276 region_model_context
*ctxt
)
5278 const gcall
*call_stmt
= return_edge
.get_call_stmt ();
5279 update_for_return_gcall (call_stmt
, ctxt
);
5282 /* Attempt to to use R to replay SUMMARY into this object.
5283 Return true if it is possible. */
5286 region_model::replay_call_summary (call_summary_replay
&r
,
5287 const region_model
&summary
)
5289 gcc_assert (summary
.get_stack_depth () == 1);
5291 m_store
.replay_call_summary (r
, summary
.m_store
);
5294 r
.get_ctxt ()->maybe_did_work ();
5296 if (!m_constraints
->replay_call_summary (r
, *summary
.m_constraints
))
5299 for (auto kv
: summary
.m_dynamic_extents
)
5301 const region
*summary_reg
= kv
.first
;
5302 const region
*caller_reg
= r
.convert_region_from_summary (summary_reg
);
5305 const svalue
*summary_sval
= kv
.second
;
5306 const svalue
*caller_sval
= r
.convert_svalue_from_summary (summary_sval
);
5309 m_dynamic_extents
.put (caller_reg
, caller_sval
);
5315 /* Given a true or false edge guarded by conditional statement COND_STMT,
5316 determine appropriate constraints for the edge to be taken.
5318 If they are feasible, add the constraints and return true.
5320 Return false if the constraints contradict existing knowledge
5321 (and so the edge should not be taken).
5322 When returning false, if OUT is non-NULL, write a new rejected_constraint
5327 apply_constraints_for_gcond (const cfg_superedge
&sedge
,
5328 const gcond
*cond_stmt
,
5329 region_model_context
*ctxt
,
5330 std::unique_ptr
<rejected_constraint
> *out
)
5332 ::edge cfg_edge
= sedge
.get_cfg_edge ();
5333 gcc_assert (cfg_edge
!= NULL
);
5334 gcc_assert (cfg_edge
->flags
& (EDGE_TRUE_VALUE
| EDGE_FALSE_VALUE
));
5336 enum tree_code op
= gimple_cond_code (cond_stmt
);
5337 tree lhs
= gimple_cond_lhs (cond_stmt
);
5338 tree rhs
= gimple_cond_rhs (cond_stmt
);
5339 if (cfg_edge
->flags
& EDGE_FALSE_VALUE
)
5340 op
= invert_tree_comparison (op
, false /* honor_nans */);
5341 return add_constraint (lhs
, op
, rhs
, ctxt
, out
);
5344 /* Return true iff SWITCH_STMT has a non-default label that contains
5348 has_nondefault_case_for_value_p (const gswitch
*switch_stmt
, tree int_cst
)
5350 /* We expect the initial label to be the default; skip it. */
5351 gcc_assert (CASE_LOW (gimple_switch_label (switch_stmt
, 0)) == NULL
);
5352 unsigned min_idx
= 1;
5353 unsigned max_idx
= gimple_switch_num_labels (switch_stmt
) - 1;
5355 /* Binary search: try to find the label containing INT_CST.
5356 This requires the cases to be sorted by CASE_LOW (done by the
5358 while (max_idx
>= min_idx
)
5360 unsigned case_idx
= (min_idx
+ max_idx
) / 2;
5361 tree label
= gimple_switch_label (switch_stmt
, case_idx
);
5362 tree low
= CASE_LOW (label
);
5364 tree high
= CASE_HIGH (label
);
5367 if (tree_int_cst_compare (int_cst
, low
) < 0)
5369 /* INT_CST is below the range of this label. */
5370 gcc_assert (case_idx
> 0);
5371 max_idx
= case_idx
- 1;
5373 else if (tree_int_cst_compare (int_cst
, high
) > 0)
5375 /* INT_CST is above the range of this case. */
5376 min_idx
= case_idx
+ 1;
5379 /* This case contains INT_CST. */
5386 /* Return true iff SWITCH_STMT (which must be on an enum value)
5387 has nondefault cases handling all values in the enum. */
5390 has_nondefault_cases_for_all_enum_values_p (const gswitch
*switch_stmt
,
5393 gcc_assert (switch_stmt
);
5394 gcc_assert (TREE_CODE (type
) == ENUMERAL_TYPE
);
5396 for (tree enum_val_iter
= TYPE_VALUES (type
);
5398 enum_val_iter
= TREE_CHAIN (enum_val_iter
))
5400 tree enum_val
= TREE_VALUE (enum_val_iter
);
5401 gcc_assert (TREE_CODE (enum_val
) == CONST_DECL
);
5402 gcc_assert (TREE_CODE (DECL_INITIAL (enum_val
)) == INTEGER_CST
);
5403 if (!has_nondefault_case_for_value_p (switch_stmt
,
5404 DECL_INITIAL (enum_val
)))
5410 /* Given an EDGE guarded by SWITCH_STMT, determine appropriate constraints
5411 for the edge to be taken.
5413 If they are feasible, add the constraints and return true.
5415 Return false if the constraints contradict existing knowledge
5416 (and so the edge should not be taken).
5417 When returning false, if OUT is non-NULL, write a new rejected_constraint
5422 apply_constraints_for_gswitch (const switch_cfg_superedge
&edge
,
5423 const gswitch
*switch_stmt
,
5424 region_model_context
*ctxt
,
5425 std::unique_ptr
<rejected_constraint
> *out
)
5427 tree index
= gimple_switch_index (switch_stmt
);
5428 const svalue
*index_sval
= get_rvalue (index
, ctxt
);
5429 bool check_index_type
= true;
5431 /* With -fshort-enum, there may be a type cast. */
5432 if (ctxt
&& index_sval
->get_kind () == SK_UNARYOP
5433 && TREE_CODE (index_sval
->get_type ()) == INTEGER_TYPE
)
5435 const unaryop_svalue
*unaryop
= as_a
<const unaryop_svalue
*> (index_sval
);
5436 if (unaryop
->get_op () == NOP_EXPR
5437 && is_a
<const initial_svalue
*> (unaryop
->get_arg ()))
5438 if (const initial_svalue
*initvalop
= (as_a
<const initial_svalue
*>
5439 (unaryop
->get_arg ())))
5440 if (TREE_CODE (initvalop
->get_type ()) == ENUMERAL_TYPE
)
5442 index_sval
= initvalop
;
5443 check_index_type
= false;
5447 /* If we're switching based on an enum type, assume that the user is only
5448 working with values from the enum. Hence if this is an
5449 implicitly-created "default", assume it doesn't get followed.
5450 This fixes numerous "uninitialized" false positives where we otherwise
5451 consider jumping past the initialization cases. */
5453 if (/* Don't check during feasibility-checking (when ctxt is NULL). */
5455 /* Must be an enum value. */
5456 && index_sval
->get_type ()
5457 && (!check_index_type
5458 || TREE_CODE (TREE_TYPE (index
)) == ENUMERAL_TYPE
)
5459 && TREE_CODE (index_sval
->get_type ()) == ENUMERAL_TYPE
5460 /* If we have a constant, then we can check it directly. */
5461 && index_sval
->get_kind () != SK_CONSTANT
5462 && edge
.implicitly_created_default_p ()
5463 && has_nondefault_cases_for_all_enum_values_p (switch_stmt
,
5464 index_sval
->get_type ())
5465 /* Don't do this if there's a chance that the index is
5466 attacker-controlled. */
5467 && !ctxt
->possibly_tainted_p (index_sval
))
5470 *out
= make_unique
<rejected_default_case
> (*this);
5474 bounded_ranges_manager
*ranges_mgr
= get_range_manager ();
5475 const bounded_ranges
*all_cases_ranges
5476 = ranges_mgr
->get_or_create_ranges_for_switch (&edge
, switch_stmt
);
5477 bool sat
= m_constraints
->add_bounded_ranges (index_sval
, all_cases_ranges
);
5479 *out
= make_unique
<rejected_ranges_constraint
> (*this, index
, all_cases_ranges
);
5480 if (sat
&& ctxt
&& !all_cases_ranges
->empty_p ())
5481 ctxt
->on_bounded_ranges (*index_sval
, *all_cases_ranges
);
5485 /* Given an edge reached by GOTO_STMT, determine appropriate constraints
5486 for the edge to be taken.
5488 If they are feasible, add the constraints and return true.
5490 Return false if the constraints contradict existing knowledge
5491 (and so the edge should not be taken). */
5494 region_model::apply_constraints_for_ggoto (const cfg_superedge
&edge
,
5495 const ggoto
*goto_stmt
,
5496 region_model_context
*ctxt
)
5498 tree dest
= gimple_goto_dest (goto_stmt
);
5499 const svalue
*dest_sval
= get_rvalue (dest
, ctxt
);
5501 /* If we know we were jumping to a specific label. */
5502 if (tree dst_label
= edge
.m_dest
->get_label ())
5504 const label_region
*dst_label_reg
5505 = m_mgr
->get_region_for_label (dst_label
);
5506 const svalue
*dst_label_ptr
5507 = m_mgr
->get_ptr_svalue (ptr_type_node
, dst_label_reg
);
5509 if (!add_constraint (dest_sval
, EQ_EXPR
, dst_label_ptr
, ctxt
))
5516 /* Apply any constraints due to an exception being thrown at LAST_STMT.
5518 If they are feasible, add the constraints and return true.
5520 Return false if the constraints contradict existing knowledge
5521 (and so the edge should not be taken).
5522 When returning false, if OUT is non-NULL, write a new rejected_constraint
5527 apply_constraints_for_exception (const gimple
*last_stmt
,
5528 region_model_context
*ctxt
,
5529 std::unique_ptr
<rejected_constraint
> *out
)
5531 gcc_assert (last_stmt
);
5532 if (const gcall
*call
= dyn_cast
<const gcall
*> (last_stmt
))
5533 if (tree callee_fndecl
= get_fndecl_for_call (call
, ctxt
))
5534 if (is_named_call_p (callee_fndecl
, "operator new", call
, 1)
5535 || is_named_call_p (callee_fndecl
, "operator new []", call
, 1))
5537 /* We have an exception thrown from operator new.
5538 Add a constraint that the result was NULL, to avoid a false
5539 leak report due to the result being lost when following
5541 if (tree lhs
= gimple_call_lhs (call
))
5542 return add_constraint (lhs
, EQ_EXPR
, null_pointer_node
, ctxt
, out
);
5548 /* For use with push_frame when handling a top-level call within the analysis.
5549 PARAM has a defined but unknown initial value.
5550 Anything it points to has escaped, since the calling context "knows"
5551 the pointer, and thus calls to unknown functions could read/write into
5553 If NONNULL is true, then assume that PARAM must be non-NULL. */
5556 region_model::on_top_level_param (tree param
,
5558 region_model_context
*ctxt
)
5560 if (POINTER_TYPE_P (TREE_TYPE (param
)))
5562 const region
*param_reg
= get_lvalue (param
, ctxt
);
5563 const svalue
*init_ptr_sval
5564 = m_mgr
->get_or_create_initial_value (param_reg
);
5565 const region
*pointee_reg
= m_mgr
->get_symbolic_region (init_ptr_sval
);
5566 m_store
.mark_as_escaped (pointee_reg
);
5569 const svalue
*null_ptr_sval
5570 = m_mgr
->get_or_create_null_ptr (TREE_TYPE (param
));
5571 add_constraint (init_ptr_sval
, NE_EXPR
, null_ptr_sval
, ctxt
);
5576 /* Update this region_model to reflect pushing a frame onto the stack
5579 If ARG_SVALS is non-NULL, use it to populate the parameters
5581 Otherwise, the params have their initial_svalues.
5583 Return the frame_region for the new frame. */
5586 region_model::push_frame (function
*fun
, const vec
<const svalue
*> *arg_svals
,
5587 region_model_context
*ctxt
)
5589 m_current_frame
= m_mgr
->get_frame_region (m_current_frame
, fun
);
5592 /* Arguments supplied from a caller frame. */
5593 tree fndecl
= fun
->decl
;
5595 for (tree iter_parm
= DECL_ARGUMENTS (fndecl
); iter_parm
;
5596 iter_parm
= DECL_CHAIN (iter_parm
), ++idx
)
5598 /* If there's a mismatching declaration, the call stmt might
5599 not have enough args. Handle this case by leaving the
5600 rest of the params as uninitialized. */
5601 if (idx
>= arg_svals
->length ())
5603 tree parm_lval
= iter_parm
;
5604 if (tree parm_default_ssa
= ssa_default_def (fun
, iter_parm
))
5605 parm_lval
= parm_default_ssa
;
5606 const region
*parm_reg
= get_lvalue (parm_lval
, ctxt
);
5607 const svalue
*arg_sval
= (*arg_svals
)[idx
];
5608 set_value (parm_reg
, arg_sval
, ctxt
);
5611 /* Handle any variadic args. */
5612 unsigned va_arg_idx
= 0;
5613 for (; idx
< arg_svals
->length (); idx
++, va_arg_idx
++)
5615 const svalue
*arg_sval
= (*arg_svals
)[idx
];
5616 const region
*var_arg_reg
5617 = m_mgr
->get_var_arg_region (m_current_frame
,
5619 set_value (var_arg_reg
, arg_sval
, ctxt
);
5624 /* Otherwise we have a top-level call within the analysis. The params
5625 have defined but unknown initial values.
5626 Anything they point to has escaped. */
5627 tree fndecl
= fun
->decl
;
5629 /* Handle "__attribute__((nonnull))". */
5630 tree fntype
= TREE_TYPE (fndecl
);
5631 bitmap nonnull_args
= get_nonnull_args (fntype
);
5633 unsigned parm_idx
= 0;
5634 for (tree iter_parm
= DECL_ARGUMENTS (fndecl
); iter_parm
;
5635 iter_parm
= DECL_CHAIN (iter_parm
))
5637 bool non_null
= (nonnull_args
5638 ? (bitmap_empty_p (nonnull_args
)
5639 || bitmap_bit_p (nonnull_args
, parm_idx
))
5641 if (tree parm_default_ssa
= ssa_default_def (fun
, iter_parm
))
5642 on_top_level_param (parm_default_ssa
, non_null
, ctxt
);
5644 on_top_level_param (iter_parm
, non_null
, ctxt
);
5648 BITMAP_FREE (nonnull_args
);
5651 return m_current_frame
;
5654 /* Get the function of the top-most frame in this region_model's stack.
5655 There must be such a frame. */
5658 region_model::get_current_function () const
5660 const frame_region
*frame
= get_current_frame ();
5662 return frame
->get_function ();
5665 /* Pop the topmost frame_region from this region_model's stack;
5667 If RESULT_LVALUE is non-null, copy any return value from the frame
5668 into the corresponding region (evaluated with respect to the *caller*
5669 frame, rather than the called frame).
5670 If OUT_RESULT is non-null, copy any return value from the frame
5673 If EVAL_RETURN_SVALUE is false, then don't evaluate the return value.
5674 This is for use when unwinding frames e.g. due to longjmp, to suppress
5675 erroneously reporting uninitialized return values.
5677 Purge the frame region and all its descendent regions.
5678 Convert any pointers that point into such regions into
5679 POISON_KIND_POPPED_STACK svalues. */
5682 region_model::pop_frame (tree result_lvalue
,
5683 const svalue
**out_result
,
5684 region_model_context
*ctxt
,
5685 bool eval_return_svalue
)
5687 gcc_assert (m_current_frame
);
5689 const region_model pre_popped_model
= *this;
5690 const frame_region
*frame_reg
= m_current_frame
;
5692 /* Notify state machines. */
5694 ctxt
->on_pop_frame (frame_reg
);
5696 /* Evaluate the result, within the callee frame. */
5697 tree fndecl
= m_current_frame
->get_function ()->decl
;
5698 tree result
= DECL_RESULT (fndecl
);
5699 const svalue
*retval
= NULL
;
5701 && TREE_TYPE (result
) != void_type_node
5702 && eval_return_svalue
)
5704 retval
= get_rvalue (result
, ctxt
);
5706 *out_result
= retval
;
5709 /* Pop the frame. */
5710 m_current_frame
= m_current_frame
->get_calling_frame ();
5712 if (result_lvalue
&& retval
)
5714 gcc_assert (eval_return_svalue
);
5716 /* Compute result_dst_reg using RESULT_LVALUE *after* popping
5717 the frame, but before poisoning pointers into the old frame. */
5718 const region
*result_dst_reg
= get_lvalue (result_lvalue
, ctxt
);
5719 set_value (result_dst_reg
, retval
, ctxt
);
5722 unbind_region_and_descendents (frame_reg
,POISON_KIND_POPPED_STACK
);
5723 notify_on_pop_frame (this, &pre_popped_model
, retval
, ctxt
);
5726 /* Get the number of frames in this region_model's stack. */
5729 region_model::get_stack_depth () const
5731 const frame_region
*frame
= get_current_frame ();
5733 return frame
->get_stack_depth ();
5738 /* Get the frame_region with the given index within the stack.
5739 The frame_region must exist. */
5741 const frame_region
*
5742 region_model::get_frame_at_index (int index
) const
5744 const frame_region
*frame
= get_current_frame ();
5746 gcc_assert (index
>= 0);
5747 gcc_assert (index
<= frame
->get_index ());
5748 while (index
!= frame
->get_index ())
5750 frame
= frame
->get_calling_frame ();
5756 /* Unbind svalues for any regions in REG and below.
5757 Find any pointers to such regions; convert them to
5758 poisoned values of kind PKIND.
5759 Also purge any dynamic extents. */
5762 region_model::unbind_region_and_descendents (const region
*reg
,
5763 enum poison_kind pkind
)
5765 /* Gather a set of base regions to be unbound. */
5766 hash_set
<const region
*> base_regs
;
5767 for (store::cluster_map_t::iterator iter
= m_store
.begin ();
5768 iter
!= m_store
.end (); ++iter
)
5770 const region
*iter_base_reg
= (*iter
).first
;
5771 if (iter_base_reg
->descendent_of_p (reg
))
5772 base_regs
.add (iter_base_reg
);
5774 for (hash_set
<const region
*>::iterator iter
= base_regs
.begin ();
5775 iter
!= base_regs
.end (); ++iter
)
5776 m_store
.purge_cluster (*iter
);
5778 /* Find any pointers to REG or its descendents; convert to poisoned. */
5779 poison_any_pointers_to_descendents (reg
, pkind
);
5781 /* Purge dynamic extents of any base regions in REG and below
5782 (e.g. VLAs and alloca stack regions). */
5783 for (auto iter
: m_dynamic_extents
)
5785 const region
*iter_reg
= iter
.first
;
5786 if (iter_reg
->descendent_of_p (reg
))
5787 unset_dynamic_extents (iter_reg
);
5791 /* Implementation of BindingVisitor.
5792 Update the bound svalues for regions below REG to use poisoned
5795 struct bad_pointer_finder
5797 bad_pointer_finder (const region
*reg
, enum poison_kind pkind
,
5798 region_model_manager
*mgr
)
5799 : m_reg (reg
), m_pkind (pkind
), m_mgr (mgr
), m_count (0)
5802 void on_binding (const binding_key
*, const svalue
*&sval
)
5804 if (const region_svalue
*ptr_sval
= sval
->dyn_cast_region_svalue ())
5806 const region
*ptr_dst
= ptr_sval
->get_pointee ();
5807 /* Poison ptrs to descendents of REG, but not to REG itself,
5808 otherwise double-free detection doesn't work (since sm-state
5809 for "free" is stored on the original ptr svalue). */
5810 if (ptr_dst
->descendent_of_p (m_reg
)
5811 && ptr_dst
!= m_reg
)
5813 sval
= m_mgr
->get_or_create_poisoned_svalue (m_pkind
,
5820 const region
*m_reg
;
5821 enum poison_kind m_pkind
;
5822 region_model_manager
*const m_mgr
;
5826 /* Find any pointers to REG or its descendents; convert them to
5827 poisoned values of kind PKIND.
5828 Return the number of pointers that were poisoned. */
5831 region_model::poison_any_pointers_to_descendents (const region
*reg
,
5832 enum poison_kind pkind
)
5834 bad_pointer_finder
bv (reg
, pkind
, m_mgr
);
5835 m_store
.for_each_binding (bv
);
5839 /* Attempt to merge THIS with OTHER_MODEL, writing the result
5840 to OUT_MODEL. Use POINT to distinguish values created as a
5841 result of merging. */
5844 region_model::can_merge_with_p (const region_model
&other_model
,
5845 const program_point
&point
,
5846 region_model
*out_model
,
5847 const extrinsic_state
*ext_state
,
5848 const program_state
*state_a
,
5849 const program_state
*state_b
) const
5851 gcc_assert (out_model
);
5852 gcc_assert (m_mgr
== other_model
.m_mgr
);
5853 gcc_assert (m_mgr
== out_model
->m_mgr
);
5855 if (m_current_frame
!= other_model
.m_current_frame
)
5857 out_model
->m_current_frame
= m_current_frame
;
5859 model_merger
m (this, &other_model
, point
, out_model
,
5860 ext_state
, state_a
, state_b
);
5862 if (!store::can_merge_p (&m_store
, &other_model
.m_store
,
5863 &out_model
->m_store
, m_mgr
->get_store_manager (),
5867 if (!m_dynamic_extents
.can_merge_with_p (other_model
.m_dynamic_extents
,
5868 &out_model
->m_dynamic_extents
))
5871 /* Merge constraints. */
5872 constraint_manager::merge (*m_constraints
,
5873 *other_model
.m_constraints
,
5874 out_model
->m_constraints
);
5876 for (auto iter
: m
.m_svals_changing_meaning
)
5877 out_model
->m_constraints
->purge_state_involving (iter
);
5882 /* Attempt to get the fndecl used at CALL, if known, or NULL_TREE
5886 region_model::get_fndecl_for_call (const gcall
*call
,
5887 region_model_context
*ctxt
)
5889 tree fn_ptr
= gimple_call_fn (call
);
5890 if (fn_ptr
== NULL_TREE
)
5892 const svalue
*fn_ptr_sval
= get_rvalue (fn_ptr
, ctxt
);
5893 if (const region_svalue
*fn_ptr_ptr
5894 = fn_ptr_sval
->dyn_cast_region_svalue ())
5896 const region
*reg
= fn_ptr_ptr
->get_pointee ();
5897 if (const function_region
*fn_reg
= reg
->dyn_cast_function_region ())
5899 tree fn_decl
= fn_reg
->get_fndecl ();
5900 cgraph_node
*node
= cgraph_node::get (fn_decl
);
5903 const cgraph_node
*ultimate_node
= node
->ultimate_alias_target ();
5905 return ultimate_node
->decl
;
5912 /* Would be much simpler to use a lambda here, if it were supported. */
5914 struct append_regions_cb_data
5916 const region_model
*model
;
5917 auto_vec
<const decl_region
*> *out
;
5920 /* Populate *OUT with all decl_regions in the current
5921 frame that have clusters within the store. */
5925 get_regions_for_current_frame (auto_vec
<const decl_region
*> *out
) const
5927 append_regions_cb_data data
;
5930 m_store
.for_each_cluster (append_regions_cb
, &data
);
5933 /* Implementation detail of get_regions_for_current_frame. */
5936 region_model::append_regions_cb (const region
*base_reg
,
5937 append_regions_cb_data
*cb_data
)
5939 if (base_reg
->get_parent_region () != cb_data
->model
->m_current_frame
)
5941 if (const decl_region
*decl_reg
= base_reg
->dyn_cast_decl_region ())
5942 cb_data
->out
->safe_push (decl_reg
);
5946 /* Abstract class for diagnostics related to the use of
5947 floating-point arithmetic where precision is needed. */
5949 class imprecise_floating_point_arithmetic
: public pending_diagnostic
5952 int get_controlling_option () const final override
5954 return OPT_Wanalyzer_imprecise_fp_arithmetic
;
5958 /* Concrete diagnostic to complain about uses of floating-point arithmetic
5959 in the size argument of malloc etc. */
5961 class float_as_size_arg
: public imprecise_floating_point_arithmetic
5964 float_as_size_arg (tree arg
) : m_arg (arg
)
5967 const char *get_kind () const final override
5969 return "float_as_size_arg_diagnostic";
5972 bool subclass_equal_p (const pending_diagnostic
&other
) const final override
5974 return same_tree_p (m_arg
, ((const float_as_size_arg
&) other
).m_arg
);
5977 bool emit (diagnostic_emission_context
&ctxt
) final override
5979 bool warned
= ctxt
.warn ("use of floating-point arithmetic here might"
5980 " yield unexpected results");
5982 inform (ctxt
.get_location (),
5983 "only use operands of an integer type"
5984 " inside the size argument");
5988 label_text
describe_final_event (const evdesc::final_event
&ev
) final
5992 return ev
.formatted_print ("operand %qE is of type %qT",
5993 m_arg
, TREE_TYPE (m_arg
));
5994 return ev
.formatted_print ("at least one operand of the size argument is"
5995 " of a floating-point type");
6002 /* Visitor to find uses of floating-point variables/constants in an svalue. */
6004 class contains_floating_point_visitor
: public visitor
6007 contains_floating_point_visitor (const svalue
*root_sval
) : m_result (NULL
)
6009 root_sval
->accept (this);
6012 const svalue
*get_svalue_to_report ()
6017 void visit_constant_svalue (const constant_svalue
*sval
) final override
6019 /* At the point the analyzer runs, constant integer operands in a floating
6020 point expression are already implictly converted to floating-points.
6021 Thus, we do prefer to report non-constants such that the diagnostic
6022 always reports a floating-point operand. */
6023 tree type
= sval
->get_type ();
6024 if (type
&& FLOAT_TYPE_P (type
) && !m_result
)
6028 void visit_conjured_svalue (const conjured_svalue
*sval
) final override
6030 tree type
= sval
->get_type ();
6031 if (type
&& FLOAT_TYPE_P (type
))
6035 void visit_initial_svalue (const initial_svalue
*sval
) final override
6037 tree type
= sval
->get_type ();
6038 if (type
&& FLOAT_TYPE_P (type
))
6043 /* Non-null if at least one floating-point operand was found. */
6044 const svalue
*m_result
;
6047 /* May complain about uses of floating-point operands in SIZE_IN_BYTES. */
6050 region_model::check_dynamic_size_for_floats (const svalue
*size_in_bytes
,
6051 region_model_context
*ctxt
) const
6055 contains_floating_point_visitor
v (size_in_bytes
);
6056 if (const svalue
*float_sval
= v
.get_svalue_to_report ())
6058 tree diag_arg
= get_representative_tree (float_sval
);
6059 ctxt
->warn (make_unique
<float_as_size_arg
> (diag_arg
));
6063 /* Return a region describing a heap-allocated block of memory.
6064 Use CTXT to complain about tainted sizes.
6066 Reuse an existing heap_allocated_region if it's not being referenced by
6067 this region_model; otherwise create a new one.
6069 Optionally (update_state_machine) transitions the pointer pointing to the
6070 heap_allocated_region from start to assumed non-null. */
6073 region_model::get_or_create_region_for_heap_alloc (const svalue
*size_in_bytes
,
6074 region_model_context
*ctxt
,
6075 bool update_state_machine
,
6076 const call_details
*cd
)
6078 /* Determine which regions are referenced in this region_model, so that
6079 we can reuse an existing heap_allocated_region if it's not in use on
6081 auto_bitmap base_regs_in_use
;
6082 get_referenced_base_regions (base_regs_in_use
);
6084 /* Don't reuse regions that are marked as TOUCHED. */
6085 for (store::cluster_map_t::iterator iter
= m_store
.begin ();
6086 iter
!= m_store
.end (); ++iter
)
6087 if ((*iter
).second
->touched_p ())
6089 const region
*base_reg
= (*iter
).first
;
6090 bitmap_set_bit (base_regs_in_use
, base_reg
->get_id ());
6094 = m_mgr
->get_or_create_region_for_heap_alloc (base_regs_in_use
);
6096 if (compat_types_p (size_in_bytes
->get_type (), size_type_node
))
6097 set_dynamic_extents (reg
, size_in_bytes
, ctxt
);
6099 if (update_state_machine
&& cd
)
6101 const svalue
*ptr_sval
6102 = m_mgr
->get_ptr_svalue (cd
->get_lhs_type (), reg
);
6103 transition_ptr_sval_non_null (ctxt
, ptr_sval
);
6109 /* Populate OUT_IDS with the set of IDs of those base regions which are
6110 reachable in this region_model. */
6113 region_model::get_referenced_base_regions (auto_bitmap
&out_ids
) const
6115 reachable_regions
reachable_regs (const_cast<region_model
*> (this));
6116 m_store
.for_each_cluster (reachable_regions::init_cluster_cb
,
6118 /* Get regions for locals that have explicitly bound values. */
6119 for (store::cluster_map_t::iterator iter
= m_store
.begin ();
6120 iter
!= m_store
.end (); ++iter
)
6122 const region
*base_reg
= (*iter
).first
;
6123 if (const region
*parent
= base_reg
->get_parent_region ())
6124 if (parent
->get_kind () == RK_FRAME
)
6125 reachable_regs
.add (base_reg
, false);
6128 bitmap_clear (out_ids
);
6129 for (auto iter_reg
: reachable_regs
)
6130 bitmap_set_bit (out_ids
, iter_reg
->get_id ());
6133 /* Return a new region describing a block of memory allocated within the
6135 Use CTXT to complain about tainted sizes. */
6138 region_model::create_region_for_alloca (const svalue
*size_in_bytes
,
6139 region_model_context
*ctxt
)
6141 const region
*reg
= m_mgr
->create_region_for_alloca (m_current_frame
);
6142 if (compat_types_p (size_in_bytes
->get_type (), size_type_node
))
6143 set_dynamic_extents (reg
, size_in_bytes
, ctxt
);
6147 /* Record that the size of REG is SIZE_IN_BYTES.
6148 Use CTXT to complain about tainted sizes. */
6151 region_model::set_dynamic_extents (const region
*reg
,
6152 const svalue
*size_in_bytes
,
6153 region_model_context
*ctxt
)
6155 assert_compat_types (size_in_bytes
->get_type (), size_type_node
);
6158 check_dynamic_size_for_taint (reg
->get_memory_space (), size_in_bytes
,
6160 check_dynamic_size_for_floats (size_in_bytes
, ctxt
);
6162 m_dynamic_extents
.put (reg
, size_in_bytes
);
6165 /* Get the recording of REG in bytes, or NULL if no dynamic size was
6169 region_model::get_dynamic_extents (const region
*reg
) const
6171 if (const svalue
* const *slot
= m_dynamic_extents
.get (reg
))
6176 /* Unset any recorded dynamic size of REG. */
6179 region_model::unset_dynamic_extents (const region
*reg
)
6181 m_dynamic_extents
.remove (reg
);
6184 /* A subclass of pending_diagnostic for complaining about uninitialized data
6185 being copied across a trust boundary to an untrusted output
6186 (e.g. copy_to_user infoleaks in the Linux kernel). */
6188 class exposure_through_uninit_copy
6189 : public pending_diagnostic_subclass
<exposure_through_uninit_copy
>
6192 exposure_through_uninit_copy (const region
*src_region
,
6193 const region
*dest_region
,
6194 const svalue
*copied_sval
)
6195 : m_src_region (src_region
),
6196 m_dest_region (dest_region
),
6197 m_copied_sval (copied_sval
)
6199 gcc_assert (m_copied_sval
->get_kind () == SK_POISONED
6200 || m_copied_sval
->get_kind () == SK_COMPOUND
);
6203 const char *get_kind () const final override
6205 return "exposure_through_uninit_copy";
6208 bool operator== (const exposure_through_uninit_copy
&other
) const
6210 return (m_src_region
== other
.m_src_region
6211 && m_dest_region
== other
.m_dest_region
6212 && m_copied_sval
== other
.m_copied_sval
);
6215 int get_controlling_option () const final override
6217 return OPT_Wanalyzer_exposure_through_uninit_copy
;
6220 bool emit (diagnostic_emission_context
&ctxt
) final override
6222 /* CWE-200: Exposure of Sensitive Information to an Unauthorized Actor. */
6224 enum memory_space mem_space
= get_src_memory_space ();
6229 warned
= ctxt
.warn ("potential exposure of sensitive information"
6230 " by copying uninitialized data"
6231 " across trust boundary");
6233 case MEMSPACE_STACK
:
6234 warned
= ctxt
.warn ("potential exposure of sensitive information"
6235 " by copying uninitialized data from stack"
6236 " across trust boundary");
6239 warned
= ctxt
.warn ("potential exposure of sensitive information"
6240 " by copying uninitialized data from heap"
6241 " across trust boundary");
6246 const location_t loc
= ctxt
.get_location ();
6247 inform_number_of_uninit_bits (loc
);
6248 complain_about_uninit_ranges (loc
);
6250 if (mem_space
== MEMSPACE_STACK
)
6251 maybe_emit_fixit_hint ();
6256 label_text
describe_final_event (const evdesc::final_event
&) final override
6258 enum memory_space mem_space
= get_src_memory_space ();
6262 return label_text::borrow ("uninitialized data copied here");
6264 case MEMSPACE_STACK
:
6265 return label_text::borrow ("uninitialized data copied from stack here");
6268 return label_text::borrow ("uninitialized data copied from heap here");
6272 void mark_interesting_stuff (interesting_t
*interest
) final override
6275 interest
->add_region_creation (m_src_region
);
6279 maybe_add_sarif_properties (sarif_object
&result_obj
) const final override
6281 sarif_property_bag
&props
= result_obj
.get_or_create_properties ();
6282 #define PROPERTY_PREFIX "gcc/-Wanalyzer-exposure-through-uninit-copy/"
6283 props
.set (PROPERTY_PREFIX
"src_region", m_src_region
->to_json ());
6284 props
.set (PROPERTY_PREFIX
"dest_region", m_dest_region
->to_json ());
6285 props
.set (PROPERTY_PREFIX
"copied_sval", m_copied_sval
->to_json ());
6286 #undef PROPERTY_PREFIX
6290 enum memory_space
get_src_memory_space () const
6292 return m_src_region
? m_src_region
->get_memory_space () : MEMSPACE_UNKNOWN
;
6295 bit_size_t
calc_num_uninit_bits () const
6297 switch (m_copied_sval
->get_kind ())
6304 const poisoned_svalue
*poisoned_sval
6305 = as_a
<const poisoned_svalue
*> (m_copied_sval
);
6306 gcc_assert (poisoned_sval
->get_poison_kind () == POISON_KIND_UNINIT
);
6308 /* Give up if don't have type information. */
6309 if (m_copied_sval
->get_type () == NULL_TREE
)
6312 bit_size_t size_in_bits
;
6313 if (int_size_in_bits (m_copied_sval
->get_type (), &size_in_bits
))
6314 return size_in_bits
;
6316 /* Give up if we can't get the size of the type. */
6322 const compound_svalue
*compound_sval
6323 = as_a
<const compound_svalue
*> (m_copied_sval
);
6324 bit_size_t result
= 0;
6325 /* Find keys for uninit svals. */
6326 for (auto iter
: *compound_sval
)
6328 const svalue
*sval
= iter
.second
;
6329 if (const poisoned_svalue
*psval
6330 = sval
->dyn_cast_poisoned_svalue ())
6331 if (psval
->get_poison_kind () == POISON_KIND_UNINIT
)
6333 const binding_key
*key
= iter
.first
;
6334 const concrete_binding
*ckey
6335 = key
->dyn_cast_concrete_binding ();
6337 result
+= ckey
->get_size_in_bits ();
6345 void inform_number_of_uninit_bits (location_t loc
) const
6347 bit_size_t num_uninit_bits
= calc_num_uninit_bits ();
6348 if (num_uninit_bits
<= 0)
6350 if (num_uninit_bits
% BITS_PER_UNIT
== 0)
6352 /* Express in bytes. */
6353 byte_size_t num_uninit_bytes
= num_uninit_bits
/ BITS_PER_UNIT
;
6354 if (num_uninit_bytes
== 1)
6355 inform (loc
, "1 byte is uninitialized");
6358 "%wu bytes are uninitialized", num_uninit_bytes
.to_uhwi ());
6362 /* Express in bits. */
6363 if (num_uninit_bits
== 1)
6364 inform (loc
, "1 bit is uninitialized");
6367 "%wu bits are uninitialized", num_uninit_bits
.to_uhwi ());
6371 void complain_about_uninit_ranges (location_t loc
) const
6373 if (const compound_svalue
*compound_sval
6374 = m_copied_sval
->dyn_cast_compound_svalue ())
6376 /* Find keys for uninit svals. */
6377 auto_vec
<const concrete_binding
*> uninit_keys
;
6378 for (auto iter
: *compound_sval
)
6380 const svalue
*sval
= iter
.second
;
6381 if (const poisoned_svalue
*psval
6382 = sval
->dyn_cast_poisoned_svalue ())
6383 if (psval
->get_poison_kind () == POISON_KIND_UNINIT
)
6385 const binding_key
*key
= iter
.first
;
6386 const concrete_binding
*ckey
6387 = key
->dyn_cast_concrete_binding ();
6389 uninit_keys
.safe_push (ckey
);
6392 /* Complain about them in sorted order. */
6393 uninit_keys
.qsort (concrete_binding::cmp_ptr_ptr
);
6395 std::unique_ptr
<record_layout
> layout
;
6397 tree type
= m_copied_sval
->get_type ();
6398 if (type
&& TREE_CODE (type
) == RECORD_TYPE
)
6400 // (std::make_unique is C++14)
6401 layout
= std::unique_ptr
<record_layout
> (new record_layout (type
));
6408 const concrete_binding
*ckey
;
6409 FOR_EACH_VEC_ELT (uninit_keys
, i
, ckey
)
6411 bit_offset_t start_bit
= ckey
->get_start_bit_offset ();
6412 bit_offset_t next_bit
= ckey
->get_next_bit_offset ();
6413 complain_about_uninit_range (loc
, start_bit
, next_bit
,
6419 void complain_about_uninit_range (location_t loc
,
6420 bit_offset_t start_bit
,
6421 bit_offset_t next_bit
,
6422 const record_layout
*layout
) const
6426 while (start_bit
< next_bit
)
6428 if (const record_layout::item
*item
6429 = layout
->get_item_at (start_bit
))
6431 gcc_assert (start_bit
>= item
->get_start_bit_offset ());
6432 gcc_assert (start_bit
< item
->get_next_bit_offset ());
6433 if (item
->get_start_bit_offset () == start_bit
6434 && item
->get_next_bit_offset () <= next_bit
)
6435 complain_about_fully_uninit_item (*item
);
6437 complain_about_partially_uninit_item (*item
);
6438 start_bit
= item
->get_next_bit_offset ();
6446 if (start_bit
>= next_bit
)
6449 if (start_bit
% 8 == 0 && next_bit
% 8 == 0)
6451 /* Express in bytes. */
6452 byte_offset_t start_byte
= start_bit
/ 8;
6453 byte_offset_t last_byte
= (next_bit
/ 8) - 1;
6454 if (last_byte
== start_byte
)
6456 "byte %wu is uninitialized",
6457 start_byte
.to_uhwi ());
6460 "bytes %wu - %wu are uninitialized",
6461 start_byte
.to_uhwi (),
6462 last_byte
.to_uhwi ());
6466 /* Express in bits. */
6467 bit_offset_t last_bit
= next_bit
- 1;
6468 if (last_bit
== start_bit
)
6470 "bit %wu is uninitialized",
6471 start_bit
.to_uhwi ());
6474 "bits %wu - %wu are uninitialized",
6475 start_bit
.to_uhwi (),
6476 last_bit
.to_uhwi ());
6481 complain_about_fully_uninit_item (const record_layout::item
&item
)
6483 tree field
= item
.m_field
;
6484 bit_size_t num_bits
= item
.m_bit_range
.m_size_in_bits
;
6485 if (item
.m_is_padding
)
6487 if (num_bits
% 8 == 0)
6489 /* Express in bytes. */
6490 byte_size_t num_bytes
= num_bits
/ BITS_PER_UNIT
;
6492 inform (DECL_SOURCE_LOCATION (field
),
6493 "padding after field %qD is uninitialized (1 byte)",
6496 inform (DECL_SOURCE_LOCATION (field
),
6497 "padding after field %qD is uninitialized (%wu bytes)",
6498 field
, num_bytes
.to_uhwi ());
6502 /* Express in bits. */
6504 inform (DECL_SOURCE_LOCATION (field
),
6505 "padding after field %qD is uninitialized (1 bit)",
6508 inform (DECL_SOURCE_LOCATION (field
),
6509 "padding after field %qD is uninitialized (%wu bits)",
6510 field
, num_bits
.to_uhwi ());
6515 if (num_bits
% 8 == 0)
6517 /* Express in bytes. */
6518 byte_size_t num_bytes
= num_bits
/ BITS_PER_UNIT
;
6520 inform (DECL_SOURCE_LOCATION (field
),
6521 "field %qD is uninitialized (1 byte)", field
);
6523 inform (DECL_SOURCE_LOCATION (field
),
6524 "field %qD is uninitialized (%wu bytes)",
6525 field
, num_bytes
.to_uhwi ());
6529 /* Express in bits. */
6531 inform (DECL_SOURCE_LOCATION (field
),
6532 "field %qD is uninitialized (1 bit)", field
);
6534 inform (DECL_SOURCE_LOCATION (field
),
6535 "field %qD is uninitialized (%wu bits)",
6536 field
, num_bits
.to_uhwi ());
6542 complain_about_partially_uninit_item (const record_layout::item
&item
)
6544 tree field
= item
.m_field
;
6545 if (item
.m_is_padding
)
6546 inform (DECL_SOURCE_LOCATION (field
),
6547 "padding after field %qD is partially uninitialized",
6550 inform (DECL_SOURCE_LOCATION (field
),
6551 "field %qD is partially uninitialized",
6553 /* TODO: ideally we'd describe what parts are uninitialized. */
6556 void maybe_emit_fixit_hint () const
6558 if (tree decl
= m_src_region
->maybe_get_decl ())
6560 gcc_rich_location
hint_richloc (DECL_SOURCE_LOCATION (decl
));
6561 hint_richloc
.add_fixit_insert_after (" = {0}");
6562 inform (&hint_richloc
,
6563 "suggest forcing zero-initialization by"
6564 " providing a %<{0}%> initializer");
6569 const region
*m_src_region
;
6570 const region
*m_dest_region
;
6571 const svalue
*m_copied_sval
;
6574 /* Return true if any part of SVAL is uninitialized. */
6577 contains_uninit_p (const svalue
*sval
)
6579 struct uninit_finder
: public visitor
6582 uninit_finder () : m_found_uninit (false) {}
6583 void visit_poisoned_svalue (const poisoned_svalue
*sval
)
6585 if (sval
->get_poison_kind () == POISON_KIND_UNINIT
)
6586 m_found_uninit
= true;
6588 bool m_found_uninit
;
6594 return v
.m_found_uninit
;
6597 /* Function for use by plugins when simulating writing data through a
6598 pointer to an "untrusted" region DST_REG (and thus crossing a security
6599 boundary), such as copying data to user space in an OS kernel.
6601 Check that COPIED_SVAL is fully initialized. If not, complain about
6602 an infoleak to CTXT.
6604 SRC_REG can be NULL; if non-NULL it is used as a hint in the diagnostic
6605 as to where COPIED_SVAL came from. */
6608 region_model::maybe_complain_about_infoleak (const region
*dst_reg
,
6609 const svalue
*copied_sval
,
6610 const region
*src_reg
,
6611 region_model_context
*ctxt
)
6613 /* Check for exposure. */
6614 if (contains_uninit_p (copied_sval
))
6615 ctxt
->warn (make_unique
<exposure_through_uninit_copy
> (src_reg
,
6620 /* Set errno to a positive symbolic int, as if some error has occurred. */
6623 region_model::set_errno (const call_details
&cd
)
6625 const region
*errno_reg
= m_mgr
->get_errno_region ();
6626 conjured_purge
p (this, cd
.get_ctxt ());
6627 const svalue
*new_errno_sval
6628 = m_mgr
->get_or_create_conjured_svalue (integer_type_node
,
6629 cd
.get_call_stmt (),
6632 = m_mgr
->get_or_create_int_cst (integer_type_node
, 0);
6633 add_constraint (new_errno_sval
, GT_EXPR
, zero
, cd
.get_ctxt ());
6634 set_value (errno_reg
, new_errno_sval
, cd
.get_ctxt ());
6637 /* class noop_region_model_context : public region_model_context. */
6640 noop_region_model_context::add_note (std::unique_ptr
<pending_note
>)
6645 noop_region_model_context::add_event (std::unique_ptr
<checker_event
>)
6650 noop_region_model_context::bifurcate (std::unique_ptr
<custom_edge_info
>)
6655 noop_region_model_context::terminate_path ()
6659 /* class region_model_context_decorator : public region_model_context. */
6662 region_model_context_decorator::add_event (std::unique_ptr
<checker_event
> event
)
6665 m_inner
->add_event (std::move (event
));
6668 /* struct model_merger. */
6670 /* Dump a multiline representation of this merger to PP. */
6673 model_merger::dump_to_pp (pretty_printer
*pp
, bool simple
) const
6675 pp_string (pp
, "model A:");
6677 m_model_a
->dump_to_pp (pp
, simple
, true);
6680 pp_string (pp
, "model B:");
6682 m_model_b
->dump_to_pp (pp
, simple
, true);
6685 pp_string (pp
, "merged model:");
6687 m_merged_model
->dump_to_pp (pp
, simple
, true);
6691 /* Dump a multiline representation of this merger to FILE. */
6694 model_merger::dump (FILE *fp
, bool simple
) const
6697 pp_format_decoder (&pp
) = default_tree_printer
;
6698 pp_show_color (&pp
) = pp_show_color (global_dc
->printer
);
6699 pp
.buffer
->stream
= fp
;
6700 dump_to_pp (&pp
, simple
);
6704 /* Dump a multiline representation of this merger to stderr. */
6707 model_merger::dump (bool simple
) const
6709 dump (stderr
, simple
);
6712 /* Return true if it's OK to merge SVAL with other svalues. */
6715 model_merger::mergeable_svalue_p (const svalue
*sval
) const
6719 /* Reject merging svalues that have non-purgable sm-state,
6720 to avoid falsely reporting memory leaks by merging them
6721 with something else. For example, given a local var "p",
6722 reject the merger of a:
6723 store_a mapping "p" to a malloc-ed ptr
6725 store_b mapping "p" to a NULL ptr. */
6727 if (!m_state_a
->can_purge_p (*m_ext_state
, sval
))
6730 if (!m_state_b
->can_purge_p (*m_ext_state
, sval
))
6736 /* Mark WIDENING_SVAL as changing meaning during the merge. */
6739 model_merger::on_widening_reuse (const widening_svalue
*widening_sval
)
6741 m_svals_changing_meaning
.add (widening_sval
);
6746 /* Dump RMODEL fully to stderr (i.e. without summarization). */
6749 debug (const region_model
&rmodel
)
6751 rmodel
.dump (false);
6754 /* class rejected_op_constraint : public rejected_constraint. */
6757 rejected_op_constraint::dump_to_pp (pretty_printer
*pp
) const
6759 region_model
m (m_model
);
6760 const svalue
*lhs_sval
= m
.get_rvalue (m_lhs
, NULL
);
6761 const svalue
*rhs_sval
= m
.get_rvalue (m_rhs
, NULL
);
6762 lhs_sval
->dump_to_pp (pp
, true);
6763 pp_printf (pp
, " %s ", op_symbol_code (m_op
));
6764 rhs_sval
->dump_to_pp (pp
, true);
6767 /* class rejected_default_case : public rejected_constraint. */
6770 rejected_default_case::dump_to_pp (pretty_printer
*pp
) const
6772 pp_string (pp
, "implicit default for enum");
6775 /* class rejected_ranges_constraint : public rejected_constraint. */
6778 rejected_ranges_constraint::dump_to_pp (pretty_printer
*pp
) const
6780 region_model
m (m_model
);
6781 const svalue
*sval
= m
.get_rvalue (m_expr
, NULL
);
6782 sval
->dump_to_pp (pp
, true);
6783 pp_string (pp
, " in ");
6784 m_ranges
->dump_to_pp (pp
, true);
6789 /* engine's ctor. */
6791 engine::engine (const supergraph
*sg
, logger
*logger
)
6792 : m_sg (sg
), m_mgr (logger
)
6796 /* Dump the managed objects by class to LOGGER, and the per-class totals. */
6799 engine::log_stats (logger
*logger
) const
6801 m_mgr
.log_stats (logger
, true);
6808 namespace selftest
{
6810 /* Build a constant tree of the given type from STR. */
6813 build_real_cst_from_string (tree type
, const char *str
)
6815 REAL_VALUE_TYPE real
;
6816 real_from_string (&real
, str
);
6817 return build_real (type
, real
);
6820 /* Append various "interesting" constants to OUT (e.g. NaN). */
6823 append_interesting_constants (auto_vec
<tree
> *out
)
6825 out
->safe_push (build_int_cst (integer_type_node
, 0));
6826 out
->safe_push (build_int_cst (integer_type_node
, 42));
6827 out
->safe_push (build_int_cst (unsigned_type_node
, 0));
6828 out
->safe_push (build_int_cst (unsigned_type_node
, 42));
6829 out
->safe_push (build_real_cst_from_string (float_type_node
, "QNaN"));
6830 out
->safe_push (build_real_cst_from_string (float_type_node
, "-QNaN"));
6831 out
->safe_push (build_real_cst_from_string (float_type_node
, "SNaN"));
6832 out
->safe_push (build_real_cst_from_string (float_type_node
, "-SNaN"));
6833 out
->safe_push (build_real_cst_from_string (float_type_node
, "0.0"));
6834 out
->safe_push (build_real_cst_from_string (float_type_node
, "-0.0"));
6835 out
->safe_push (build_real_cst_from_string (float_type_node
, "Inf"));
6836 out
->safe_push (build_real_cst_from_string (float_type_node
, "-Inf"));
6839 /* Verify that tree_cmp is a well-behaved comparator for qsort, even
6840 if the underlying constants aren't comparable. */
6843 test_tree_cmp_on_constants ()
6845 auto_vec
<tree
> csts
;
6846 append_interesting_constants (&csts
);
6848 /* Try sorting every triple. */
6849 const unsigned num
= csts
.length ();
6850 for (unsigned i
= 0; i
< num
; i
++)
6851 for (unsigned j
= 0; j
< num
; j
++)
6852 for (unsigned k
= 0; k
< num
; k
++)
6854 auto_vec
<tree
> v (3);
6855 v
.quick_push (csts
[i
]);
6856 v
.quick_push (csts
[j
]);
6857 v
.quick_push (csts
[k
]);
6862 /* Implementation detail of the ASSERT_CONDITION_* macros. */
6865 assert_condition (const location
&loc
,
6866 region_model
&model
,
6867 const svalue
*lhs
, tree_code op
, const svalue
*rhs
,
6870 tristate actual
= model
.eval_condition (lhs
, op
, rhs
);
6871 ASSERT_EQ_AT (loc
, actual
, expected
);
6874 /* Implementation detail of the ASSERT_CONDITION_* macros. */
6877 assert_condition (const location
&loc
,
6878 region_model
&model
,
6879 tree lhs
, tree_code op
, tree rhs
,
6882 tristate actual
= model
.eval_condition (lhs
, op
, rhs
, NULL
);
6883 ASSERT_EQ_AT (loc
, actual
, expected
);
6886 /* Implementation detail of ASSERT_DUMP_TREE_EQ. */
6889 assert_dump_tree_eq (const location
&loc
, tree t
, const char *expected
)
6891 auto_fix_quotes sentinel
;
6893 pp_format_decoder (&pp
) = default_tree_printer
;
6895 ASSERT_STREQ_AT (loc
, pp_formatted_text (&pp
), expected
);
6898 /* Assert that dump_tree (T) is EXPECTED. */
6900 #define ASSERT_DUMP_TREE_EQ(T, EXPECTED) \
6901 SELFTEST_BEGIN_STMT \
6902 assert_dump_tree_eq ((SELFTEST_LOCATION), (T), (EXPECTED)); \
6905 /* Implementation detail of ASSERT_DUMP_EQ. */
6908 assert_dump_eq (const location
&loc
,
6909 const region_model
&model
,
6911 const char *expected
)
6913 auto_fix_quotes sentinel
;
6915 pp_format_decoder (&pp
) = default_tree_printer
;
6917 model
.dump_to_pp (&pp
, summarize
, true);
6918 ASSERT_STREQ_AT (loc
, pp_formatted_text (&pp
), expected
);
6921 /* Assert that MODEL.dump_to_pp (SUMMARIZE) is EXPECTED. */
6923 #define ASSERT_DUMP_EQ(MODEL, SUMMARIZE, EXPECTED) \
6924 SELFTEST_BEGIN_STMT \
6925 assert_dump_eq ((SELFTEST_LOCATION), (MODEL), (SUMMARIZE), (EXPECTED)); \
6928 /* Smoketest for region_model::dump_to_pp. */
6933 region_model_manager mgr
;
6934 region_model
model (&mgr
);
6936 ASSERT_DUMP_EQ (model
, false,
6938 "m_called_unknown_fn: FALSE\n"
6939 "constraint_manager:\n"
6942 ASSERT_DUMP_EQ (model
, true,
6944 "m_called_unknown_fn: FALSE\n"
6945 "constraint_manager:\n"
6950 /* Helper function for selftests. Create a struct or union type named NAME,
6951 with the fields given by the FIELD_DECLS in FIELDS.
6952 If IS_STRUCT is true create a RECORD_TYPE (aka a struct), otherwise
6953 create a UNION_TYPE. */
6956 make_test_compound_type (const char *name
, bool is_struct
,
6957 const auto_vec
<tree
> *fields
)
6959 tree t
= make_node (is_struct
? RECORD_TYPE
: UNION_TYPE
);
6960 TYPE_NAME (t
) = get_identifier (name
);
6963 tree fieldlist
= NULL
;
6966 FOR_EACH_VEC_ELT (*fields
, i
, field
)
6968 gcc_assert (TREE_CODE (field
) == FIELD_DECL
);
6969 DECL_CONTEXT (field
) = t
;
6970 fieldlist
= chainon (field
, fieldlist
);
6972 fieldlist
= nreverse (fieldlist
);
6973 TYPE_FIELDS (t
) = fieldlist
;
6979 /* Selftest fixture for creating the type "struct coord {int x; int y; };". */
6985 auto_vec
<tree
> fields
;
6986 m_x_field
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
6987 get_identifier ("x"), integer_type_node
);
6988 fields
.safe_push (m_x_field
);
6989 m_y_field
= build_decl (UNKNOWN_LOCATION
, FIELD_DECL
,
6990 get_identifier ("y"), integer_type_node
);
6991 fields
.safe_push (m_y_field
);
6992 m_coord_type
= make_test_compound_type ("coord", true, &fields
);
7000 /* Verify usage of a struct. */
7007 tree c
= build_global_decl ("c", ct
.m_coord_type
);
7008 tree c_x
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_x_field
),
7009 c
, ct
.m_x_field
, NULL_TREE
);
7010 tree c_y
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_y_field
),
7011 c
, ct
.m_y_field
, NULL_TREE
);
7013 tree int_17
= build_int_cst (integer_type_node
, 17);
7014 tree int_m3
= build_int_cst (integer_type_node
, -3);
7016 region_model_manager mgr
;
7017 region_model
model (&mgr
);
7018 model
.set_value (c_x
, int_17
, NULL
);
7019 model
.set_value (c_y
, int_m3
, NULL
);
7021 /* Verify get_offset for "c.x". */
7023 const region
*c_x_reg
= model
.get_lvalue (c_x
, NULL
);
7024 region_offset offset
= c_x_reg
->get_offset (&mgr
);
7025 ASSERT_EQ (offset
.get_base_region (), model
.get_lvalue (c
, NULL
));
7026 ASSERT_EQ (offset
.get_bit_offset (), 0);
7029 /* Verify get_offset for "c.y". */
7031 const region
*c_y_reg
= model
.get_lvalue (c_y
, NULL
);
7032 region_offset offset
= c_y_reg
->get_offset (&mgr
);
7033 ASSERT_EQ (offset
.get_base_region (), model
.get_lvalue (c
, NULL
));
7034 ASSERT_EQ (offset
.get_bit_offset (), INT_TYPE_SIZE
);
7038 /* Verify usage of an array element. */
7043 tree tlen
= size_int (10);
7044 tree arr_type
= build_array_type (char_type_node
, build_index_type (tlen
));
7046 tree a
= build_global_decl ("a", arr_type
);
7048 region_model_manager mgr
;
7049 region_model
model (&mgr
);
7050 tree int_0
= build_int_cst (integer_type_node
, 0);
7051 tree a_0
= build4 (ARRAY_REF
, char_type_node
,
7052 a
, int_0
, NULL_TREE
, NULL_TREE
);
7053 tree char_A
= build_int_cst (char_type_node
, 'A');
7054 model
.set_value (a_0
, char_A
, NULL
);
7057 /* Verify that region_model::get_representative_tree works as expected. */
7060 test_get_representative_tree ()
7062 region_model_manager mgr
;
7066 tree string_cst
= build_string (4, "foo");
7067 region_model
m (&mgr
);
7068 const svalue
*str_sval
= m
.get_rvalue (string_cst
, NULL
);
7069 tree rep
= m
.get_representative_tree (str_sval
);
7070 ASSERT_EQ (rep
, string_cst
);
7073 /* String literal. */
7075 tree string_cst_ptr
= build_string_literal (4, "foo");
7076 region_model
m (&mgr
);
7077 const svalue
*str_sval
= m
.get_rvalue (string_cst_ptr
, NULL
);
7078 tree rep
= m
.get_representative_tree (str_sval
);
7079 ASSERT_DUMP_TREE_EQ (rep
, "&\"foo\"[0]");
7082 /* Value of an element within an array. */
7084 tree tlen
= size_int (10);
7085 tree arr_type
= build_array_type (char_type_node
, build_index_type (tlen
));
7086 tree a
= build_global_decl ("a", arr_type
);
7087 placeholder_svalue
test_sval (mgr
.alloc_symbol_id (),
7088 char_type_node
, "test value");
7090 /* Value of a[3]. */
7092 test_region_model_context ctxt
;
7093 region_model
model (&mgr
);
7094 tree int_3
= build_int_cst (integer_type_node
, 3);
7095 tree a_3
= build4 (ARRAY_REF
, char_type_node
,
7096 a
, int_3
, NULL_TREE
, NULL_TREE
);
7097 const region
*a_3_reg
= model
.get_lvalue (a_3
, &ctxt
);
7098 model
.set_value (a_3_reg
, &test_sval
, &ctxt
);
7099 tree rep
= model
.get_representative_tree (&test_sval
);
7100 ASSERT_DUMP_TREE_EQ (rep
, "a[3]");
7103 /* Value of a[0]. */
7105 test_region_model_context ctxt
;
7106 region_model
model (&mgr
);
7107 tree idx
= build_int_cst (integer_type_node
, 0);
7108 tree a_0
= build4 (ARRAY_REF
, char_type_node
,
7109 a
, idx
, NULL_TREE
, NULL_TREE
);
7110 const region
*a_0_reg
= model
.get_lvalue (a_0
, &ctxt
);
7111 model
.set_value (a_0_reg
, &test_sval
, &ctxt
);
7112 tree rep
= model
.get_representative_tree (&test_sval
);
7113 ASSERT_DUMP_TREE_EQ (rep
, "a[0]");
7117 /* Value of a field within a struct. */
7121 tree c
= build_global_decl ("c", ct
.m_coord_type
);
7122 tree c_x
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_x_field
),
7123 c
, ct
.m_x_field
, NULL_TREE
);
7124 tree c_y
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_y_field
),
7125 c
, ct
.m_y_field
, NULL_TREE
);
7127 test_region_model_context ctxt
;
7129 /* Value of initial field. */
7131 region_model
m (&mgr
);
7132 const region
*c_x_reg
= m
.get_lvalue (c_x
, &ctxt
);
7133 placeholder_svalue
test_sval_x (mgr
.alloc_symbol_id (),
7134 integer_type_node
, "test x val");
7135 m
.set_value (c_x_reg
, &test_sval_x
, &ctxt
);
7136 tree rep
= m
.get_representative_tree (&test_sval_x
);
7137 ASSERT_DUMP_TREE_EQ (rep
, "c.x");
7140 /* Value of non-initial field. */
7142 region_model
m (&mgr
);
7143 const region
*c_y_reg
= m
.get_lvalue (c_y
, &ctxt
);
7144 placeholder_svalue
test_sval_y (mgr
.alloc_symbol_id (),
7145 integer_type_node
, "test y val");
7146 m
.set_value (c_y_reg
, &test_sval_y
, &ctxt
);
7147 tree rep
= m
.get_representative_tree (&test_sval_y
);
7148 ASSERT_DUMP_TREE_EQ (rep
, "c.y");
7153 /* Verify that calling region_model::get_rvalue repeatedly on the same
7154 tree constant retrieves the same svalue *. */
7157 test_unique_constants ()
7159 tree int_0
= build_int_cst (integer_type_node
, 0);
7160 tree int_42
= build_int_cst (integer_type_node
, 42);
7162 test_region_model_context ctxt
;
7163 region_model_manager mgr
;
7164 region_model
model (&mgr
);
7165 ASSERT_EQ (model
.get_rvalue (int_0
, &ctxt
), model
.get_rvalue (int_0
, &ctxt
));
7166 ASSERT_EQ (model
.get_rvalue (int_42
, &ctxt
),
7167 model
.get_rvalue (int_42
, &ctxt
));
7168 ASSERT_NE (model
.get_rvalue (int_0
, &ctxt
), model
.get_rvalue (int_42
, &ctxt
));
7169 ASSERT_EQ (ctxt
.get_num_diagnostics (), 0);
7171 /* A "(const int)42" will be a different tree from "(int)42)"... */
7172 tree const_int_type_node
7173 = build_qualified_type (integer_type_node
, TYPE_QUAL_CONST
);
7174 tree const_int_42
= build_int_cst (const_int_type_node
, 42);
7175 ASSERT_NE (int_42
, const_int_42
);
7176 /* It should have a different const_svalue. */
7177 const svalue
*int_42_sval
= model
.get_rvalue (int_42
, &ctxt
);
7178 const svalue
*const_int_42_sval
= model
.get_rvalue (const_int_42
, &ctxt
);
7179 ASSERT_NE (int_42_sval
, const_int_42_sval
);
7180 /* But they should compare as equal. */
7181 ASSERT_CONDITION_TRUE (model
, int_42_sval
, EQ_EXPR
, const_int_42_sval
);
7182 ASSERT_CONDITION_FALSE (model
, int_42_sval
, NE_EXPR
, const_int_42_sval
);
7185 /* Verify that each type gets its own singleton unknown_svalue within a
7186 region_model_manager, and that NULL_TREE gets its own singleton. */
7189 test_unique_unknowns ()
7191 region_model_manager mgr
;
7192 const svalue
*unknown_int
7193 = mgr
.get_or_create_unknown_svalue (integer_type_node
);
7194 /* Repeated calls with the same type should get the same "unknown"
7196 const svalue
*unknown_int_2
7197 = mgr
.get_or_create_unknown_svalue (integer_type_node
);
7198 ASSERT_EQ (unknown_int
, unknown_int_2
);
7200 /* Different types (or the NULL type) should have different
7202 const svalue
*unknown_NULL_type
= mgr
.get_or_create_unknown_svalue (NULL
);
7203 ASSERT_NE (unknown_NULL_type
, unknown_int
);
7205 /* Repeated calls with NULL for the type should get the same "unknown"
7207 const svalue
*unknown_NULL_type_2
= mgr
.get_or_create_unknown_svalue (NULL
);
7208 ASSERT_EQ (unknown_NULL_type
, unknown_NULL_type_2
);
7211 /* Verify that initial_svalue are handled as expected. */
7214 test_initial_svalue_folding ()
7216 region_model_manager mgr
;
7217 tree x
= build_global_decl ("x", integer_type_node
);
7218 tree y
= build_global_decl ("y", integer_type_node
);
7220 test_region_model_context ctxt
;
7221 region_model
model (&mgr
);
7222 const svalue
*x_init
= model
.get_rvalue (x
, &ctxt
);
7223 const svalue
*y_init
= model
.get_rvalue (y
, &ctxt
);
7224 ASSERT_NE (x_init
, y_init
);
7225 const region
*x_reg
= model
.get_lvalue (x
, &ctxt
);
7226 ASSERT_EQ (x_init
, mgr
.get_or_create_initial_value (x_reg
));
7230 /* Verify that unary ops are folded as expected. */
7233 test_unaryop_svalue_folding ()
7235 region_model_manager mgr
;
7236 tree x
= build_global_decl ("x", integer_type_node
);
7237 tree y
= build_global_decl ("y", integer_type_node
);
7239 test_region_model_context ctxt
;
7240 region_model
model (&mgr
);
7241 const svalue
*x_init
= model
.get_rvalue (x
, &ctxt
);
7242 const svalue
*y_init
= model
.get_rvalue (y
, &ctxt
);
7243 const region
*x_reg
= model
.get_lvalue (x
, &ctxt
);
7244 ASSERT_EQ (x_init
, mgr
.get_or_create_initial_value (x_reg
));
7246 /* "(int)x" -> "x". */
7247 ASSERT_EQ (x_init
, mgr
.get_or_create_cast (integer_type_node
, x_init
));
7249 /* "(void *)x" -> something other than "x". */
7250 ASSERT_NE (x_init
, mgr
.get_or_create_cast (ptr_type_node
, x_init
));
7252 /* "!(x == y)" -> "x != y". */
7253 ASSERT_EQ (mgr
.get_or_create_unaryop
7254 (boolean_type_node
, TRUTH_NOT_EXPR
,
7255 mgr
.get_or_create_binop (boolean_type_node
, EQ_EXPR
,
7257 mgr
.get_or_create_binop (boolean_type_node
, NE_EXPR
,
7259 /* "!(x > y)" -> "x <= y". */
7260 ASSERT_EQ (mgr
.get_or_create_unaryop
7261 (boolean_type_node
, TRUTH_NOT_EXPR
,
7262 mgr
.get_or_create_binop (boolean_type_node
, GT_EXPR
,
7264 mgr
.get_or_create_binop (boolean_type_node
, LE_EXPR
,
7268 /* Verify that binops on constant svalues are folded. */
7271 test_binop_svalue_folding ()
7274 tree cst_int
[NUM_CSTS
];
7275 region_model_manager mgr
;
7276 const svalue
*cst_sval
[NUM_CSTS
];
7277 for (int i
= 0; i
< NUM_CSTS
; i
++)
7279 cst_int
[i
] = build_int_cst (integer_type_node
, i
);
7280 cst_sval
[i
] = mgr
.get_or_create_constant_svalue (cst_int
[i
]);
7281 ASSERT_EQ (cst_sval
[i
]->get_kind (), SK_CONSTANT
);
7282 ASSERT_EQ (cst_sval
[i
]->maybe_get_constant (), cst_int
[i
]);
7285 for (int i
= 0; i
< NUM_CSTS
; i
++)
7286 for (int j
= 0; j
< NUM_CSTS
; j
++)
7289 ASSERT_NE (cst_sval
[i
], cst_sval
[j
]);
7290 if (i
+ j
< NUM_CSTS
)
7293 = mgr
.get_or_create_binop (integer_type_node
, PLUS_EXPR
,
7294 cst_sval
[i
], cst_sval
[j
]);
7295 ASSERT_EQ (sum
, cst_sval
[i
+ j
]);
7299 const svalue
*difference
7300 = mgr
.get_or_create_binop (integer_type_node
, MINUS_EXPR
,
7301 cst_sval
[i
], cst_sval
[j
]);
7302 ASSERT_EQ (difference
, cst_sval
[i
- j
]);
7304 if (i
* j
< NUM_CSTS
)
7306 const svalue
*product
7307 = mgr
.get_or_create_binop (integer_type_node
, MULT_EXPR
,
7308 cst_sval
[i
], cst_sval
[j
]);
7309 ASSERT_EQ (product
, cst_sval
[i
* j
]);
7311 const svalue
*eq
= mgr
.get_or_create_binop (integer_type_node
, EQ_EXPR
,
7312 cst_sval
[i
], cst_sval
[j
]);
7313 ASSERT_EQ (eq
, i
== j
? cst_sval
[1] : cst_sval
[0]);
7314 const svalue
*neq
= mgr
.get_or_create_binop (integer_type_node
, NE_EXPR
,
7315 cst_sval
[i
], cst_sval
[j
]);
7316 ASSERT_EQ (neq
, i
!= j
? cst_sval
[1] : cst_sval
[0]);
7320 tree x
= build_global_decl ("x", integer_type_node
);
7322 test_region_model_context ctxt
;
7323 region_model
model (&mgr
);
7324 const svalue
*x_init
= model
.get_rvalue (x
, &ctxt
);
7326 /* PLUS_EXPR folding. */
7327 const svalue
*x_init_plus_zero
7328 = mgr
.get_or_create_binop (integer_type_node
, PLUS_EXPR
,
7329 x_init
, cst_sval
[0]);
7330 ASSERT_EQ (x_init_plus_zero
, x_init
);
7331 const svalue
*zero_plus_x_init
7332 = mgr
.get_or_create_binop (integer_type_node
, PLUS_EXPR
,
7333 cst_sval
[0], x_init
);
7334 ASSERT_EQ (zero_plus_x_init
, x_init
);
7336 /* MULT_EXPR folding. */
7337 const svalue
*x_init_times_zero
7338 = mgr
.get_or_create_binop (integer_type_node
, MULT_EXPR
,
7339 x_init
, cst_sval
[0]);
7340 ASSERT_EQ (x_init_times_zero
, cst_sval
[0]);
7341 const svalue
*zero_times_x_init
7342 = mgr
.get_or_create_binop (integer_type_node
, MULT_EXPR
,
7343 cst_sval
[0], x_init
);
7344 ASSERT_EQ (zero_times_x_init
, cst_sval
[0]);
7346 const svalue
*x_init_times_one
7347 = mgr
.get_or_create_binop (integer_type_node
, MULT_EXPR
,
7348 x_init
, cst_sval
[1]);
7349 ASSERT_EQ (x_init_times_one
, x_init
);
7350 const svalue
*one_times_x_init
7351 = mgr
.get_or_create_binop (integer_type_node
, MULT_EXPR
,
7352 cst_sval
[1], x_init
);
7353 ASSERT_EQ (one_times_x_init
, x_init
);
7356 // TODO: do we want to use the match-and-simplify DSL for this?
7358 /* Verify that binops put any constants on the RHS. */
7359 const svalue
*four_times_x_init
7360 = mgr
.get_or_create_binop (integer_type_node
, MULT_EXPR
,
7361 cst_sval
[4], x_init
);
7362 const svalue
*x_init_times_four
7363 = mgr
.get_or_create_binop (integer_type_node
, MULT_EXPR
,
7364 x_init
, cst_sval
[4]);
7365 ASSERT_EQ (four_times_x_init
, x_init_times_four
);
7366 const binop_svalue
*binop
= four_times_x_init
->dyn_cast_binop_svalue ();
7367 ASSERT_EQ (binop
->get_op (), MULT_EXPR
);
7368 ASSERT_EQ (binop
->get_arg0 (), x_init
);
7369 ASSERT_EQ (binop
->get_arg1 (), cst_sval
[4]);
7371 /* Verify that ((x + 1) + 1) == (x + 2). */
7372 const svalue
*x_init_plus_one
7373 = mgr
.get_or_create_binop (integer_type_node
, PLUS_EXPR
,
7374 x_init
, cst_sval
[1]);
7375 const svalue
*x_init_plus_two
7376 = mgr
.get_or_create_binop (integer_type_node
, PLUS_EXPR
,
7377 x_init
, cst_sval
[2]);
7378 const svalue
*x_init_plus_one_plus_one
7379 = mgr
.get_or_create_binop (integer_type_node
, PLUS_EXPR
,
7380 x_init_plus_one
, cst_sval
[1]);
7381 ASSERT_EQ (x_init_plus_one_plus_one
, x_init_plus_two
);
7383 /* Verify various binops on booleans. */
7385 const svalue
*sval_true
= mgr
.get_or_create_int_cst (boolean_type_node
, 1);
7386 const svalue
*sval_false
= mgr
.get_or_create_int_cst (boolean_type_node
, 0);
7387 const svalue
*sval_unknown
7388 = mgr
.get_or_create_unknown_svalue (boolean_type_node
);
7389 const placeholder_svalue
sval_placeholder (mgr
.alloc_symbol_id (),
7390 boolean_type_node
, "v");
7391 for (auto op
: {BIT_IOR_EXPR
, TRUTH_OR_EXPR
})
7393 ASSERT_EQ (mgr
.get_or_create_binop (boolean_type_node
, op
,
7394 sval_true
, sval_unknown
),
7396 ASSERT_EQ (mgr
.get_or_create_binop (boolean_type_node
, op
,
7397 sval_false
, sval_unknown
),
7399 ASSERT_EQ (mgr
.get_or_create_binop (boolean_type_node
, op
,
7400 sval_false
, &sval_placeholder
),
7403 for (auto op
: {BIT_AND_EXPR
, TRUTH_AND_EXPR
})
7405 ASSERT_EQ (mgr
.get_or_create_binop (boolean_type_node
, op
,
7406 sval_false
, sval_unknown
),
7408 ASSERT_EQ (mgr
.get_or_create_binop (boolean_type_node
, op
,
7409 sval_true
, sval_unknown
),
7411 ASSERT_EQ (mgr
.get_or_create_binop (boolean_type_node
, op
,
7412 sval_true
, &sval_placeholder
),
7418 /* Verify that sub_svalues are folded as expected. */
7421 test_sub_svalue_folding ()
7424 tree c
= build_global_decl ("c", ct
.m_coord_type
);
7425 tree c_x
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_x_field
),
7426 c
, ct
.m_x_field
, NULL_TREE
);
7428 region_model_manager mgr
;
7429 region_model
model (&mgr
);
7430 test_region_model_context ctxt
;
7431 const region
*c_x_reg
= model
.get_lvalue (c_x
, &ctxt
);
7433 /* Verify that sub_svalue of "unknown" simply
7434 yields an unknown. */
7436 const svalue
*unknown
= mgr
.get_or_create_unknown_svalue (ct
.m_coord_type
);
7437 const svalue
*sub
= mgr
.get_or_create_sub_svalue (TREE_TYPE (ct
.m_x_field
),
7439 ASSERT_EQ (sub
->get_kind (), SK_UNKNOWN
);
7440 ASSERT_EQ (sub
->get_type (), TREE_TYPE (ct
.m_x_field
));
7443 /* Get BIT within VAL as a symbolic value within MGR. */
7445 static const svalue
*
7446 get_bit (region_model_manager
*mgr
,
7448 unsigned HOST_WIDE_INT val
)
7450 const svalue
*inner_svalue
7451 = mgr
->get_or_create_int_cst (unsigned_type_node
, val
);
7452 return mgr
->get_or_create_bits_within (boolean_type_node
,
7457 /* Verify that bits_within_svalues are folded as expected. */
7460 test_bits_within_svalue_folding ()
7462 region_model_manager mgr
;
7464 const svalue
*zero
= mgr
.get_or_create_int_cst (boolean_type_node
, 0);
7465 const svalue
*one
= mgr
.get_or_create_int_cst (boolean_type_node
, 1);
7468 const unsigned val
= 0x0000;
7469 for (unsigned bit
= 0; bit
< 16; bit
++)
7470 ASSERT_EQ (get_bit (&mgr
, bit
, val
), zero
);
7474 const unsigned val
= 0x0001;
7475 ASSERT_EQ (get_bit (&mgr
, 0, val
), one
);
7476 for (unsigned bit
= 1; bit
< 16; bit
++)
7477 ASSERT_EQ (get_bit (&mgr
, bit
, val
), zero
);
7481 const unsigned val
= 0x8000;
7482 for (unsigned bit
= 0; bit
< 15; bit
++)
7483 ASSERT_EQ (get_bit (&mgr
, bit
, val
), zero
);
7484 ASSERT_EQ (get_bit (&mgr
, 15, val
), one
);
7488 const unsigned val
= 0xFFFF;
7489 for (unsigned bit
= 0; bit
< 16; bit
++)
7490 ASSERT_EQ (get_bit (&mgr
, bit
, val
), one
);
7494 /* Test that region::descendent_of_p works as expected. */
7497 test_descendent_of_p ()
7499 region_model_manager mgr
;
7500 const region
*stack
= mgr
.get_stack_region ();
7501 const region
*heap
= mgr
.get_heap_region ();
7502 const region
*code
= mgr
.get_code_region ();
7503 const region
*globals
= mgr
.get_globals_region ();
7505 /* descendent_of_p should return true when used on the region itself. */
7506 ASSERT_TRUE (stack
->descendent_of_p (stack
));
7507 ASSERT_FALSE (stack
->descendent_of_p (heap
));
7508 ASSERT_FALSE (stack
->descendent_of_p (code
));
7509 ASSERT_FALSE (stack
->descendent_of_p (globals
));
7511 tree x
= build_global_decl ("x", integer_type_node
);
7512 const region
*x_reg
= mgr
.get_region_for_global (x
);
7513 ASSERT_TRUE (x_reg
->descendent_of_p (globals
));
7515 /* A cast_region should be a descendent of the original region. */
7516 const region
*cast_reg
= mgr
.get_cast_region (x_reg
, ptr_type_node
);
7517 ASSERT_TRUE (cast_reg
->descendent_of_p (x_reg
));
7520 /* Verify that bit_range_region works as expected. */
7523 test_bit_range_regions ()
7525 tree x
= build_global_decl ("x", integer_type_node
);
7526 region_model_manager mgr
;
7527 const region
*x_reg
= mgr
.get_region_for_global (x
);
7529 = mgr
.get_bit_range (x_reg
, char_type_node
, bit_range (0, 8));
7531 = mgr
.get_bit_range (x_reg
, char_type_node
, bit_range (8, 8));
7532 ASSERT_TRUE (byte0
->descendent_of_p (x_reg
));
7533 ASSERT_TRUE (byte1
->descendent_of_p (x_reg
));
7534 ASSERT_NE (byte0
, byte1
);
7537 /* Verify that simple assignments work as expected. */
7542 tree int_0
= build_int_cst (integer_type_node
, 0);
7543 tree x
= build_global_decl ("x", integer_type_node
);
7544 tree y
= build_global_decl ("y", integer_type_node
);
7546 /* "x == 0", then use of y, then "y = 0;". */
7547 region_model_manager mgr
;
7548 region_model
model (&mgr
);
7549 ADD_SAT_CONSTRAINT (model
, x
, EQ_EXPR
, int_0
);
7550 ASSERT_CONDITION_UNKNOWN (model
, y
, EQ_EXPR
, int_0
);
7551 model
.set_value (model
.get_lvalue (y
, NULL
),
7552 model
.get_rvalue (int_0
, NULL
),
7554 ASSERT_CONDITION_TRUE (model
, y
, EQ_EXPR
, int_0
);
7555 ASSERT_CONDITION_TRUE (model
, y
, EQ_EXPR
, x
);
7558 /* Verify that compound assignments work as expected. */
7561 test_compound_assignment ()
7565 tree c
= build_global_decl ("c", ct
.m_coord_type
);
7566 tree c_x
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_x_field
),
7567 c
, ct
.m_x_field
, NULL_TREE
);
7568 tree c_y
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_y_field
),
7569 c
, ct
.m_y_field
, NULL_TREE
);
7570 tree d
= build_global_decl ("d", ct
.m_coord_type
);
7571 tree d_x
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_x_field
),
7572 d
, ct
.m_x_field
, NULL_TREE
);
7573 tree d_y
= build3 (COMPONENT_REF
, TREE_TYPE (ct
.m_y_field
),
7574 d
, ct
.m_y_field
, NULL_TREE
);
7576 tree int_17
= build_int_cst (integer_type_node
, 17);
7577 tree int_m3
= build_int_cst (integer_type_node
, -3);
7579 region_model_manager mgr
;
7580 region_model
model (&mgr
);
7581 model
.set_value (c_x
, int_17
, NULL
);
7582 model
.set_value (c_y
, int_m3
, NULL
);
7585 const svalue
*sval
= model
.get_rvalue (c
, NULL
);
7586 model
.set_value (model
.get_lvalue (d
, NULL
), sval
, NULL
);
7588 /* Check that the fields have the same svalues. */
7589 ASSERT_EQ (model
.get_rvalue (c_x
, NULL
), model
.get_rvalue (d_x
, NULL
));
7590 ASSERT_EQ (model
.get_rvalue (c_y
, NULL
), model
.get_rvalue (d_y
, NULL
));
7593 /* Verify the details of pushing and popping stack frames. */
7596 test_stack_frames ()
7598 tree int_42
= build_int_cst (integer_type_node
, 42);
7599 tree int_10
= build_int_cst (integer_type_node
, 10);
7600 tree int_5
= build_int_cst (integer_type_node
, 5);
7601 tree int_0
= build_int_cst (integer_type_node
, 0);
7603 auto_vec
<tree
> param_types
;
7604 tree parent_fndecl
= make_fndecl (integer_type_node
,
7607 allocate_struct_function (parent_fndecl
, true);
7609 tree child_fndecl
= make_fndecl (integer_type_node
,
7612 allocate_struct_function (child_fndecl
, true);
7614 /* "a" and "b" in the parent frame. */
7615 tree a
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
7616 get_identifier ("a"),
7618 DECL_CONTEXT (a
) = parent_fndecl
;
7619 tree b
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
7620 get_identifier ("b"),
7622 DECL_CONTEXT (b
) = parent_fndecl
;
7623 /* "x" and "y" in a child frame. */
7624 tree x
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
7625 get_identifier ("x"),
7627 DECL_CONTEXT (x
) = child_fndecl
;
7628 tree y
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
7629 get_identifier ("y"),
7631 DECL_CONTEXT (y
) = child_fndecl
;
7634 tree p
= build_global_decl ("p", ptr_type_node
);
7637 tree q
= build_global_decl ("q", ptr_type_node
);
7639 region_model_manager mgr
;
7640 test_region_model_context ctxt
;
7641 region_model
model (&mgr
);
7643 /* Push stack frame for "parent_fn". */
7644 const region
*parent_frame_reg
7645 = model
.push_frame (DECL_STRUCT_FUNCTION (parent_fndecl
),
7647 ASSERT_EQ (model
.get_current_frame (), parent_frame_reg
);
7648 ASSERT_TRUE (model
.region_exists_p (parent_frame_reg
));
7649 const region
*a_in_parent_reg
= model
.get_lvalue (a
, &ctxt
);
7650 model
.set_value (a_in_parent_reg
,
7651 model
.get_rvalue (int_42
, &ctxt
),
7653 ASSERT_EQ (a_in_parent_reg
->maybe_get_frame_region (), parent_frame_reg
);
7655 model
.add_constraint (b
, LT_EXPR
, int_10
, &ctxt
);
7656 ASSERT_EQ (model
.eval_condition (b
, LT_EXPR
, int_10
, &ctxt
),
7657 tristate (tristate::TS_TRUE
));
7659 /* Push stack frame for "child_fn". */
7660 const region
*child_frame_reg
7661 = model
.push_frame (DECL_STRUCT_FUNCTION (child_fndecl
), NULL
, &ctxt
);
7662 ASSERT_EQ (model
.get_current_frame (), child_frame_reg
);
7663 ASSERT_TRUE (model
.region_exists_p (child_frame_reg
));
7664 const region
*x_in_child_reg
= model
.get_lvalue (x
, &ctxt
);
7665 model
.set_value (x_in_child_reg
,
7666 model
.get_rvalue (int_0
, &ctxt
),
7668 ASSERT_EQ (x_in_child_reg
->maybe_get_frame_region (), child_frame_reg
);
7670 model
.add_constraint (y
, NE_EXPR
, int_5
, &ctxt
);
7671 ASSERT_EQ (model
.eval_condition (y
, NE_EXPR
, int_5
, &ctxt
),
7672 tristate (tristate::TS_TRUE
));
7674 /* Point a global pointer at a local in the child frame: p = &x. */
7675 const region
*p_in_globals_reg
= model
.get_lvalue (p
, &ctxt
);
7676 model
.set_value (p_in_globals_reg
,
7677 mgr
.get_ptr_svalue (ptr_type_node
, x_in_child_reg
),
7679 ASSERT_EQ (p_in_globals_reg
->maybe_get_frame_region (), NULL
);
7681 /* Point another global pointer at p: q = &p. */
7682 const region
*q_in_globals_reg
= model
.get_lvalue (q
, &ctxt
);
7683 model
.set_value (q_in_globals_reg
,
7684 mgr
.get_ptr_svalue (ptr_type_node
, p_in_globals_reg
),
7687 /* Test region::descendent_of_p. */
7688 ASSERT_TRUE (child_frame_reg
->descendent_of_p (child_frame_reg
));
7689 ASSERT_TRUE (x_in_child_reg
->descendent_of_p (child_frame_reg
));
7690 ASSERT_FALSE (a_in_parent_reg
->descendent_of_p (child_frame_reg
));
7692 /* Pop the "child_fn" frame from the stack. */
7693 model
.pop_frame (NULL
, NULL
, &ctxt
);
7694 ASSERT_FALSE (model
.region_exists_p (child_frame_reg
));
7695 ASSERT_TRUE (model
.region_exists_p (parent_frame_reg
));
7697 /* Verify that p (which was pointing at the local "x" in the popped
7698 frame) has been poisoned. */
7699 const svalue
*new_p_sval
= model
.get_rvalue (p
, NULL
);
7700 ASSERT_EQ (new_p_sval
->get_kind (), SK_POISONED
);
7701 ASSERT_EQ (new_p_sval
->dyn_cast_poisoned_svalue ()->get_poison_kind (),
7702 POISON_KIND_POPPED_STACK
);
7704 /* Verify that q still points to p, in spite of the region
7706 const svalue
*new_q_sval
= model
.get_rvalue (q
, &ctxt
);
7707 ASSERT_EQ (new_q_sval
->get_kind (), SK_REGION
);
7708 ASSERT_EQ (new_q_sval
->maybe_get_region (),
7709 model
.get_lvalue (p
, &ctxt
));
7711 /* Verify that top of stack has been updated. */
7712 ASSERT_EQ (model
.get_current_frame (), parent_frame_reg
);
7714 /* Verify locals in parent frame. */
7715 /* Verify "a" still has its value. */
7716 const svalue
*new_a_sval
= model
.get_rvalue (a
, &ctxt
);
7717 ASSERT_EQ (new_a_sval
->get_kind (), SK_CONSTANT
);
7718 ASSERT_EQ (new_a_sval
->dyn_cast_constant_svalue ()->get_constant (),
7720 /* Verify "b" still has its constraint. */
7721 ASSERT_EQ (model
.eval_condition (b
, LT_EXPR
, int_10
, &ctxt
),
7722 tristate (tristate::TS_TRUE
));
7725 /* Verify that get_representative_path_var works as expected, that
7726 we can map from regions to parms and back within a recursive call
7730 test_get_representative_path_var ()
7732 auto_vec
<tree
> param_types
;
7733 tree fndecl
= make_fndecl (integer_type_node
,
7736 allocate_struct_function (fndecl
, true);
7739 tree n
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
7740 get_identifier ("n"),
7742 DECL_CONTEXT (n
) = fndecl
;
7744 region_model_manager mgr
;
7745 test_region_model_context ctxt
;
7746 region_model
model (&mgr
);
7748 /* Push 5 stack frames for "factorial", each with a param */
7749 auto_vec
<const region
*> parm_regs
;
7750 auto_vec
<const svalue
*> parm_svals
;
7751 for (int depth
= 0; depth
< 5; depth
++)
7753 const region
*frame_n_reg
7754 = model
.push_frame (DECL_STRUCT_FUNCTION (fndecl
), NULL
, &ctxt
);
7755 const region
*parm_n_reg
= model
.get_lvalue (path_var (n
, depth
), &ctxt
);
7756 parm_regs
.safe_push (parm_n_reg
);
7758 ASSERT_EQ (parm_n_reg
->get_parent_region (), frame_n_reg
);
7759 const svalue
*sval_n
= mgr
.get_or_create_initial_value (parm_n_reg
);
7760 parm_svals
.safe_push (sval_n
);
7763 /* Verify that we can recognize that the regions are the parms,
7765 for (int depth
= 0; depth
< 5; depth
++)
7769 ASSERT_EQ (model
.get_representative_path_var (parm_regs
[depth
],
7771 path_var (n
, depth
+ 1));
7773 /* ...and that we can lookup lvalues for locals for all frames,
7774 not just the top. */
7775 ASSERT_EQ (model
.get_lvalue (path_var (n
, depth
), NULL
),
7777 /* ...and that we can locate the svalues. */
7780 ASSERT_EQ (model
.get_representative_path_var (parm_svals
[depth
],
7782 path_var (n
, depth
+ 1));
7787 /* Ensure that region_model::operator== works as expected. */
7792 tree int_42
= build_int_cst (integer_type_node
, 42);
7793 tree int_17
= build_int_cst (integer_type_node
, 17);
7795 /* Verify that "empty" region_model instances are equal to each other. */
7796 region_model_manager mgr
;
7797 region_model
model0 (&mgr
);
7798 region_model
model1 (&mgr
);
7799 ASSERT_EQ (model0
, model1
);
7801 /* Verify that setting state in model1 makes the models non-equal. */
7802 tree x
= build_global_decl ("x", integer_type_node
);
7803 model0
.set_value (x
, int_42
, NULL
);
7804 ASSERT_EQ (model0
.get_rvalue (x
, NULL
)->maybe_get_constant (), int_42
);
7805 ASSERT_NE (model0
, model1
);
7807 /* Verify the copy-ctor. */
7808 region_model
model2 (model0
);
7809 ASSERT_EQ (model0
, model2
);
7810 ASSERT_EQ (model2
.get_rvalue (x
, NULL
)->maybe_get_constant (), int_42
);
7811 ASSERT_NE (model1
, model2
);
7813 /* Verify that models obtained from copy-ctor are independently editable
7814 w/o affecting the original model. */
7815 model2
.set_value (x
, int_17
, NULL
);
7816 ASSERT_NE (model0
, model2
);
7817 ASSERT_EQ (model2
.get_rvalue (x
, NULL
)->maybe_get_constant (), int_17
);
7818 ASSERT_EQ (model0
.get_rvalue (x
, NULL
)->maybe_get_constant (), int_42
);
7821 /* Verify that region models for
7828 test_canonicalization_2 ()
7830 tree int_42
= build_int_cst (integer_type_node
, 42);
7831 tree int_113
= build_int_cst (integer_type_node
, 113);
7832 tree x
= build_global_decl ("x", integer_type_node
);
7833 tree y
= build_global_decl ("y", integer_type_node
);
7835 region_model_manager mgr
;
7836 region_model
model0 (&mgr
);
7837 model0
.set_value (model0
.get_lvalue (x
, NULL
),
7838 model0
.get_rvalue (int_42
, NULL
),
7840 model0
.set_value (model0
.get_lvalue (y
, NULL
),
7841 model0
.get_rvalue (int_113
, NULL
),
7844 region_model
model1 (&mgr
);
7845 model1
.set_value (model1
.get_lvalue (y
, NULL
),
7846 model1
.get_rvalue (int_113
, NULL
),
7848 model1
.set_value (model1
.get_lvalue (x
, NULL
),
7849 model1
.get_rvalue (int_42
, NULL
),
7852 ASSERT_EQ (model0
, model1
);
7855 /* Verify that constraints for
7859 are equal after canonicalization. */
7862 test_canonicalization_3 ()
7864 tree int_3
= build_int_cst (integer_type_node
, 3);
7865 tree int_42
= build_int_cst (integer_type_node
, 42);
7866 tree x
= build_global_decl ("x", integer_type_node
);
7867 tree y
= build_global_decl ("y", integer_type_node
);
7869 region_model_manager mgr
;
7870 region_model
model0 (&mgr
);
7871 model0
.add_constraint (x
, GT_EXPR
, int_3
, NULL
);
7872 model0
.add_constraint (y
, GT_EXPR
, int_42
, NULL
);
7874 region_model
model1 (&mgr
);
7875 model1
.add_constraint (y
, GT_EXPR
, int_42
, NULL
);
7876 model1
.add_constraint (x
, GT_EXPR
, int_3
, NULL
);
7878 model0
.canonicalize ();
7879 model1
.canonicalize ();
7880 ASSERT_EQ (model0
, model1
);
7883 /* Verify that we can canonicalize a model containing NaN and other real
7887 test_canonicalization_4 ()
7889 auto_vec
<tree
> csts
;
7890 append_interesting_constants (&csts
);
7892 region_model_manager mgr
;
7893 region_model
model (&mgr
);
7895 for (tree cst
: csts
)
7896 model
.get_rvalue (cst
, NULL
);
7898 model
.canonicalize ();
7901 /* Assert that if we have two region_model instances
7902 with values VAL_A and VAL_B for EXPR that they are
7903 mergable. Write the merged model to *OUT_MERGED_MODEL,
7904 and the merged svalue ptr to *OUT_MERGED_SVALUE.
7905 If VAL_A or VAL_B are NULL_TREE, don't populate EXPR
7906 for that region_model. */
7909 assert_region_models_merge (tree expr
, tree val_a
, tree val_b
,
7910 region_model
*out_merged_model
,
7911 const svalue
**out_merged_svalue
)
7913 region_model_manager
*mgr
= out_merged_model
->get_manager ();
7914 program_point
point (program_point::origin (*mgr
));
7915 test_region_model_context ctxt
;
7916 region_model
model0 (mgr
);
7917 region_model
model1 (mgr
);
7919 model0
.set_value (model0
.get_lvalue (expr
, &ctxt
),
7920 model0
.get_rvalue (val_a
, &ctxt
),
7923 model1
.set_value (model1
.get_lvalue (expr
, &ctxt
),
7924 model1
.get_rvalue (val_b
, &ctxt
),
7927 /* They should be mergeable. */
7928 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, out_merged_model
));
7929 *out_merged_svalue
= out_merged_model
->get_rvalue (expr
, &ctxt
);
7932 /* Verify that we can merge region_model instances. */
7935 test_state_merging ()
7937 tree int_42
= build_int_cst (integer_type_node
, 42);
7938 tree int_113
= build_int_cst (integer_type_node
, 113);
7939 tree x
= build_global_decl ("x", integer_type_node
);
7940 tree y
= build_global_decl ("y", integer_type_node
);
7941 tree z
= build_global_decl ("z", integer_type_node
);
7942 tree p
= build_global_decl ("p", ptr_type_node
);
7944 tree addr_of_y
= build1 (ADDR_EXPR
, ptr_type_node
, y
);
7945 tree addr_of_z
= build1 (ADDR_EXPR
, ptr_type_node
, z
);
7947 auto_vec
<tree
> param_types
;
7948 tree test_fndecl
= make_fndecl (integer_type_node
, "test_fn", param_types
);
7949 allocate_struct_function (test_fndecl
, true);
7952 tree a
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
7953 get_identifier ("a"),
7955 DECL_CONTEXT (a
) = test_fndecl
;
7956 tree addr_of_a
= build1 (ADDR_EXPR
, ptr_type_node
, a
);
7958 /* Param "q", a pointer. */
7959 tree q
= build_decl (UNKNOWN_LOCATION
, PARM_DECL
,
7960 get_identifier ("q"),
7962 DECL_CONTEXT (q
) = test_fndecl
;
7964 region_model_manager mgr
;
7965 program_point
point (program_point::origin (mgr
));
7968 region_model
model0 (&mgr
);
7969 region_model
model1 (&mgr
);
7970 region_model
merged (&mgr
);
7971 /* Verify empty models can be merged. */
7972 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
7973 ASSERT_EQ (model0
, merged
);
7976 /* Verify that we can merge two contradictory constraints on the
7977 value for a global. */
7978 /* TODO: verify that the merged model doesn't have a value for
7981 region_model
model0 (&mgr
);
7982 region_model
model1 (&mgr
);
7983 region_model
merged (&mgr
);
7984 test_region_model_context ctxt
;
7985 model0
.add_constraint (x
, EQ_EXPR
, int_42
, &ctxt
);
7986 model1
.add_constraint (x
, EQ_EXPR
, int_113
, &ctxt
);
7987 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
7988 ASSERT_NE (model0
, merged
);
7989 ASSERT_NE (model1
, merged
);
7992 /* Verify handling of a PARM_DECL. */
7994 test_region_model_context ctxt
;
7995 region_model
model0 (&mgr
);
7996 region_model
model1 (&mgr
);
7997 ASSERT_EQ (model0
.get_stack_depth (), 0);
7998 model0
.push_frame (DECL_STRUCT_FUNCTION (test_fndecl
), NULL
, &ctxt
);
7999 ASSERT_EQ (model0
.get_stack_depth (), 1);
8000 model1
.push_frame (DECL_STRUCT_FUNCTION (test_fndecl
), NULL
, &ctxt
);
8002 placeholder_svalue
test_sval (mgr
.alloc_symbol_id (),
8003 integer_type_node
, "test sval");
8004 model0
.set_value (model0
.get_lvalue (a
, &ctxt
), &test_sval
, &ctxt
);
8005 model1
.set_value (model1
.get_lvalue (a
, &ctxt
), &test_sval
, &ctxt
);
8006 ASSERT_EQ (model0
, model1
);
8008 /* They should be mergeable, and the result should be the same. */
8009 region_model
merged (&mgr
);
8010 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8011 ASSERT_EQ (model0
, merged
);
8012 /* In particular, "a" should have the placeholder value. */
8013 ASSERT_EQ (merged
.get_rvalue (a
, &ctxt
), &test_sval
);
8016 /* Verify handling of a global. */
8018 test_region_model_context ctxt
;
8019 region_model
model0 (&mgr
);
8020 region_model
model1 (&mgr
);
8022 placeholder_svalue
test_sval (mgr
.alloc_symbol_id (),
8023 integer_type_node
, "test sval");
8024 model0
.set_value (model0
.get_lvalue (x
, &ctxt
), &test_sval
, &ctxt
);
8025 model1
.set_value (model1
.get_lvalue (x
, &ctxt
), &test_sval
, &ctxt
);
8026 ASSERT_EQ (model0
, model1
);
8028 /* They should be mergeable, and the result should be the same. */
8029 region_model
merged (&mgr
);
8030 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8031 ASSERT_EQ (model0
, merged
);
8032 /* In particular, "x" should have the placeholder value. */
8033 ASSERT_EQ (merged
.get_rvalue (x
, &ctxt
), &test_sval
);
8036 /* Use global-handling to verify various combinations of values. */
8038 /* Two equal constant values. */
8040 region_model
merged (&mgr
);
8041 const svalue
*merged_x_sval
;
8042 assert_region_models_merge (x
, int_42
, int_42
, &merged
, &merged_x_sval
);
8044 /* In particular, there should be a constant value for "x". */
8045 ASSERT_EQ (merged_x_sval
->get_kind (), SK_CONSTANT
);
8046 ASSERT_EQ (merged_x_sval
->dyn_cast_constant_svalue ()->get_constant (),
8050 /* Two non-equal constant values. */
8052 region_model
merged (&mgr
);
8053 const svalue
*merged_x_sval
;
8054 assert_region_models_merge (x
, int_42
, int_113
, &merged
, &merged_x_sval
);
8056 /* In particular, there should be a "widening" value for "x". */
8057 ASSERT_EQ (merged_x_sval
->get_kind (), SK_WIDENING
);
8060 /* Initial and constant. */
8062 region_model
merged (&mgr
);
8063 const svalue
*merged_x_sval
;
8064 assert_region_models_merge (x
, NULL_TREE
, int_113
, &merged
, &merged_x_sval
);
8066 /* In particular, there should be an unknown value for "x". */
8067 ASSERT_EQ (merged_x_sval
->get_kind (), SK_UNKNOWN
);
8070 /* Constant and initial. */
8072 region_model
merged (&mgr
);
8073 const svalue
*merged_x_sval
;
8074 assert_region_models_merge (x
, int_42
, NULL_TREE
, &merged
, &merged_x_sval
);
8076 /* In particular, there should be an unknown value for "x". */
8077 ASSERT_EQ (merged_x_sval
->get_kind (), SK_UNKNOWN
);
8080 /* Unknown and constant. */
8083 /* Pointers: NULL and NULL. */
8086 /* Pointers: NULL and non-NULL. */
8089 /* Pointers: non-NULL and non-NULL: ptr to a local. */
8091 region_model
model0 (&mgr
);
8092 model0
.push_frame (DECL_STRUCT_FUNCTION (test_fndecl
), NULL
, NULL
);
8093 model0
.set_value (model0
.get_lvalue (p
, NULL
),
8094 model0
.get_rvalue (addr_of_a
, NULL
), NULL
);
8096 region_model
model1 (model0
);
8097 ASSERT_EQ (model0
, model1
);
8099 /* They should be mergeable, and the result should be the same. */
8100 region_model
merged (&mgr
);
8101 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8102 ASSERT_EQ (model0
, merged
);
8105 /* Pointers: non-NULL and non-NULL: ptr to a global. */
8107 region_model
merged (&mgr
);
8108 /* p == &y in both input models. */
8109 const svalue
*merged_p_sval
;
8110 assert_region_models_merge (p
, addr_of_y
, addr_of_y
, &merged
,
8113 /* We should get p == &y in the merged model. */
8114 ASSERT_EQ (merged_p_sval
->get_kind (), SK_REGION
);
8115 const region_svalue
*merged_p_ptr
8116 = merged_p_sval
->dyn_cast_region_svalue ();
8117 const region
*merged_p_star_reg
= merged_p_ptr
->get_pointee ();
8118 ASSERT_EQ (merged_p_star_reg
, merged
.get_lvalue (y
, NULL
));
8121 /* Pointers: non-NULL ptrs to different globals: should be unknown. */
8123 region_model
merged (&mgr
);
8124 /* x == &y vs x == &z in the input models; these are actually casts
8125 of the ptrs to "int". */
8126 const svalue
*merged_x_sval
;
8128 assert_region_models_merge (x
, addr_of_y
, addr_of_z
, &merged
,
8131 /* We should get x == unknown in the merged model. */
8132 ASSERT_EQ (merged_x_sval
->get_kind (), SK_UNKNOWN
);
8135 /* Pointers: non-NULL and non-NULL: ptr to a heap region. */
8137 test_region_model_context ctxt
;
8138 region_model
model0 (&mgr
);
8139 tree size
= build_int_cst (size_type_node
, 1024);
8140 const svalue
*size_sval
= mgr
.get_or_create_constant_svalue (size
);
8141 const region
*new_reg
8142 = model0
.get_or_create_region_for_heap_alloc (size_sval
, &ctxt
);
8143 const svalue
*ptr_sval
= mgr
.get_ptr_svalue (ptr_type_node
, new_reg
);
8144 model0
.set_value (model0
.get_lvalue (p
, &ctxt
),
8147 region_model
model1 (model0
);
8149 ASSERT_EQ (model0
, model1
);
8151 region_model
merged (&mgr
);
8152 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8154 /* The merged model ought to be identical. */
8155 ASSERT_EQ (model0
, merged
);
8158 /* Two regions sharing the same placeholder svalue should continue sharing
8159 it after self-merger. */
8161 test_region_model_context ctxt
;
8162 region_model
model0 (&mgr
);
8163 placeholder_svalue
placeholder_sval (mgr
.alloc_symbol_id (),
8164 integer_type_node
, "test");
8165 model0
.set_value (model0
.get_lvalue (x
, &ctxt
),
8166 &placeholder_sval
, &ctxt
);
8167 model0
.set_value (model0
.get_lvalue (y
, &ctxt
), &placeholder_sval
, &ctxt
);
8168 region_model
model1 (model0
);
8170 /* They should be mergeable, and the result should be the same. */
8171 region_model
merged (&mgr
);
8172 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8173 ASSERT_EQ (model0
, merged
);
8175 /* In particular, we should have x == y. */
8176 ASSERT_EQ (merged
.eval_condition (x
, EQ_EXPR
, y
, &ctxt
),
8177 tristate (tristate::TS_TRUE
));
8181 region_model
model0 (&mgr
);
8182 region_model
model1 (&mgr
);
8183 test_region_model_context ctxt
;
8184 model0
.add_constraint (x
, EQ_EXPR
, int_42
, &ctxt
);
8185 model1
.add_constraint (x
, NE_EXPR
, int_42
, &ctxt
);
8186 region_model
merged (&mgr
);
8187 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8191 region_model
model0 (&mgr
);
8192 region_model
model1 (&mgr
);
8193 test_region_model_context ctxt
;
8194 model0
.add_constraint (x
, EQ_EXPR
, int_42
, &ctxt
);
8195 model1
.add_constraint (x
, NE_EXPR
, int_42
, &ctxt
);
8196 model1
.add_constraint (x
, EQ_EXPR
, int_113
, &ctxt
);
8197 region_model
merged (&mgr
);
8198 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8201 // TODO: what can't we merge? need at least one such test
8203 /* TODO: various things
8206 - every combination, but in particular
8212 test_region_model_context ctxt
;
8213 region_model
model0 (&mgr
);
8215 const region
*x_reg
= model0
.get_lvalue (x
, &ctxt
);
8216 const region
*x_as_ptr
= mgr
.get_cast_region (x_reg
, ptr_type_node
);
8217 model0
.set_value (x_as_ptr
, model0
.get_rvalue (addr_of_y
, &ctxt
), &ctxt
);
8219 region_model
model1 (model0
);
8220 ASSERT_EQ (model1
, model0
);
8222 /* They should be mergeable, and the result should be the same. */
8223 region_model
merged (&mgr
);
8224 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8227 /* Verify that we can merge a model in which a local in an older stack
8228 frame points to a local in a more recent stack frame. */
8230 region_model
model0 (&mgr
);
8231 model0
.push_frame (DECL_STRUCT_FUNCTION (test_fndecl
), NULL
, NULL
);
8232 const region
*q_in_first_frame
= model0
.get_lvalue (q
, NULL
);
8234 /* Push a second frame. */
8235 const region
*reg_2nd_frame
8236 = model0
.push_frame (DECL_STRUCT_FUNCTION (test_fndecl
), NULL
, NULL
);
8238 /* Have a pointer in the older frame point to a local in the
8239 more recent frame. */
8240 const svalue
*sval_ptr
= model0
.get_rvalue (addr_of_a
, NULL
);
8241 model0
.set_value (q_in_first_frame
, sval_ptr
, NULL
);
8243 /* Verify that it's pointing at the newer frame. */
8244 const region
*reg_pointee
= sval_ptr
->maybe_get_region ();
8245 ASSERT_EQ (reg_pointee
->get_parent_region (), reg_2nd_frame
);
8247 model0
.canonicalize ();
8249 region_model
model1 (model0
);
8250 ASSERT_EQ (model0
, model1
);
8252 /* They should be mergeable, and the result should be the same
8253 (after canonicalization, at least). */
8254 region_model
merged (&mgr
);
8255 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8256 merged
.canonicalize ();
8257 ASSERT_EQ (model0
, merged
);
8260 /* Verify that we can merge a model in which a local points to a global. */
8262 region_model
model0 (&mgr
);
8263 model0
.push_frame (DECL_STRUCT_FUNCTION (test_fndecl
), NULL
, NULL
);
8264 model0
.set_value (model0
.get_lvalue (q
, NULL
),
8265 model0
.get_rvalue (addr_of_y
, NULL
), NULL
);
8267 region_model
model1 (model0
);
8268 ASSERT_EQ (model0
, model1
);
8270 /* They should be mergeable, and the result should be the same
8271 (after canonicalization, at least). */
8272 region_model
merged (&mgr
);
8273 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8274 ASSERT_EQ (model0
, merged
);
8278 /* Verify that constraints are correctly merged when merging region_model
8282 test_constraint_merging ()
8284 tree int_0
= build_int_cst (integer_type_node
, 0);
8285 tree int_5
= build_int_cst (integer_type_node
, 5);
8286 tree x
= build_global_decl ("x", integer_type_node
);
8287 tree y
= build_global_decl ("y", integer_type_node
);
8288 tree z
= build_global_decl ("z", integer_type_node
);
8289 tree n
= build_global_decl ("n", integer_type_node
);
8291 region_model_manager mgr
;
8292 test_region_model_context ctxt
;
8294 /* model0: 0 <= (x == y) < n. */
8295 region_model
model0 (&mgr
);
8296 model0
.add_constraint (x
, EQ_EXPR
, y
, &ctxt
);
8297 model0
.add_constraint (x
, GE_EXPR
, int_0
, NULL
);
8298 model0
.add_constraint (x
, LT_EXPR
, n
, NULL
);
8300 /* model1: z != 5 && (0 <= x < n). */
8301 region_model
model1 (&mgr
);
8302 model1
.add_constraint (z
, NE_EXPR
, int_5
, NULL
);
8303 model1
.add_constraint (x
, GE_EXPR
, int_0
, NULL
);
8304 model1
.add_constraint (x
, LT_EXPR
, n
, NULL
);
8306 /* They should be mergeable; the merged constraints should
8307 be: (0 <= x < n). */
8308 program_point
point (program_point::origin (mgr
));
8309 region_model
merged (&mgr
);
8310 ASSERT_TRUE (model0
.can_merge_with_p (model1
, point
, &merged
));
8312 ASSERT_EQ (merged
.eval_condition (x
, GE_EXPR
, int_0
, &ctxt
),
8313 tristate (tristate::TS_TRUE
));
8314 ASSERT_EQ (merged
.eval_condition (x
, LT_EXPR
, n
, &ctxt
),
8315 tristate (tristate::TS_TRUE
));
8317 ASSERT_EQ (merged
.eval_condition (z
, NE_EXPR
, int_5
, &ctxt
),
8318 tristate (tristate::TS_UNKNOWN
));
8319 ASSERT_EQ (merged
.eval_condition (x
, LT_EXPR
, y
, &ctxt
),
8320 tristate (tristate::TS_UNKNOWN
));
8323 /* Verify that widening_svalue::eval_condition_without_cm works as
8327 test_widening_constraints ()
8329 region_model_manager mgr
;
8330 function_point
point (program_point::origin (mgr
).get_function_point ());
8331 tree int_0
= build_int_cst (integer_type_node
, 0);
8332 tree int_m1
= build_int_cst (integer_type_node
, -1);
8333 tree int_1
= build_int_cst (integer_type_node
, 1);
8334 tree int_256
= build_int_cst (integer_type_node
, 256);
8335 test_region_model_context ctxt
;
8336 const svalue
*int_0_sval
= mgr
.get_or_create_constant_svalue (int_0
);
8337 const svalue
*int_1_sval
= mgr
.get_or_create_constant_svalue (int_1
);
8338 const svalue
*w_zero_then_one_sval
8339 = mgr
.get_or_create_widening_svalue (integer_type_node
, point
,
8340 int_0_sval
, int_1_sval
);
8341 const widening_svalue
*w_zero_then_one
8342 = w_zero_then_one_sval
->dyn_cast_widening_svalue ();
8343 ASSERT_EQ (w_zero_then_one
->get_direction (),
8344 widening_svalue::DIR_ASCENDING
);
8345 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (LT_EXPR
, int_m1
),
8346 tristate::TS_FALSE
);
8347 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (LT_EXPR
, int_0
),
8348 tristate::TS_FALSE
);
8349 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (LT_EXPR
, int_1
),
8350 tristate::TS_UNKNOWN
);
8351 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (LT_EXPR
, int_256
),
8352 tristate::TS_UNKNOWN
);
8354 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (LE_EXPR
, int_m1
),
8355 tristate::TS_FALSE
);
8356 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (LE_EXPR
, int_0
),
8357 tristate::TS_UNKNOWN
);
8358 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (LE_EXPR
, int_1
),
8359 tristate::TS_UNKNOWN
);
8360 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (LE_EXPR
, int_256
),
8361 tristate::TS_UNKNOWN
);
8363 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (GT_EXPR
, int_m1
),
8365 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (GT_EXPR
, int_0
),
8366 tristate::TS_UNKNOWN
);
8367 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (GT_EXPR
, int_1
),
8368 tristate::TS_UNKNOWN
);
8369 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (GT_EXPR
, int_256
),
8370 tristate::TS_UNKNOWN
);
8372 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (GE_EXPR
, int_m1
),
8374 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (GE_EXPR
, int_0
),
8376 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (GE_EXPR
, int_1
),
8377 tristate::TS_UNKNOWN
);
8378 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (GE_EXPR
, int_256
),
8379 tristate::TS_UNKNOWN
);
8381 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (EQ_EXPR
, int_m1
),
8382 tristate::TS_FALSE
);
8383 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (EQ_EXPR
, int_0
),
8384 tristate::TS_UNKNOWN
);
8385 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (EQ_EXPR
, int_1
),
8386 tristate::TS_UNKNOWN
);
8387 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (EQ_EXPR
, int_256
),
8388 tristate::TS_UNKNOWN
);
8390 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (NE_EXPR
, int_m1
),
8392 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (NE_EXPR
, int_0
),
8393 tristate::TS_UNKNOWN
);
8394 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (NE_EXPR
, int_1
),
8395 tristate::TS_UNKNOWN
);
8396 ASSERT_EQ (w_zero_then_one
->eval_condition_without_cm (NE_EXPR
, int_256
),
8397 tristate::TS_UNKNOWN
);
8400 /* Verify merging constraints for states simulating successive iterations
8403 for (i = 0; i < 256; i++)
8410 i_11 = PHI <i_15(2), i_23(3)>
8420 and thus these ops (and resultant states):
8423 add_constraint (i_11 <= 255) [for the true edge]
8424 {i_11: 0} [constraint was a no-op]
8428 {i_11: WIDENED (at phi, 0, 1)}
8429 add_constraint (i_11 <= 255) [for the true edge]
8430 {i_11: WIDENED (at phi, 0, 1); WIDENED <= 255}
8432 {i_23: (WIDENED (at phi, 0, 1) + 1); WIDENED <= 255}
8433 i_11 = PHI(); merge with state at phi above
8434 {i_11: WIDENED (at phi, 0, 1); WIDENED <= 256}
8435 [changing meaning of "WIDENED" here]
8437 T: {i_11: WIDENED (at phi, 0, 1); WIDENED <= 255}; cache hit
8444 region_model_manager mgr
;
8445 program_point
point (program_point::origin (mgr
));
8447 tree int_0
= build_int_cst (integer_type_node
, 0);
8448 tree int_1
= build_int_cst (integer_type_node
, 1);
8449 tree int_256
= build_int_cst (integer_type_node
, 256);
8450 tree i
= build_global_decl ("i", integer_type_node
);
8452 test_region_model_context ctxt
;
8455 region_model
model0 (&mgr
);
8456 model0
.set_value (i
, int_0
, &ctxt
);
8459 region_model
model1 (&mgr
);
8460 model1
.set_value (i
, int_1
, &ctxt
);
8462 /* Should merge "i" to a widened value. */
8463 region_model
model2 (&mgr
);
8464 ASSERT_TRUE (model1
.can_merge_with_p (model0
, point
, &model2
));
8465 const svalue
*merged_i
= model2
.get_rvalue (i
, &ctxt
);
8466 ASSERT_EQ (merged_i
->get_kind (), SK_WIDENING
);
8467 const widening_svalue
*w
= merged_i
->dyn_cast_widening_svalue ();
8468 ASSERT_EQ (w
->get_direction (), widening_svalue::DIR_ASCENDING
);
8470 /* Add constraint: i < 256 */
8471 model2
.add_constraint (i
, LT_EXPR
, int_256
, &ctxt
);
8472 ASSERT_EQ (model2
.eval_condition (i
, LT_EXPR
, int_256
, &ctxt
),
8473 tristate (tristate::TS_TRUE
));
8474 ASSERT_EQ (model2
.eval_condition (i
, GE_EXPR
, int_0
, &ctxt
),
8475 tristate (tristate::TS_TRUE
));
8477 /* Try merging with the initial state. */
8478 region_model
model3 (&mgr
);
8479 ASSERT_TRUE (model2
.can_merge_with_p (model0
, point
, &model3
));
8480 /* Merging the merged value with the initial value should be idempotent,
8481 so that the analysis converges. */
8482 ASSERT_EQ (model3
.get_rvalue (i
, &ctxt
), merged_i
);
8483 /* Merger of 0 and a widening value with constraint < CST
8484 should retain the constraint, even though it was implicit
8486 ASSERT_EQ (model3
.eval_condition (i
, LT_EXPR
, int_256
, &ctxt
),
8487 tristate (tristate::TS_TRUE
));
8488 /* ...and we should have equality: the analysis should have converged. */
8489 ASSERT_EQ (model3
, model2
);
8491 /* "i_23 = i_11 + 1;" */
8492 region_model
model4 (model3
);
8493 ASSERT_EQ (model4
, model2
);
8494 model4
.set_value (i
, build2 (PLUS_EXPR
, integer_type_node
, i
, int_1
), &ctxt
);
8495 const svalue
*plus_one
= model4
.get_rvalue (i
, &ctxt
);
8496 ASSERT_EQ (plus_one
->get_kind (), SK_BINOP
);
8498 /* Try merging with the "i: 1" state. */
8499 region_model
model5 (&mgr
);
8500 ASSERT_TRUE (model4
.can_merge_with_p (model1
, point
, &model5
));
8501 ASSERT_EQ (model5
.get_rvalue (i
, &ctxt
), plus_one
);
8502 ASSERT_EQ (model5
, model4
);
8504 /* "i_11 = PHI();" merge with state at phi above.
8505 For i, we should have a merger of WIDENING with WIDENING + 1,
8506 and this should be WIDENING again. */
8507 region_model
model6 (&mgr
);
8508 ASSERT_TRUE (model5
.can_merge_with_p (model2
, point
, &model6
));
8509 const svalue
*merged_widening
= model6
.get_rvalue (i
, &ctxt
);
8510 ASSERT_EQ (merged_widening
->get_kind (), SK_WIDENING
);
8513 /* Verify that if we mark a pointer to a malloc-ed region as non-NULL,
8514 all cast pointers to that region are also known to be non-NULL. */
8517 test_malloc_constraints ()
8519 region_model_manager mgr
;
8520 region_model
model (&mgr
);
8521 tree p
= build_global_decl ("p", ptr_type_node
);
8522 tree char_star
= build_pointer_type (char_type_node
);
8523 tree q
= build_global_decl ("q", char_star
);
8524 tree null_ptr
= build_int_cst (ptr_type_node
, 0);
8526 const svalue
*size_in_bytes
8527 = mgr
.get_or_create_unknown_svalue (size_type_node
);
8529 = model
.get_or_create_region_for_heap_alloc (size_in_bytes
, NULL
);
8530 const svalue
*sval
= mgr
.get_ptr_svalue (ptr_type_node
, reg
);
8531 model
.set_value (model
.get_lvalue (p
, NULL
), sval
, NULL
);
8532 model
.set_value (q
, p
, NULL
);
8534 ASSERT_CONDITION_UNKNOWN (model
, p
, NE_EXPR
, null_ptr
);
8535 ASSERT_CONDITION_UNKNOWN (model
, p
, EQ_EXPR
, null_ptr
);
8536 ASSERT_CONDITION_UNKNOWN (model
, q
, NE_EXPR
, null_ptr
);
8537 ASSERT_CONDITION_UNKNOWN (model
, q
, EQ_EXPR
, null_ptr
);
8539 model
.add_constraint (p
, NE_EXPR
, null_ptr
, NULL
);
8541 ASSERT_CONDITION_TRUE (model
, p
, NE_EXPR
, null_ptr
);
8542 ASSERT_CONDITION_FALSE (model
, p
, EQ_EXPR
, null_ptr
);
8543 ASSERT_CONDITION_TRUE (model
, q
, NE_EXPR
, null_ptr
);
8544 ASSERT_CONDITION_FALSE (model
, q
, EQ_EXPR
, null_ptr
);
8547 /* Smoketest of getting and setting the value of a variable. */
8553 tree i
= build_global_decl ("i", integer_type_node
);
8555 tree int_17
= build_int_cst (integer_type_node
, 17);
8556 tree int_m3
= build_int_cst (integer_type_node
, -3);
8558 region_model_manager mgr
;
8559 region_model
model (&mgr
);
8561 const region
*i_reg
= model
.get_lvalue (i
, NULL
);
8562 ASSERT_EQ (i_reg
->get_kind (), RK_DECL
);
8564 /* Reading "i" should give a symbolic "initial value". */
8565 const svalue
*sval_init
= model
.get_rvalue (i
, NULL
);
8566 ASSERT_EQ (sval_init
->get_kind (), SK_INITIAL
);
8567 ASSERT_EQ (sval_init
->dyn_cast_initial_svalue ()->get_region (), i_reg
);
8568 /* ..and doing it again should give the same "initial value". */
8569 ASSERT_EQ (model
.get_rvalue (i
, NULL
), sval_init
);
8572 model
.set_value (i
, int_17
, NULL
);
8573 ASSERT_EQ (model
.get_rvalue (i
, NULL
),
8574 model
.get_rvalue (int_17
, NULL
));
8577 model
.set_value (i
, int_m3
, NULL
);
8578 ASSERT_EQ (model
.get_rvalue (i
, NULL
),
8579 model
.get_rvalue (int_m3
, NULL
));
8581 /* Verify get_offset for "i". */
8583 region_offset offset
= i_reg
->get_offset (&mgr
);
8584 ASSERT_EQ (offset
.get_base_region (), i_reg
);
8585 ASSERT_EQ (offset
.get_bit_offset (), 0);
8592 /* "int arr[10];" */
8593 tree tlen
= size_int (10);
8595 = build_array_type (integer_type_node
, build_index_type (tlen
));
8596 tree arr
= build_global_decl ("arr", arr_type
);
8599 tree i
= build_global_decl ("i", integer_type_node
);
8601 tree int_0
= build_int_cst (integer_type_node
, 0);
8602 tree int_1
= build_int_cst (integer_type_node
, 1);
8604 tree arr_0
= build4 (ARRAY_REF
, integer_type_node
,
8605 arr
, int_0
, NULL_TREE
, NULL_TREE
);
8606 tree arr_1
= build4 (ARRAY_REF
, integer_type_node
,
8607 arr
, int_1
, NULL_TREE
, NULL_TREE
);
8608 tree arr_i
= build4 (ARRAY_REF
, integer_type_node
,
8609 arr
, i
, NULL_TREE
, NULL_TREE
);
8611 tree int_17
= build_int_cst (integer_type_node
, 17);
8612 tree int_42
= build_int_cst (integer_type_node
, 42);
8613 tree int_m3
= build_int_cst (integer_type_node
, -3);
8615 region_model_manager mgr
;
8616 region_model
model (&mgr
);
8617 /* "arr[0] = 17;". */
8618 model
.set_value (arr_0
, int_17
, NULL
);
8619 /* "arr[1] = -3;". */
8620 model
.set_value (arr_1
, int_m3
, NULL
);
8622 ASSERT_EQ (model
.get_rvalue (arr_0
, NULL
), model
.get_rvalue (int_17
, NULL
));
8623 ASSERT_EQ (model
.get_rvalue (arr_1
, NULL
), model
.get_rvalue (int_m3
, NULL
));
8625 /* Overwrite a pre-existing binding: "arr[1] = 42;". */
8626 model
.set_value (arr_1
, int_42
, NULL
);
8627 ASSERT_EQ (model
.get_rvalue (arr_1
, NULL
), model
.get_rvalue (int_42
, NULL
));
8629 /* Verify get_offset for "arr[0]". */
8631 const region
*arr_0_reg
= model
.get_lvalue (arr_0
, NULL
);
8632 region_offset offset
= arr_0_reg
->get_offset (&mgr
);
8633 ASSERT_EQ (offset
.get_base_region (), model
.get_lvalue (arr
, NULL
));
8634 ASSERT_EQ (offset
.get_bit_offset (), 0);
8637 /* Verify get_offset for "arr[1]". */
8639 const region
*arr_1_reg
= model
.get_lvalue (arr_1
, NULL
);
8640 region_offset offset
= arr_1_reg
->get_offset (&mgr
);
8641 ASSERT_EQ (offset
.get_base_region (), model
.get_lvalue (arr
, NULL
));
8642 ASSERT_EQ (offset
.get_bit_offset (), INT_TYPE_SIZE
);
8645 /* Verify get_offset for "arr[i]". */
8647 const region
*arr_i_reg
= model
.get_lvalue (arr_i
, NULL
);
8648 region_offset offset
= arr_i_reg
->get_offset (&mgr
);
8649 ASSERT_EQ (offset
.get_base_region (), model
.get_lvalue (arr
, NULL
));
8650 ASSERT_EQ (offset
.get_symbolic_byte_offset ()->get_kind (), SK_BINOP
);
8653 /* "arr[i] = i;" - this should remove the earlier bindings. */
8654 model
.set_value (arr_i
, i
, NULL
);
8655 ASSERT_EQ (model
.get_rvalue (arr_i
, NULL
), model
.get_rvalue (i
, NULL
));
8656 ASSERT_EQ (model
.get_rvalue (arr_0
, NULL
)->get_kind (), SK_UNKNOWN
);
8658 /* "arr[0] = 17;" - this should remove the arr[i] binding. */
8659 model
.set_value (arr_0
, int_17
, NULL
);
8660 ASSERT_EQ (model
.get_rvalue (arr_0
, NULL
), model
.get_rvalue (int_17
, NULL
));
8661 ASSERT_EQ (model
.get_rvalue (arr_i
, NULL
)->get_kind (), SK_UNKNOWN
);
8664 /* Smoketest of dereferencing a pointer via MEM_REF. */
8674 tree x
= build_global_decl ("x", integer_type_node
);
8675 tree int_star
= build_pointer_type (integer_type_node
);
8676 tree p
= build_global_decl ("p", int_star
);
8678 tree int_17
= build_int_cst (integer_type_node
, 17);
8679 tree addr_of_x
= build1 (ADDR_EXPR
, int_star
, x
);
8680 tree offset_0
= build_int_cst (integer_type_node
, 0);
8681 tree star_p
= build2 (MEM_REF
, integer_type_node
, p
, offset_0
);
8683 region_model_manager mgr
;
8684 region_model
model (&mgr
);
8687 model
.set_value (x
, int_17
, NULL
);
8690 model
.set_value (p
, addr_of_x
, NULL
);
8692 const svalue
*sval
= model
.get_rvalue (star_p
, NULL
);
8693 ASSERT_EQ (sval
->maybe_get_constant (), int_17
);
8696 /* Test for a POINTER_PLUS_EXPR followed by a MEM_REF.
8697 Analogous to this code:
8698 void test_6 (int a[10])
8700 __analyzer_eval (a[3] == 42); [should be UNKNOWN]
8702 __analyzer_eval (a[3] == 42); [should be TRUE]
8704 from data-model-1.c, which looks like this at the gimple level:
8705 # __analyzer_eval (a[3] == 42); [should be UNKNOWN]
8706 int *_1 = a_10(D) + 12; # POINTER_PLUS_EXPR
8707 int _2 = *_1; # MEM_REF
8708 _Bool _3 = _2 == 42;
8710 __analyzer_eval (_4);
8713 int *_5 = a_10(D) + 12; # POINTER_PLUS_EXPR
8716 # __analyzer_eval (a[3] == 42); [should be TRUE]
8717 int *_6 = a_10(D) + 12; # POINTER_PLUS_EXPR
8718 int _7 = *_6; # MEM_REF
8719 _Bool _8 = _7 == 42;
8721 __analyzer_eval (_9); */
8724 test_POINTER_PLUS_EXPR_then_MEM_REF ()
8726 tree int_star
= build_pointer_type (integer_type_node
);
8727 tree a
= build_global_decl ("a", int_star
);
8728 tree offset_12
= build_int_cst (size_type_node
, 12);
8729 tree pointer_plus_expr
= build2 (POINTER_PLUS_EXPR
, int_star
, a
, offset_12
);
8730 tree offset_0
= build_int_cst (integer_type_node
, 0);
8731 tree mem_ref
= build2 (MEM_REF
, integer_type_node
,
8732 pointer_plus_expr
, offset_0
);
8733 region_model_manager mgr
;
8734 region_model
m (&mgr
);
8736 tree int_42
= build_int_cst (integer_type_node
, 42);
8737 m
.set_value (mem_ref
, int_42
, NULL
);
8738 ASSERT_EQ (m
.get_rvalue (mem_ref
, NULL
)->maybe_get_constant (), int_42
);
8741 /* Verify that malloc works. */
8746 tree int_star
= build_pointer_type (integer_type_node
);
8747 tree p
= build_global_decl ("p", int_star
);
8748 tree n
= build_global_decl ("n", integer_type_node
);
8749 tree n_times_4
= build2 (MULT_EXPR
, size_type_node
,
8750 n
, build_int_cst (size_type_node
, 4));
8752 region_model_manager mgr
;
8753 test_region_model_context ctxt
;
8754 region_model
model (&mgr
);
8756 /* "p = malloc (n * 4);". */
8757 const svalue
*size_sval
= model
.get_rvalue (n_times_4
, &ctxt
);
8759 = model
.get_or_create_region_for_heap_alloc (size_sval
, &ctxt
);
8760 const svalue
*ptr
= mgr
.get_ptr_svalue (int_star
, reg
);
8761 model
.set_value (model
.get_lvalue (p
, &ctxt
), ptr
, &ctxt
);
8762 ASSERT_EQ (model
.get_capacity (reg
), size_sval
);
8765 /* Verify that alloca works. */
8770 auto_vec
<tree
> param_types
;
8771 tree fndecl
= make_fndecl (integer_type_node
,
8774 allocate_struct_function (fndecl
, true);
8777 tree int_star
= build_pointer_type (integer_type_node
);
8778 tree p
= build_global_decl ("p", int_star
);
8779 tree n
= build_global_decl ("n", integer_type_node
);
8780 tree n_times_4
= build2 (MULT_EXPR
, size_type_node
,
8781 n
, build_int_cst (size_type_node
, 4));
8783 region_model_manager mgr
;
8784 test_region_model_context ctxt
;
8785 region_model
model (&mgr
);
8787 /* Push stack frame. */
8788 const region
*frame_reg
8789 = model
.push_frame (DECL_STRUCT_FUNCTION (fndecl
),
8791 /* "p = alloca (n * 4);". */
8792 const svalue
*size_sval
= model
.get_rvalue (n_times_4
, &ctxt
);
8793 const region
*reg
= model
.create_region_for_alloca (size_sval
, &ctxt
);
8794 ASSERT_EQ (reg
->get_parent_region (), frame_reg
);
8795 const svalue
*ptr
= mgr
.get_ptr_svalue (int_star
, reg
);
8796 model
.set_value (model
.get_lvalue (p
, &ctxt
), ptr
, &ctxt
);
8797 ASSERT_EQ (model
.get_capacity (reg
), size_sval
);
8799 /* Verify that the pointers to the alloca region are replaced by
8800 poisoned values when the frame is popped. */
8801 model
.pop_frame (NULL
, NULL
, &ctxt
);
8802 ASSERT_EQ (model
.get_rvalue (p
, NULL
)->get_kind (), SK_POISONED
);
8805 /* Verify that svalue::involves_p works. */
8810 region_model_manager mgr
;
8811 tree int_star
= build_pointer_type (integer_type_node
);
8812 tree p
= build_global_decl ("p", int_star
);
8813 tree q
= build_global_decl ("q", int_star
);
8815 test_region_model_context ctxt
;
8816 region_model
model (&mgr
);
8817 const svalue
*p_init
= model
.get_rvalue (p
, &ctxt
);
8818 const svalue
*q_init
= model
.get_rvalue (q
, &ctxt
);
8820 ASSERT_TRUE (p_init
->involves_p (p_init
));
8821 ASSERT_FALSE (p_init
->involves_p (q_init
));
8823 const region
*star_p_reg
= mgr
.get_symbolic_region (p_init
);
8824 const region
*star_q_reg
= mgr
.get_symbolic_region (q_init
);
8826 const svalue
*init_star_p
= mgr
.get_or_create_initial_value (star_p_reg
);
8827 const svalue
*init_star_q
= mgr
.get_or_create_initial_value (star_q_reg
);
8829 ASSERT_TRUE (init_star_p
->involves_p (p_init
));
8830 ASSERT_FALSE (p_init
->involves_p (init_star_p
));
8831 ASSERT_FALSE (init_star_p
->involves_p (q_init
));
8832 ASSERT_TRUE (init_star_q
->involves_p (q_init
));
8833 ASSERT_FALSE (init_star_q
->involves_p (p_init
));
8836 /* Run all of the selftests within this file. */
8839 analyzer_region_model_cc_tests ()
8841 test_tree_cmp_on_constants ();
8845 test_get_representative_tree ();
8846 test_unique_constants ();
8847 test_unique_unknowns ();
8848 test_initial_svalue_folding ();
8849 test_unaryop_svalue_folding ();
8850 test_binop_svalue_folding ();
8851 test_sub_svalue_folding ();
8852 test_bits_within_svalue_folding ();
8853 test_descendent_of_p ();
8854 test_bit_range_regions ();
8856 test_compound_assignment ();
8857 test_stack_frames ();
8858 test_get_representative_path_var ();
8860 test_canonicalization_2 ();
8861 test_canonicalization_3 ();
8862 test_canonicalization_4 ();
8863 test_state_merging ();
8864 test_constraint_merging ();
8865 test_widening_constraints ();
8866 test_iteration_1 ();
8867 test_malloc_constraints ();
8871 test_POINTER_PLUS_EXPR_then_MEM_REF ();
8877 } // namespace selftest
8879 #endif /* CHECKING_P */
8883 #endif /* #if ENABLE_ANALYZER */