xref: /netbsd-src/external/gpl3/gcc/dist/gcc/analyzer/program-state.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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 (&regs);
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