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