]> gcc.gnu.org Git - gcc.git/blob - gcc/analyzer/program-state.cc
analyzer: simplify some includes
[gcc.git] / gcc / analyzer / program-state.cc
1 /* Classes for representing the state of interest at a given path of analysis.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5 This file is part of GCC.
6
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)
10 any later version.
11
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.
16
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/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "diagnostic-core.h"
26 #include "diagnostic.h"
27 #include "analyzer/analyzer.h"
28 #include "analyzer/analyzer-logging.h"
29 #include "analyzer/sm.h"
30 #include "sbitmap.h"
31 #include "bitmap.h"
32 #include "ordered-hash-map.h"
33 #include "selftest.h"
34 #include "analyzer/call-string.h"
35 #include "analyzer/program-point.h"
36 #include "analyzer/store.h"
37 #include "analyzer/region-model.h"
38 #include "analyzer/program-state.h"
39 #include "analyzer/constraint-manager.h"
40 #include "diagnostic-event-id.h"
41 #include "analyzer/pending-diagnostic.h"
42 #include "analyzer/diagnostic-manager.h"
43 #include "cfg.h"
44 #include "basic-block.h"
45 #include "gimple.h"
46 #include "gimple-iterator.h"
47 #include "cgraph.h"
48 #include "digraph.h"
49 #include "analyzer/supergraph.h"
50 #include "analyzer/program-state.h"
51 #include "analyzer/exploded-graph.h"
52 #include "analyzer/state-purge.h"
53 #include "analyzer/call-summary.h"
54 #include "analyzer/analyzer-selftests.h"
55
56 #if ENABLE_ANALYZER
57
58 namespace ana {
59
60 /* class extrinsic_state. */
61
62 /* Dump a multiline representation of this state to PP. */
63
64 void
65 extrinsic_state::dump_to_pp (pretty_printer *pp) const
66 {
67 pp_printf (pp, "extrinsic_state: %i checker(s)\n", get_num_checkers ());
68 unsigned i;
69 state_machine *checker;
70 FOR_EACH_VEC_ELT (m_checkers, i, checker)
71 {
72 pp_printf (pp, "m_checkers[%i]: %qs\n", i, checker->get_name ());
73 checker->dump_to_pp (pp);
74 }
75 }
76
77 /* Dump a multiline representation of this state to OUTF. */
78
79 void
80 extrinsic_state::dump_to_file (FILE *outf) const
81 {
82 pretty_printer pp;
83 if (outf == stderr)
84 pp_show_color (&pp) = pp_show_color (global_dc->printer);
85 pp.buffer->stream = outf;
86 dump_to_pp (&pp);
87 pp_flush (&pp);
88 }
89
90 /* Dump a multiline representation of this state to stderr. */
91
92 DEBUG_FUNCTION void
93 extrinsic_state::dump () const
94 {
95 dump_to_file (stderr);
96 }
97
98 /* Return a new json::object of the form
99 {"checkers" : array of objects, one for each state_machine}. */
100
101 json::object *
102 extrinsic_state::to_json () const
103 {
104 json::object *ext_state_obj = new json::object ();
105
106 {
107 json::array *checkers_arr = new json::array ();
108 unsigned i;
109 state_machine *sm;
110 FOR_EACH_VEC_ELT (m_checkers, i, sm)
111 checkers_arr->append (sm->to_json ());
112 ext_state_obj->set ("checkers", checkers_arr);
113 }
114
115 return ext_state_obj;
116 }
117
118 /* Get the region_model_manager for this extrinsic_state. */
119
120 region_model_manager *
121 extrinsic_state::get_model_manager () const
122 {
123 if (m_engine)
124 return m_engine->get_model_manager ();
125 else
126 return NULL; /* for selftests. */
127 }
128
129 /* Try to find a state machine named NAME.
130 If found, return true and write its index to *OUT.
131 Otherwise return false. */
132
133 bool
134 extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const
135 {
136 unsigned i;
137 state_machine *sm;
138 FOR_EACH_VEC_ELT (m_checkers, i, sm)
139 if (0 == strcmp (name, sm->get_name ()))
140 {
141 /* Found NAME. */
142 *out = i;
143 return true;
144 }
145
146 /* NAME not found. */
147 return false;
148 }
149
150 /* struct sm_state_map::entry_t. */
151
152 int
153 sm_state_map::entry_t::cmp (const entry_t &entry_a, const entry_t &entry_b)
154 {
155 gcc_assert (entry_a.m_state);
156 gcc_assert (entry_b.m_state);
157 if (int cmp_state = ((int)entry_a.m_state->get_id ()
158 - (int)entry_b.m_state->get_id ()))
159 return cmp_state;
160 if (entry_a.m_origin && entry_b.m_origin)
161 return svalue::cmp_ptr (entry_a.m_origin, entry_b.m_origin);
162 if (entry_a.m_origin)
163 return 1;
164 if (entry_b.m_origin)
165 return -1;
166 return 0;
167 }
168
169 /* class sm_state_map. */
170
171 /* sm_state_map's ctor. */
172
173 sm_state_map::sm_state_map (const state_machine &sm)
174 : m_sm (sm), m_map (), m_global_state (sm.get_start_state ())
175 {
176 }
177
178 /* Clone the sm_state_map. */
179
180 sm_state_map *
181 sm_state_map::clone () const
182 {
183 return new sm_state_map (*this);
184 }
185
186 /* Print this sm_state_map to PP.
187 If MODEL is non-NULL, print representative tree values where
188 available. */
189
190 void
191 sm_state_map::print (const region_model *model,
192 bool simple, bool multiline,
193 pretty_printer *pp) const
194 {
195 bool first = true;
196 if (!multiline)
197 pp_string (pp, "{");
198 if (m_global_state != m_sm.get_start_state ())
199 {
200 if (multiline)
201 pp_string (pp, " ");
202 pp_string (pp, "global: ");
203 m_global_state->dump_to_pp (pp);
204 if (multiline)
205 pp_newline (pp);
206 first = false;
207 }
208 auto_vec <const svalue *> keys (m_map.elements ());
209 for (map_t::iterator iter = m_map.begin ();
210 iter != m_map.end ();
211 ++iter)
212 keys.quick_push ((*iter).first);
213 keys.qsort (svalue::cmp_ptr_ptr);
214 unsigned i;
215 const svalue *sval;
216 FOR_EACH_VEC_ELT (keys, i, sval)
217 {
218 if (multiline)
219 pp_string (pp, " ");
220 else if (!first)
221 pp_string (pp, ", ");
222 first = false;
223 if (!flag_dump_noaddr)
224 {
225 pp_pointer (pp, sval);
226 pp_string (pp, ": ");
227 }
228 sval->dump_to_pp (pp, simple);
229
230 entry_t e = *const_cast <map_t &> (m_map).get (sval);
231 pp_string (pp, ": ");
232 e.m_state->dump_to_pp (pp);
233 if (model)
234 if (tree rep = model->get_representative_tree (sval))
235 {
236 pp_string (pp, " (");
237 dump_quoted_tree (pp, rep);
238 pp_character (pp, ')');
239 }
240 if (e.m_origin)
241 {
242 pp_string (pp, " (origin: ");
243 if (!flag_dump_noaddr)
244 {
245 pp_pointer (pp, e.m_origin);
246 pp_string (pp, ": ");
247 }
248 e.m_origin->dump_to_pp (pp, simple);
249 if (model)
250 if (tree rep = model->get_representative_tree (e.m_origin))
251 {
252 pp_string (pp, " (");
253 dump_quoted_tree (pp, rep);
254 pp_character (pp, ')');
255 }
256 pp_string (pp, ")");
257 }
258 if (multiline)
259 pp_newline (pp);
260 }
261 if (!multiline)
262 pp_string (pp, "}");
263 }
264
265 /* Dump this object to stderr. */
266
267 DEBUG_FUNCTION void
268 sm_state_map::dump (bool simple) const
269 {
270 pretty_printer pp;
271 pp_format_decoder (&pp) = default_tree_printer;
272 pp_show_color (&pp) = pp_show_color (global_dc->printer);
273 pp.buffer->stream = stderr;
274 print (NULL, simple, true, &pp);
275 pp_newline (&pp);
276 pp_flush (&pp);
277 }
278
279 /* Return a new json::object of the form
280 {"global" : (optional) value for global state,
281 SVAL_DESC : value for state}. */
282
283 json::object *
284 sm_state_map::to_json () const
285 {
286 json::object *map_obj = new json::object ();
287
288 if (m_global_state != m_sm.get_start_state ())
289 map_obj->set ("global", m_global_state->to_json ());
290 for (map_t::iterator iter = m_map.begin ();
291 iter != m_map.end ();
292 ++iter)
293 {
294 const svalue *sval = (*iter).first;
295 entry_t e = (*iter).second;
296
297 label_text sval_desc = sval->get_desc ();
298 map_obj->set (sval_desc.get (), e.m_state->to_json ());
299
300 /* This doesn't yet JSONify e.m_origin. */
301 }
302 return map_obj;
303 }
304
305 /* Return true if no states have been set within this map
306 (all expressions are for the start state). */
307
308 bool
309 sm_state_map::is_empty_p () const
310 {
311 return m_map.elements () == 0 && m_global_state == m_sm.get_start_state ();
312 }
313
314 /* Generate a hash value for this sm_state_map. */
315
316 hashval_t
317 sm_state_map::hash () const
318 {
319 hashval_t result = 0;
320
321 /* Accumulate the result by xoring a hash for each slot, so that the
322 result doesn't depend on the ordering of the slots in the map. */
323
324 for (map_t::iterator iter = m_map.begin ();
325 iter != m_map.end ();
326 ++iter)
327 {
328 inchash::hash hstate;
329 hstate.add_ptr ((*iter).first);
330 entry_t e = (*iter).second;
331 hstate.add_int (e.m_state->get_id ());
332 hstate.add_ptr (e.m_origin);
333 result ^= hstate.end ();
334 }
335 result ^= m_global_state->get_id ();
336
337 return result;
338 }
339
340 /* Equality operator for sm_state_map. */
341
342 bool
343 sm_state_map::operator== (const sm_state_map &other) const
344 {
345 if (m_global_state != other.m_global_state)
346 return false;
347
348 if (m_map.elements () != other.m_map.elements ())
349 return false;
350
351 for (map_t::iterator iter = m_map.begin ();
352 iter != m_map.end ();
353 ++iter)
354 {
355 const svalue *sval = (*iter).first;
356 entry_t e = (*iter).second;
357 entry_t *other_slot = const_cast <map_t &> (other.m_map).get (sval);
358 if (other_slot == NULL)
359 return false;
360 if (e != *other_slot)
361 return false;
362 }
363
364 gcc_checking_assert (hash () == other.hash ());
365
366 return true;
367 }
368
369 /* Get the state of SVAL within this object.
370 States default to the start state. */
371
372 state_machine::state_t
373 sm_state_map::get_state (const svalue *sval,
374 const extrinsic_state &ext_state) const
375 {
376 gcc_assert (sval);
377
378 sval = canonicalize_svalue (sval, ext_state);
379
380 if (entry_t *slot
381 = const_cast <map_t &> (m_map).get (sval))
382 return slot->m_state;
383
384 /* SVAL has no explicit sm-state.
385 If this sm allows for state inheritance, then SVAL might have implicit
386 sm-state inherited via a parent.
387 For example INIT_VAL(foo.field) might inherit taintedness state from
388 INIT_VAL(foo). */
389 if (m_sm.inherited_state_p ())
390 if (region_model_manager *mgr = ext_state.get_model_manager ())
391 {
392 if (const initial_svalue *init_sval = sval->dyn_cast_initial_svalue ())
393 {
394 const region *reg = init_sval->get_region ();
395 /* Try recursing upwards (up to the base region for the
396 cluster). */
397 if (!reg->base_region_p ())
398 if (const region *parent_reg = reg->get_parent_region ())
399 {
400 const svalue *parent_init_sval
401 = mgr->get_or_create_initial_value (parent_reg);
402 state_machine::state_t parent_state
403 = get_state (parent_init_sval, ext_state);
404 if (parent_state)
405 return parent_state;
406 }
407 }
408 else if (const sub_svalue *sub_sval = sval->dyn_cast_sub_svalue ())
409 {
410 const svalue *parent_sval = sub_sval->get_parent ();
411 if (state_machine::state_t parent_state
412 = get_state (parent_sval, ext_state))
413 return parent_state;
414 }
415 }
416
417 if (state_machine::state_t state
418 = m_sm.alt_get_inherited_state (*this, sval, ext_state))
419 return state;
420
421 return m_sm.get_default_state (sval);
422 }
423
424 /* Get the "origin" svalue for any state of SVAL. */
425
426 const svalue *
427 sm_state_map::get_origin (const svalue *sval,
428 const extrinsic_state &ext_state) const
429 {
430 gcc_assert (sval);
431
432 sval = canonicalize_svalue (sval, ext_state);
433
434 entry_t *slot
435 = const_cast <map_t &> (m_map).get (sval);
436 if (slot)
437 return slot->m_origin;
438 else
439 return NULL;
440 }
441
442 /* Set the state of SID within MODEL to STATE, recording that
443 the state came from ORIGIN. */
444
445 void
446 sm_state_map::set_state (region_model *model,
447 const svalue *sval,
448 state_machine::state_t state,
449 const svalue *origin,
450 const extrinsic_state &ext_state)
451 {
452 if (model == NULL)
453 return;
454
455 /* Reject attempts to set state on UNKNOWN/POISONED. */
456 if (!sval->can_have_associated_state_p ())
457 return;
458
459 equiv_class &ec = model->get_constraints ()->get_equiv_class (sval);
460 if (!set_state (ec, state, origin, ext_state))
461 return;
462 }
463
464 /* Set the state of EC to STATE, recording that the state came from
465 ORIGIN.
466 Return true if any states of svalue_ids within EC changed. */
467
468 bool
469 sm_state_map::set_state (const equiv_class &ec,
470 state_machine::state_t state,
471 const svalue *origin,
472 const extrinsic_state &ext_state)
473 {
474 bool any_changed = false;
475 for (const svalue *sval : ec.m_vars)
476 any_changed |= impl_set_state (sval, state, origin, ext_state);
477 return any_changed;
478 }
479
480 /* Set state of SVAL to STATE, bypassing equivalence classes.
481 Return true if the state changed. */
482
483 bool
484 sm_state_map::impl_set_state (const svalue *sval,
485 state_machine::state_t state,
486 const svalue *origin,
487 const extrinsic_state &ext_state)
488 {
489 sval = canonicalize_svalue (sval, ext_state);
490
491 if (get_state (sval, ext_state) == state)
492 return false;
493
494 gcc_assert (sval->can_have_associated_state_p ());
495
496 if (m_sm.inherited_state_p ())
497 {
498 if (const compound_svalue *compound_sval
499 = sval->dyn_cast_compound_svalue ())
500 for (auto iter : *compound_sval)
501 {
502 const svalue *inner_sval = iter.second;
503 if (inner_sval->can_have_associated_state_p ())
504 impl_set_state (inner_sval, state, origin, ext_state);
505 }
506 }
507
508 /* Special-case state 0 as the default value. */
509 if (state == 0)
510 {
511 if (m_map.get (sval))
512 m_map.remove (sval);
513 return true;
514 }
515 gcc_assert (sval);
516 m_map.put (sval, entry_t (state, origin));
517 return true;
518 }
519
520 /* Set the "global" state within this state map to STATE. */
521
522 void
523 sm_state_map::set_global_state (state_machine::state_t state)
524 {
525 m_global_state = state;
526 }
527
528 /* Get the "global" state within this state map. */
529
530 state_machine::state_t
531 sm_state_map::get_global_state () const
532 {
533 return m_global_state;
534 }
535
536 /* Purge any state for SVAL.
537 If !SM::can_purge_p, then report the state as leaking,
538 using CTXT. */
539
540 void
541 sm_state_map::on_svalue_leak (const svalue *sval,
542 impl_region_model_context *ctxt)
543 {
544 if (state_machine::state_t state = get_state (sval, ctxt->m_ext_state))
545 {
546 if (!m_sm.can_purge_p (state))
547 ctxt->on_state_leak (m_sm, sval, state);
548 m_map.remove (sval);
549 }
550 }
551
552 /* Purge any state for svalues that aren't live with respect to LIVE_SVALUES
553 and MODEL. */
554
555 void
556 sm_state_map::on_liveness_change (const svalue_set &live_svalues,
557 const region_model *model,
558 impl_region_model_context *ctxt)
559 {
560 svalue_set svals_to_unset;
561 uncertainty_t *uncertainty = ctxt->get_uncertainty ();
562
563 auto_vec<const svalue *> leaked_svals (m_map.elements ());
564 for (map_t::iterator iter = m_map.begin ();
565 iter != m_map.end ();
566 ++iter)
567 {
568 const svalue *iter_sval = (*iter).first;
569 if (!iter_sval->live_p (&live_svalues, model))
570 {
571 svals_to_unset.add (iter_sval);
572 entry_t e = (*iter).second;
573 if (!m_sm.can_purge_p (e.m_state))
574 leaked_svals.quick_push (iter_sval);
575 }
576 if (uncertainty)
577 if (uncertainty->unknown_sm_state_p (iter_sval))
578 svals_to_unset.add (iter_sval);
579 }
580
581 leaked_svals.qsort (svalue::cmp_ptr_ptr);
582
583 unsigned i;
584 const svalue *sval;
585 FOR_EACH_VEC_ELT (leaked_svals, i, sval)
586 {
587 entry_t e = *m_map.get (sval);
588 ctxt->on_state_leak (m_sm, sval, e.m_state);
589 }
590
591 for (svalue_set::iterator iter = svals_to_unset.begin ();
592 iter != svals_to_unset.end (); ++iter)
593 m_map.remove (*iter);
594 }
595
596 /* Purge state from SVAL (in response to a call to an unknown function). */
597
598 void
599 sm_state_map::on_unknown_change (const svalue *sval,
600 bool is_mutable,
601 const extrinsic_state &ext_state)
602 {
603 svalue_set svals_to_unset;
604
605 for (map_t::iterator iter = m_map.begin ();
606 iter != m_map.end ();
607 ++iter)
608 {
609 const svalue *key = (*iter).first;
610 entry_t e = (*iter).second;
611 /* We only want to purge state for some states when things
612 are mutable. For example, in sm-malloc.cc, an on-stack ptr
613 doesn't stop being stack-allocated when passed to an unknown fn. */
614 if (!m_sm.reset_when_passed_to_unknown_fn_p (e.m_state, is_mutable))
615 continue;
616 if (key == sval)
617 svals_to_unset.add (key);
618 /* If we have INIT_VAL(BASE_REG), then unset any INIT_VAL(REG)
619 for REG within BASE_REG. */
620 if (const initial_svalue *init_sval = sval->dyn_cast_initial_svalue ())
621 if (const initial_svalue *init_key = key->dyn_cast_initial_svalue ())
622 {
623 const region *changed_reg = init_sval->get_region ();
624 const region *changed_key = init_key->get_region ();
625 if (changed_key->get_base_region () == changed_reg)
626 svals_to_unset.add (key);
627 }
628 }
629
630 for (svalue_set::iterator iter = svals_to_unset.begin ();
631 iter != svals_to_unset.end (); ++iter)
632 impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state);
633 }
634
635 /* Purge state for things involving SVAL.
636 For use when SVAL changes meaning, at the def_stmt on an SSA_NAME. */
637
638 void
639 sm_state_map::purge_state_involving (const svalue *sval,
640 const extrinsic_state &ext_state)
641 {
642 /* Currently svalue::involves_p requires this. */
643 if (!(sval->get_kind () == SK_INITIAL
644 || sval->get_kind () == SK_CONJURED))
645 return;
646
647 svalue_set svals_to_unset;
648
649 for (map_t::iterator iter = m_map.begin ();
650 iter != m_map.end ();
651 ++iter)
652 {
653 const svalue *key = (*iter).first;
654 entry_t e = (*iter).second;
655 if (!m_sm.can_purge_p (e.m_state))
656 continue;
657 if (key->involves_p (sval))
658 svals_to_unset.add (key);
659 }
660
661 for (svalue_set::iterator iter = svals_to_unset.begin ();
662 iter != svals_to_unset.end (); ++iter)
663 impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state);
664 }
665
666 /* Comparator for imposing an order on sm_state_map instances. */
667
668 int
669 sm_state_map::cmp (const sm_state_map &smap_a, const sm_state_map &smap_b)
670 {
671 if (int cmp_count = smap_a.elements () - smap_b.elements ())
672 return cmp_count;
673
674 auto_vec <const svalue *> keys_a (smap_a.elements ());
675 for (map_t::iterator iter = smap_a.begin ();
676 iter != smap_a.end ();
677 ++iter)
678 keys_a.quick_push ((*iter).first);
679 keys_a.qsort (svalue::cmp_ptr_ptr);
680
681 auto_vec <const svalue *> keys_b (smap_b.elements ());
682 for (map_t::iterator iter = smap_b.begin ();
683 iter != smap_b.end ();
684 ++iter)
685 keys_b.quick_push ((*iter).first);
686 keys_b.qsort (svalue::cmp_ptr_ptr);
687
688 unsigned i;
689 const svalue *sval_a;
690 FOR_EACH_VEC_ELT (keys_a, i, sval_a)
691 {
692 const svalue *sval_b = keys_b[i];
693 if (int cmp_sval = svalue::cmp_ptr (sval_a, sval_b))
694 return cmp_sval;
695 const entry_t *e_a = const_cast <map_t &> (smap_a.m_map).get (sval_a);
696 const entry_t *e_b = const_cast <map_t &> (smap_b.m_map).get (sval_b);
697 if (int cmp_entry = entry_t::cmp (*e_a, *e_b))
698 return cmp_entry;
699 }
700
701 return 0;
702 }
703
704 /* Canonicalize SVAL before getting/setting it within the map.
705 Convert all NULL pointers to (void *) to avoid state explosions
706 involving all of the various (foo *)NULL vs (bar *)NULL. */
707
708 const svalue *
709 sm_state_map::canonicalize_svalue (const svalue *sval,
710 const extrinsic_state &ext_state)
711 {
712 region_model_manager *mgr = ext_state.get_model_manager ();
713 if (mgr && sval->get_type () && POINTER_TYPE_P (sval->get_type ()))
714 if (tree cst = sval->maybe_get_constant ())
715 if (zerop (cst))
716 return mgr->get_or_create_constant_svalue (null_pointer_node);
717
718 return sval;
719 }
720
721 /* class program_state. */
722
723 /* program_state's ctor. */
724
725 program_state::program_state (const extrinsic_state &ext_state)
726 : m_region_model (NULL),
727 m_checker_states (ext_state.get_num_checkers ()),
728 m_valid (true)
729 {
730 engine *eng = ext_state.get_engine ();
731 region_model_manager *mgr = eng->get_model_manager ();
732 m_region_model = new region_model (mgr);
733 const int num_states = ext_state.get_num_checkers ();
734 for (int i = 0; i < num_states; i++)
735 {
736 sm_state_map *sm = new sm_state_map (ext_state.get_sm (i));
737 m_checker_states.quick_push (sm);
738 }
739 }
740
741 /* Attempt to to use R to replay SUMMARY into this object.
742 Return true if it is possible. */
743
744 bool
745 sm_state_map::replay_call_summary (call_summary_replay &r,
746 const sm_state_map &summary)
747 {
748 for (auto kv : summary.m_map)
749 {
750 const svalue *summary_sval = kv.first;
751 const svalue *caller_sval = r.convert_svalue_from_summary (summary_sval);
752 if (!caller_sval)
753 continue;
754 const svalue *summary_origin = kv.second.m_origin;
755 const svalue *caller_origin
756 = (summary_origin
757 ? r.convert_svalue_from_summary (summary_origin)
758 : NULL);
759 // caller_origin can be NULL.
760 m_map.put (caller_sval, entry_t (kv.second.m_state, caller_origin));
761 }
762 m_global_state = summary.m_global_state;
763 return true;
764 }
765
766 /* program_state's copy ctor. */
767
768 program_state::program_state (const program_state &other)
769 : m_region_model (new region_model (*other.m_region_model)),
770 m_checker_states (other.m_checker_states.length ()),
771 m_valid (true)
772 {
773 int i;
774 sm_state_map *smap;
775 FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
776 m_checker_states.quick_push (smap->clone ());
777 }
778
779 /* program_state's assignment operator. */
780
781 program_state&
782 program_state::operator= (const program_state &other)
783 {
784 delete m_region_model;
785 m_region_model = new region_model (*other.m_region_model);
786
787 int i;
788 sm_state_map *smap;
789 FOR_EACH_VEC_ELT (m_checker_states, i, smap)
790 delete smap;
791 m_checker_states.truncate (0);
792 gcc_assert (m_checker_states.space (other.m_checker_states.length ()));
793
794 FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
795 m_checker_states.quick_push (smap->clone ());
796
797 m_valid = other.m_valid;
798
799 return *this;
800 }
801
802 /* Move constructor for program_state (when building with C++11). */
803 program_state::program_state (program_state &&other)
804 : m_region_model (other.m_region_model),
805 m_checker_states (other.m_checker_states.length ())
806 {
807 other.m_region_model = NULL;
808
809 int i;
810 sm_state_map *smap;
811 FOR_EACH_VEC_ELT (other.m_checker_states, i, smap)
812 m_checker_states.quick_push (smap);
813 other.m_checker_states.truncate (0);
814
815 m_valid = other.m_valid;
816 }
817
818 /* program_state's dtor. */
819
820 program_state::~program_state ()
821 {
822 delete m_region_model;
823 }
824
825 /* Generate a hash value for this program_state. */
826
827 hashval_t
828 program_state::hash () const
829 {
830 hashval_t result = m_region_model->hash ();
831
832 int i;
833 sm_state_map *smap;
834 FOR_EACH_VEC_ELT (m_checker_states, i, smap)
835 result ^= smap->hash ();
836 return result;
837 }
838
839 /* Equality operator for program_state.
840 All parts of the program_state (region model, checker states) must
841 equal their counterparts in OTHER for the two program_states to be
842 considered equal. */
843
844 bool
845 program_state::operator== (const program_state &other) const
846 {
847 if (!(*m_region_model == *other.m_region_model))
848 return false;
849
850 int i;
851 sm_state_map *smap;
852 FOR_EACH_VEC_ELT (m_checker_states, i, smap)
853 if (!(*smap == *other.m_checker_states[i]))
854 return false;
855
856 gcc_checking_assert (hash () == other.hash ());
857
858 return true;
859 }
860
861 /* Print a compact representation of this state to PP. */
862
863 void
864 program_state::print (const extrinsic_state &ext_state,
865 pretty_printer *pp) const
866 {
867 pp_printf (pp, "rmodel: ");
868 m_region_model->dump_to_pp (pp, true, false);
869 pp_newline (pp);
870
871 int i;
872 sm_state_map *smap;
873 FOR_EACH_VEC_ELT (m_checker_states, i, smap)
874 {
875 if (!smap->is_empty_p ())
876 {
877 pp_printf (pp, "%s: ", ext_state.get_name (i));
878 smap->print (m_region_model, true, false, pp);
879 pp_newline (pp);
880 }
881 }
882 if (!m_valid)
883 {
884 pp_printf (pp, "invalid state");
885 pp_newline (pp);
886 }
887 }
888
889 /* Dump a representation of this state to PP. */
890
891 void
892 program_state::dump_to_pp (const extrinsic_state &ext_state,
893 bool /*summarize*/, bool multiline,
894 pretty_printer *pp) const
895 {
896 if (!multiline)
897 pp_string (pp, "{");
898 {
899 pp_printf (pp, "rmodel:");
900 if (multiline)
901 pp_newline (pp);
902 else
903 pp_string (pp, " {");
904 m_region_model->dump_to_pp (pp, true, multiline);
905 if (!multiline)
906 pp_string (pp, "}");
907 }
908
909 int i;
910 sm_state_map *smap;
911 FOR_EACH_VEC_ELT (m_checker_states, i, smap)
912 {
913 if (!smap->is_empty_p ())
914 {
915 if (!multiline)
916 pp_string (pp, " {");
917 pp_printf (pp, "%s: ", ext_state.get_name (i));
918 if (multiline)
919 pp_newline (pp);
920 smap->print (m_region_model, true, multiline, pp);
921 if (!multiline)
922 pp_string (pp, "}");
923 }
924 }
925
926 if (!m_valid)
927 {
928 if (!multiline)
929 pp_space (pp);
930 pp_printf (pp, "invalid state");
931 if (multiline)
932 pp_newline (pp);
933 }
934 if (!multiline)
935 pp_string (pp, "}");
936 }
937
938 /* Dump a representation of this state to OUTF. */
939
940 void
941 program_state::dump_to_file (const extrinsic_state &ext_state,
942 bool summarize, bool multiline,
943 FILE *outf) const
944 {
945 pretty_printer pp;
946 pp_format_decoder (&pp) = default_tree_printer;
947 if (outf == stderr)
948 pp_show_color (&pp) = pp_show_color (global_dc->printer);
949 pp.buffer->stream = outf;
950 dump_to_pp (ext_state, summarize, multiline, &pp);
951 pp_flush (&pp);
952 }
953
954 /* Dump a multiline representation of this state to stderr. */
955
956 DEBUG_FUNCTION void
957 program_state::dump (const extrinsic_state &ext_state,
958 bool summarize) const
959 {
960 dump_to_file (ext_state, summarize, true, stderr);
961 }
962
963 /* Return a new json::object of the form
964 {"store" : object for store,
965 "constraints" : object for constraint_manager,
966 "curr_frame" : (optional) str for current frame,
967 "checkers" : { STATE_NAME : object per sm_state_map },
968 "valid" : true/false}. */
969
970 json::object *
971 program_state::to_json (const extrinsic_state &ext_state) const
972 {
973 json::object *state_obj = new json::object ();
974
975 state_obj->set ("store", m_region_model->get_store ()->to_json ());
976 state_obj->set ("constraints",
977 m_region_model->get_constraints ()->to_json ());
978 if (m_region_model->get_current_frame ())
979 state_obj->set ("curr_frame",
980 m_region_model->get_current_frame ()->to_json ());
981
982 /* Provide m_checker_states as an object, using names as keys. */
983 {
984 json::object *checkers_obj = new json::object ();
985
986 int i;
987 sm_state_map *smap;
988 FOR_EACH_VEC_ELT (m_checker_states, i, smap)
989 if (!smap->is_empty_p ())
990 checkers_obj->set (ext_state.get_name (i), smap->to_json ());
991
992 state_obj->set ("checkers", checkers_obj);
993 }
994
995 state_obj->set ("valid", new json::literal (m_valid));
996
997 return state_obj;
998 }
999
1000 /* Update this program_state to reflect a top-level call to FUN.
1001 The params will have initial_svalues. */
1002
1003 void
1004 program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED,
1005 function *fun)
1006 {
1007 m_region_model->push_frame (fun, NULL, NULL);
1008 }
1009
1010 /* Get the current function of this state. */
1011
1012 function *
1013 program_state::get_current_function () const
1014 {
1015 return m_region_model->get_current_function ();
1016 }
1017
1018 /* Determine if following edge SUCC from ENODE is valid within the graph EG
1019 and update this state accordingly in-place.
1020
1021 Return true if the edge can be followed, or false otherwise.
1022
1023 Check for relevant conditionals and switch-values for conditionals
1024 and switch statements, adding the relevant conditions to this state.
1025 Push/pop frames for interprocedural edges and update params/returned
1026 values.
1027
1028 This is the "state" half of exploded_node::on_edge. */
1029
1030 bool
1031 program_state::on_edge (exploded_graph &eg,
1032 exploded_node *enode,
1033 const superedge *succ,
1034 uncertainty_t *uncertainty)
1035 {
1036 /* Update state. */
1037 const program_point &point = enode->get_point ();
1038 const gimple *last_stmt = point.get_supernode ()->get_last_stmt ();
1039
1040 /* For conditionals and switch statements, add the
1041 relevant conditions (for the specific edge) to new_state;
1042 skip edges for which the resulting constraints
1043 are impossible.
1044 This also updates frame information for call/return superedges.
1045 Adding the relevant conditions for the edge could also trigger
1046 sm-state transitions (e.g. transitions due to ptrs becoming known
1047 to be NULL or non-NULL) */
1048
1049 impl_region_model_context ctxt (eg, enode,
1050 &enode->get_state (),
1051 this,
1052 uncertainty, NULL,
1053 last_stmt);
1054 if (!m_region_model->maybe_update_for_edge (*succ,
1055 last_stmt,
1056 &ctxt, NULL))
1057 {
1058 logger * const logger = eg.get_logger ();
1059 if (logger)
1060 logger->log ("edge to SN: %i is impossible"
1061 " due to region_model constraints",
1062 succ->m_dest->m_index);
1063 return false;
1064 }
1065
1066 program_state::detect_leaks (enode->get_state (), *this,
1067 NULL, eg.get_ext_state (),
1068 &ctxt);
1069
1070 return true;
1071 }
1072
1073 /* Update this program_state to reflect a call to function
1074 represented by CALL_STMT.
1075 currently used only when the call doesn't have a superedge representing
1076 the call ( like call via a function pointer ) */
1077 void
1078 program_state::push_call (exploded_graph &eg,
1079 exploded_node *enode,
1080 const gcall *call_stmt,
1081 uncertainty_t *uncertainty)
1082 {
1083 /* Update state. */
1084 const program_point &point = enode->get_point ();
1085 const gimple *last_stmt = point.get_supernode ()->get_last_stmt ();
1086
1087 impl_region_model_context ctxt (eg, enode,
1088 &enode->get_state (),
1089 this,
1090 uncertainty,
1091 NULL,
1092 last_stmt);
1093 m_region_model->update_for_gcall (call_stmt, &ctxt);
1094 }
1095
1096 /* Update this program_state to reflect a return from function
1097 call to which is represented by CALL_STMT.
1098 currently used only when the call doesn't have a superedge representing
1099 the return */
1100 void
1101 program_state::returning_call (exploded_graph &eg,
1102 exploded_node *enode,
1103 const gcall *call_stmt,
1104 uncertainty_t *uncertainty)
1105 {
1106 /* Update state. */
1107 const program_point &point = enode->get_point ();
1108 const gimple *last_stmt = point.get_supernode ()->get_last_stmt ();
1109
1110 impl_region_model_context ctxt (eg, enode,
1111 &enode->get_state (),
1112 this,
1113 uncertainty,
1114 NULL,
1115 last_stmt);
1116 m_region_model->update_for_return_gcall (call_stmt, &ctxt);
1117 }
1118
1119 /* Generate a simpler version of THIS, discarding state that's no longer
1120 relevant at POINT.
1121 The idea is that we're more likely to be able to consolidate
1122 multiple (point, state) into single exploded_nodes if we discard
1123 irrelevant state (e.g. at the end of functions). */
1124
1125 program_state
1126 program_state::prune_for_point (exploded_graph &eg,
1127 const program_point &point,
1128 exploded_node *enode_for_diag,
1129 uncertainty_t *uncertainty) const
1130 {
1131 logger * const logger = eg.get_logger ();
1132 LOG_SCOPE (logger);
1133
1134 function *fun = point.get_function ();
1135 if (!fun)
1136 return *this;
1137
1138 program_state new_state (*this);
1139
1140 const state_purge_map *pm = eg.get_purge_map ();
1141 if (pm)
1142 {
1143 unsigned num_ssas_purged = 0;
1144 unsigned num_decls_purged = 0;
1145 auto_vec<const decl_region *> regs;
1146 new_state.m_region_model->get_regions_for_current_frame (&regs);
1147 regs.qsort (region::cmp_ptr_ptr);
1148 unsigned i;
1149 const decl_region *reg;
1150 FOR_EACH_VEC_ELT (regs, i, reg)
1151 {
1152 const tree node = reg->get_decl ();
1153 if (TREE_CODE (node) == SSA_NAME)
1154 {
1155 const tree ssa_name = node;
1156 const state_purge_per_ssa_name &per_ssa
1157 = pm->get_data_for_ssa_name (node);
1158 if (!per_ssa.needed_at_point_p (point.get_function_point ()))
1159 {
1160 /* Don't purge bindings of SSA names to svalues
1161 that have unpurgable sm-state, so that leaks are
1162 reported at the end of the function, rather than
1163 at the last place that such an SSA name is referred to.
1164
1165 But do purge them for temporaries (when SSA_NAME_VAR is
1166 NULL), so that we report for cases where a leak happens when
1167 a variable is overwritten with another value, so that the leak
1168 is reported at the point of overwrite, rather than having
1169 temporaries keep the value reachable until the frame is
1170 popped. */
1171 const svalue *sval
1172 = new_state.m_region_model->get_store_value (reg, NULL);
1173 if (!new_state.can_purge_p (eg.get_ext_state (), sval)
1174 && SSA_NAME_VAR (ssa_name))
1175 {
1176 /* (currently only state maps can keep things
1177 alive). */
1178 if (logger)
1179 logger->log ("not purging binding for %qE"
1180 " (used by state map)", ssa_name);
1181 continue;
1182 }
1183
1184 new_state.m_region_model->purge_region (reg);
1185 num_ssas_purged++;
1186 }
1187 }
1188 else
1189 {
1190 const tree decl = node;
1191 gcc_assert (TREE_CODE (node) == VAR_DECL
1192 || TREE_CODE (node) == PARM_DECL
1193 || TREE_CODE (node) == RESULT_DECL);
1194 if (const state_purge_per_decl *per_decl
1195 = pm->get_any_data_for_decl (decl))
1196 if (!per_decl->needed_at_point_p (point.get_function_point ()))
1197 {
1198 /* Don't purge bindings of decls if there are svalues
1199 that have unpurgable sm-state within the decl's cluster,
1200 so that leaks are reported at the end of the function,
1201 rather than at the last place that such a decl is
1202 referred to. */
1203 if (!new_state.can_purge_base_region_p (eg.get_ext_state (),
1204 reg))
1205 {
1206 /* (currently only state maps can keep things
1207 alive). */
1208 if (logger)
1209 logger->log ("not purging binding for %qE"
1210 " (value in binding used by state map)",
1211 decl);
1212 continue;
1213 }
1214
1215 new_state.m_region_model->purge_region (reg);
1216 num_decls_purged++;
1217 }
1218 }
1219 }
1220
1221 if (num_ssas_purged > 0 || num_decls_purged > 0)
1222 {
1223 if (logger)
1224 {
1225 logger->log ("num_ssas_purged: %i", num_ssas_purged);
1226 logger->log ("num_decl_purged: %i", num_decls_purged);
1227 }
1228 impl_region_model_context ctxt (eg, enode_for_diag,
1229 this,
1230 &new_state,
1231 uncertainty, NULL,
1232 point.get_stmt ());
1233 detect_leaks (*this, new_state, NULL, eg.get_ext_state (), &ctxt);
1234 }
1235 }
1236
1237 new_state.m_region_model->canonicalize ();
1238
1239 return new_state;
1240 }
1241
1242 /* Return true if there are no unpurgeable bindings within BASE_REG. */
1243
1244 bool
1245 program_state::can_purge_base_region_p (const extrinsic_state &ext_state,
1246 const region *base_reg) const
1247 {
1248 binding_cluster *cluster
1249 = m_region_model->get_store ()->get_cluster (base_reg);
1250 if (!cluster)
1251 return true;
1252
1253 for (auto iter : *cluster)
1254 {
1255 const svalue *sval = iter.second;
1256 if (!can_purge_p (ext_state, sval))
1257 return false;
1258 }
1259
1260 return true;
1261 }
1262
1263 /* Get a representative tree to use for describing SVAL. */
1264
1265 tree
1266 program_state::get_representative_tree (const svalue *sval) const
1267 {
1268 gcc_assert (m_region_model);
1269 return m_region_model->get_representative_tree (sval);
1270 }
1271
1272 /* Attempt to merge this state with OTHER, both at POINT.
1273 Write the result to *OUT.
1274 If the states were merged successfully, return true. */
1275
1276 bool
1277 program_state::can_merge_with_p (const program_state &other,
1278 const extrinsic_state &ext_state,
1279 const program_point &point,
1280 program_state *out) const
1281 {
1282 gcc_assert (out);
1283 gcc_assert (m_region_model);
1284
1285 /* Early reject if there are sm-differences between the states. */
1286 int i;
1287 sm_state_map *smap;
1288 FOR_EACH_VEC_ELT (out->m_checker_states, i, smap)
1289 if (*m_checker_states[i] != *other.m_checker_states[i])
1290 return false;
1291
1292 /* Attempt to merge the region_models. */
1293 if (!m_region_model->can_merge_with_p (*other.m_region_model,
1294 point,
1295 out->m_region_model,
1296 &ext_state,
1297 this, &other))
1298 return false;
1299
1300 /* Copy m_checker_states to OUT. */
1301 FOR_EACH_VEC_ELT (out->m_checker_states, i, smap)
1302 {
1303 delete smap;
1304 out->m_checker_states[i] = m_checker_states[i]->clone ();
1305 }
1306
1307 out->m_region_model->canonicalize ();
1308
1309 return true;
1310 }
1311
1312 /* Assert that this object is valid. */
1313
1314 void
1315 program_state::validate (const extrinsic_state &ext_state) const
1316 {
1317 /* Skip this in a release build. */
1318 #if !CHECKING_P
1319 return;
1320 #endif
1321
1322 gcc_assert (m_checker_states.length () == ext_state.get_num_checkers ());
1323 m_region_model->validate ();
1324 }
1325
1326 static void
1327 log_set_of_svalues (logger *logger, const char *name,
1328 const svalue_set &set)
1329 {
1330 logger->log (name);
1331 logger->inc_indent ();
1332 auto_vec<const svalue *> sval_vecs (set.elements ());
1333 for (svalue_set::iterator iter = set.begin ();
1334 iter != set.end (); ++iter)
1335 sval_vecs.quick_push (*iter);
1336 sval_vecs.qsort (svalue::cmp_ptr_ptr);
1337 unsigned i;
1338 const svalue *sval;
1339 FOR_EACH_VEC_ELT (sval_vecs, i, sval)
1340 {
1341 logger->start_log_line ();
1342 pretty_printer *pp = logger->get_printer ();
1343 if (!flag_dump_noaddr)
1344 {
1345 pp_pointer (pp, sval);
1346 pp_string (pp, ": ");
1347 }
1348 sval->dump_to_pp (pp, false);
1349 logger->end_log_line ();
1350 }
1351 logger->dec_indent ();
1352 }
1353
1354 /* Compare the sets of svalues reachable from each of SRC_STATE and DEST_STATE.
1355 For all svalues that are reachable in SRC_STATE and are not live in
1356 DEST_STATE (whether explicitly reachable in DEST_STATE, or implicitly live
1357 based on the former set), call CTXT->on_svalue_leak for them.
1358
1359 Call on_liveness_change on both the CTXT and on the DEST_STATE's
1360 constraint_manager, purging dead svalues from sm-state and from
1361 constraints, respectively.
1362
1363 This function should be called at each fine-grained state change, not
1364 just at exploded edges. */
1365
1366 void
1367 program_state::detect_leaks (const program_state &src_state,
1368 const program_state &dest_state,
1369 const svalue *extra_sval,
1370 const extrinsic_state &ext_state,
1371 region_model_context *ctxt)
1372 {
1373 logger *logger = ext_state.get_logger ();
1374 LOG_SCOPE (logger);
1375 const uncertainty_t *uncertainty = ctxt->get_uncertainty ();
1376 if (logger)
1377 {
1378 pretty_printer *pp = logger->get_printer ();
1379 logger->start_log_line ();
1380 pp_string (pp, "src_state: ");
1381 src_state.dump_to_pp (ext_state, true, false, pp);
1382 logger->end_log_line ();
1383 logger->start_log_line ();
1384 pp_string (pp, "dest_state: ");
1385 dest_state.dump_to_pp (ext_state, true, false, pp);
1386 logger->end_log_line ();
1387 if (extra_sval)
1388 {
1389 logger->start_log_line ();
1390 pp_string (pp, "extra_sval: ");
1391 extra_sval->dump_to_pp (pp, true);
1392 logger->end_log_line ();
1393 }
1394 if (uncertainty)
1395 {
1396 logger->start_log_line ();
1397 pp_string (pp, "uncertainty: ");
1398 uncertainty->dump_to_pp (pp, true);
1399 logger->end_log_line ();
1400 }
1401 }
1402
1403 /* Get svalues reachable from each of src_state and dest_state.
1404 Get svalues *known* to be reachable in src_state.
1405 Pass in uncertainty for dest_state so that we additionally get svalues that
1406 *might* still be reachable in dst_state. */
1407 svalue_set known_src_svalues;
1408 src_state.m_region_model->get_reachable_svalues (&known_src_svalues,
1409 NULL, NULL);
1410 svalue_set maybe_dest_svalues;
1411 dest_state.m_region_model->get_reachable_svalues (&maybe_dest_svalues,
1412 extra_sval, uncertainty);
1413
1414 if (logger)
1415 {
1416 log_set_of_svalues (logger, "src_state known reachable svalues:",
1417 known_src_svalues);
1418 log_set_of_svalues (logger, "dest_state maybe reachable svalues:",
1419 maybe_dest_svalues);
1420 }
1421
1422 auto_vec <const svalue *> dead_svals (known_src_svalues.elements ());
1423 for (svalue_set::iterator iter = known_src_svalues.begin ();
1424 iter != known_src_svalues.end (); ++iter)
1425 {
1426 const svalue *sval = (*iter);
1427 /* For each sval reachable from SRC_STATE, determine if it is
1428 live in DEST_STATE: either explicitly reachable, implicitly
1429 live based on the set of explicitly reachable svalues,
1430 or possibly reachable as recorded in uncertainty.
1431 Record those that have ceased to be live i.e. were known
1432 to be live, and are now not known to be even possibly-live. */
1433 if (!sval->live_p (&maybe_dest_svalues, dest_state.m_region_model))
1434 dead_svals.quick_push (sval);
1435 }
1436
1437 /* Call CTXT->on_svalue_leak on all svals in SRC_STATE that have ceased
1438 to be live, sorting them first to ensure deterministic behavior. */
1439 dead_svals.qsort (svalue::cmp_ptr_ptr);
1440 unsigned i;
1441 const svalue *sval;
1442 FOR_EACH_VEC_ELT (dead_svals, i, sval)
1443 ctxt->on_svalue_leak (sval);
1444
1445 /* Purge dead svals from sm-state. */
1446 ctxt->on_liveness_change (maybe_dest_svalues,
1447 dest_state.m_region_model);
1448
1449 /* Purge dead svals from constraints. */
1450 dest_state.m_region_model->get_constraints ()->on_liveness_change
1451 (maybe_dest_svalues, dest_state.m_region_model);
1452
1453 /* Purge dead heap-allocated regions from dynamic extents. */
1454 for (const svalue *sval : dead_svals)
1455 if (const region *reg = sval->maybe_get_region ())
1456 if (reg->get_kind () == RK_HEAP_ALLOCATED)
1457 dest_state.m_region_model->unset_dynamic_extents (reg);
1458 }
1459
1460 /* Attempt to to use R to replay SUMMARY into this object.
1461 Return true if it is possible. */
1462
1463 bool
1464 program_state::replay_call_summary (call_summary_replay &r,
1465 const program_state &summary)
1466 {
1467 if (!m_region_model->replay_call_summary (r, *summary.m_region_model))
1468 return false;
1469
1470 for (unsigned sm_idx = 0; sm_idx < m_checker_states.length (); sm_idx++)
1471 {
1472 const sm_state_map *summary_sm_map = summary.m_checker_states[sm_idx];
1473 m_checker_states[sm_idx]->replay_call_summary (r, *summary_sm_map);
1474 }
1475
1476 if (!summary.m_valid)
1477 m_valid = false;
1478
1479 return true;
1480 }
1481
1482 /* Handle calls to "__analyzer_dump_state". */
1483
1484 void
1485 program_state::impl_call_analyzer_dump_state (const gcall *call,
1486 const extrinsic_state &ext_state,
1487 region_model_context *ctxt)
1488 {
1489 call_details cd (call, m_region_model, ctxt);
1490 const char *sm_name = cd.get_arg_string_literal (0);
1491 if (!sm_name)
1492 {
1493 error_at (call->location, "cannot determine state machine");
1494 return;
1495 }
1496 unsigned sm_idx;
1497 if (!ext_state.get_sm_idx_by_name (sm_name, &sm_idx))
1498 {
1499 error_at (call->location, "unrecognized state machine %qs", sm_name);
1500 return;
1501 }
1502 const sm_state_map *smap = m_checker_states[sm_idx];
1503
1504 const svalue *sval = cd.get_arg_svalue (1);
1505
1506 /* Strip off cast to int (due to variadic args). */
1507 if (const svalue *cast = sval->maybe_undo_cast ())
1508 sval = cast;
1509
1510 state_machine::state_t state = smap->get_state (sval, ext_state);
1511 warning_at (call->location, 0, "state: %qs", state->get_name ());
1512 }
1513
1514 #if CHECKING_P
1515
1516 namespace selftest {
1517
1518 /* Tests for sm_state_map. */
1519
1520 static void
1521 test_sm_state_map ()
1522 {
1523 tree x = build_global_decl ("x", integer_type_node);
1524 tree y = build_global_decl ("y", integer_type_node);
1525 tree z = build_global_decl ("z", integer_type_node);
1526
1527 state_machine *sm = make_malloc_state_machine (NULL);
1528 auto_delete_vec <state_machine> checkers;
1529 checkers.safe_push (sm);
1530 engine eng;
1531 extrinsic_state ext_state (checkers, &eng);
1532 state_machine::state_t start = sm->get_start_state ();
1533
1534 /* Test setting states on svalue_id instances directly. */
1535 {
1536 const state_machine::state test_state_42 ("test state 42", 42);
1537 const state_machine::state_t TEST_STATE_42 = &test_state_42;
1538 region_model_manager mgr;
1539 region_model model (&mgr);
1540 const svalue *x_sval = model.get_rvalue (x, NULL);
1541 const svalue *y_sval = model.get_rvalue (y, NULL);
1542 const svalue *z_sval = model.get_rvalue (z, NULL);
1543
1544 sm_state_map map (*sm);
1545 ASSERT_TRUE (map.is_empty_p ());
1546 ASSERT_EQ (map.get_state (x_sval, ext_state), start);
1547
1548 map.impl_set_state (x_sval, TEST_STATE_42, z_sval, ext_state);
1549 ASSERT_EQ (map.get_state (x_sval, ext_state), TEST_STATE_42);
1550 ASSERT_EQ (map.get_origin (x_sval, ext_state), z_sval);
1551 ASSERT_EQ (map.get_state (y_sval, ext_state), start);
1552 ASSERT_FALSE (map.is_empty_p ());
1553
1554 map.impl_set_state (y_sval, 0, z_sval, ext_state);
1555 ASSERT_EQ (map.get_state (y_sval, ext_state), start);
1556
1557 map.impl_set_state (x_sval, 0, z_sval, ext_state);
1558 ASSERT_EQ (map.get_state (x_sval, ext_state), start);
1559 ASSERT_TRUE (map.is_empty_p ());
1560 }
1561
1562 const state_machine::state test_state_5 ("test state 5", 5);
1563 const state_machine::state_t TEST_STATE_5 = &test_state_5;
1564
1565 /* Test setting states via equivalence classes. */
1566 {
1567 region_model_manager mgr;
1568 region_model model (&mgr);
1569 const svalue *x_sval = model.get_rvalue (x, NULL);
1570 const svalue *y_sval = model.get_rvalue (y, NULL);
1571 const svalue *z_sval = model.get_rvalue (z, NULL);
1572
1573 sm_state_map map (*sm);
1574 ASSERT_TRUE (map.is_empty_p ());
1575 ASSERT_EQ (map.get_state (x_sval, ext_state), start);
1576 ASSERT_EQ (map.get_state (y_sval, ext_state), start);
1577
1578 model.add_constraint (x, EQ_EXPR, y, NULL);
1579
1580 /* Setting x to a state should also update y, as they
1581 are in the same equivalence class. */
1582 map.set_state (&model, x_sval, TEST_STATE_5, z_sval, ext_state);
1583 ASSERT_EQ (map.get_state (x_sval, ext_state), TEST_STATE_5);
1584 ASSERT_EQ (map.get_state (y_sval, ext_state), TEST_STATE_5);
1585 ASSERT_EQ (map.get_origin (x_sval, ext_state), z_sval);
1586 ASSERT_EQ (map.get_origin (y_sval, ext_state), z_sval);
1587 }
1588
1589 /* Test equality and hashing. */
1590 {
1591 region_model_manager mgr;
1592 region_model model (&mgr);
1593 const svalue *y_sval = model.get_rvalue (y, NULL);
1594 const svalue *z_sval = model.get_rvalue (z, NULL);
1595
1596 sm_state_map map0 (*sm);
1597 sm_state_map map1 (*sm);
1598 sm_state_map map2 (*sm);
1599
1600 ASSERT_EQ (map0.hash (), map1.hash ());
1601 ASSERT_EQ (map0, map1);
1602
1603 map1.impl_set_state (y_sval, TEST_STATE_5, z_sval, ext_state);
1604 ASSERT_NE (map0.hash (), map1.hash ());
1605 ASSERT_NE (map0, map1);
1606
1607 /* Make the same change to map2. */
1608 map2.impl_set_state (y_sval, TEST_STATE_5, z_sval, ext_state);
1609 ASSERT_EQ (map1.hash (), map2.hash ());
1610 ASSERT_EQ (map1, map2);
1611 }
1612
1613 /* Equality and hashing shouldn't depend on ordering. */
1614 {
1615 const state_machine::state test_state_2 ("test state 2", 2);
1616 const state_machine::state_t TEST_STATE_2 = &test_state_2;
1617 const state_machine::state test_state_3 ("test state 3", 3);
1618 const state_machine::state_t TEST_STATE_3 = &test_state_3;
1619 sm_state_map map0 (*sm);
1620 sm_state_map map1 (*sm);
1621 sm_state_map map2 (*sm);
1622
1623 ASSERT_EQ (map0.hash (), map1.hash ());
1624 ASSERT_EQ (map0, map1);
1625
1626 region_model_manager mgr;
1627 region_model model (&mgr);
1628 const svalue *x_sval = model.get_rvalue (x, NULL);
1629 const svalue *y_sval = model.get_rvalue (y, NULL);
1630 const svalue *z_sval = model.get_rvalue (z, NULL);
1631
1632 map1.impl_set_state (x_sval, TEST_STATE_2, NULL, ext_state);
1633 map1.impl_set_state (y_sval, TEST_STATE_3, NULL, ext_state);
1634 map1.impl_set_state (z_sval, TEST_STATE_2, NULL, ext_state);
1635
1636 map2.impl_set_state (z_sval, TEST_STATE_2, NULL, ext_state);
1637 map2.impl_set_state (y_sval, TEST_STATE_3, NULL, ext_state);
1638 map2.impl_set_state (x_sval, TEST_STATE_2, NULL, ext_state);
1639
1640 ASSERT_EQ (map1.hash (), map2.hash ());
1641 ASSERT_EQ (map1, map2);
1642 }
1643
1644 // TODO: coverage for purging
1645 }
1646
1647 /* Check program_state works as expected. */
1648
1649 static void
1650 test_program_state_1 ()
1651 {
1652 /* Create a program_state for a global ptr "p" that has
1653 malloc sm-state, pointing to a region on the heap. */
1654 tree p = build_global_decl ("p", ptr_type_node);
1655
1656 state_machine *sm = make_malloc_state_machine (NULL);
1657 const state_machine::state_t UNCHECKED_STATE
1658 = sm->get_state_by_name ("unchecked");
1659 auto_delete_vec <state_machine> checkers;
1660 checkers.safe_push (sm);
1661
1662 engine eng;
1663 extrinsic_state ext_state (checkers, &eng);
1664 region_model_manager *mgr = eng.get_model_manager ();
1665 program_state s (ext_state);
1666 region_model *model = s.m_region_model;
1667 const svalue *size_in_bytes
1668 = mgr->get_or_create_unknown_svalue (size_type_node);
1669 const region *new_reg
1670 = model->create_region_for_heap_alloc (size_in_bytes, NULL);
1671 const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg);
1672 model->set_value (model->get_lvalue (p, NULL),
1673 ptr_sval, NULL);
1674 sm_state_map *smap = s.m_checker_states[0];
1675
1676 smap->impl_set_state (ptr_sval, UNCHECKED_STATE, NULL, ext_state);
1677 ASSERT_EQ (smap->get_state (ptr_sval, ext_state), UNCHECKED_STATE);
1678 }
1679
1680 /* Check that program_state works for string literals. */
1681
1682 static void
1683 test_program_state_2 ()
1684 {
1685 /* Create a program_state for a global ptr "p" that points to
1686 a string constant. */
1687 tree p = build_global_decl ("p", ptr_type_node);
1688
1689 tree string_cst_ptr = build_string_literal (4, "foo");
1690
1691 auto_delete_vec <state_machine> checkers;
1692 engine eng;
1693 extrinsic_state ext_state (checkers, &eng);
1694
1695 program_state s (ext_state);
1696 region_model *model = s.m_region_model;
1697 const region *p_reg = model->get_lvalue (p, NULL);
1698 const svalue *str_sval = model->get_rvalue (string_cst_ptr, NULL);
1699 model->set_value (p_reg, str_sval, NULL);
1700 }
1701
1702 /* Verify that program_states with identical sm-state can be merged,
1703 and that the merged program_state preserves the sm-state. */
1704
1705 static void
1706 test_program_state_merging ()
1707 {
1708 /* Create a program_state for a global ptr "p" that has
1709 malloc sm-state, pointing to a region on the heap. */
1710 tree p = build_global_decl ("p", ptr_type_node);
1711
1712 engine eng;
1713 region_model_manager *mgr = eng.get_model_manager ();
1714 program_point point (program_point::origin (*mgr));
1715 auto_delete_vec <state_machine> checkers;
1716 checkers.safe_push (make_malloc_state_machine (NULL));
1717 extrinsic_state ext_state (checkers, &eng);
1718
1719 program_state s0 (ext_state);
1720 uncertainty_t uncertainty;
1721 impl_region_model_context ctxt (&s0, ext_state, &uncertainty);
1722
1723 region_model *model0 = s0.m_region_model;
1724 const svalue *size_in_bytes
1725 = mgr->get_or_create_unknown_svalue (size_type_node);
1726 const region *new_reg
1727 = model0->create_region_for_heap_alloc (size_in_bytes, NULL);
1728 const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg);
1729 model0->set_value (model0->get_lvalue (p, &ctxt),
1730 ptr_sval, &ctxt);
1731 sm_state_map *smap = s0.m_checker_states[0];
1732 const state_machine::state test_state ("test state", 0);
1733 const state_machine::state_t TEST_STATE = &test_state;
1734 smap->impl_set_state (ptr_sval, TEST_STATE, NULL, ext_state);
1735 ASSERT_EQ (smap->get_state (ptr_sval, ext_state), TEST_STATE);
1736
1737 model0->canonicalize ();
1738
1739 /* Verify that canonicalization preserves sm-state. */
1740 ASSERT_EQ (smap->get_state (model0->get_rvalue (p, NULL), ext_state),
1741 TEST_STATE);
1742
1743 /* Make a copy of the program_state. */
1744 program_state s1 (s0);
1745 ASSERT_EQ (s0, s1);
1746
1747 /* We have two identical states with "p" pointing to a heap region
1748 with the given sm-state.
1749 They ought to be mergeable, preserving the sm-state. */
1750 program_state merged (ext_state);
1751 ASSERT_TRUE (s0.can_merge_with_p (s1, ext_state, point, &merged));
1752 merged.validate (ext_state);
1753
1754 /* Verify that the merged state has the sm-state for "p". */
1755 region_model *merged_model = merged.m_region_model;
1756 sm_state_map *merged_smap = merged.m_checker_states[0];
1757 ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, NULL),
1758 ext_state),
1759 TEST_STATE);
1760
1761 /* Try canonicalizing. */
1762 merged.m_region_model->canonicalize ();
1763 merged.validate (ext_state);
1764
1765 /* Verify that the merged state still has the sm-state for "p". */
1766 ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, NULL),
1767 ext_state),
1768 TEST_STATE);
1769
1770 /* After canonicalization, we ought to have equality with the inputs. */
1771 ASSERT_EQ (s0, merged);
1772 }
1773
1774 /* Verify that program_states with different global-state in an sm-state
1775 can't be merged. */
1776
1777 static void
1778 test_program_state_merging_2 ()
1779 {
1780 engine eng;
1781 region_model_manager *mgr = eng.get_model_manager ();
1782 program_point point (program_point::origin (*mgr));
1783 auto_delete_vec <state_machine> checkers;
1784 checkers.safe_push (make_signal_state_machine (NULL));
1785 extrinsic_state ext_state (checkers, &eng);
1786
1787 const state_machine::state test_state_0 ("test state 0", 0);
1788 const state_machine::state test_state_1 ("test state 1", 1);
1789 const state_machine::state_t TEST_STATE_0 = &test_state_0;
1790 const state_machine::state_t TEST_STATE_1 = &test_state_1;
1791
1792 program_state s0 (ext_state);
1793 {
1794 sm_state_map *smap0 = s0.m_checker_states[0];
1795 smap0->set_global_state (TEST_STATE_0);
1796 ASSERT_EQ (smap0->get_global_state (), TEST_STATE_0);
1797 }
1798
1799 program_state s1 (ext_state);
1800 {
1801 sm_state_map *smap1 = s1.m_checker_states[0];
1802 smap1->set_global_state (TEST_STATE_1);
1803 ASSERT_EQ (smap1->get_global_state (), TEST_STATE_1);
1804 }
1805
1806 ASSERT_NE (s0, s1);
1807
1808 /* They ought to not be mergeable. */
1809 program_state merged (ext_state);
1810 ASSERT_FALSE (s0.can_merge_with_p (s1, ext_state, point, &merged));
1811 }
1812
1813 /* Run all of the selftests within this file. */
1814
1815 void
1816 analyzer_program_state_cc_tests ()
1817 {
1818 test_sm_state_map ();
1819 test_program_state_1 ();
1820 test_program_state_2 ();
1821 test_program_state_merging ();
1822 test_program_state_merging_2 ();
1823 }
1824
1825 } // namespace selftest
1826
1827 #endif /* CHECKING_P */
1828
1829 } // namespace ana
1830
1831 #endif /* #if ENABLE_ANALYZER */
This page took 0.116725 seconds and 5 git commands to generate.