xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/analyzer/engine.cc (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1 /* The analysis "engine".
2    Copyright (C) 2019-2020 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 "fold-const.h"
26 #include "gcc-rich-location.h"
27 #include "alloc-pool.h"
28 #include "fibonacci_heap.h"
29 #include "shortest-paths.h"
30 #include "diagnostic-core.h"
31 #include "diagnostic-event-id.h"
32 #include "diagnostic-path.h"
33 #include "function.h"
34 #include "pretty-print.h"
35 #include "sbitmap.h"
36 #include "bitmap.h"
37 #include "tristate.h"
38 #include "ordered-hash-map.h"
39 #include "selftest.h"
40 #include "analyzer/analyzer.h"
41 #include "analyzer/analyzer-logging.h"
42 #include "analyzer/region-model.h"
43 #include "analyzer/constraint-manager.h"
44 #include "analyzer/sm.h"
45 #include "analyzer/pending-diagnostic.h"
46 #include "analyzer/diagnostic-manager.h"
47 #include "cfg.h"
48 #include "basic-block.h"
49 #include "gimple.h"
50 #include "gimple-iterator.h"
51 #include "gimple-pretty-print.h"
52 #include "cgraph.h"
53 #include "digraph.h"
54 #include "analyzer/supergraph.h"
55 #include "analyzer/call-string.h"
56 #include "analyzer/program-point.h"
57 #include "analyzer/program-state.h"
58 #include "analyzer/exploded-graph.h"
59 #include "analyzer/analysis-plan.h"
60 #include "analyzer/checker-path.h"
61 #include "analyzer/state-purge.h"
62 #include "analyzer/bar-chart.h"
63 
64 /* For an overview, see gcc/doc/analyzer.texi.  */
65 
66 #if ENABLE_ANALYZER
67 
68 namespace ana {
69 
70 static int readability_comparator (const void *p1, const void *p2);
71 
72 /* class impl_region_model_context : public region_model_context.  */
73 
74 impl_region_model_context::
impl_region_model_context(exploded_graph & eg,const exploded_node * enode_for_diag,const program_state * old_state,program_state * new_state,state_change * change,const gimple * stmt,stmt_finder * stmt_finder)75 impl_region_model_context (exploded_graph &eg,
76 			   const exploded_node *enode_for_diag,
77 			   const program_state *old_state,
78 			   program_state *new_state,
79 			   state_change *change,
80 			   const gimple *stmt,
81 			   stmt_finder *stmt_finder)
82 : m_eg (&eg), m_logger (eg.get_logger ()),
83   m_enode_for_diag (enode_for_diag),
84   m_old_state (old_state),
85   m_new_state (new_state),
86   m_change (change),
87   m_stmt (stmt),
88   m_stmt_finder (stmt_finder),
89   m_ext_state (eg.get_ext_state ())
90 {
91 }
92 
93 impl_region_model_context::
impl_region_model_context(program_state * state,state_change * change,const extrinsic_state & ext_state,logger * logger)94 impl_region_model_context (program_state *state,
95 			   state_change *change,
96 			   const extrinsic_state &ext_state,
97 			   logger *logger)
98 : m_eg (NULL), m_logger (logger), m_enode_for_diag (NULL),
99   m_old_state (NULL),
100   m_new_state (state),
101   m_change (change),
102   m_stmt (NULL),
103   m_stmt_finder (NULL),
104   m_ext_state (ext_state)
105 {
106 }
107 
108 void
warn(pending_diagnostic * d)109 impl_region_model_context::warn (pending_diagnostic *d)
110 {
111   LOG_FUNC (get_logger ());
112   if (m_eg)
113     m_eg->get_diagnostic_manager ().add_diagnostic
114       (m_enode_for_diag, m_enode_for_diag->get_supernode (),
115        m_stmt, m_stmt_finder, d);
116 }
117 
118 void
remap_svalue_ids(const svalue_id_map & map)119 impl_region_model_context::remap_svalue_ids (const svalue_id_map &map)
120 {
121   m_new_state->remap_svalue_ids (map);
122   if (m_change)
123     m_change->remap_svalue_ids (map);
124 }
125 
126 int
on_svalue_purge(svalue_id first_unused_sid,const svalue_id_map & map)127 impl_region_model_context::on_svalue_purge (svalue_id first_unused_sid,
128 					    const svalue_id_map &map)
129 {
130   int total = 0;
131   int sm_idx;
132   sm_state_map *smap;
133   FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
134     {
135       const state_machine &sm = m_ext_state.get_sm (sm_idx);
136       total += smap->on_svalue_purge (sm, sm_idx, first_unused_sid,
137 				      map, this);
138     }
139   if (m_change)
140     total += m_change->on_svalue_purge (first_unused_sid);
141   return total;
142 }
143 
144 void
on_unknown_change(svalue_id sid)145 impl_region_model_context::on_unknown_change (svalue_id sid)
146 {
147   int sm_idx;
148   sm_state_map *smap;
149   FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
150     smap->on_unknown_change (sid);
151 }
152 
153 /* class setjmp_svalue : public svalue.  */
154 
155 /* Compare the fields of this setjmp_svalue with OTHER, returning true
156    if they are equal.
157    For use by svalue::operator==.  */
158 
159 bool
compare_fields(const setjmp_svalue & other) const160 setjmp_svalue::compare_fields (const setjmp_svalue &other) const
161 {
162   return m_setjmp_record == other.m_setjmp_record;
163 }
164 
165 /* Implementation of svalue::add_to_hash vfunc for setjmp_svalue.  */
166 
167 void
add_to_hash(inchash::hash & hstate) const168 setjmp_svalue::add_to_hash (inchash::hash &hstate) const
169 {
170   hstate.add_int (m_setjmp_record.m_enode->m_index);
171 }
172 
173 /* Get the index of the stored exploded_node.  */
174 
175 int
get_enode_index() const176 setjmp_svalue::get_enode_index () const
177 {
178   return m_setjmp_record.m_enode->m_index;
179 }
180 
181 /* Implementation of svalue::print_details vfunc for setjmp_svalue.  */
182 
183 void
print_details(const region_model & model ATTRIBUTE_UNUSED,svalue_id this_sid ATTRIBUTE_UNUSED,pretty_printer * pp) const184 setjmp_svalue::print_details (const region_model &model ATTRIBUTE_UNUSED,
185 			      svalue_id this_sid ATTRIBUTE_UNUSED,
186 			      pretty_printer *pp) const
187 {
188   pp_printf (pp, "setjmp: EN: %i", get_enode_index ());
189 }
190 
191 /* Concrete implementation of sm_context, wiring it up to the rest of this
192    file.  */
193 
194 class impl_sm_context : public sm_context
195 {
196 public:
impl_sm_context(exploded_graph & eg,int sm_idx,const state_machine & sm,const exploded_node * enode_for_diag,const program_state * old_state,program_state * new_state,state_change * change,const sm_state_map * old_smap,sm_state_map * new_smap,stmt_finder * stmt_finder=NULL)197   impl_sm_context (exploded_graph &eg,
198 		   int sm_idx,
199 		   const state_machine &sm,
200 		   const exploded_node *enode_for_diag,
201 		   const program_state *old_state,
202 		   program_state *new_state,
203 		   state_change *change,
204 		   const sm_state_map *old_smap,
205 		   sm_state_map *new_smap,
206 		   stmt_finder *stmt_finder = NULL)
207   : sm_context (sm_idx, sm),
208     m_logger (eg.get_logger ()),
209     m_eg (eg), m_enode_for_diag (enode_for_diag),
210     m_old_state (old_state), m_new_state (new_state),
211     m_change (change),
212     m_old_smap (old_smap), m_new_smap (new_smap),
213     m_stmt_finder (stmt_finder)
214   {
215   }
216 
get_logger() const217   logger *get_logger () const { return m_logger.get_logger (); }
218 
get_fndecl_for_call(const gcall * call)219   tree get_fndecl_for_call (const gcall *call) FINAL OVERRIDE
220   {
221     impl_region_model_context old_ctxt
222       (m_eg, m_enode_for_diag, NULL, NULL/*m_enode->get_state ()*/,
223        m_change, call);
224     region_model *model = m_new_state->m_region_model;
225     return model->get_fndecl_for_call (call, &old_ctxt);
226   }
227 
on_transition(const supernode * node ATTRIBUTE_UNUSED,const gimple * stmt ATTRIBUTE_UNUSED,tree var,state_machine::state_t from,state_machine::state_t to,tree origin)228   void on_transition (const supernode *node  ATTRIBUTE_UNUSED,
229 		      const gimple *stmt  ATTRIBUTE_UNUSED,
230 		      tree var,
231 		      state_machine::state_t from,
232 		      state_machine::state_t to,
233 		      tree origin) FINAL OVERRIDE
234   {
235     logger * const logger = get_logger ();
236     LOG_FUNC (logger);
237     impl_region_model_context old_ctxt
238       (m_eg, m_enode_for_diag, NULL, NULL/*m_enode->get_state ()*/,
239        m_change, stmt);
240     svalue_id var_old_sid
241       = m_old_state->m_region_model->get_rvalue (var, &old_ctxt);
242 
243     impl_region_model_context new_ctxt (m_eg, m_enode_for_diag,
244 					m_old_state, m_new_state,
245 					m_change, NULL);
246     svalue_id var_new_sid
247       = m_new_state->m_region_model->get_rvalue (var, &new_ctxt);
248     svalue_id origin_new_sid
249       = m_new_state->m_region_model->get_rvalue (origin, &new_ctxt);
250 
251     state_machine::state_t current = m_old_smap->get_state (var_old_sid);
252     if (current == from)
253       {
254 	if (logger)
255 	  logger->log ("%s: state transition of %qE: %s -> %s",
256 		       m_sm.get_name (),
257 		       var,
258 		       m_sm.get_state_name (from),
259 		       m_sm.get_state_name (to));
260 	m_new_smap->set_state (m_new_state->m_region_model, var_new_sid,
261 			       to, origin_new_sid);
262 	if (m_change)
263 	  m_change->add_sm_change (m_sm_idx, var_new_sid, from, to);
264       }
265   }
266 
warn_for_state(const supernode * snode,const gimple * stmt,tree var,state_machine::state_t state,pending_diagnostic * d)267   void warn_for_state (const supernode *snode, const gimple *stmt,
268 		       tree var, state_machine::state_t state,
269 		       pending_diagnostic *d) FINAL OVERRIDE
270   {
271     LOG_FUNC (get_logger ());
272     gcc_assert (d); // take ownership
273 
274     impl_region_model_context old_ctxt
275       (m_eg, m_enode_for_diag, m_old_state, m_new_state, m_change, NULL);
276     state_machine::state_t current;
277     if (var)
278       {
279 	svalue_id var_old_sid
280 	  = m_old_state->m_region_model->get_rvalue (var, &old_ctxt);
281 	current = m_old_smap->get_state (var_old_sid);
282       }
283     else
284       current = m_old_smap->get_global_state ();
285 
286     if (state == current)
287       {
288 	m_eg.get_diagnostic_manager ().add_diagnostic
289 	  (&m_sm, m_enode_for_diag, snode, stmt, m_stmt_finder,
290 	   var, state, d);
291       }
292     else
293       delete d;
294   }
295 
296   /* Hook for picking more readable trees for SSA names of temporaries,
297      so that rather than e.g.
298        "double-free of '<unknown>'"
299      we can print:
300        "double-free of 'inbuf.data'".  */
301 
get_readable_tree(tree expr)302   tree get_readable_tree (tree expr) FINAL OVERRIDE
303   {
304     /* Only for SSA_NAMEs of temporaries; otherwise, return EXPR, as it's
305        likely to be the least surprising tree to report.  */
306     if (TREE_CODE (expr) != SSA_NAME)
307       return expr;
308     if (SSA_NAME_VAR (expr) != NULL)
309       return expr;
310 
311     gcc_assert (m_new_state);
312     svalue_id sid = m_new_state->m_region_model->get_rvalue (expr, NULL);
313     /* Find trees for all regions storing the value.  */
314     auto_vec<path_var> pvs;
315     m_new_state->m_region_model->get_path_vars_for_svalue (sid, &pvs);
316     if (pvs.length () < 1)
317       return expr;
318     /* Pick the "best" such tree.  */
319     // TODO: should we also consider (and consolidate) equiv classes?
320     pvs.qsort (readability_comparator);
321     return pvs[0].m_tree;
322   }
323 
get_global_state() const324   state_machine::state_t get_global_state () const FINAL OVERRIDE
325   {
326     return m_old_state->m_checker_states[m_sm_idx]->get_global_state ();
327   }
328 
set_global_state(state_machine::state_t state)329   void set_global_state (state_machine::state_t state) FINAL OVERRIDE
330   {
331     m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
332   }
333 
on_custom_transition(custom_transition * transition)334   void on_custom_transition (custom_transition *transition) FINAL OVERRIDE
335   {
336     transition->impl_transition (&m_eg,
337 				 const_cast<exploded_node *> (m_enode_for_diag),
338 				 m_sm_idx);
339   }
340 
341   log_user m_logger;
342   exploded_graph &m_eg;
343   const exploded_node *m_enode_for_diag;
344   const program_state *m_old_state;
345   program_state *m_new_state;
346   state_change *m_change;
347   const sm_state_map *m_old_smap;
348   sm_state_map *m_new_smap;
349   stmt_finder *m_stmt_finder;
350 };
351 
352 /* Subclass of stmt_finder for finding the best stmt to report the leak at,
353    given the emission path.  */
354 
355 class leak_stmt_finder : public stmt_finder
356 {
357 public:
leak_stmt_finder(const exploded_graph & eg,tree var)358   leak_stmt_finder (const exploded_graph &eg, tree var)
359   : m_eg (eg), m_var (var) {}
360 
clone() const361   stmt_finder *clone () const FINAL OVERRIDE
362   {
363     return new leak_stmt_finder (m_eg, m_var);
364   }
365 
find_stmt(const exploded_path & epath)366   const gimple *find_stmt (const exploded_path &epath)
367     FINAL OVERRIDE
368   {
369     logger * const logger = m_eg.get_logger ();
370     LOG_FUNC (logger);
371 
372     if (TREE_CODE (m_var) == SSA_NAME)
373       {
374 	/* Locate the final write to this SSA name in the path.  */
375 	const gimple *def_stmt = SSA_NAME_DEF_STMT (m_var);
376 
377 	int idx_of_def_stmt;
378 	bool found = epath.find_stmt_backwards (def_stmt, &idx_of_def_stmt);
379 	if (!found)
380 	  goto not_found;
381 
382 	/* What was the next write to the underlying var
383 	   after the SSA name was set? (if any).  */
384 
385 	for (unsigned idx = idx_of_def_stmt + 1;
386 	     idx < epath.m_edges.length ();
387 	     ++idx)
388 	  {
389 	    const exploded_edge *eedge = epath.m_edges[idx];
390 	    if (logger)
391 	      logger->log ("eedge[%i]: EN %i -> EN %i",
392 			   idx,
393 			   eedge->m_src->m_index,
394 			   eedge->m_dest->m_index);
395 	    const exploded_node *dst_node = eedge->m_dest;
396 	    const program_point &dst_point = dst_node->get_point ();
397 	    const gimple *stmt = dst_point.get_stmt ();
398 	    if (!stmt)
399 	      continue;
400 	    if (const gassign *assign = dyn_cast <const gassign *> (stmt))
401 	      {
402 		tree lhs = gimple_assign_lhs (assign);
403 		if (TREE_CODE (lhs) == SSA_NAME
404 		    && SSA_NAME_VAR (lhs) == SSA_NAME_VAR (m_var))
405 		  return assign;
406 	      }
407 	  }
408       }
409 
410   not_found:
411 
412     /* Look backwards for the first statement with a location.  */
413     int i;
414     const exploded_edge *eedge;
415     FOR_EACH_VEC_ELT_REVERSE (epath.m_edges, i, eedge)
416       {
417 	if (logger)
418 	  logger->log ("eedge[%i]: EN %i -> EN %i",
419 		       i,
420 		       eedge->m_src->m_index,
421 		       eedge->m_dest->m_index);
422 	const exploded_node *dst_node = eedge->m_dest;
423 	const program_point &dst_point = dst_node->get_point ();
424 	const gimple *stmt = dst_point.get_stmt ();
425 	if (stmt)
426 	  if (get_pure_location (stmt->location) != UNKNOWN_LOCATION)
427 	    return stmt;
428       }
429 
430     gcc_unreachable ();
431     return NULL;
432   }
433 
434 private:
435   const exploded_graph &m_eg;
436   tree m_var;
437 };
438 
439 /* A measurement of how good EXPR is for presenting to the user, so
440    that e.g. we can say prefer printing
441      "leak of 'tmp.m_ptr'"
442    over:
443      "leak of '<unknown>'".  */
444 
445 static int
readability(const_tree expr)446 readability (const_tree expr)
447 {
448   gcc_assert (expr);
449   switch (TREE_CODE (expr))
450     {
451     case COMPONENT_REF:
452     case MEM_REF:
453       /* Impose a slight readability penalty relative to that of
454 	 operand 0.  */
455       return readability (TREE_OPERAND (expr, 0)) - 1;
456 
457     case SSA_NAME:
458       {
459 	if (tree var = SSA_NAME_VAR (expr))
460 	  return readability (var);
461 	/* Avoid printing '<unknown>' for SSA names for temporaries.  */
462 	return -1;
463       }
464       break;
465 
466     case VAR_DECL:
467       /* Arbitrarily-chosen "high readability" value.  */
468       return 256;
469 
470     default:
471       return 0;
472     }
473 
474   return 0;
475 }
476 
477 /* A qsort comparator for trees to sort them into most user-readable to
478    least user-readable.  */
479 
480 static int
readability_comparator(const void * p1,const void * p2)481 readability_comparator (const void *p1, const void *p2)
482 {
483   path_var pv1 = *(path_var const *)p1;
484   path_var pv2 = *(path_var const *)p2;
485 
486   /* TODO: should we consider stack depths?  */
487   int r1 = readability (pv1.m_tree);
488   int r2 = readability (pv2.m_tree);
489 
490   return r2 - r1;
491 }
492 
493 /* Create an sm_context and use it to call SM's on_leak vfunc, so that
494    it can potentially complain about a leak of DST_SID (in a new region_model)
495    in the given STATE, where MAP can be used to map SID back to an "old"
496    region_model.  */
497 
498 void
on_state_leak(const state_machine & sm,int sm_idx,svalue_id dst_sid,svalue_id first_unused_sid,const svalue_id_map & map,state_machine::state_t state)499 impl_region_model_context::on_state_leak (const state_machine &sm,
500 					  int sm_idx,
501 					  svalue_id dst_sid,
502 					  svalue_id first_unused_sid,
503 					  const svalue_id_map &map,
504 					  state_machine::state_t state)
505 {
506   logger * const logger = get_logger ();
507   LOG_SCOPE (logger);
508   if (logger)
509     logger->log ("considering leak of sv%i", dst_sid.as_int ());
510 
511   if (!m_eg)
512     return;
513 
514   /* m_old_state also needs to be non-NULL so that the sm_ctxt can look
515      up the old state of the sid.  */
516   gcc_assert (m_old_state);
517 
518   /* Don't report on sid leaking if it's equal to one of the used sids.
519      For example, given:
520        some_non_trivial_expression = malloc (sizeof (struct foo));
521      we have:
522        _1 = malloc;                         (void *)
523        some_non_trivial_expression = _1;    (struct foo *)
524      and at leak-detection time we may have:
525        sv5: {type: 'struct foo *', &r3}  (used)
526        sv6: {type: 'void *', &r3}         (unused)
527      where both point to the same region.  We don't want to report a
528      leak of sv6, so we reject the report due to its equality with sv5.  */
529   gcc_assert (m_new_state);
530   gcc_assert (!first_unused_sid.null_p ());
531   for (int i = 0; i < first_unused_sid.as_int (); i++)
532     {
533       svalue_id used_sid = svalue_id::from_int (i);
534 
535       /* Use the "_without_cm" form of eval_condition, since
536 	 we're half-way through purging - we don't want to introduce new
537 	 equivalence classes into the constraint_manager for "sid" and
538 	 for each of the used_sids.  */
539       const region_model &rm = *m_new_state->m_region_model;
540       tristate eq = rm.eval_condition_without_cm (dst_sid, EQ_EXPR, used_sid);
541       if (eq.is_true ())
542 	{
543 	  if (logger)
544 	    logger->log ("rejecting leak of sv%i due to equality with sv%i",
545 			 dst_sid.as_int (), used_sid.as_int ());
546 	  return;
547 	}
548     }
549 
550   /* SID has leaked within the new state: no regions use it.
551      We need to convert it back to a tree, but since no regions use it, we
552      have to use MAP to convert it back to an svalue_id within the old state.
553      We can then look that svalue_id up to locate regions and thus tree(s)
554      that use it.  */
555 
556   svalue_id old_sid = map.get_src_for_dst (dst_sid);
557 
558   auto_vec<path_var> leaked_pvs;
559   m_old_state->m_region_model->get_path_vars_for_svalue (old_sid, &leaked_pvs);
560 
561   if (leaked_pvs.length () < 1)
562     return;
563 
564   /* Find "best" leaked tree.
565      Sort the leaks into most human-readable first, through
566      to least user-readable.  Given that we only emit one
567      leak per EC, this ought to ensure that we pick the most
568      user-readable description of each leaking EC.
569      This assumes that all vars in the EC have the same state.  */
570   leaked_pvs.qsort (readability_comparator);
571 
572   tree leaked_tree = leaked_pvs[0].m_tree;
573   if (logger)
574     logger->log ("best leaked_tree: %qE", leaked_tree);
575 
576   leak_stmt_finder stmt_finder (*m_eg, leaked_tree);
577   impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
578 			   m_old_state, m_new_state,
579 			   m_change,
580 			   m_old_state->m_checker_states[sm_idx],
581 			   m_new_state->m_checker_states[sm_idx],
582 			   &stmt_finder);
583   gcc_assert (m_enode_for_diag);
584 
585   /* Don't complain about leaks when returning from "main".  */
586   if (m_enode_for_diag->get_supernode ()
587       && m_enode_for_diag->get_supernode ()->return_p ())
588     {
589       tree fndecl = m_enode_for_diag->get_function ()->decl;
590       if (0 == strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main"))
591 	{
592 	  if (logger)
593 	    logger->log ("not reporting leak from main");
594 	  return;
595 	}
596     }
597 
598   pending_diagnostic *pd = sm.on_leak (leaked_tree);
599   if (pd)
600     m_eg->get_diagnostic_manager ().add_diagnostic
601       (&sm, m_enode_for_diag, m_enode_for_diag->get_supernode (),
602        m_stmt, &stmt_finder,
603        leaked_tree, state, pd);
604 }
605 
606 /* Implementation of region_model_context::on_inherited_svalue vfunc
607    for impl_region_model_context.
608    Notify all checkers that CHILD_SID has been created from PARENT_SID,
609    so that those state machines that inherit state can propagate the state
610    from parent to child.  */
611 
612 void
on_inherited_svalue(svalue_id parent_sid,svalue_id child_sid)613 impl_region_model_context::on_inherited_svalue (svalue_id parent_sid,
614 						svalue_id child_sid)
615 {
616   if (!m_new_state)
617     return;
618 
619   int sm_idx;
620   sm_state_map *smap;
621   FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
622     {
623       const state_machine &sm = m_ext_state.get_sm (sm_idx);
624       if (sm.inherited_state_p ())
625 	smap->on_inherited_svalue (parent_sid, child_sid);
626     }
627 }
628 
629 /* Implementation of region_model_context::on_cast vfunc
630    for impl_region_model_context.
631    Notify all checkers that DST_SID is a cast of SRC_SID, so that sm-state
632    can be propagated from src to dst.  */
633 
634 void
on_cast(svalue_id src_sid,svalue_id dst_sid)635 impl_region_model_context::on_cast (svalue_id src_sid,
636 				    svalue_id dst_sid)
637 {
638   if (!m_new_state)
639     return;
640 
641   int sm_idx;
642   sm_state_map *smap;
643   FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
644     smap->on_cast (src_sid, dst_sid);
645 }
646 
647 /* Implementation of region_model_context::on_condition vfunc.
648    Notify all state machines about the condition, which could lead to
649    state transitions.  */
650 
651 void
on_condition(tree lhs,enum tree_code op,tree rhs)652 impl_region_model_context::on_condition (tree lhs, enum tree_code op, tree rhs)
653 {
654   int sm_idx;
655   sm_state_map *smap;
656   FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
657     {
658       const state_machine &sm = m_ext_state.get_sm (sm_idx);
659       impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
660 			       m_old_state, m_new_state,
661 			       m_change,
662 			       m_old_state->m_checker_states[sm_idx],
663 			       m_new_state->m_checker_states[sm_idx]);
664       sm.on_condition (&sm_ctxt,
665 		       m_enode_for_diag->get_supernode (), m_stmt,
666 		       lhs, op, rhs);
667     }
668 }
669 
670 /* Implementation of region_model_context::on_phi vfunc.
671    Notify all state machines about the phi, which could lead to
672    state transitions.  */
673 
674 void
on_phi(const gphi * phi,tree rhs)675 impl_region_model_context::on_phi (const gphi *phi, tree rhs)
676 {
677   int sm_idx;
678   sm_state_map *smap;
679   FOR_EACH_VEC_ELT (m_new_state->m_checker_states, sm_idx, smap)
680     {
681       const state_machine &sm = m_ext_state.get_sm (sm_idx);
682       impl_sm_context sm_ctxt (*m_eg, sm_idx, sm, m_enode_for_diag,
683 			       m_old_state, m_new_state,
684 			       m_change,
685 			       m_old_state->m_checker_states[sm_idx],
686 			       m_new_state->m_checker_states[sm_idx]);
687       sm.on_phi (&sm_ctxt, m_enode_for_diag->get_supernode (), phi, rhs);
688     }
689 }
690 
691 /* Implementation of region_model_context::on_unexpected_tree_code vfunc.
692    Mark the new state as being invalid for further exploration.
693    TODO(stage1): introduce a warning for when this occurs.  */
694 
695 void
on_unexpected_tree_code(tree t,const dump_location_t & loc)696 impl_region_model_context::on_unexpected_tree_code (tree t,
697 						    const dump_location_t &loc)
698 {
699   logger * const logger = get_logger ();
700   if (logger)
701     logger->log ("unhandled tree code: %qs in %qs at %s:%i",
702 		 t ? get_tree_code_name (TREE_CODE (t)) : "(null)",
703 		 loc.get_impl_location ().m_function,
704 		 loc.get_impl_location ().m_file,
705 		 loc.get_impl_location ().m_line);
706   if (m_new_state)
707     m_new_state->m_valid = false;
708 }
709 
710 /* struct point_and_state.  */
711 
712 /* Assert that this object is sane.  */
713 
714 void
validate(const extrinsic_state & ext_state) const715 point_and_state::validate (const extrinsic_state &ext_state) const
716 {
717   /* Skip this in a release build.  */
718 #if !CHECKING_P
719   return;
720 #endif
721 
722   m_point.validate ();
723 
724   m_state.validate (ext_state);
725 
726   /* Verify that the callstring's model of the stack corresponds to that
727      of the region_model.  */
728   /* They should have the same depth.  */
729   gcc_assert (m_point.get_stack_depth ()
730 	      == m_state.m_region_model->get_stack_depth ());
731   /* Check the functions in the callstring vs those in the frames
732      at each depth.  */
733   for (int depth = 0; depth < m_point.get_stack_depth (); ++depth)
734     {
735       gcc_assert (m_point.get_function_at_depth (depth)
736 		  == m_state.m_region_model->get_function_at_depth (depth));
737     }
738 }
739 
740 /* Subroutine of print_enode_indices: print a run of indices from START_IDX
741    to END_IDX to PP, using and updating *FIRST_RUN.  */
742 
743 static void
print_run(pretty_printer * pp,int start_idx,int end_idx,bool * first_run)744 print_run (pretty_printer *pp, int start_idx, int end_idx,
745 	   bool *first_run)
746 {
747   if (!(*first_run))
748     pp_string (pp, ", ");
749   *first_run = false;
750   if (start_idx == end_idx)
751     pp_printf (pp, "EN: %i", start_idx);
752   else
753     pp_printf (pp, "EN: %i-%i", start_idx, end_idx);
754 }
755 
756 /* Print the indices within ENODES to PP, collecting them as
757    runs/singletons e.g. "EN: 4-7, EN: 20-23, EN: 42".  */
758 
759 static void
print_enode_indices(pretty_printer * pp,const auto_vec<exploded_node * > & enodes)760 print_enode_indices (pretty_printer *pp,
761 		     const auto_vec<exploded_node *> &enodes)
762 {
763   int cur_start_idx = -1;
764   int cur_finish_idx = -1;
765   bool first_run = true;
766   unsigned i;
767   exploded_node *enode;
768   FOR_EACH_VEC_ELT (enodes, i, enode)
769     {
770       if (cur_start_idx == -1)
771 	{
772 	  gcc_assert (cur_finish_idx == -1);
773 	  cur_start_idx = cur_finish_idx = enode->m_index;
774 	}
775       else
776 	{
777 	  if (enode->m_index == cur_finish_idx + 1)
778 	    /* Continuation of a run.  */
779 	    cur_finish_idx = enode->m_index;
780 	  else
781 	    {
782 	      /* Finish existing run, start a new one.  */
783 	      gcc_assert (cur_start_idx >= 0);
784 	      gcc_assert (cur_finish_idx >= 0);
785 	      print_run (pp, cur_start_idx, cur_finish_idx,
786 			 &first_run);
787 	      cur_start_idx = cur_finish_idx = enode->m_index;
788 	    }
789 	}
790     }
791   /* Finish any existing run.  */
792   if (cur_start_idx >= 0)
793     {
794       gcc_assert (cur_finish_idx >= 0);
795       print_run (pp, cur_start_idx, cur_finish_idx,
796 		 &first_run);
797     }
798 }
799 
800 /* class exploded_node : public dnode<eg_traits>.  */
801 
802 /* exploded_node's ctor.  */
803 
exploded_node(const point_and_state & ps,int index)804 exploded_node::exploded_node (const point_and_state &ps,
805 			      int index)
806 : m_ps (ps), m_status (STATUS_WORKLIST), m_index (index)
807 {
808   gcc_checking_assert (ps.get_state ().m_region_model->canonicalized_p ());
809 }
810 
811 /* For use by dump_dot, get a value for the .dot "fillcolor" attribute.
812    Colorize by sm-state, to make it easier to see how sm-state propagates
813    through the exploded_graph.  */
814 
815 const char *
get_dot_fillcolor() const816 exploded_node::get_dot_fillcolor () const
817 {
818   const program_state &state = get_state ();
819 
820   /* We want to be able to easily distinguish the no-sm-state case,
821      and to be able to distinguish cases where there's a single state
822      from each other.
823 
824      Sum the sm_states, and use the result to choose from a table,
825      modulo table-size, special-casing the "no sm-state" case.   */
826   int total_sm_state = 0;
827   int i;
828   sm_state_map *smap;
829   FOR_EACH_VEC_ELT (state.m_checker_states, i, smap)
830     {
831       for (sm_state_map::iterator_t iter = smap->begin ();
832 	 iter != smap->end ();
833 	   ++iter)
834 	total_sm_state += (*iter).second.m_state;
835       total_sm_state += smap->get_global_state ();
836     }
837 
838   if (total_sm_state > 0)
839     {
840       /* An arbitrarily-picked collection of light colors.  */
841       const char * const colors[]
842 	= {"azure", "coral", "cornsilk", "lightblue", "yellow"};
843       const int num_colors = sizeof (colors) / sizeof (colors[0]);
844       return colors[total_sm_state % num_colors];
845     }
846   else
847     /* No sm-state.   */
848     return "lightgrey";
849 }
850 
851 /* Implementation of dnode::dump_dot vfunc for exploded_node.  */
852 
853 void
dump_dot(graphviz_out * gv,const dump_args_t & args) const854 exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &args) const
855 {
856   pretty_printer *pp = gv->get_pp ();
857 
858   dump_dot_id (pp);
859   pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=\"",
860 	     get_dot_fillcolor ());
861   pp_write_text_to_stream (pp);
862 
863   pp_printf (pp, "EN: %i", m_index);
864   if (m_status == STATUS_MERGER)
865     pp_string (pp, " (merger)");
866   pp_newline (pp);
867 
868   format f (true);
869   m_ps.get_point ().print (pp, f);
870   pp_newline (pp);
871 
872   const extrinsic_state &ext_state = args.m_eg.get_ext_state ();
873   const program_state &state = m_ps.get_state ();
874   state.dump_to_pp (ext_state, true, pp);
875   pp_newline (pp);
876 
877   {
878     int i;
879     sm_state_map *smap;
880     FOR_EACH_VEC_ELT (state.m_checker_states, i, smap)
881       {
882 	if (!smap->is_empty_p ())
883 	  {
884 	    pp_printf (pp, "%s: ", ext_state.get_name (i));
885 	    smap->print (ext_state.get_sm (i), state.m_region_model, pp);
886 	    pp_newline (pp);
887 	  }
888       }
889   }
890 
891   /* Dump any saved_diagnostics at this enode.  */
892   {
893     const diagnostic_manager &dm = args.m_eg.get_diagnostic_manager ();
894     for (unsigned i = 0; i < dm.get_num_diagnostics (); i++)
895       {
896 	const saved_diagnostic *sd = dm.get_saved_diagnostic (i);
897 	if (sd->m_enode == this)
898 	  {
899 	    pp_printf (pp, "DIAGNOSTIC: %s", sd->m_d->get_kind ());
900 	    pp_newline (pp);
901 	  }
902       }
903   }
904 
905   pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
906 
907   pp_string (pp, "\"];\n\n");
908   pp_flush (pp);
909 }
910 
911 /* Dump this to PP in a form suitable for use as an id in .dot output.  */
912 
913 void
dump_dot_id(pretty_printer * pp) const914 exploded_node::dump_dot_id (pretty_printer *pp) const
915 {
916   pp_printf (pp, "exploded_node_%i", m_index);
917 }
918 
919 /* Dump a multiline representation of this node to PP.  */
920 
921 void
dump_to_pp(pretty_printer * pp,const extrinsic_state & ext_state) const922 exploded_node::dump_to_pp (pretty_printer *pp,
923 			   const extrinsic_state &ext_state) const
924 {
925   pp_printf (pp, "EN: %i", m_index);
926   pp_newline (pp);
927 
928   format f (true);
929   m_ps.get_point ().print (pp, f);
930   pp_newline (pp);
931 
932   m_ps.get_state ().dump_to_pp (ext_state, false, pp);
933   pp_newline (pp);
934 }
935 
936 /* Dump a multiline representation of this node to FILE.  */
937 
938 void
dump(FILE * fp,const extrinsic_state & ext_state) const939 exploded_node::dump (FILE *fp,
940 		     const extrinsic_state &ext_state) const
941 {
942   pretty_printer pp;
943   pp_format_decoder (&pp) = default_tree_printer;
944   pp_show_color (&pp) = pp_show_color (global_dc->printer);
945   pp.buffer->stream = fp;
946   dump_to_pp (&pp, ext_state);
947   pp_flush (&pp);
948 }
949 
950 /* Dump a multiline representation of this node to stderr.  */
951 
952 DEBUG_FUNCTION void
dump(const extrinsic_state & ext_state) const953 exploded_node::dump (const extrinsic_state &ext_state) const
954 {
955   dump (stderr, ext_state);
956 }
957 
958 } // namespace ana
959 
960 /* Return true if FNDECL has a gimple body.  */
961 // TODO: is there a pre-canned way to do this?
962 
963 bool
fndecl_has_gimple_body_p(tree fndecl)964 fndecl_has_gimple_body_p (tree fndecl)
965 {
966   if (fndecl == NULL_TREE)
967     return false;
968 
969   cgraph_node *n = cgraph_node::get (fndecl);
970   if (!n)
971     return false;
972 
973   return n->has_gimple_body_p ();
974 }
975 
976 namespace ana {
977 
978 /* A pending_diagnostic subclass for implementing "__analyzer_dump_path".  */
979 
980 class dump_path_diagnostic
981   : public pending_diagnostic_subclass<dump_path_diagnostic>
982 {
983 public:
emit(rich_location * richloc)984   bool emit (rich_location *richloc) FINAL OVERRIDE
985   {
986     inform (richloc, "path");
987     return true;
988   }
989 
get_kind() const990   const char *get_kind () const FINAL OVERRIDE { return "dump_path_diagnostic"; }
991 
operator ==(const dump_path_diagnostic &) const992   bool operator== (const dump_path_diagnostic &) const
993   {
994     return true;
995   }
996 };
997 
998 /* Modify STATE in place, applying the effects of the stmt at this node's
999    point.  */
1000 
1001 exploded_node::on_stmt_flags
on_stmt(exploded_graph & eg,const supernode * snode,const gimple * stmt,program_state * state,state_change * change) const1002 exploded_node::on_stmt (exploded_graph &eg,
1003 			const supernode *snode,
1004 			const gimple *stmt,
1005 			program_state *state,
1006 			state_change *change) const
1007 {
1008   /* Preserve the old state.  It is used here for looking
1009      up old checker states, for determining state transitions, and
1010      also within impl_region_model_context and impl_sm_context for
1011      going from tree to svalue_id.  */
1012   const program_state old_state (*state);
1013 
1014   impl_region_model_context ctxt (eg, this,
1015 				  &old_state, state, change,
1016 				  stmt);
1017 
1018   if (const gassign *assign = dyn_cast <const gassign *> (stmt))
1019     state->m_region_model->on_assignment (assign, &ctxt);
1020 
1021   if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
1022     state->m_region_model->on_return (return_, &ctxt);
1023 
1024   /* Track whether we have a gcall to a function that's not recognized by
1025      anything, for which we don't have a function body, or for which we
1026      don't know the fndecl.  */
1027   bool unknown_side_effects = false;
1028   if (const gcall *call = dyn_cast <const gcall *> (stmt))
1029     {
1030       /* Debugging/test support.  */
1031       if (is_special_named_call_p (call, "__analyzer_dump", 0))
1032 	{
1033 	  /* Handle the builtin "__analyzer_dump" by dumping state
1034 	     to stderr.  */
1035 	  dump (eg.get_ext_state ());
1036 	}
1037       else if (is_special_named_call_p (call, "__analyzer_dump_path", 0))
1038 	{
1039 	  /* Handle the builtin "__analyzer_dump_path" by queuing a
1040 	     diagnostic at this exploded_node.  */
1041 	  ctxt.warn (new dump_path_diagnostic ());
1042 	}
1043       else if (is_special_named_call_p (call, "__analyzer_dump_region_model", 0))
1044 	{
1045 	  /* Handle the builtin "__analyzer_dump_region_model" by dumping
1046 	     the region model's state to stderr.  */
1047 	  state->m_region_model->dump (false);
1048 	}
1049       else if (is_special_named_call_p (call, "__analyzer_eval", 1))
1050 	{
1051 	  /* Handle the builtin "__analyzer_eval" by evaluating the input
1052 	     and dumping as a dummy warning, so that test cases can use
1053 	     dg-warning to validate the result (and so unexpected warnings will
1054 	     lead to DejaGnu failures).  */
1055 	  tree t_arg = gimple_call_arg (call, 0);
1056 	  tristate t
1057 	    = state->m_region_model->eval_condition (t_arg,
1058 						     NE_EXPR,
1059 						     integer_zero_node,
1060 						     &ctxt);
1061 	  warning_at (call->location, 0, "%s", t.as_string ());
1062 	}
1063       else if (is_special_named_call_p (call, "__analyzer_break", 0))
1064 	{
1065 	  /* Handle the builtin "__analyzer_break" by triggering a
1066 	     breakpoint.  */
1067 	  /* TODO: is there a good cross-platform way to do this?  */
1068 	  raise (SIGINT);
1069 	}
1070       else if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
1071 					1))
1072 	{
1073 	  /* This is handled elsewhere.  */
1074 	}
1075       else if (is_setjmp_call_p (call))
1076 	state->m_region_model->on_setjmp (call, this, &ctxt);
1077       else if (is_longjmp_call_p (call))
1078 	{
1079 	  on_longjmp (eg, call, state, &ctxt);
1080 	  return on_stmt_flags::terminate_path ();
1081 	}
1082       else
1083 	unknown_side_effects = state->m_region_model->on_call_pre (call, &ctxt);
1084     }
1085 
1086   bool any_sm_changes = false;
1087   int sm_idx;
1088   sm_state_map *smap;
1089   FOR_EACH_VEC_ELT (old_state.m_checker_states, sm_idx, smap)
1090     {
1091       const state_machine &sm = eg.get_ext_state ().get_sm (sm_idx);
1092       const sm_state_map *old_smap
1093 	= old_state.m_checker_states[sm_idx];
1094       sm_state_map *new_smap = state->m_checker_states[sm_idx];
1095       impl_sm_context sm_ctxt (eg, sm_idx, sm, this, &old_state, state,
1096 			       change,
1097 			       old_smap, new_smap);
1098       /* Allow the state_machine to handle the stmt.  */
1099       if (sm.on_stmt (&sm_ctxt, snode, stmt))
1100 	unknown_side_effects = false;
1101       else
1102 	{
1103 	  /* For those stmts that were not handled by the state machine.  */
1104 	  if (const gcall *call = dyn_cast <const gcall *> (stmt))
1105 	    {
1106 	      tree callee_fndecl
1107 		= state->m_region_model->get_fndecl_for_call (call, &ctxt);
1108 
1109 	      if (!fndecl_has_gimple_body_p (callee_fndecl))
1110 		new_smap->purge_for_unknown_fncall (eg, sm, call, callee_fndecl,
1111 						    state->m_region_model,
1112 						    &ctxt);
1113 	    }
1114 	}
1115       if (*old_smap != *new_smap)
1116 	any_sm_changes = true;
1117     }
1118 
1119   if (const gcall *call = dyn_cast <const gcall *> (stmt))
1120     state->m_region_model->on_call_post (call, unknown_side_effects, &ctxt);
1121 
1122   return on_stmt_flags (any_sm_changes);
1123 }
1124 
1125 /* Consider the effect of following superedge SUCC from this node.
1126 
1127    Return true if it's feasible to follow the edge, or false
1128    if it's infeasible.
1129 
1130    Examples: if it's the "true" branch within
1131    a CFG and we know the conditional is false, we know it's infeasible.
1132    If it's one of multiple interprocedual "return" edges, then only
1133    the edge back to the most recent callsite is feasible.
1134 
1135    Update NEXT_STATE accordingly (e.g. to record that a condition was
1136    true or false, or that the NULL-ness of a pointer has been checked,
1137    pushing/popping stack frames, etc).
1138 
1139    Update NEXT_POINT accordingly (updating the call string).  */
1140 
1141 bool
on_edge(exploded_graph & eg,const superedge * succ,program_point * next_point,program_state * next_state,state_change * change) const1142 exploded_node::on_edge (exploded_graph &eg,
1143 			const superedge *succ,
1144 			program_point *next_point,
1145 			program_state *next_state,
1146 			state_change *change) const
1147 {
1148   LOG_FUNC (eg.get_logger ());
1149 
1150   if (!next_point->on_edge (eg, succ))
1151     return false;
1152 
1153   if (!next_state->on_edge (eg, *this, succ, change))
1154     return false;
1155 
1156   return true;
1157 }
1158 
1159 /* Verify that the stack at LONGJMP_POINT is still valid, given a call
1160    to "setjmp" at SETJMP_POINT - the stack frame that "setjmp" was
1161    called in must still be valid.
1162 
1163    Caveat: this merely checks the call_strings in the points; it doesn't
1164    detect the case where a frame returns and is then called again.  */
1165 
1166 static bool
valid_longjmp_stack_p(const program_point & longjmp_point,const program_point & setjmp_point)1167 valid_longjmp_stack_p (const program_point &longjmp_point,
1168 		       const program_point &setjmp_point)
1169 {
1170   const call_string &cs_at_longjmp = longjmp_point.get_call_string ();
1171   const call_string &cs_at_setjmp = setjmp_point.get_call_string ();
1172 
1173   if (cs_at_longjmp.length () < cs_at_setjmp.length ())
1174     return false;
1175 
1176   /* Check that the call strings match, up to the depth of the
1177      setjmp point.  */
1178   for (unsigned depth = 0; depth < cs_at_setjmp.length (); depth++)
1179     if (cs_at_longjmp[depth] != cs_at_setjmp[depth])
1180       return false;
1181 
1182   return true;
1183 }
1184 
1185 /* A pending_diagnostic subclass for complaining about bad longjmps,
1186    where the enclosing function of the "setjmp" has returned (and thus
1187    the stack frame no longer exists).  */
1188 
1189 class stale_jmp_buf : public pending_diagnostic_subclass<dump_path_diagnostic>
1190 {
1191 public:
stale_jmp_buf(const gcall * setjmp_call,const gcall * longjmp_call)1192   stale_jmp_buf (const gcall *setjmp_call, const gcall *longjmp_call)
1193   : m_setjmp_call (setjmp_call), m_longjmp_call (longjmp_call)
1194   {}
1195 
emit(rich_location * richloc)1196   bool emit (rich_location *richloc) FINAL OVERRIDE
1197   {
1198     return warning_at
1199       (richloc, OPT_Wanalyzer_stale_setjmp_buffer,
1200        "%qs called after enclosing function of %qs has returned",
1201        get_user_facing_name (m_longjmp_call),
1202        get_user_facing_name (m_setjmp_call));
1203   }
1204 
get_kind() const1205   const char *get_kind () const FINAL OVERRIDE
1206   { return "stale_jmp_buf"; }
1207 
operator ==(const stale_jmp_buf & other) const1208   bool operator== (const stale_jmp_buf &other) const
1209   {
1210     return (m_setjmp_call == other.m_setjmp_call
1211 	    && m_longjmp_call == other.m_longjmp_call);
1212   }
1213 
1214 private:
1215   const gcall *m_setjmp_call;
1216   const gcall *m_longjmp_call;
1217 };
1218 
1219 /* Handle LONGJMP_CALL, a call to longjmp or siglongjmp.
1220 
1221    Attempt to locate where setjmp/sigsetjmp was called on the jmp_buf and build
1222    an exploded_node and exploded_edge to it representing a rewind to that frame,
1223    handling the various kinds of failure that can occur.  */
1224 
1225 void
on_longjmp(exploded_graph & eg,const gcall * longjmp_call,program_state * new_state,region_model_context * ctxt) const1226 exploded_node::on_longjmp (exploded_graph &eg,
1227 			   const gcall *longjmp_call,
1228 			   program_state *new_state,
1229 			   region_model_context *ctxt) const
1230 {
1231   tree buf_ptr = gimple_call_arg (longjmp_call, 0);
1232 
1233   region_model *new_region_model = new_state->m_region_model;
1234   region_id buf_rid = new_region_model->deref_rvalue (buf_ptr, ctxt);
1235   region *buf = new_region_model->get_region (buf_rid);
1236   if (!buf)
1237     return;
1238 
1239   svalue_id buf_content_sid
1240     = buf->get_value (*new_region_model, false, ctxt);
1241   svalue *buf_content_sval = new_region_model->get_svalue (buf_content_sid);
1242   if (!buf_content_sval)
1243     return;
1244   setjmp_svalue *setjmp_sval = buf_content_sval->dyn_cast_setjmp_svalue ();
1245   if (!setjmp_sval)
1246     return;
1247 
1248   const setjmp_record tmp_setjmp_record = setjmp_sval->get_setjmp_record ();
1249 
1250   /* Build a custom enode and eedge for rewinding from the longjmp/siglongjmp
1251      call back to the setjmp/sigsetjmp.  */
1252   rewind_info_t rewind_info (tmp_setjmp_record, longjmp_call);
1253 
1254   const gcall *setjmp_call = rewind_info.get_setjmp_call ();
1255   const program_point &setjmp_point = rewind_info.get_setjmp_point ();
1256 
1257   const program_point &longjmp_point = get_point ();
1258 
1259   /* Verify that the setjmp's call_stack hasn't been popped.  */
1260   if (!valid_longjmp_stack_p (longjmp_point, setjmp_point))
1261     {
1262       ctxt->warn (new stale_jmp_buf (setjmp_call, longjmp_call));
1263       return;
1264     }
1265 
1266   gcc_assert (longjmp_point.get_stack_depth ()
1267 	      >= setjmp_point.get_stack_depth ());
1268 
1269   /* Update the state for use by the destination node.  */
1270 
1271   /* Stash the current number of diagnostics so that we can update
1272      any that this adds to show where the longjmp is rewinding to.  */
1273 
1274   diagnostic_manager *dm = &eg.get_diagnostic_manager ();
1275   unsigned prev_num_diagnostics = dm->get_num_diagnostics ();
1276 
1277   new_region_model->on_longjmp (longjmp_call, setjmp_call,
1278 				setjmp_point.get_stack_depth (), ctxt);
1279 
1280   program_point next_point
1281     = program_point::after_supernode (setjmp_point.get_supernode (),
1282 				      setjmp_point.get_call_string ());
1283 
1284   state_change change;
1285   exploded_node *next = eg.get_or_create_node (next_point, *new_state, &change);
1286 
1287   /* Create custom exploded_edge for a longjmp.  */
1288   if (next)
1289     {
1290       exploded_edge *eedge
1291 	= eg.add_edge (const_cast<exploded_node *> (this), next, NULL,
1292 		       change,
1293 		       new rewind_info_t (tmp_setjmp_record, longjmp_call));
1294 
1295       /* For any diagnostics that were queued here (such as leaks) we want
1296 	 the checker_path to show the rewinding events after the "final event"
1297 	 so that the user sees where the longjmp is rewinding to (otherwise the
1298 	 path is meaningless).
1299 
1300 	 For example, we want to emit something like:
1301                         |   NN | {
1302                         |   NN |   longjmp (env, 1);
1303                         |      |   ~~~~~~~~~~~~~~~~
1304                         |      |   |
1305                         |      |   (10) 'ptr' leaks here; was allocated at (7)
1306                         |      |   (11) rewinding from 'longjmp' in 'inner'...
1307                         |
1308           <-------------+
1309           |
1310         'outer': event 12
1311           |
1312           |   NN |   i = setjmp(env);
1313           |      |       ^~~~~~
1314           |      |       |
1315           |      |       (12) ...to 'setjmp' in 'outer' (saved at (2))
1316 
1317 	 where the "final" event above is event (10), but we want to append
1318 	 events (11) and (12) afterwards.
1319 
1320 	 Do this by setting m_trailing_eedge on any diagnostics that were
1321 	 just saved.  */
1322       unsigned num_diagnostics = dm->get_num_diagnostics ();
1323       for (unsigned i = prev_num_diagnostics; i < num_diagnostics; i++)
1324 	{
1325 	  saved_diagnostic *sd = dm->get_saved_diagnostic (i);
1326 	  sd->m_trailing_eedge = eedge;
1327 	}
1328     }
1329 }
1330 
1331 /* Subroutine of exploded_graph::process_node for finding the successors
1332    of the supernode for a function exit basic block.
1333 
1334    Ensure that pop_frame is called, potentially queuing diagnostics about
1335    leaks.  */
1336 
1337 void
detect_leaks(exploded_graph & eg) const1338 exploded_node::detect_leaks (exploded_graph &eg) const
1339 {
1340   LOG_FUNC_1 (eg.get_logger (), "EN: %i", m_index);
1341 
1342   gcc_assert (get_point ().get_supernode ()->return_p ());
1343 
1344   /* If we're not a "top-level" function, do nothing; pop_frame
1345      will be called when handling the return superedge.  */
1346   if (get_point ().get_stack_depth () > 1)
1347     return;
1348 
1349   /* We have a "top-level" function.  */
1350   gcc_assert (get_point ().get_stack_depth () == 1);
1351 
1352   const program_state &old_state = get_state ();
1353 
1354   /* Work with a temporary copy of the state: pop the frame, and see
1355      what leaks (via purge_unused_svalues).  */
1356   program_state new_state (old_state);
1357 
1358   gcc_assert (new_state.m_region_model);
1359 
1360   purge_stats stats;
1361   impl_region_model_context ctxt (eg, this,
1362 				  &old_state, &new_state,
1363 				  NULL,
1364 				  get_stmt ());
1365   new_state.m_region_model->pop_frame (region_id::null (),
1366 				       true, &stats, &ctxt);
1367 }
1368 
1369 /* Dump the successors and predecessors of this enode to OUTF.  */
1370 
1371 void
dump_succs_and_preds(FILE * outf) const1372 exploded_node::dump_succs_and_preds (FILE *outf) const
1373 {
1374   unsigned i;
1375   exploded_edge *e;
1376   {
1377     auto_vec<exploded_node *> preds (m_preds.length ());
1378     FOR_EACH_VEC_ELT (m_preds, i, e)
1379       preds.quick_push (e->m_src);
1380     pretty_printer pp;
1381     print_enode_indices (&pp, preds);
1382     fprintf (outf, "preds: %s\n",
1383 	     pp_formatted_text (&pp));
1384   }
1385   {
1386     auto_vec<exploded_node *> succs (m_succs.length ());
1387     FOR_EACH_VEC_ELT (m_succs, i, e)
1388       succs.quick_push (e->m_dest);
1389     pretty_printer pp;
1390     print_enode_indices (&pp, succs);
1391     fprintf (outf, "succs: %s\n",
1392 	     pp_formatted_text (&pp));
1393   }
1394 }
1395 
1396 /* class rewind_info_t : public exploded_edge::custom_info_t.  */
1397 
1398 /* Implementation of exploded_edge::custom_info_t::update_model vfunc
1399    for rewind_info_t.
1400 
1401    Update state for the special-case of a rewind of a longjmp
1402    to a setjmp (which doesn't have a superedge, but does affect
1403    state).  */
1404 
1405 void
update_model(region_model * model,const exploded_edge & eedge)1406 rewind_info_t::update_model (region_model *model,
1407 			     const exploded_edge &eedge)
1408 {
1409   const program_point &longjmp_point = eedge.m_src->get_point ();
1410   const program_point &setjmp_point = eedge.m_dest->get_point ();
1411 
1412   gcc_assert (longjmp_point.get_stack_depth ()
1413 	      >= setjmp_point.get_stack_depth ());
1414 
1415   model->on_longjmp (get_longjmp_call (),
1416 		     get_setjmp_call (),
1417 		     setjmp_point.get_stack_depth (), NULL);
1418 }
1419 
1420 /* Implementation of exploded_edge::custom_info_t::add_events_to_path vfunc
1421    for rewind_info_t.  */
1422 
1423 void
add_events_to_path(checker_path * emission_path,const exploded_edge & eedge)1424 rewind_info_t::add_events_to_path (checker_path *emission_path,
1425 				   const exploded_edge &eedge)
1426 {
1427   const exploded_node *src_node = eedge.m_src;
1428   const program_point &src_point = src_node->get_point ();
1429   const int src_stack_depth = src_point.get_stack_depth ();
1430   const exploded_node *dst_node = eedge.m_dest;
1431   const program_point &dst_point = dst_node->get_point ();
1432   const int dst_stack_depth = dst_point.get_stack_depth ();
1433 
1434   emission_path->add_event
1435     (new rewind_from_longjmp_event
1436      (&eedge, get_longjmp_call ()->location,
1437       src_point.get_fndecl (),
1438       src_stack_depth, this));
1439   emission_path->add_event
1440     (new rewind_to_setjmp_event
1441      (&eedge, get_setjmp_call ()->location,
1442       dst_point.get_fndecl (),
1443       dst_stack_depth, this));
1444 }
1445 
1446 /* class exploded_edge : public dedge<eg_traits>.  */
1447 
1448 /* exploded_edge's ctor.  */
1449 
exploded_edge(exploded_node * src,exploded_node * dest,const extrinsic_state & ext_state,const superedge * sedge,const state_change & change,custom_info_t * custom_info)1450 exploded_edge::exploded_edge (exploded_node *src, exploded_node *dest,
1451 			      const extrinsic_state &ext_state,
1452 			      const superedge *sedge,
1453 			      const state_change &change,
1454 			      custom_info_t *custom_info)
1455 : dedge<eg_traits> (src, dest), m_sedge (sedge), m_change (change),
1456   m_custom_info (custom_info)
1457 {
1458   change.validate (dest->get_state (), ext_state);
1459 }
1460 
1461 /* exploded_edge's dtor.  */
1462 
~exploded_edge()1463 exploded_edge::~exploded_edge ()
1464 {
1465   delete m_custom_info;
1466 }
1467 
1468 /* Implementation of dedge::dump_dot vfunc for exploded_edge.
1469    Use the label of the underlying superedge, if any.  */
1470 
1471 void
dump_dot(graphviz_out * gv,const dump_args_t & args) const1472 exploded_edge::dump_dot (graphviz_out *gv, const dump_args_t &args) const
1473 {
1474   pretty_printer *pp = gv->get_pp ();
1475 
1476   const char *style = "\"solid,bold\"";
1477   const char *color = "black";
1478   int weight = 10;
1479   const char *constraint = "true";
1480 
1481   if (m_sedge)
1482     switch (m_sedge->m_kind)
1483       {
1484       default:
1485 	gcc_unreachable ();
1486       case SUPEREDGE_CFG_EDGE:
1487 	break;
1488       case SUPEREDGE_CALL:
1489 	color = "red";
1490 	//constraint = "false";
1491 	break;
1492       case SUPEREDGE_RETURN:
1493 	color = "green";
1494 	//constraint = "false";
1495 	break;
1496       case SUPEREDGE_INTRAPROCEDURAL_CALL:
1497 	style = "\"dotted\"";
1498 	break;
1499       }
1500   if (m_custom_info)
1501     {
1502       color = "red";
1503       style = "\"dotted\"";
1504     }
1505 
1506   m_src->dump_dot_id (pp);
1507   pp_string (pp, " -> ");
1508   m_dest->dump_dot_id (pp);
1509   pp_printf (pp,
1510 	     (" [style=%s, color=%s, weight=%d, constraint=%s,"
1511 	      " headlabel=\""),
1512 	     style, color, weight, constraint);
1513 
1514   if (m_sedge)
1515     m_sedge->dump_label_to_pp (pp, false);
1516   else if (m_custom_info)
1517     m_custom_info->print (pp);
1518 
1519   m_change.dump (pp, args.m_eg.get_ext_state ());
1520   //pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
1521 
1522   pp_printf (pp, "\"];\n");
1523 }
1524 
1525 /* struct stats.  */
1526 
1527 /* stats' ctor.  */
1528 
stats(int num_supernodes)1529 stats::stats (int num_supernodes)
1530 : m_node_reuse_count (0),
1531   m_node_reuse_after_merge_count (0),
1532   m_num_supernodes (num_supernodes)
1533 {
1534   for (int i = 0; i < NUM_POINT_KINDS; i++)
1535     m_num_nodes[i] = 0;
1536 }
1537 
1538 /* Log these stats in multiline form to LOGGER.  */
1539 
1540 void
log(logger * logger) const1541 stats::log (logger *logger) const
1542 {
1543   gcc_assert (logger);
1544   for (int i = 0; i < NUM_POINT_KINDS; i++)
1545     if (m_num_nodes[i] > 0)
1546       logger->log ("m_num_nodes[%s]: %i",
1547 		   point_kind_to_string (static_cast <enum point_kind> (i)),
1548 		   m_num_nodes[i]);
1549   logger->log ("m_node_reuse_count: %i", m_node_reuse_count);
1550   logger->log ("m_node_reuse_after_merge_count: %i",
1551 	       m_node_reuse_after_merge_count);
1552 }
1553 
1554 /* Dump these stats in multiline form to OUT.  */
1555 
1556 void
dump(FILE * out) const1557 stats::dump (FILE *out) const
1558 {
1559   for (int i = 0; i < NUM_POINT_KINDS; i++)
1560     if (m_num_nodes[i] > 0)
1561       fprintf (out, "m_num_nodes[%s]: %i\n",
1562 	       point_kind_to_string (static_cast <enum point_kind> (i)),
1563 	       m_num_nodes[i]);
1564   fprintf (out, "m_node_reuse_count: %i\n", m_node_reuse_count);
1565   fprintf (out, "m_node_reuse_after_merge_count: %i\n",
1566 	   m_node_reuse_after_merge_count);
1567 
1568   if (m_num_supernodes > 0)
1569     fprintf (out, "PK_AFTER_SUPERNODE nodes per supernode: %.2f\n",
1570 	     (float)m_num_nodes[PK_AFTER_SUPERNODE] / (float)m_num_supernodes);
1571 }
1572 
1573 /* Return the total number of enodes recorded within this object.  */
1574 
1575 int
get_total_enodes() const1576 stats::get_total_enodes () const
1577 {
1578   int result = 0;
1579   for (int i = 0; i < NUM_POINT_KINDS; i++)
1580     result += m_num_nodes[i];
1581   return result;
1582 }
1583 
1584 /* strongly_connected_components's ctor.  Tarjan's SCC algorithm.  */
1585 
1586 strongly_connected_components::
strongly_connected_components(const supergraph & sg,logger * logger)1587 strongly_connected_components (const supergraph &sg, logger *logger)
1588 : m_sg (sg), m_per_node (m_sg.num_nodes ())
1589 {
1590   LOG_SCOPE (logger);
1591   auto_timevar tv (TV_ANALYZER_SCC);
1592 
1593   for (int i = 0; i < m_sg.num_nodes (); i++)
1594     m_per_node.quick_push (per_node_data ());
1595 
1596   for (int i = 0; i < m_sg.num_nodes (); i++)
1597     if (m_per_node[i].m_index == -1)
1598       strong_connect (i);
1599 
1600   if (0)
1601     dump ();
1602 }
1603 
1604 /* Dump this object to stderr.  */
1605 
1606 DEBUG_FUNCTION void
dump() const1607 strongly_connected_components::dump () const
1608 {
1609   for (int i = 0; i < m_sg.num_nodes (); i++)
1610     {
1611       const per_node_data &v = m_per_node[i];
1612       fprintf (stderr, "SN %i: index: %i lowlink: %i on_stack: %i\n",
1613 	       i, v.m_index, v.m_lowlink, v.m_on_stack);
1614     }
1615 }
1616 
1617 /* Subroutine of strongly_connected_components's ctor, part of Tarjan's
1618    SCC algorithm.  */
1619 
1620 void
strong_connect(unsigned index)1621 strongly_connected_components::strong_connect (unsigned index)
1622 {
1623   supernode *v_snode = m_sg.get_node_by_index (index);
1624 
1625   /* Set the depth index for v to the smallest unused index.  */
1626   per_node_data *v = &m_per_node[index];
1627   v->m_index = index;
1628   v->m_lowlink = index;
1629   m_stack.safe_push (index);
1630   v->m_on_stack = true;
1631   index++;
1632 
1633   /* Consider successors of v.  */
1634   unsigned i;
1635   superedge *sedge;
1636   FOR_EACH_VEC_ELT (v_snode->m_succs, i, sedge)
1637     {
1638       supernode *w_snode = sedge->m_dest;
1639       per_node_data *w = &m_per_node[w_snode->m_index];
1640       if (w->m_index == -1)
1641 	{
1642 	  /* Successor w has not yet been visited; recurse on it.  */
1643 	  strong_connect (w_snode->m_index);
1644 	  v->m_lowlink = MIN (v->m_lowlink, w->m_lowlink);
1645 	}
1646       else if (w->m_on_stack)
1647 	{
1648 	  /* Successor w is in stack S and hence in the current SCC
1649 	     If w is not on stack, then (v, w) is a cross-edge in the DFS
1650 	     tree and must be ignored.  */
1651 	  v->m_lowlink = MIN (v->m_lowlink, w->m_index);
1652 	}
1653     }
1654 
1655   /* If v is a root node, pop the stack and generate an SCC.  */
1656 
1657   if (v->m_lowlink == v->m_index)
1658     {
1659       per_node_data *w;
1660       do {
1661 	int idx = m_stack.pop ();
1662 	w = &m_per_node[idx];
1663 	w->m_on_stack = false;
1664       } while (w != v);
1665     }
1666 }
1667 
1668 /* worklist's ctor.  */
1669 
worklist(const exploded_graph & eg,const analysis_plan & plan)1670 worklist::worklist (const exploded_graph &eg, const analysis_plan &plan)
1671 : m_scc (eg.get_supergraph (), eg.get_logger ()),
1672   m_plan (plan),
1673   m_queue (key_t (*this, NULL))
1674 {
1675 }
1676 
1677 /* Return the number of nodes in the worklist.  */
1678 
1679 unsigned
length() const1680 worklist::length () const
1681 {
1682   return m_queue.nodes ();
1683 }
1684 
1685 /* Return the next node in the worklist, removing it.  */
1686 
1687 exploded_node *
take_next()1688 worklist::take_next ()
1689 {
1690   return m_queue.extract_min ();
1691 }
1692 
1693 /* Return the next node in the worklist without removing it.  */
1694 
1695 exploded_node *
peek_next()1696 worklist::peek_next ()
1697 {
1698   return m_queue.min ();
1699 }
1700 
1701 /* Add ENODE to the worklist.  */
1702 
1703 void
add_node(exploded_node * enode)1704 worklist::add_node (exploded_node *enode)
1705 {
1706   gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
1707   m_queue.insert (key_t (*this, enode), enode);
1708 }
1709 
1710 /* Comparator for implementing worklist::key_t comparison operators.
1711    Return negative if KA is before KB
1712    Return positive if KA is after KB
1713    Return 0 if they are equal.  */
1714 
1715 int
cmp(const worklist::key_t & ka,const worklist::key_t & kb)1716 worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb)
1717 {
1718   const program_point &point_a = ka.m_enode->get_point ();
1719   const program_point &point_b = kb.m_enode->get_point ();
1720   const call_string &call_string_a = point_a.get_call_string ();
1721   const call_string &call_string_b = point_b.get_call_string ();
1722 
1723   /* Order empty-callstring points with different functions based on the
1724      analysis_plan, so that we generate summaries before they are used.  */
1725   if (flag_analyzer_call_summaries
1726       && call_string_a.empty_p ()
1727       && call_string_b.empty_p ()
1728       && point_a.get_function () != NULL
1729       && point_b.get_function () != NULL
1730       && point_a.get_function () != point_b.get_function ())
1731     {
1732       return ka.m_worklist.m_plan.cmp_function (point_a.get_function (),
1733 						point_b.get_function ());
1734     }
1735 
1736   /* First, order by SCC.  */
1737   int scc_id_a = ka.get_scc_id (ka.m_enode);
1738   int scc_id_b = kb.get_scc_id (kb.m_enode);
1739   if (scc_id_a != scc_id_b)
1740     return scc_id_a - scc_id_b;
1741 
1742   /* If in same SCC, order by supernode index (an arbitrary but stable
1743      ordering).  */
1744   const supernode *snode_a = ka.m_enode->get_supernode ();
1745   const supernode *snode_b = kb.m_enode->get_supernode ();
1746   if (snode_a == NULL)
1747     {
1748       if (snode_b != NULL)
1749 	/* One is NULL.  */
1750 	return -1;
1751       else
1752 	/* Both are NULL.  */
1753 	return 0;
1754     }
1755   if (snode_b == NULL)
1756     /* One is NULL.  */
1757     return 1;
1758   /* Neither are NULL.  */
1759   gcc_assert (snode_a && snode_b);
1760   if (snode_a->m_index != snode_b->m_index)
1761     return snode_a->m_index - snode_b->m_index;
1762 
1763   gcc_assert (snode_a == snode_b);
1764 
1765   /* Order within supernode via program point.  */
1766   int within_snode_cmp
1767     = function_point::cmp_within_supernode (point_a.get_function_point (),
1768 					    point_b.get_function_point ());
1769   if (within_snode_cmp)
1770     return within_snode_cmp;
1771 
1772   /* The points might vary by callstring; try sorting by callstring.  */
1773   int cs_cmp = call_string::cmp (call_string_a, call_string_b);
1774   if (cs_cmp)
1775     return cs_cmp;
1776 
1777   /* Otherwise, we ought to have the same program_point.  */
1778   gcc_assert (point_a == point_b);
1779 
1780   const program_state &state_a = ka.m_enode->get_state ();
1781   const program_state &state_b = kb.m_enode->get_state ();
1782 
1783   /* Sort by sm-state, so that identical sm-states are grouped
1784      together in the worklist.
1785      For now, sort by the hash value (might not be deterministic).  */
1786   for (unsigned sm_idx = 0; sm_idx < state_a.m_checker_states.length ();
1787        ++sm_idx)
1788     {
1789       sm_state_map *smap_a = state_a.m_checker_states[sm_idx];
1790       sm_state_map *smap_b = state_b.m_checker_states[sm_idx];
1791 
1792       hashval_t hash_a = smap_a->hash ();
1793       hashval_t hash_b = smap_b->hash ();
1794       if (hash_a < hash_b)
1795 	return -1;
1796       else if (hash_a > hash_b)
1797 	return 1;
1798     }
1799 
1800   /* Otherwise, we have two enodes at the same program point but with
1801      different states.  We don't have a good total ordering on states,
1802      so order them by enode index, so that we have at least have a
1803      stable sort.  */
1804   return ka.m_enode->m_index - kb.m_enode->m_index;
1805 }
1806 
1807 /* exploded_graph's ctor.  */
1808 
exploded_graph(const supergraph & sg,logger * logger,const extrinsic_state & ext_state,const state_purge_map * purge_map,const analysis_plan & plan,int verbosity)1809 exploded_graph::exploded_graph (const supergraph &sg, logger *logger,
1810 				const extrinsic_state &ext_state,
1811 				const state_purge_map *purge_map,
1812 				const analysis_plan &plan,
1813 				int verbosity)
1814 : m_sg (sg), m_logger (logger),
1815   m_worklist (*this, plan),
1816   m_ext_state (ext_state),
1817   m_purge_map (purge_map),
1818   m_plan (plan),
1819   m_diagnostic_manager (logger, verbosity),
1820   m_global_stats (m_sg.num_nodes ()),
1821   m_functionless_stats (m_sg.num_nodes ()),
1822   m_PK_AFTER_SUPERNODE_per_snode (m_sg.num_nodes ())
1823 {
1824   m_origin = get_or_create_node (program_point (function_point (NULL, NULL,
1825 								0, PK_ORIGIN),
1826 						call_string ()),
1827 				 program_state (ext_state), NULL);
1828   for (int i = 0; i < m_sg.num_nodes (); i++)
1829     m_PK_AFTER_SUPERNODE_per_snode.quick_push (i);
1830 }
1831 
1832 /* exploded_graph's dtor.  */
1833 
~exploded_graph()1834 exploded_graph::~exploded_graph ()
1835 {
1836   for (function_stat_map_t::iterator iter = m_per_function_stats.begin ();
1837        iter != m_per_function_stats.end ();
1838        ++iter)
1839     delete (*iter).second;
1840 
1841   for (point_map_t::iterator iter = m_per_point_data.begin ();
1842        iter != m_per_point_data.end ();
1843        ++iter)
1844     delete (*iter).second;
1845 }
1846 
1847 /* Ensure that there is an exploded_node representing an external call to
1848    FUN, adding it to the worklist if creating it.
1849 
1850    Add an edge from the origin exploded_node to the function entrypoint
1851    exploded_node.
1852 
1853    Return the exploded_node for the entrypoint to the function.  */
1854 
1855 exploded_node *
add_function_entry(function * fun)1856 exploded_graph::add_function_entry (function *fun)
1857 {
1858   program_point point = program_point::from_function_entry (m_sg, fun);
1859   program_state state (m_ext_state);
1860   impl_region_model_context ctxt (&state, NULL, m_ext_state, get_logger ());
1861   state.m_region_model->push_frame (fun, NULL, &ctxt);
1862 
1863   if (!state.m_valid)
1864     return NULL;
1865 
1866   exploded_node *enode = get_or_create_node (point, state, NULL);
1867   /* We should never fail to add such a node.  */
1868   gcc_assert (enode);
1869   state_change change;
1870   add_edge (m_origin, enode, NULL, change);
1871   return enode;
1872 }
1873 
1874 /* Get or create an exploded_node for (POINT, STATE).
1875    If a new node is created, it is added to the worklist.
1876    If CHANGE is non-NULL, use it to suppress some purging of state,
1877    to make generation of state_change_event instances easier.  */
1878 
1879 exploded_node *
get_or_create_node(const program_point & point,const program_state & state,state_change * change)1880 exploded_graph::get_or_create_node (const program_point &point,
1881 				    const program_state &state,
1882 				    state_change *change)
1883 {
1884   logger * const logger = get_logger ();
1885   LOG_FUNC (logger);
1886   if (logger)
1887     {
1888       format f (false);
1889       pretty_printer *pp = logger->get_printer ();
1890       logger->start_log_line ();
1891       pp_string (pp, "point: ");
1892       point.print (pp, f);
1893       logger->end_log_line ();
1894       logger->start_log_line ();
1895       pp_string (pp, "state: ");
1896       state.dump_to_pp (m_ext_state, true, pp);
1897       logger->end_log_line ();
1898     }
1899 
1900   /* Stop exploring paths for which we don't know how to effectively
1901      model the state.  */
1902   if (!state.m_valid)
1903     {
1904       if (logger)
1905 	logger->log ("invalid state; not creating node");
1906       return NULL;
1907     }
1908 
1909   auto_cfun sentinel (point.get_function ());
1910 
1911   state.validate (get_ext_state ());
1912 
1913   //state.dump (get_ext_state ());
1914 
1915   /* Prune state to try to improve the chances of a cache hit,
1916      avoiding generating redundant nodes.  */
1917   program_state pruned_state = state.prune_for_point (*this, point, change);
1918 
1919   pruned_state.validate (get_ext_state ());
1920 
1921   //pruned_state.dump (get_ext_state ());
1922 
1923   if (logger)
1924     {
1925       pretty_printer *pp = logger->get_printer ();
1926       logger->start_log_line ();
1927       pp_string (pp, "pruned_state: ");
1928       pruned_state.dump_to_pp (m_ext_state, true, pp);
1929       logger->end_log_line ();
1930       pruned_state.m_region_model->dump_to_pp (logger->get_printer (), true);
1931     }
1932 
1933   stats *per_fn_stats = get_or_create_function_stats (point.get_function ());
1934 
1935   stats *per_cs_stats
1936     = &get_or_create_per_call_string_data (point.get_call_string ())->m_stats;
1937 
1938   point_and_state ps (point, pruned_state);
1939   ps.validate (m_ext_state);
1940   if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
1941     {
1942       /* An exploded_node for PS already exists.  */
1943       if (logger)
1944 	logger->log ("reused EN: %i", (*slot)->m_index);
1945       m_global_stats.m_node_reuse_count++;
1946       per_fn_stats->m_node_reuse_count++;
1947       per_cs_stats->m_node_reuse_count++;
1948       return *slot;
1949     }
1950 
1951   per_program_point_data *per_point_data
1952     = get_or_create_per_program_point_data (point);
1953 
1954   /* Consider merging state with another enode at this program_point.  */
1955   if (flag_analyzer_state_merge)
1956     {
1957       exploded_node *existing_enode;
1958       unsigned i;
1959       FOR_EACH_VEC_ELT (per_point_data->m_enodes, i, existing_enode)
1960 	{
1961 	  if (logger)
1962 	    logger->log ("considering merging with existing EN: %i for point",
1963 			 existing_enode->m_index);
1964 	  gcc_assert (existing_enode->get_point () == point);
1965 	  const program_state &existing_state = existing_enode->get_state ();
1966 
1967 	  /* This merges successfully within the loop.  */
1968 
1969 	  program_state merged_state (m_ext_state);
1970 	  if (pruned_state.can_merge_with_p (existing_state, m_ext_state,
1971 					     &merged_state))
1972 	    {
1973 	      if (logger)
1974 		logger->log ("merging new state with that of EN: %i",
1975 			     existing_enode->m_index);
1976 
1977 	      /* Try again for a cache hit.
1978 		 Whether we get one or not, merged_state's value_ids have no
1979 		 relationship to those of the input state, and thus to those
1980 		 of CHANGE, so we must purge any svalue_ids from *CHANGE.  */
1981 	      ps.set_state (merged_state);
1982 	      if (change)
1983 		change->on_svalue_purge (svalue_id::from_int (0));
1984 
1985 	      if (exploded_node **slot = m_point_and_state_to_node.get (&ps))
1986 		{
1987 		  /* An exploded_node for PS already exists.  */
1988 		  if (logger)
1989 		    logger->log ("reused EN: %i", (*slot)->m_index);
1990 		  m_global_stats.m_node_reuse_after_merge_count++;
1991 		  per_fn_stats->m_node_reuse_after_merge_count++;
1992 		  per_cs_stats->m_node_reuse_after_merge_count++;
1993 		  return *slot;
1994 		}
1995 	    }
1996 	  else
1997 	    if (logger)
1998 	      logger->log ("not merging new state with that of EN: %i",
1999 			   existing_enode->m_index);
2000 	}
2001     }
2002 
2003   /* Impose a limit on the number of enodes per program point, and
2004      simply stop if we exceed it.  */
2005   if ((int)per_point_data->m_enodes.length ()
2006       > param_analyzer_max_enodes_per_program_point)
2007     {
2008       if (logger)
2009 	logger->log ("not creating enode; too many at program point");
2010       warning_at (point.get_location (), OPT_Wanalyzer_too_complex,
2011 		  "terminating analysis for this program point");
2012       per_point_data->m_excess_enodes++;
2013       return NULL;
2014     }
2015 
2016   ps.validate (m_ext_state);
2017 
2018   /* An exploded_node for "ps" doesn't already exist; create one.  */
2019   exploded_node *node = new exploded_node (ps, m_nodes.length ());
2020   add_node (node);
2021   m_point_and_state_to_node.put (node->get_ps_key (), node);
2022 
2023   /* Update per-program_point data.  */
2024   per_point_data->m_enodes.safe_push (node);
2025 
2026   const enum point_kind node_pk = node->get_point ().get_kind ();
2027   m_global_stats.m_num_nodes[node_pk]++;
2028   per_fn_stats->m_num_nodes[node_pk]++;
2029   per_cs_stats->m_num_nodes[node_pk]++;
2030 
2031   if (node_pk == PK_AFTER_SUPERNODE)
2032     m_PK_AFTER_SUPERNODE_per_snode[point.get_supernode ()->m_index]++;
2033 
2034   if (logger)
2035     {
2036       format f (false);
2037       pretty_printer *pp = logger->get_printer ();
2038       logger->log ("created EN: %i", node->m_index);
2039       logger->start_log_line ();
2040       pp_string (pp, "point: ");
2041       point.print (pp, f);
2042       logger->end_log_line ();
2043       logger->start_log_line ();
2044       pp_string (pp, "pruned_state: ");
2045       pruned_state.dump_to_pp (m_ext_state, true, pp);
2046       logger->end_log_line ();
2047     }
2048 
2049   /* Add the new node to the worlist.  */
2050   m_worklist.add_node (node);
2051   return node;
2052 }
2053 
2054 /* Add an exploded_edge from SRC to DEST, recording its association
2055    with SEDGE (which may be NULL), and, if non-NULL, taking ownership
2056    of REWIND_INFO.
2057    Return the newly-created eedge.  */
2058 
2059 exploded_edge *
add_edge(exploded_node * src,exploded_node * dest,const superedge * sedge,const state_change & change,exploded_edge::custom_info_t * custom_info)2060 exploded_graph::add_edge (exploded_node *src, exploded_node *dest,
2061 			  const superedge *sedge,
2062 			  const state_change &change,
2063 			  exploded_edge::custom_info_t *custom_info)
2064 {
2065   exploded_edge *e = new exploded_edge (src, dest, m_ext_state,
2066 					sedge, change, custom_info);
2067   digraph<eg_traits>::add_edge (e);
2068   return e;
2069 }
2070 
2071 /* Ensure that this graph has per-program_point-data for POINT;
2072    borrow a pointer to it.  */
2073 
2074 per_program_point_data *
2075 exploded_graph::
get_or_create_per_program_point_data(const program_point & point)2076 get_or_create_per_program_point_data (const program_point &point)
2077 {
2078   if (per_program_point_data **slot = m_per_point_data.get (&point))
2079     return *slot;
2080 
2081   per_program_point_data *per_point_data = new per_program_point_data (point);
2082   m_per_point_data.put (&per_point_data->m_key, per_point_data);
2083   return per_point_data;
2084 }
2085 
2086 /* Ensure that this graph has per-call_string-data for CS;
2087    borrow a pointer to it.  */
2088 
2089 per_call_string_data *
get_or_create_per_call_string_data(const call_string & cs)2090 exploded_graph::get_or_create_per_call_string_data (const call_string &cs)
2091 {
2092   if (per_call_string_data **slot = m_per_call_string_data.get (&cs))
2093     return *slot;
2094 
2095   per_call_string_data *data = new per_call_string_data (cs, m_sg.num_nodes ());
2096   m_per_call_string_data.put (&data->m_key,
2097 			      data);
2098   return data;
2099 }
2100 
2101 /* Ensure that this graph has per-function-data for FUN;
2102    borrow a pointer to it.  */
2103 
2104 per_function_data *
get_or_create_per_function_data(function * fun)2105 exploded_graph::get_or_create_per_function_data (function *fun)
2106 {
2107   if (per_function_data **slot = m_per_function_data.get (fun))
2108     return *slot;
2109 
2110   per_function_data *data = new per_function_data ();
2111   m_per_function_data.put (fun, data);
2112   return data;
2113 }
2114 
2115 /* Get this graph's per-function-data for FUN if there is any,
2116    otherwise NULL.  */
2117 
2118 per_function_data *
get_per_function_data(function * fun) const2119 exploded_graph::get_per_function_data (function *fun) const
2120 {
2121   if (per_function_data **slot
2122         = const_cast <per_function_data_t &> (m_per_function_data).get (fun))
2123     return *slot;
2124 
2125   return NULL;
2126 }
2127 
2128 /* Return true if NODE and FUN should be traversed directly, rather than
2129    called via other functions.  */
2130 
2131 static bool
toplevel_function_p(cgraph_node * node,function * fun,logger * logger)2132 toplevel_function_p (cgraph_node *node, function *fun, logger *logger)
2133 {
2134   /* TODO: better logic here
2135      e.g. only if more than one caller, and significantly complicated.
2136      Perhaps some whole-callgraph analysis to decide if it's worth summarizing
2137      an edge, and if so, we need summaries.  */
2138   if (flag_analyzer_call_summaries)
2139     {
2140       int num_call_sites = 0;
2141       for (cgraph_edge *edge = node->callers; edge; edge = edge->next_caller)
2142 	++num_call_sites;
2143 
2144       /* For now, if there's more than one in-edge, and we want call
2145 	 summaries, do it at the top level so that there's a chance
2146 	 we'll have a summary when we need one.  */
2147       if (num_call_sites > 1)
2148 	{
2149 	  if (logger)
2150 	    logger->log ("traversing %qE (%i call sites)",
2151 			 fun->decl, num_call_sites);
2152 	  return true;
2153 	}
2154     }
2155 
2156   if (!TREE_PUBLIC (fun->decl))
2157     {
2158       if (logger)
2159 	logger->log ("not traversing %qE (static)", fun->decl);
2160       return false;
2161     }
2162 
2163   if (logger)
2164     logger->log ("traversing %qE (all checks passed)", fun->decl);
2165 
2166   return true;
2167 }
2168 
2169 /* Add initial nodes to EG, with entrypoints for externally-callable
2170    functions.  */
2171 
2172 void
build_initial_worklist()2173 exploded_graph::build_initial_worklist ()
2174 {
2175   logger * const logger = get_logger ();
2176   LOG_SCOPE (logger);
2177 
2178   cgraph_node *node;
2179   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
2180   {
2181     function *fun = node->get_fun ();
2182     if (!toplevel_function_p (node, fun, logger))
2183       continue;
2184     exploded_node *enode = add_function_entry (fun);
2185     if (logger)
2186       {
2187 	if (enode)
2188 	  logger->log ("created EN %i for %qE entrypoint",
2189 		       enode->m_index, fun->decl);
2190 	else
2191 	  logger->log ("did not create enode for %qE entrypoint", fun->decl);
2192       }
2193   }
2194 }
2195 
2196 /* The main loop of the analysis.
2197    Take freshly-created exploded_nodes from the worklist, calling
2198    process_node on them to explore the <point, state> graph.
2199    Add edges to their successors, potentially creating new successors
2200    (which are also added to the worklist).  */
2201 
2202 void
process_worklist()2203 exploded_graph::process_worklist ()
2204 {
2205   logger * const logger = get_logger ();
2206   LOG_SCOPE (logger);
2207   auto_timevar tv (TV_ANALYZER_WORKLIST);
2208 
2209   while (m_worklist.length () > 0)
2210     {
2211       exploded_node *node = m_worklist.take_next ();
2212       gcc_assert (node->get_status () == exploded_node::STATUS_WORKLIST);
2213       gcc_assert (node->m_succs.length () == 0
2214 		  || node == m_origin);
2215 
2216       if (logger)
2217 	logger->log ("next to process: EN: %i", node->m_index);
2218 
2219       /* Avoid exponential explosions of nodes by attempting to merge
2220 	 nodes that are at the same program point and which have
2221 	 sufficiently similar state.  */
2222       if (flag_analyzer_state_merge && node != m_origin)
2223 	if (exploded_node *node_2 = m_worklist.peek_next ())
2224 	  {
2225 	    gcc_assert (node_2->get_status ()
2226 			== exploded_node::STATUS_WORKLIST);
2227 	    gcc_assert (node->m_succs.length () == 0);
2228 	    gcc_assert (node_2->m_succs.length () == 0);
2229 
2230 	    gcc_assert (node != node_2);
2231 
2232 	    if (logger)
2233 	      logger->log ("peek worklist: EN: %i", node_2->m_index);
2234 
2235 	    if (node->get_point () == node_2->get_point ())
2236 	      {
2237 		if (logger)
2238 		  {
2239 		    format f (false);
2240 		    pretty_printer *pp = logger->get_printer ();
2241 		    logger->start_log_line ();
2242 		    logger->log_partial
2243 		      ("got potential merge EN: %i and EN: %i at ",
2244 		       node->m_index, node_2->m_index);
2245 		    node->get_point ().print (pp, f);
2246 		    logger->end_log_line ();
2247 		  }
2248 
2249 		const program_state &state = node->get_state ();
2250 		const program_state &state_2 = node_2->get_state ();
2251 
2252 		/* They shouldn't be equal, or we wouldn't have two
2253 		   separate nodes.  */
2254 		gcc_assert (state != state_2);
2255 
2256 		program_state merged_state (m_ext_state);
2257 		state_change change;
2258 		if (state.can_merge_with_p (state_2, m_ext_state,
2259 					    &merged_state))
2260 		  {
2261 		    if (logger)
2262 		      logger->log ("merging EN: %i and EN: %i",
2263 				   node->m_index, node_2->m_index);
2264 
2265 		    if (merged_state == state)
2266 		      {
2267 			/* Then merge node_2 into node by adding an edge.  */
2268 			add_edge (node_2, node, NULL, change);
2269 
2270 			/* Remove node_2 from the worklist.  */
2271 			m_worklist.take_next ();
2272 			node_2->set_status (exploded_node::STATUS_MERGER);
2273 
2274 			/* Continue processing "node" below.  */
2275 		      }
2276 		    else if (merged_state == state_2)
2277 		      {
2278 			/* Then merge node into node_2, and leave node_2
2279 			   in the worklist, to be processed on the next
2280 			   iteration.  */
2281 			add_edge (node, node_2, NULL, change);
2282 			node->set_status (exploded_node::STATUS_MERGER);
2283 			continue;
2284 		      }
2285 		    else
2286 		      {
2287 			/* We have a merged state that differs from
2288 			   both state and state_2.  */
2289 
2290 			/* Remove node_2 from the worklist.  */
2291 			m_worklist.take_next ();
2292 
2293 			/* Create (or get) an exploded node for the merged
2294 			   states, adding to the worklist.  */
2295 			exploded_node *merged_enode
2296 			  = get_or_create_node (node->get_point (),
2297 						merged_state, &change);
2298 			if (merged_enode == NULL)
2299 			  continue;
2300 
2301 			if (logger)
2302 			  logger->log ("merged EN: %i and EN: %i into EN: %i",
2303 				       node->m_index, node_2->m_index,
2304 				       merged_enode->m_index);
2305 
2306 			/* "node" and "node_2" have both now been removed
2307 			   from the worklist; we should not process them.
2308 
2309 			   "merged_enode" may be a new node; if so it will be
2310 			   processed in a subsequent iteration.
2311 			   Alternatively, "merged_enode" could be an existing
2312 			   node; one way the latter can
2313 			   happen is if we end up merging a succession of
2314 			   similar nodes into one.  */
2315 
2316 			/* If merged_node is one of the two we were merging,
2317 			   add it back to the worklist to ensure it gets
2318 			   processed.
2319 
2320 			   Add edges from the merged nodes to it (but not a
2321 			   self-edge).  */
2322 			if (merged_enode == node)
2323 			  m_worklist.add_node (merged_enode);
2324 			else
2325 			  {
2326 			    add_edge (node, merged_enode, NULL, change);
2327 			    node->set_status (exploded_node::STATUS_MERGER);
2328 			  }
2329 
2330 			if (merged_enode == node_2)
2331 			  m_worklist.add_node (merged_enode);
2332 			else
2333 			  {
2334 			    add_edge (node_2, merged_enode, NULL, change);
2335 			    node_2->set_status (exploded_node::STATUS_MERGER);
2336 			  }
2337 
2338 			continue;
2339 		      }
2340 		  }
2341 
2342 		/* TODO: should we attempt more than two nodes,
2343 		   or just do pairs of nodes?  (and hope that we get
2344 		   a cascade of mergers).  */
2345 	      }
2346 	}
2347 
2348       process_node (node);
2349 
2350       /* Impose a hard limit on the number of exploded nodes, to ensure
2351 	 that the analysis terminates in the face of pathological state
2352 	 explosion (or bugs).
2353 
2354 	 Specifically, the limit is on the number of PK_AFTER_SUPERNODE
2355 	 exploded nodes, looking at supernode exit events.
2356 
2357 	 We use exit rather than entry since there can be multiple
2358 	 entry ENs, one per phi; the number of PK_AFTER_SUPERNODE ought
2359 	 to be equivalent to the number of supernodes multiplied by the
2360 	 number of states.  */
2361       const int limit = m_sg.num_nodes () * param_analyzer_bb_explosion_factor;
2362       if (m_global_stats.m_num_nodes[PK_AFTER_SUPERNODE] > limit)
2363 	{
2364 	  if (logger)
2365 	    logger->log ("bailing out; too many nodes");
2366 	  warning_at (node->get_point ().get_location (),
2367 		      OPT_Wanalyzer_too_complex,
2368 		      "analysis bailed out early"
2369 		      " (%i 'after-snode' enodes; %i enodes)",
2370 		      m_global_stats.m_num_nodes[PK_AFTER_SUPERNODE],
2371 		      m_nodes.length ());
2372 	  return;
2373 	}
2374     }
2375 }
2376 
2377 /* Return true if STMT must appear at the start of its exploded node, and
2378    thus we can't consolidate its effects within a run of other statements,
2379    where PREV_STMT was the previous statement.  */
2380 
2381 static bool
stmt_requires_new_enode_p(const gimple * stmt,const gimple * prev_stmt)2382 stmt_requires_new_enode_p (const gimple *stmt,
2383 			   const gimple *prev_stmt)
2384 {
2385   /* Stop consolidating at calls to
2386      "__analyzer_dump_exploded_nodes", so they always appear at the
2387      start of an exploded_node.  */
2388   if (const gcall *call = dyn_cast <const gcall *> (stmt))
2389     if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
2390 			 1))
2391       return true;
2392 
2393   /* If we had a PREV_STMT with an unknown location, and this stmt
2394      has a known location, then if a state change happens here, it
2395      could be consolidated into PREV_STMT, giving us an event with
2396      no location.  Ensure that STMT gets its own exploded_node to
2397      avoid this.  */
2398   if (get_pure_location (prev_stmt->location) == UNKNOWN_LOCATION
2399       && get_pure_location (stmt->location) != UNKNOWN_LOCATION)
2400     return true;
2401 
2402   return false;
2403 }
2404 
2405 /* The core of exploded_graph::process_worklist (the main analysis loop),
2406    handling one node in the worklist.
2407 
2408    Get successor <point, state> pairs for NODE, calling get_or_create on
2409    them, and adding an exploded_edge to each successors.
2410 
2411    Freshly-created nodes will be added to the worklist.  */
2412 
2413 void
process_node(exploded_node * node)2414 exploded_graph::process_node (exploded_node *node)
2415 {
2416   logger * const logger = get_logger ();
2417   LOG_FUNC_1 (logger, "EN: %i", node->m_index);
2418 
2419   node->set_status (exploded_node::STATUS_PROCESSED);
2420 
2421   const program_point &point = node->get_point ();
2422 
2423   /* Update cfun and input_location in case of an ICE: make it easier to
2424      track down which source construct we're failing to handle.  */
2425   auto_cfun sentinel (node->get_function ());
2426   const gimple *stmt = point.get_stmt ();
2427   if (stmt)
2428     input_location = stmt->location;
2429 
2430   const program_state &state = node->get_state ();
2431   if (logger)
2432     {
2433       pretty_printer *pp = logger->get_printer ();
2434       logger->start_log_line ();
2435       pp_string (pp, "point: ");
2436       point.print (pp, format (false));
2437       pp_string (pp, ", state: ");
2438       state.dump_to_pp (m_ext_state, true, pp);
2439       logger->end_log_line ();
2440     }
2441 
2442   switch (point.get_kind ())
2443     {
2444     default:
2445       gcc_unreachable ();
2446     case PK_ORIGIN:
2447       /* This node exists to simplify finding the shortest path
2448 	 to an exploded_node.  */
2449       break;
2450 
2451     case PK_BEFORE_SUPERNODE:
2452       {
2453 	program_state next_state (state);
2454 	state_change change;
2455 
2456 	if (point.get_from_edge ())
2457 	  {
2458 	    impl_region_model_context ctxt (*this, node,
2459 					    &state, &next_state, &change,
2460 					    NULL);
2461 	    const cfg_superedge *last_cfg_superedge
2462 	      = point.get_from_edge ()->dyn_cast_cfg_superedge ();
2463 	    if (last_cfg_superedge)
2464 	      next_state.m_region_model->update_for_phis
2465 		(node->get_supernode (),
2466 		 last_cfg_superedge,
2467 		 &ctxt);
2468 	  }
2469 
2470 	if (point.get_supernode ()->m_stmts.length () > 0)
2471 	  {
2472 	    program_point next_point
2473 	      = program_point::before_stmt (point.get_supernode (), 0,
2474 					    point.get_call_string ());
2475 	    exploded_node *next
2476 	      = get_or_create_node (next_point, next_state, &change);
2477 	    if (next)
2478 	      add_edge (node, next, NULL, change);
2479 	  }
2480 	else
2481 	  {
2482 	    program_point next_point
2483 	      = program_point::after_supernode (point.get_supernode (),
2484 						point.get_call_string ());
2485 	    exploded_node *next = get_or_create_node (next_point, next_state,
2486 						      &change);
2487 	    if (next)
2488 	      add_edge (node, next, NULL, change);
2489 	  }
2490       }
2491       break;
2492     case PK_BEFORE_STMT:
2493       {
2494 	/* Determine the effect of a run of one or more statements
2495 	   within one supernode, generating an edge to the program_point
2496 	   after the last statement that's processed.
2497 
2498 	   Stop iterating statements and thus consolidating into one enode
2499 	   when:
2500 	   - reaching the end of the statements in the supernode
2501 	   - if an sm-state-change occurs (so that it gets its own
2502 	     exploded_node)
2503 	   - if "-fanalyzer-fine-grained" is active
2504 	   - encountering certain statements must appear at the start of
2505 	   their enode (for which stmt_requires_new_enode_p returns true)
2506 
2507 	   Update next_state in-place, to get the result of the one
2508 	   or more stmts that are processed.  */
2509 	program_state next_state (state);
2510 	state_change change;
2511 	const supernode *snode = point.get_supernode ();
2512 	unsigned stmt_idx;
2513 	const gimple *prev_stmt = NULL;
2514 	for (stmt_idx = point.get_stmt_idx ();
2515 	     stmt_idx < snode->m_stmts.length ();
2516 	     stmt_idx++)
2517 	  {
2518 	    const gimple *stmt = snode->m_stmts[stmt_idx];
2519 
2520 	    if (stmt_idx > point.get_stmt_idx ())
2521 	      if (stmt_requires_new_enode_p (stmt, prev_stmt))
2522 		{
2523 		  stmt_idx--;
2524 		  break;
2525 		}
2526 	    prev_stmt = stmt;
2527 
2528 	    /* Process the stmt.  */
2529 	    exploded_node::on_stmt_flags flags
2530 	      = node->on_stmt (*this, snode, stmt, &next_state, &change);
2531 
2532 	    /* If flags.m_terminate_path, stop analyzing; any nodes/edges
2533 	       will have been added by on_stmt (e.g. for handling longjmp).  */
2534 	    if (flags.m_terminate_path)
2535 	      return;
2536 
2537 	    if (flags.m_sm_changes || flag_analyzer_fine_grained)
2538 	      break;
2539 	  }
2540 	unsigned next_idx = stmt_idx + 1;
2541 	program_point next_point
2542 	  = (next_idx < point.get_supernode ()->m_stmts.length ()
2543 	     ? program_point::before_stmt (point.get_supernode (), next_idx,
2544 					   point.get_call_string ())
2545 	     : program_point::after_supernode (point.get_supernode (),
2546 					       point.get_call_string ()));
2547 	exploded_node *next = get_or_create_node (next_point,
2548 						  next_state, &change);
2549 	if (next)
2550 	  add_edge (node, next, NULL, change);
2551       }
2552       break;
2553     case PK_AFTER_SUPERNODE:
2554       {
2555 	/* If this is an EXIT BB, detect leaks, and potentially
2556 	   create a function summary.  */
2557 	if (point.get_supernode ()->return_p ())
2558 	  {
2559 	    node->detect_leaks (*this);
2560 	    if (flag_analyzer_call_summaries
2561 		&& point.get_call_string ().empty_p ())
2562 	      {
2563 		/* TODO: create function summary
2564 		   There can be more than one; each corresponds to a different
2565 		   final enode in the function.  */
2566 		if (logger)
2567 		  {
2568 		    pretty_printer *pp = logger->get_printer ();
2569 		    logger->start_log_line ();
2570 		    logger->log_partial
2571 		      ("would create function summary for %qE; state: ",
2572 		       point.get_fndecl ());
2573 		    state.dump_to_pp (m_ext_state, true, pp);
2574 		    logger->end_log_line ();
2575 		  }
2576 		per_function_data *per_fn_data
2577 		  = get_or_create_per_function_data (point.get_function ());
2578 		per_fn_data->add_call_summary (node);
2579 	      }
2580 	  }
2581 	/* Traverse into successors of the supernode.  */
2582 	int i;
2583 	superedge *succ;
2584 	FOR_EACH_VEC_ELT (point.get_supernode ()->m_succs, i, succ)
2585 	  {
2586 	    if (logger)
2587 	      logger->log ("considering SN: %i -> SN: %i",
2588 			   succ->m_src->m_index, succ->m_dest->m_index);
2589 
2590 	    state_change change;
2591 
2592 	    program_point next_point
2593 	      = program_point::before_supernode (succ->m_dest, succ,
2594 						 point.get_call_string ());
2595 	    program_state next_state (state);
2596 
2597 	    if (!node->on_edge (*this, succ, &next_point, &next_state, &change))
2598 	      {
2599 		if (logger)
2600 		  logger->log ("skipping impossible edge to SN: %i",
2601 			       succ->m_dest->m_index);
2602 		continue;
2603 	      }
2604 
2605 	    exploded_node *next = get_or_create_node (next_point, next_state,
2606 						      &change);
2607 	    if (next)
2608 	      add_edge (node, next, succ, change);
2609 	  }
2610       }
2611       break;
2612     }
2613 }
2614 
2615 /* Ensure that this graph has a stats instance for FN, return it.
2616    FN can be NULL, in which case a stats instances is returned covering
2617    "functionless" parts of the graph (the origin node).  */
2618 
2619 stats *
get_or_create_function_stats(function * fn)2620 exploded_graph::get_or_create_function_stats (function *fn)
2621 {
2622   if (!fn)
2623     return &m_functionless_stats;
2624 
2625   if (stats **slot = m_per_function_stats.get (fn))
2626     return *slot;
2627   else
2628     {
2629       int num_supernodes = fn ? n_basic_blocks_for_fn (fn) : 0;
2630       /* not quite the num supernodes, but nearly.  */
2631       stats *new_stats = new stats (num_supernodes);
2632       m_per_function_stats.put (fn, new_stats);
2633       return new_stats;
2634     }
2635 }
2636 
2637 /* Print bar charts to PP showing:
2638    - the number of enodes per function, and
2639    - for each function:
2640      - the number of enodes per supernode/BB
2641      - the number of excess enodes per supernode/BB beyond the
2642        per-program-point limit, if there were any.  */
2643 
2644 void
print_bar_charts(pretty_printer * pp) const2645 exploded_graph::print_bar_charts (pretty_printer *pp) const
2646 {
2647   cgraph_node *cgnode;
2648 
2649   pp_string (pp, "enodes per function:");
2650   pp_newline (pp);
2651   bar_chart enodes_per_function;
2652   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cgnode)
2653     {
2654       function *fn = cgnode->get_fun ();
2655       const stats * const *s_ptr
2656 	= const_cast <function_stat_map_t &> (m_per_function_stats).get (fn);
2657       enodes_per_function.add_item (function_name (fn),
2658 				    s_ptr ? (*s_ptr)->get_total_enodes () : 0);
2659     }
2660   enodes_per_function.print (pp);
2661 
2662   /* Accumulate number of enodes per supernode.  */
2663   auto_vec<unsigned> enodes_per_supernode (m_sg.num_nodes ());
2664   for (int i = 0; i < m_sg.num_nodes (); i++)
2665     enodes_per_supernode.quick_push (0);
2666   int i;
2667   exploded_node *enode;
2668   FOR_EACH_VEC_ELT (m_nodes, i, enode)
2669     {
2670       const supernode *iter_snode = enode->get_supernode ();
2671       if (!iter_snode)
2672 	continue;
2673       enodes_per_supernode[iter_snode->m_index]++;
2674     }
2675 
2676   /* Accumulate excess enodes per supernode.  */
2677   auto_vec<unsigned> excess_enodes_per_supernode (m_sg.num_nodes ());
2678   for (int i = 0; i < m_sg.num_nodes (); i++)
2679     excess_enodes_per_supernode.quick_push (0);
2680   for (point_map_t::iterator iter = m_per_point_data.begin ();
2681        iter != m_per_point_data.end (); ++iter)
2682     {
2683       const program_point *point = (*iter).first;
2684       const supernode *iter_snode = point->get_supernode ();
2685       if (!iter_snode)
2686 	continue;
2687       const per_program_point_data *point_data = (*iter).second;
2688       excess_enodes_per_supernode[iter_snode->m_index]
2689 	+= point_data->m_excess_enodes;
2690     }
2691 
2692   /* Show per-function bar_charts of enodes per supernode/BB.  */
2693   pp_string (pp, "per-function enodes per supernode/BB:");
2694   pp_newline (pp);
2695   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (cgnode)
2696     {
2697       function *fn = cgnode->get_fun ();
2698       pp_printf (pp, "function: %qs", function_name (fn));
2699       pp_newline (pp);
2700 
2701       bar_chart enodes_per_snode;
2702       bar_chart excess_enodes_per_snode;
2703       bool have_excess_enodes = false;
2704       for (int i = 0; i < m_sg.num_nodes (); i++)
2705 	{
2706 	  const supernode *iter_snode = m_sg.get_node_by_index (i);
2707 	  if (iter_snode->get_function () != fn)
2708 	    continue;
2709 	  pretty_printer tmp_pp;
2710 	  pp_printf (&tmp_pp, "sn %i (bb %i)",
2711 		     iter_snode->m_index, iter_snode->m_bb->index);
2712 	  enodes_per_snode.add_item (pp_formatted_text (&tmp_pp),
2713 				     enodes_per_supernode[iter_snode->m_index]);
2714 	  const int num_excess
2715 	    = excess_enodes_per_supernode[iter_snode->m_index];
2716 	  excess_enodes_per_snode.add_item (pp_formatted_text (&tmp_pp),
2717 					    num_excess);
2718 	  if (num_excess)
2719 	    have_excess_enodes = true;
2720 	}
2721       enodes_per_snode.print (pp);
2722       if (have_excess_enodes)
2723 	{
2724 	  pp_printf (pp, "EXCESS ENODES:");
2725 	  pp_newline (pp);
2726 	  excess_enodes_per_snode.print (pp);
2727 	}
2728     }
2729 }
2730 
2731 /* Write all stats information to this graph's logger, if any.  */
2732 
2733 void
log_stats() const2734 exploded_graph::log_stats () const
2735 {
2736   logger * const logger = get_logger ();
2737   if (!logger)
2738     return;
2739 
2740   LOG_SCOPE (logger);
2741 
2742   logger->log ("m_sg.num_nodes (): %i", m_sg.num_nodes ());
2743   logger->log ("m_nodes.length (): %i", m_nodes.length ());
2744   logger->log ("m_edges.length (): %i", m_edges.length ());
2745   logger->log ("remaining enodes in worklist: %i", m_worklist.length ());
2746 
2747   logger->log ("global stats:");
2748   m_global_stats.log (logger);
2749 
2750   for (function_stat_map_t::iterator iter = m_per_function_stats.begin ();
2751        iter != m_per_function_stats.end ();
2752        ++iter)
2753     {
2754       function *fn = (*iter).first;
2755       log_scope s (logger, function_name (fn));
2756       (*iter).second->log (logger);
2757     }
2758 
2759   print_bar_charts (logger->get_printer ());
2760 }
2761 
2762 /* Dump all stats information to OUT.  */
2763 
2764 void
dump_stats(FILE * out) const2765 exploded_graph::dump_stats (FILE *out) const
2766 {
2767   fprintf (out, "m_sg.num_nodes (): %i\n", m_sg.num_nodes ());
2768   fprintf (out, "m_nodes.length (): %i\n", m_nodes.length ());
2769   fprintf (out, "m_edges.length (): %i\n", m_edges.length ());
2770   fprintf (out, "remaining enodes in worklist: %i", m_worklist.length ());
2771 
2772   fprintf (out, "global stats:\n");
2773   m_global_stats.dump (out);
2774 
2775   for (function_stat_map_t::iterator iter = m_per_function_stats.begin ();
2776        iter != m_per_function_stats.end ();
2777        ++iter)
2778     {
2779       function *fn = (*iter).first;
2780       fprintf (out, "function: %s\n", function_name (fn));
2781       (*iter).second->dump (out);
2782     }
2783 
2784   fprintf (out, "PK_AFTER_SUPERNODE per supernode:\n");
2785   for (unsigned i = 0; i < m_PK_AFTER_SUPERNODE_per_snode.length (); i++)
2786     fprintf (out, "  SN %i: %3i\n", i, m_PK_AFTER_SUPERNODE_per_snode[i]);
2787 }
2788 
2789 void
dump_states_for_supernode(FILE * out,const supernode * snode) const2790 exploded_graph::dump_states_for_supernode (FILE *out,
2791 					   const supernode *snode) const
2792 {
2793   fprintf (out, "PK_AFTER_SUPERNODE nodes for SN: %i\n", snode->m_index);
2794   int i;
2795   exploded_node *enode;
2796   int state_idx = 0;
2797   FOR_EACH_VEC_ELT (m_nodes, i, enode)
2798     {
2799       const supernode *iter_snode = enode->get_supernode ();
2800       if (enode->get_point ().get_kind () == PK_AFTER_SUPERNODE
2801 	  && iter_snode == snode)
2802 	{
2803 	  pretty_printer pp;
2804 	  pp_format_decoder (&pp) = default_tree_printer;
2805 	  enode->get_state ().dump_to_pp (m_ext_state, true, &pp);
2806 	  fprintf (out, "state %i: EN: %i\n  %s\n",
2807 		   state_idx++, enode->m_index,
2808 		   pp_formatted_text (&pp));
2809 	}
2810     }
2811   fprintf (out, "#exploded_node for PK_AFTER_SUPERNODE for SN: %i = %i\n",
2812 	   snode->m_index, state_idx);
2813 }
2814 
2815 /* Look for the last use of SEARCH_STMT within this path.
2816    If found write the edge's index to *OUT_IDX and return true, otherwise
2817    return false.  */
2818 
2819 bool
find_stmt_backwards(const gimple * search_stmt,int * out_idx) const2820 exploded_path::find_stmt_backwards (const gimple *search_stmt,
2821 				    int *out_idx) const
2822 {
2823   int i;
2824   const exploded_edge *eedge;
2825   FOR_EACH_VEC_ELT_REVERSE (m_edges, i, eedge)
2826     {
2827       const exploded_node *dst_node = eedge->m_dest;
2828       const program_point &dst_point = dst_node->get_point ();
2829       const gimple *stmt = dst_point.get_stmt ();
2830       if (stmt == search_stmt)
2831 	{
2832 	  *out_idx = i;
2833 	  return true;
2834 	}
2835     }
2836   return false;
2837 }
2838 
2839 /* Get the final exploded_node in this path, which must be non-empty.  */
2840 
2841 exploded_node *
get_final_enode() const2842 exploded_path::get_final_enode () const
2843 {
2844   gcc_assert (m_edges.length () > 0);
2845   return m_edges[m_edges.length () - 1]->m_dest;
2846 }
2847 
2848 /* Check state along this path, returning true if it is feasible.
2849    If OUT is non-NULL, and the path is infeasible, write a new
2850    feasibility_problem to *OUT.  */
2851 
2852 bool
feasible_p(logger * logger,feasibility_problem ** out) const2853 exploded_path::feasible_p (logger *logger, feasibility_problem **out) const
2854 {
2855   LOG_SCOPE (logger);
2856 
2857   /* Traverse the path, updating this model.  */
2858   region_model model;
2859   for (unsigned i = 0; i < m_edges.length (); i++)
2860     {
2861       const exploded_edge *eedge = m_edges[i];
2862       if (logger)
2863 	logger->log ("considering edge %i: EN:%i -> EN:%i",
2864 		     i,
2865 		     eedge->m_src->m_index,
2866 		     eedge->m_dest->m_index);
2867       const exploded_node &src_enode = *eedge->m_src;
2868       const program_point &src_point = src_enode.get_point ();
2869       if (logger)
2870 	{
2871 	  logger->start_log_line ();
2872 	  src_point.print (logger->get_printer (), format (false));
2873 	  logger->end_log_line ();
2874 	}
2875 
2876       if (const gimple *stmt = src_point.get_stmt ())
2877 	{
2878 	  /* Update cfun and input_location in case of ICE: make it easier to
2879 	     track down which source construct we're failing to handle.  */
2880 	  auto_cfun sentinel (src_point.get_function ());
2881 	  input_location = stmt->location;
2882 
2883 	  if (const gassign *assign = dyn_cast <const gassign *> (stmt))
2884 	    model.on_assignment (assign, NULL);
2885 	  else if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
2886 	    model.on_return (return_, NULL);
2887 	}
2888 
2889       const superedge *sedge = eedge->m_sedge;
2890       if (sedge)
2891 	{
2892 	  if (logger)
2893 	    logger->log ("  sedge: SN:%i -> SN:%i %s",
2894 			 sedge->m_src->m_index,
2895 			 sedge->m_dest->m_index,
2896 			 sedge->get_description (false));
2897 
2898 	  const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
2899 	  if (!model.maybe_update_for_edge (*sedge, last_stmt, NULL))
2900 	    {
2901 	      if (logger)
2902 		{
2903 		  logger->log ("rejecting due to region model");
2904 		  model.dump_to_pp (logger->get_printer (), false);
2905 		}
2906 	      if (out)
2907 		*out = new feasibility_problem (i, model, *eedge, last_stmt);
2908 	      return false;
2909 	    }
2910 	}
2911       else
2912 	{
2913 	  /* Special-case the initial eedge from the origin node to the
2914 	     initial function by pushing a frame for it.  */
2915 	  if (i == 0)
2916 	    {
2917 	      gcc_assert (eedge->m_src->m_index == 0);
2918 	      gcc_assert (src_point.get_kind () == PK_ORIGIN);
2919 	      gcc_assert (eedge->m_dest->get_point ().get_kind ()
2920 			  == PK_BEFORE_SUPERNODE);
2921 	      function *fun = eedge->m_dest->get_function ();
2922 	      gcc_assert (fun);
2923 	      model.push_frame (fun, NULL, NULL);
2924 	      if (logger)
2925 		logger->log ("  pushing frame for %qD", fun->decl);
2926 	    }
2927 	  else if (eedge->m_custom_info)
2928 	    eedge->m_custom_info->update_model (&model, *eedge);
2929 	}
2930 
2931       /* Handle phi nodes on an edge leaving a PK_BEFORE_SUPERNODE (to
2932 	 a PK_BEFORE_STMT, or a PK_AFTER_SUPERNODE if no stmts).
2933 	 This will typically not be associated with a superedge.  */
2934       if (src_point.get_from_edge ())
2935 	{
2936 	  const cfg_superedge *last_cfg_superedge
2937 	    = src_point.get_from_edge ()->dyn_cast_cfg_superedge ();
2938 	  if (last_cfg_superedge)
2939 	    {
2940 	      if (logger)
2941 		logger->log ("  update for phis");
2942 	      model.update_for_phis (src_enode.get_supernode (),
2943 				     last_cfg_superedge,
2944 				     NULL);
2945 	    }
2946 	}
2947 
2948       if (logger)
2949 	{
2950 	  logger->log ("state after edge %i: EN:%i -> EN:%i",
2951 		       i,
2952 		       eedge->m_src->m_index,
2953 		       eedge->m_dest->m_index);
2954 	  logger->start_log_line ();
2955 	  model.dump_to_pp (logger->get_printer (), true);
2956 	  logger->end_log_line ();
2957 	}
2958     }
2959 
2960   return true;
2961 }
2962 
2963 /* Dump this path in multiline form to PP.  */
2964 
2965 void
dump_to_pp(pretty_printer * pp) const2966 exploded_path::dump_to_pp (pretty_printer *pp) const
2967 {
2968   for (unsigned i = 0; i < m_edges.length (); i++)
2969     {
2970       const exploded_edge *eedge = m_edges[i];
2971       pp_printf (pp, "m_edges[%i]: EN %i -> EN %i",
2972 		 i,
2973 		 eedge->m_src->m_index,
2974 		 eedge->m_dest->m_index);
2975       pp_newline (pp);
2976     }
2977 }
2978 
2979 /* Dump this path in multiline form to FP.  */
2980 
2981 void
dump(FILE * fp) const2982 exploded_path::dump (FILE *fp) const
2983 {
2984   pretty_printer pp;
2985   pp_format_decoder (&pp) = default_tree_printer;
2986   pp_show_color (&pp) = pp_show_color (global_dc->printer);
2987   pp.buffer->stream = fp;
2988   dump_to_pp (&pp);
2989   pp_flush (&pp);
2990 }
2991 
2992 /* Dump this path in multiline form to stderr.  */
2993 
2994 DEBUG_FUNCTION void
dump() const2995 exploded_path::dump () const
2996 {
2997   dump (stderr);
2998 }
2999 
3000 /* A family of cluster subclasses for use when generating .dot output for
3001    exploded graphs (-fdump-analyzer-exploded-graph), for grouping the
3002    enodes into hierarchical boxes.
3003 
3004    All functionless enodes appear in the top-level graph.
3005    Every (function, call_string) pair gets its own cluster.  Within that
3006    cluster, each supernode gets its own cluster.
3007 
3008    Hence all enodes relating to a particular function with a particular
3009    callstring will be in a cluster together; all enodes for the same
3010    function but with a different callstring will be in a different
3011    cluster.  */
3012 
3013 /* Base class of cluster for clustering exploded_node instances in .dot
3014    output, based on various subclass-specific criteria.  */
3015 
3016 class exploded_cluster : public cluster<eg_traits>
3017 {
3018 };
3019 
3020 /* Cluster containing all exploded_node instances for one supernode.  */
3021 
3022 class supernode_cluster : public exploded_cluster
3023 {
3024 public:
supernode_cluster(const supernode * supernode)3025   supernode_cluster (const supernode *supernode) : m_supernode (supernode) {}
3026 
3027   // TODO: dtor?
3028 
dump_dot(graphviz_out * gv,const dump_args_t & args) const3029   void dump_dot (graphviz_out *gv, const dump_args_t &args) const FINAL OVERRIDE
3030   {
3031     gv->println ("subgraph \"cluster_supernode_%p\" {",
3032 		 (const void *)this);
3033     gv->indent ();
3034     gv->println ("style=\"dashed\";");
3035     gv->println ("label=\"SN: %i (bb: %i)\";",
3036 		 m_supernode->m_index, m_supernode->m_bb->index);
3037 
3038     int i;
3039     exploded_node *enode;
3040     FOR_EACH_VEC_ELT (m_enodes, i, enode)
3041       enode->dump_dot (gv, args);
3042 
3043     /* Terminate subgraph.  */
3044     gv->outdent ();
3045     gv->println ("}");
3046   }
3047 
add_node(exploded_node * en)3048   void add_node (exploded_node *en) FINAL OVERRIDE
3049   {
3050     m_enodes.safe_push (en);
3051   }
3052 
3053 private:
3054   const supernode *m_supernode;
3055   auto_vec <exploded_node *> m_enodes;
3056 };
3057 
3058 /* Cluster containing all supernode_cluster instances for one
3059    (function, call_string) pair.  */
3060 
3061 class function_call_string_cluster : public exploded_cluster
3062 {
3063 public:
function_call_string_cluster(function * fun,call_string cs)3064   function_call_string_cluster (function *fun, call_string cs)
3065   : m_fun (fun), m_cs (cs) {}
3066 
~function_call_string_cluster()3067   ~function_call_string_cluster ()
3068   {
3069     for (map_t::iterator iter = m_map.begin ();
3070 	 iter != m_map.end ();
3071 	 ++iter)
3072       delete (*iter).second;
3073   }
3074 
dump_dot(graphviz_out * gv,const dump_args_t & args) const3075   void dump_dot (graphviz_out *gv, const dump_args_t &args) const FINAL OVERRIDE
3076   {
3077     const char *funcname = function_name (m_fun);
3078 
3079     gv->println ("subgraph \"cluster_function_%p\" {", (const void *)this);
3080     gv->indent ();
3081     gv->write_indent ();
3082     gv->print ("label=\"call string: ");
3083     m_cs.print (gv->get_pp ());
3084     gv->print (" function: %s \";", funcname);
3085     gv->print ("\n");
3086 
3087     for (map_t::iterator iter = m_map.begin ();
3088 	 iter != m_map.end ();
3089 	 ++iter)
3090       (*iter).second->dump_dot (gv, args);
3091 
3092     /* Terminate subgraph.  */
3093     gv->outdent ();
3094     gv->println ("}");
3095   }
3096 
add_node(exploded_node * en)3097   void add_node (exploded_node *en) FINAL OVERRIDE
3098   {
3099     const supernode *supernode = en->get_supernode ();
3100     gcc_assert (supernode);
3101     supernode_cluster **slot = m_map.get (supernode);
3102     if (slot)
3103       (*slot)->add_node (en);
3104     else
3105       {
3106 	supernode_cluster *child = new supernode_cluster (supernode);
3107 	m_map.put (supernode, child);
3108 	child->add_node (en);
3109       }
3110   }
3111 
3112 private:
3113   function *m_fun;
3114   call_string m_cs;
3115   typedef ordered_hash_map<const supernode *, supernode_cluster *> map_t;
3116   map_t m_map;
3117 };
3118 
3119 /* Keys for root_cluster.  */
3120 
3121 struct function_call_string
3122 {
function_call_stringana::function_call_string3123   function_call_string (function *fun, call_string cs)
3124   : m_fun (fun), m_cs (cs)
3125   {
3126     gcc_assert (fun);
3127   }
3128 
3129   function *m_fun;
3130   call_string m_cs;
3131 };
3132 
3133 } // namespace ana
3134 
3135 template <> struct default_hash_traits<function_call_string>
3136 : public pod_hash_traits<function_call_string>
3137 {
3138   static const bool empty_zero_p = false;
3139 };
3140 
3141 template <>
3142 inline hashval_t
hash(value_type v)3143 pod_hash_traits<function_call_string>::hash (value_type v)
3144 {
3145   return pointer_hash <function>::hash (v.m_fun) ^ v.m_cs.hash ();
3146 }
3147 
3148 template <>
3149 inline bool
equal(const value_type & existing,const value_type & candidate)3150 pod_hash_traits<function_call_string>::equal (const value_type &existing,
3151 					      const value_type &candidate)
3152 {
3153   return existing.m_fun == candidate.m_fun && existing.m_cs == candidate.m_cs;
3154 }
3155 template <>
3156 inline void
mark_deleted(value_type & v)3157 pod_hash_traits<function_call_string>::mark_deleted (value_type &v)
3158 {
3159   v.m_fun = reinterpret_cast<function *> (1);
3160 }
3161 template <>
3162 inline void
mark_empty(value_type & v)3163 pod_hash_traits<function_call_string>::mark_empty (value_type &v)
3164 {
3165   v.m_fun = NULL;
3166 }
3167 template <>
3168 inline bool
is_deleted(value_type v)3169 pod_hash_traits<function_call_string>::is_deleted (value_type v)
3170 {
3171   return v.m_fun == reinterpret_cast<function *> (1);
3172 }
3173 template <>
3174 inline bool
is_empty(value_type v)3175 pod_hash_traits<function_call_string>::is_empty (value_type v)
3176 {
3177   return v.m_fun == NULL;
3178 }
3179 
3180 namespace ana {
3181 
3182 /* Top-level cluster for generating .dot output for exploded graphs,
3183    handling the functionless nodes, and grouping the remaining nodes by
3184    callstring.  */
3185 
3186 class root_cluster : public exploded_cluster
3187 {
3188 public:
~root_cluster()3189   ~root_cluster ()
3190   {
3191     for (map_t::iterator iter = m_map.begin ();
3192 	 iter != m_map.end ();
3193 	 ++iter)
3194       delete (*iter).second;
3195   }
3196 
dump_dot(graphviz_out * gv,const dump_args_t & args) const3197   void dump_dot (graphviz_out *gv, const dump_args_t &args) const FINAL OVERRIDE
3198   {
3199     int i;
3200     exploded_node *enode;
3201     FOR_EACH_VEC_ELT (m_functionless_enodes, i, enode)
3202       enode->dump_dot (gv, args);
3203 
3204     for (map_t::iterator iter = m_map.begin ();
3205 	 iter != m_map.end ();
3206 	 ++iter)
3207       (*iter).second->dump_dot (gv, args);
3208   }
3209 
add_node(exploded_node * en)3210   void add_node (exploded_node *en) FINAL OVERRIDE
3211   {
3212     function *fun = en->get_function ();
3213     if (!fun)
3214       {
3215 	m_functionless_enodes.safe_push (en);
3216 	return;
3217       }
3218 
3219     const call_string &cs = en->get_point ().get_call_string ();
3220     function_call_string key (fun, cs);
3221     function_call_string_cluster **slot = m_map.get (key);
3222     if (slot)
3223       (*slot)->add_node (en);
3224     else
3225       {
3226 	function_call_string_cluster *child
3227 	  = new function_call_string_cluster (fun, cs);
3228 	m_map.put (key, child);
3229 	child->add_node (en);
3230       }
3231   }
3232 
3233 private:
3234   /* This can't be an ordered_hash_map, as we can't store vec<call_string>,
3235      since it's not a POD; vec<>::quick_push has:
3236        *slot = obj;
3237      and the slot isn't initialized, so the assignment op dies when cleaning up
3238      un-inited *slot (within the truncate call).  */
3239   typedef hash_map<function_call_string, function_call_string_cluster *> map_t;
3240   map_t m_map;
3241 
3242   /* This should just be the origin exploded_node.  */
3243   auto_vec <exploded_node *> m_functionless_enodes;
3244 };
3245 
3246 /* Subclass of range_label for use within
3247    exploded_graph::dump_exploded_nodes for implementing
3248    -fdump-analyzer-exploded-nodes: a label for a specific
3249    exploded_node.  */
3250 
3251 class enode_label : public range_label
3252 {
3253  public:
enode_label(const extrinsic_state & ext_state,exploded_node * enode)3254   enode_label (const extrinsic_state &ext_state,
3255 	       exploded_node *enode)
3256   : m_ext_state (ext_state), m_enode (enode) {}
3257 
get_text(unsigned) const3258   label_text get_text (unsigned) const FINAL OVERRIDE
3259   {
3260     pretty_printer pp;
3261     pp_format_decoder (&pp) = default_tree_printer;
3262     m_enode->get_state ().dump_to_pp (m_ext_state, true, &pp);
3263     return make_label_text (false, "EN: %i: %s",
3264 			    m_enode->m_index, pp_formatted_text (&pp));
3265   }
3266 
3267 private:
3268   const extrinsic_state &m_ext_state;
3269   exploded_node *m_enode;
3270 };
3271 
3272 /* Postprocessing support for dumping the exploded nodes.
3273    Handle -fdump-analyzer-exploded-nodes,
3274    -fdump-analyzer-exploded-nodes-2, and the
3275    "__analyzer_dump_exploded_nodes" builtin.  */
3276 
3277 void
dump_exploded_nodes() const3278 exploded_graph::dump_exploded_nodes () const
3279 {
3280   // TODO
3281   /* Locate calls to __analyzer_dump_exploded_nodes.  */
3282   // Print how many egs there are for them?
3283   /* Better: log them as we go, and record the exploded nodes
3284      in question.  */
3285 
3286   /* Show every enode.  */
3287 
3288   /* Gather them by stmt, so that we can more clearly see the
3289      "hotspots" requiring numerous exploded nodes.  */
3290 
3291   /* Alternatively, simply throw them all into one big rich_location
3292      and see if the label-printing will sort it out...
3293      This requires them all to be in the same source file.  */
3294 
3295   if (flag_dump_analyzer_exploded_nodes)
3296     {
3297       auto_timevar tv (TV_ANALYZER_DUMP);
3298       gcc_rich_location richloc (UNKNOWN_LOCATION);
3299       unsigned i;
3300       exploded_node *enode;
3301       FOR_EACH_VEC_ELT (m_nodes, i, enode)
3302 	{
3303 	  if (const gimple *stmt = enode->get_stmt ())
3304 	    {
3305 	      if (get_pure_location (richloc.get_loc ()) == UNKNOWN_LOCATION)
3306 		richloc.set_range (0, stmt->location, SHOW_RANGE_WITH_CARET);
3307 	      else
3308 		richloc.add_range (stmt->location,
3309 				   SHOW_RANGE_WITHOUT_CARET,
3310 				   new enode_label (m_ext_state, enode));
3311 	    }
3312 	}
3313       warning_at (&richloc, 0, "%i exploded nodes", m_nodes.length ());
3314 
3315       /* Repeat the warning without all the labels, so that message is visible
3316 	 (the other one may well have scrolled past the terminal limit).  */
3317       warning_at (richloc.get_loc (), 0,
3318 		  "%i exploded nodes", m_nodes.length ());
3319 
3320       if (m_worklist.length () > 0)
3321 	warning_at (richloc.get_loc (), 0,
3322 		    "worklist still contains %i nodes", m_worklist.length ());
3323     }
3324 
3325   /* Dump the egraph in textual form to a dump file.  */
3326   if (flag_dump_analyzer_exploded_nodes_2)
3327     {
3328       auto_timevar tv (TV_ANALYZER_DUMP);
3329       char *filename
3330 	= concat (dump_base_name, ".eg.txt", NULL);
3331       FILE *outf = fopen (filename, "w");
3332       if (!outf)
3333 	error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
3334       free (filename);
3335 
3336       fprintf (outf, "exploded graph for %s\n", dump_base_name);
3337       fprintf (outf, "  nodes: %i\n", m_nodes.length ());
3338       fprintf (outf, "  edges: %i\n", m_edges.length ());
3339 
3340       unsigned i;
3341       exploded_node *enode;
3342       FOR_EACH_VEC_ELT (m_nodes, i, enode)
3343 	{
3344 	  fprintf (outf, "\nEN %i:\n", enode->m_index);
3345 	  enode->dump_succs_and_preds (outf);
3346 	  pretty_printer pp;
3347 	  enode->get_point ().print (&pp, format (true));
3348 	  fprintf (outf, "%s\n", pp_formatted_text (&pp));
3349 	  enode->get_state ().dump_to_file (m_ext_state, false, outf);
3350 	}
3351 
3352       fclose (outf);
3353     }
3354 
3355   /* Dump the egraph in textual form to multiple dump files, one per enode.  */
3356   if (flag_dump_analyzer_exploded_nodes_3)
3357     {
3358       auto_timevar tv (TV_ANALYZER_DUMP);
3359 
3360       unsigned i;
3361       exploded_node *enode;
3362       FOR_EACH_VEC_ELT (m_nodes, i, enode)
3363 	{
3364 	  char *filename
3365 	    = xasprintf ("%s.en-%i.txt", dump_base_name, i);
3366 	  FILE *outf = fopen (filename, "w");
3367 	  if (!outf)
3368 	    error_at (UNKNOWN_LOCATION, "unable to open %qs for writing", filename);
3369 	  free (filename);
3370 
3371 	  fprintf (outf, "EN %i:\n", enode->m_index);
3372 	  enode->dump_succs_and_preds (outf);
3373 	  pretty_printer pp;
3374 	  enode->get_point ().print (&pp, format (true));
3375 	  fprintf (outf, "%s\n", pp_formatted_text (&pp));
3376 	  enode->get_state ().dump_to_file (m_ext_state, false, outf);
3377 
3378 	  fclose (outf);
3379 	}
3380     }
3381 
3382   /* Emit a warning at any call to "__analyzer_dump_exploded_nodes",
3383      giving the number of processed exploded nodes for "before-stmt",
3384      and the IDs of processed, merger, and worklist enodes.
3385 
3386      We highlight the count of *processed* enodes since this is of most
3387      interest in DejaGnu tests for ensuring that state merger has
3388      happened.
3389 
3390      We don't show the count of merger and worklist enodes, as this is
3391      more of an implementation detail of the merging/worklist that we
3392      don't want to bake into our expected DejaGnu messages.  */
3393 
3394   unsigned i;
3395   exploded_node *enode;
3396   hash_set<const gimple *> seen;
3397   FOR_EACH_VEC_ELT (m_nodes, i, enode)
3398     {
3399       if (enode->get_point ().get_kind () != PK_BEFORE_STMT)
3400 	continue;
3401 
3402       if (const gimple *stmt = enode->get_stmt ())
3403 	if (const gcall *call = dyn_cast <const gcall *> (stmt))
3404 	  if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
3405 				       1))
3406 	    {
3407 	      if (seen.contains (stmt))
3408 		continue;
3409 
3410 	      auto_vec<exploded_node *> processed_enodes;
3411 	      auto_vec<exploded_node *> merger_enodes;
3412 	      auto_vec<exploded_node *> worklist_enodes;
3413 	      /* This is O(N^2).  */
3414 	      unsigned j;
3415 	      exploded_node *other_enode;
3416 	      FOR_EACH_VEC_ELT (m_nodes, j, other_enode)
3417 		{
3418 		  if (other_enode->get_point ().get_kind () != PK_BEFORE_STMT)
3419 		    continue;
3420 		  if (other_enode->get_stmt () == stmt)
3421 		    switch (other_enode->get_status ())
3422 		      {
3423 		      default:
3424 			gcc_unreachable ();
3425 		      case exploded_node::STATUS_WORKLIST:
3426 			worklist_enodes.safe_push (other_enode);
3427 			break;
3428 		      case exploded_node::STATUS_PROCESSED:
3429 			processed_enodes.safe_push (other_enode);
3430 			break;
3431 		      case exploded_node::STATUS_MERGER:
3432 			merger_enodes.safe_push (other_enode);
3433 			break;
3434 		      }
3435 		}
3436 
3437 	      pretty_printer pp;
3438 	      pp_character (&pp, '[');
3439 	      print_enode_indices (&pp, processed_enodes);
3440 	      if (merger_enodes.length () > 0)
3441 		{
3442 		  pp_string (&pp, "] merger(s): [");
3443 		  print_enode_indices (&pp, merger_enodes);
3444 		}
3445 	      if (worklist_enodes.length () > 0)
3446 		{
3447 		  pp_string (&pp, "] worklist: [");
3448 		  print_enode_indices (&pp, worklist_enodes);
3449 		}
3450 	      pp_character (&pp, ']');
3451 
3452 	      warning_n (stmt->location, 0, processed_enodes.length (),
3453 			 "%i processed enode: %s",
3454 			 "%i processed enodes: %s",
3455 			 processed_enodes.length (), pp_formatted_text (&pp));
3456 	      seen.add (stmt);
3457 
3458 	      /* If the argument is non-zero, then print all of the states
3459 		 of the various enodes.  */
3460 	      tree t_arg = fold (gimple_call_arg (call, 0));
3461 	      if (TREE_CODE (t_arg) != INTEGER_CST)
3462 		{
3463 		  error_at (call->location,
3464 			    "integer constant required for arg 1");
3465 		  return;
3466 		}
3467 	      int i_arg = TREE_INT_CST_LOW (t_arg);
3468 	      if (i_arg)
3469 		{
3470 		  exploded_node *other_enode;
3471 		  FOR_EACH_VEC_ELT (processed_enodes, j, other_enode)
3472 		    {
3473 		      fprintf (stderr, "%i of %i: EN %i:\n",
3474 			       j + 1, processed_enodes.length (),
3475 			       other_enode->m_index);
3476 		      other_enode->dump_succs_and_preds (stderr);
3477 		      /* Dump state.  */
3478 		      other_enode->get_state ().dump (m_ext_state, false);
3479 		    }
3480 		}
3481 	    }
3482     }
3483 }
3484 
3485 /* A collection of classes for visualizing the callgraph in .dot form
3486    (as represented in the supergraph).  */
3487 
3488 /* Forward decls.  */
3489 class viz_callgraph_node;
3490 class viz_callgraph_edge;
3491 class viz_callgraph;
3492 class viz_callgraph_cluster;
3493 
3494 /* Traits for using "digraph.h" to visualize the callgraph.  */
3495 
3496 struct viz_callgraph_traits
3497 {
3498   typedef viz_callgraph_node node_t;
3499   typedef viz_callgraph_edge edge_t;
3500   typedef viz_callgraph graph_t;
3501   struct dump_args_t
3502   {
dump_args_tana::viz_callgraph_traits::dump_args_t3503     dump_args_t (const exploded_graph *eg) : m_eg (eg) {}
3504     const exploded_graph *m_eg;
3505   };
3506   typedef viz_callgraph_cluster cluster_t;
3507 };
3508 
3509 /* Subclass of dnode representing a function within the callgraph.  */
3510 
3511 class viz_callgraph_node : public dnode<viz_callgraph_traits>
3512 {
3513   friend class viz_callgraph;
3514 
3515 public:
viz_callgraph_node(function * fun,int index)3516   viz_callgraph_node (function *fun, int index)
3517   : m_fun (fun), m_index (index), m_num_supernodes (0), m_num_superedges (0)
3518   {
3519     gcc_assert (fun);
3520   }
3521 
dump_dot(graphviz_out * gv,const dump_args_t & args) const3522   void dump_dot (graphviz_out *gv, const dump_args_t &args) const FINAL OVERRIDE
3523   {
3524     pretty_printer *pp = gv->get_pp ();
3525 
3526     dump_dot_id (pp);
3527     pp_printf (pp, " [shape=none,margin=0,style=filled,fillcolor=%s,label=<",
3528 	       "lightgrey");
3529     pp_string (pp, "<TABLE BORDER=\"0\">");
3530     pp_write_text_to_stream (pp);
3531 
3532     gv->begin_trtd ();
3533     pp_printf (pp, "VCG: %i: %s", m_index, function_name (m_fun));
3534     gv->end_tdtr ();
3535     pp_newline (pp);
3536 
3537     gv->begin_trtd ();
3538     pp_printf (pp, "supernodes: %i\n", m_num_supernodes);
3539     gv->end_tdtr ();
3540     pp_newline (pp);
3541 
3542     gv->begin_trtd ();
3543     pp_printf (pp, "superedges: %i\n", m_num_superedges);
3544     gv->end_tdtr ();
3545     pp_newline (pp);
3546 
3547     if (args.m_eg)
3548       {
3549 	unsigned i;
3550 	exploded_node *enode;
3551 	unsigned num_enodes = 0;
3552 	FOR_EACH_VEC_ELT (args.m_eg->m_nodes, i, enode)
3553 	  {
3554 	    if (enode->get_point ().get_function () == m_fun)
3555 	      num_enodes++;
3556 	  }
3557 	gv->begin_trtd ();
3558 	pp_printf (pp, "enodes: %i\n", num_enodes);
3559 	gv->end_tdtr ();
3560 	pp_newline (pp);
3561 
3562 	// TODO: also show the per-callstring breakdown
3563 	const exploded_graph::call_string_data_map_t *per_cs_data
3564 	  = args.m_eg->get_per_call_string_data ();
3565 	for (exploded_graph::call_string_data_map_t::iterator iter
3566 	       = per_cs_data->begin ();
3567 	     iter != per_cs_data->end ();
3568 	     ++iter)
3569 	  {
3570 	    const call_string *cs = (*iter).first;
3571 	    //per_call_string_data *data = (*iter).second;
3572 	    num_enodes = 0;
3573 	    FOR_EACH_VEC_ELT (args.m_eg->m_nodes, i, enode)
3574 	      {
3575 		if (enode->get_point ().get_function () == m_fun
3576 		    && enode->get_point ().get_call_string () == *cs)
3577 		  num_enodes++;
3578 	      }
3579 	    if (num_enodes > 0)
3580 	      {
3581 		gv->begin_trtd ();
3582 		cs->print (pp);
3583 		pp_printf (pp, ": %i\n", num_enodes);
3584 		pp_write_text_as_html_like_dot_to_stream (pp);
3585 		gv->end_tdtr ();
3586 	      }
3587 	  }
3588 
3589 	/* Show any summaries.  */
3590 	per_function_data *data = args.m_eg->get_per_function_data (m_fun);
3591 	if (data)
3592 	  {
3593 	    pp_newline (pp);
3594 	    gv->begin_trtd ();
3595 	    pp_printf (pp, "summaries: %i\n", data->m_summaries.length ());
3596 	    pp_write_text_as_html_like_dot_to_stream (pp);
3597 	    gv->end_tdtr ();
3598 	  }
3599       }
3600 
3601     pp_string (pp, "</TABLE>>];\n\n");
3602     pp_flush (pp);
3603   }
3604 
dump_dot_id(pretty_printer * pp) const3605   void dump_dot_id (pretty_printer *pp) const
3606   {
3607     pp_printf (pp, "vcg_%i", m_index);
3608   }
3609 
3610 private:
3611   function *m_fun;
3612   int m_index;
3613   int m_num_supernodes;
3614   int m_num_superedges;
3615 };
3616 
3617 /* Subclass of dedge representing a callgraph edge.  */
3618 
3619 class viz_callgraph_edge : public dedge<viz_callgraph_traits>
3620 {
3621 public:
viz_callgraph_edge(viz_callgraph_node * src,viz_callgraph_node * dest)3622   viz_callgraph_edge (viz_callgraph_node *src, viz_callgraph_node *dest)
3623   : dedge<viz_callgraph_traits> (src, dest)
3624   {}
3625 
dump_dot(graphviz_out * gv,const dump_args_t &) const3626   void dump_dot (graphviz_out *gv, const dump_args_t &) const
3627     FINAL OVERRIDE
3628   {
3629     pretty_printer *pp = gv->get_pp ();
3630 
3631     const char *style = "\"solid,bold\"";
3632     const char *color = "black";
3633     int weight = 10;
3634     const char *constraint = "true";
3635 
3636     m_src->dump_dot_id (pp);
3637     pp_string (pp, " -> ");
3638     m_dest->dump_dot_id (pp);
3639     pp_printf (pp,
3640 	       (" [style=%s, color=%s, weight=%d, constraint=%s,"
3641 		" headlabel=\""),
3642 	       style, color, weight, constraint);
3643     pp_printf (pp, "\"];\n");
3644   }
3645 };
3646 
3647 /* Subclass of digraph representing the callgraph.  */
3648 
3649 class viz_callgraph : public digraph<viz_callgraph_traits>
3650 {
3651 public:
3652   viz_callgraph (const supergraph &sg);
3653 
get_vcg_node_for_function(function * fun)3654   viz_callgraph_node *get_vcg_node_for_function (function *fun)
3655   {
3656     return *m_map.get (fun);
3657   }
3658 
get_vcg_node_for_snode(supernode * snode)3659   viz_callgraph_node *get_vcg_node_for_snode (supernode *snode)
3660   {
3661     return get_vcg_node_for_function (snode->m_fun);
3662   }
3663 
3664 private:
3665   hash_map<function *, viz_callgraph_node *> m_map;
3666 };
3667 
3668 /* Placeholder subclass of cluster.  */
3669 
3670 class viz_callgraph_cluster : public cluster<viz_callgraph_traits>
3671 {
3672 };
3673 
3674 /* viz_callgraph's ctor.  */
3675 
viz_callgraph(const supergraph & sg)3676 viz_callgraph::viz_callgraph (const supergraph &sg)
3677 {
3678   cgraph_node *node;
3679   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3680     {
3681       function *fun = node->get_fun ();
3682       viz_callgraph_node *vcg_node
3683 	= new viz_callgraph_node (fun, m_nodes.length ());
3684       m_map.put (fun, vcg_node);
3685       add_node (vcg_node);
3686     }
3687 
3688   unsigned i;
3689   superedge *sedge;
3690   FOR_EACH_VEC_ELT (sg.m_edges, i, sedge)
3691     {
3692       viz_callgraph_node *vcg_src = get_vcg_node_for_snode (sedge->m_src);
3693       if (vcg_src->m_fun)
3694 	get_vcg_node_for_function (vcg_src->m_fun)->m_num_superedges++;
3695       if (sedge->dyn_cast_call_superedge ())
3696 	{
3697 	  viz_callgraph_node *vcg_dest = get_vcg_node_for_snode (sedge->m_dest);
3698 	  viz_callgraph_edge *vcg_edge
3699 	    = new viz_callgraph_edge (vcg_src, vcg_dest);
3700 	  add_edge (vcg_edge);
3701 	}
3702     }
3703 
3704   supernode *snode;
3705   FOR_EACH_VEC_ELT (sg.m_nodes, i, snode)
3706     {
3707       if (snode->m_fun)
3708 	get_vcg_node_for_function (snode->m_fun)->m_num_supernodes++;
3709     }
3710 }
3711 
3712 /* Dump the callgraph to FILENAME.  */
3713 
3714 static void
dump_callgraph(const supergraph & sg,const char * filename,const exploded_graph * eg)3715 dump_callgraph (const supergraph &sg, const char *filename,
3716 		const exploded_graph *eg)
3717 {
3718   FILE *outf = fopen (filename, "w");
3719   if (!outf)
3720     return;
3721 
3722   // TODO
3723   viz_callgraph vcg (sg);
3724   vcg.dump_dot (filename, NULL, viz_callgraph_traits::dump_args_t (eg));
3725 
3726   fclose (outf);
3727 }
3728 
3729 /* Dump the callgraph to "<srcfile>.callgraph.dot".  */
3730 
3731 static void
dump_callgraph(const supergraph & sg,const exploded_graph * eg)3732 dump_callgraph (const supergraph &sg, const exploded_graph *eg)
3733 {
3734   auto_timevar tv (TV_ANALYZER_DUMP);
3735   char *filename = concat (dump_base_name, ".callgraph.dot", NULL);
3736   dump_callgraph (sg, filename, eg);
3737   free (filename);
3738 }
3739 
3740 /* Subclass of dot_annotator for implementing
3741    DUMP_BASE_NAME.supergraph-eg.dot, a post-analysis dump of the supergraph.
3742 
3743    Annotate the supergraph nodes by printing the exploded nodes in concise
3744    form within them, next to their pertinent statements where appropriate,
3745    colorizing the exploded nodes based on sm-state.
3746    Also show saved diagnostics within the exploded nodes, giving information
3747    on whether they were feasible, and, if infeasible, where the problem
3748    was.  */
3749 
3750 class exploded_graph_annotator : public dot_annotator
3751 {
3752 public:
exploded_graph_annotator(const exploded_graph & eg)3753   exploded_graph_annotator (const exploded_graph &eg)
3754   : m_eg (eg)
3755   {
3756     /* Avoid O(N^2) by prepopulating m_enodes_per_snodes.  */
3757     unsigned i;
3758     supernode *snode;
3759     FOR_EACH_VEC_ELT (eg.get_supergraph ().m_nodes, i, snode)
3760       m_enodes_per_snodes.safe_push (new auto_vec <exploded_node *> ());
3761     exploded_node *enode;
3762     FOR_EACH_VEC_ELT (m_eg.m_nodes, i, enode)
3763       if (enode->get_supernode ())
3764 	m_enodes_per_snodes[enode->get_supernode ()->m_index]->safe_push (enode);
3765   }
3766 
3767   /* Show exploded nodes for BEFORE_SUPERNODE points before N.  */
add_node_annotations(graphviz_out * gv,const supernode & n,bool within_table) const3768   bool add_node_annotations (graphviz_out *gv, const supernode &n,
3769 			     bool within_table)
3770     const FINAL OVERRIDE
3771   {
3772     if (!within_table)
3773       return false;
3774     gv->begin_tr ();
3775     pretty_printer *pp = gv->get_pp ();
3776 
3777     gv->begin_td ();
3778     pp_string (pp, "BEFORE");
3779     gv->end_td ();
3780 
3781     unsigned i;
3782     exploded_node *enode;
3783     bool had_enode = false;
3784     FOR_EACH_VEC_ELT (*m_enodes_per_snodes[n.m_index], i, enode)
3785       {
3786 	gcc_assert (enode->get_supernode () == &n);
3787 	const program_point &point = enode->get_point ();
3788 	if (point.get_kind () != PK_BEFORE_SUPERNODE)
3789 	  continue;
3790 	print_enode (gv, enode);
3791 	had_enode = true;
3792       }
3793     if (!had_enode)
3794       pp_string (pp, "<TD BGCOLOR=\"red\">UNREACHED</TD>");
3795     pp_flush (pp);
3796     gv->end_tr ();
3797     return true;
3798   }
3799 
3800   /* Show exploded nodes for STMT.  */
add_stmt_annotations(graphviz_out * gv,const gimple * stmt,bool within_row) const3801   void add_stmt_annotations (graphviz_out *gv, const gimple *stmt,
3802 			     bool within_row)
3803     const FINAL OVERRIDE
3804   {
3805     if (!within_row)
3806       return;
3807     pretty_printer *pp = gv->get_pp ();
3808 
3809     const supernode *snode
3810       = m_eg.get_supergraph ().get_supernode_for_stmt (stmt);
3811     unsigned i;
3812     exploded_node *enode;
3813     bool had_td = false;
3814     FOR_EACH_VEC_ELT (*m_enodes_per_snodes[snode->m_index], i, enode)
3815       {
3816 	const program_point &point = enode->get_point ();
3817 	if (point.get_kind () != PK_BEFORE_STMT)
3818 	  continue;
3819 	if (point.get_stmt () != stmt)
3820 	  continue;
3821 	print_enode (gv, enode);
3822 	had_td = true;
3823       }
3824     pp_flush (pp);
3825     if (!had_td)
3826       {
3827 	gv->begin_td ();
3828 	gv->end_td ();
3829       }
3830   }
3831 
3832   /* Show exploded nodes for AFTER_SUPERNODE points after N.  */
add_after_node_annotations(graphviz_out * gv,const supernode & n) const3833   bool add_after_node_annotations (graphviz_out *gv, const supernode &n)
3834     const FINAL OVERRIDE
3835   {
3836     gv->begin_tr ();
3837     pretty_printer *pp = gv->get_pp ();
3838 
3839     gv->begin_td ();
3840     pp_string (pp, "AFTER");
3841     gv->end_td ();
3842 
3843     unsigned i;
3844     exploded_node *enode;
3845     FOR_EACH_VEC_ELT (*m_enodes_per_snodes[n.m_index], i, enode)
3846       {
3847 	gcc_assert (enode->get_supernode () == &n);
3848 	const program_point &point = enode->get_point ();
3849 	if (point.get_kind () != PK_AFTER_SUPERNODE)
3850 	  continue;
3851 	print_enode (gv, enode);
3852       }
3853     pp_flush (pp);
3854     gv->end_tr ();
3855     return true;
3856   }
3857 
3858 private:
3859   /* Concisely print a TD element for ENODE, showing the index, status,
3860      and any saved_diagnostics at the enode.  Colorize it to show sm-state.
3861 
3862      Ideally we'd dump ENODE's state here, hidden behind some kind of
3863      interactive disclosure method like a tooltip, so that the states
3864      can be explored without overwhelming the graph.
3865      However, I wasn't able to get graphviz/xdot to show tooltips on
3866      individual elements within a HTML-like label.  */
print_enode(graphviz_out * gv,const exploded_node * enode) const3867   void print_enode (graphviz_out *gv, const exploded_node *enode) const
3868   {
3869     pretty_printer *pp = gv->get_pp ();
3870     pp_printf (pp, "<TD BGCOLOR=\"%s\">",
3871 	       enode->get_dot_fillcolor ());
3872     pp_printf (pp, "<TABLE BORDER=\"0\">");
3873     gv->begin_trtd ();
3874     pp_printf (pp, "EN: %i", enode->m_index);
3875     switch (enode->get_status ())
3876       {
3877       default:
3878 	gcc_unreachable ();
3879       case exploded_node::STATUS_WORKLIST:
3880 	pp_string (pp, "(W)");
3881 	break;
3882       case exploded_node::STATUS_PROCESSED:
3883 	break;
3884       case exploded_node::STATUS_MERGER:
3885 	pp_string (pp, "(M)");
3886 	break;
3887       }
3888     gv->end_tdtr ();
3889     /* Dump any saved_diagnostics at this enode.  */
3890     {
3891       const diagnostic_manager &dm = m_eg.get_diagnostic_manager ();
3892       for (unsigned i = 0; i < dm.get_num_diagnostics (); i++)
3893 	{
3894 	  const saved_diagnostic *sd = dm.get_saved_diagnostic (i);
3895 	  if (sd->m_enode == enode)
3896 	    print_saved_diagnostic (gv, sd);
3897 	}
3898     }
3899     pp_printf (pp, "</TABLE>");
3900     pp_printf (pp, "</TD>");
3901   }
3902 
3903   /* Print a TABLE element for SD, showing the kind, the length of the
3904      exploded_path, whether the path was feasible, and if infeasible,
3905      what the problem was.  */
print_saved_diagnostic(graphviz_out * gv,const saved_diagnostic * sd) const3906   void print_saved_diagnostic (graphviz_out *gv,
3907 			       const saved_diagnostic *sd) const
3908   {
3909     pretty_printer *pp = gv->get_pp ();
3910     gv->begin_trtd ();
3911     pp_printf (pp, "<TABLE BORDER=\"0\">");
3912     gv->begin_tr ();
3913     pp_string (pp, "<TD BGCOLOR=\"green\">");
3914     pp_printf (pp, "DIAGNOSTIC: %s", sd->m_d->get_kind ());
3915     gv->end_tdtr ();
3916     gv->begin_trtd ();
3917     pp_printf (pp, "epath length: %i", sd->get_epath_length ());
3918     gv->end_tdtr ();
3919     switch (sd->get_status ())
3920       {
3921       default:
3922       case saved_diagnostic::STATUS_NEW:
3923 	gcc_unreachable ();
3924 	break;
3925       case saved_diagnostic::STATUS_INFEASIBLE_PATH:
3926 	{
3927 	  gv->begin_trtd ();
3928 	  pp_printf (pp, "INFEASIBLE");
3929 	  gv->end_tdtr ();
3930 	  const feasibility_problem *p = sd->get_feasibility_problem ();
3931 	  gcc_assert (p);
3932 	  gv->begin_trtd ();
3933 	  pp_printf (pp, "at eedge %i: EN:%i -> EN:%i",
3934 		     p->m_eedge_idx,
3935 		     p->m_eedge.m_src->m_index,
3936 		     p->m_eedge.m_dest->m_index);
3937 	  pp_write_text_as_html_like_dot_to_stream (pp);
3938 	  gv->end_tdtr ();
3939 	  gv->begin_trtd ();
3940 	  p->m_eedge.m_sedge->dump (pp);
3941 	  pp_write_text_as_html_like_dot_to_stream (pp);
3942 	  gv->end_tdtr ();
3943 	  gv->begin_trtd ();
3944 	  pp_gimple_stmt_1 (pp, p->m_last_stmt, 0, (dump_flags_t)0);
3945 	  pp_write_text_as_html_like_dot_to_stream (pp);
3946 	  gv->end_tdtr ();
3947 	  /* Ideally we'd print p->m_model here; see the notes above about
3948 	     tooltips.  */
3949 	}
3950 	break;
3951       case saved_diagnostic::STATUS_FEASIBLE_PATH:
3952 	gv->begin_trtd ();
3953 	pp_printf (pp, "FEASIBLE");
3954 	gv->end_tdtr ();
3955 	break;
3956       }
3957     pp_printf (pp, "</TABLE>");
3958     gv->end_tdtr ();
3959   }
3960 
3961   const exploded_graph &m_eg;
3962   auto_delete_vec<auto_vec <exploded_node *> > m_enodes_per_snodes;
3963 };
3964 
3965 /* Run the analysis "engine".  */
3966 
3967 void
impl_run_checkers(logger * logger)3968 impl_run_checkers (logger *logger)
3969 {
3970   LOG_SCOPE (logger);
3971 
3972   /* If using LTO, ensure that the cgraph nodes have function bodies.  */
3973   cgraph_node *node;
3974   FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
3975     node->get_untransformed_body ();
3976 
3977   /* Create the supergraph.  */
3978   supergraph sg (logger);
3979 
3980   state_purge_map *purge_map = NULL;
3981 
3982   if (flag_analyzer_state_purge)
3983     purge_map = new state_purge_map (sg, logger);
3984 
3985   if (flag_dump_analyzer_supergraph)
3986     {
3987       /* Dump supergraph pre-analysis.  */
3988       auto_timevar tv (TV_ANALYZER_DUMP);
3989       char *filename = concat (dump_base_name, ".supergraph.dot", NULL);
3990       supergraph::dump_args_t args ((enum supergraph_dot_flags)0, NULL);
3991       sg.dump_dot (filename, args);
3992       free (filename);
3993     }
3994 
3995   if (flag_dump_analyzer_state_purge)
3996     {
3997       auto_timevar tv (TV_ANALYZER_DUMP);
3998       state_purge_annotator a (purge_map);
3999       char *filename = concat (dump_base_name, ".state-purge.dot", NULL);
4000       supergraph::dump_args_t args ((enum supergraph_dot_flags)0, &a);
4001       sg.dump_dot (filename, args);
4002       free (filename);
4003     }
4004 
4005   auto_delete_vec <state_machine> checkers;
4006   make_checkers (checkers, logger);
4007 
4008   if (logger)
4009     {
4010       int i;
4011       state_machine *sm;
4012       FOR_EACH_VEC_ELT (checkers, i, sm)
4013 	logger->log ("checkers[%i]: %s", i, sm->get_name ());
4014     }
4015 
4016   /* Extrinsic state shared by nodes in the graph.  */
4017   const extrinsic_state ext_state (checkers);
4018 
4019   const analysis_plan plan (sg, logger);
4020 
4021   /* The exploded graph.  */
4022   exploded_graph eg (sg, logger, ext_state, purge_map, plan,
4023 		     analyzer_verbosity);
4024 
4025   /* Add entrypoints to the graph for externally-callable functions.  */
4026   eg.build_initial_worklist ();
4027 
4028   /* Now process the worklist, exploring the <point, state> graph.  */
4029   eg.process_worklist ();
4030 
4031   if (flag_dump_analyzer_exploded_graph)
4032     {
4033       auto_timevar tv (TV_ANALYZER_DUMP);
4034       char *filename
4035 	= concat (dump_base_name, ".eg.dot", NULL);
4036       exploded_graph::dump_args_t args (eg);
4037       root_cluster c;
4038       eg.dump_dot (filename, &c, args);
4039       free (filename);
4040     }
4041 
4042   /* Now emit any saved diagnostics.  */
4043   eg.get_diagnostic_manager ().emit_saved_diagnostics (eg);
4044 
4045   eg.dump_exploded_nodes ();
4046 
4047   eg.log_stats ();
4048 
4049   if (flag_dump_analyzer_callgraph)
4050     dump_callgraph (sg, &eg);
4051 
4052   if (flag_dump_analyzer_supergraph)
4053     {
4054       /* Dump post-analysis form of supergraph.  */
4055       auto_timevar tv (TV_ANALYZER_DUMP);
4056       char *filename = concat (dump_base_name, ".supergraph-eg.dot", NULL);
4057       exploded_graph_annotator a (eg);
4058       supergraph::dump_args_t args ((enum supergraph_dot_flags)0, &a);
4059       sg.dump_dot (filename, args);
4060       free (filename);
4061     }
4062 
4063   delete purge_map;
4064 }
4065 
4066 /* External entrypoint to the analysis "engine".
4067    Set up any dumps, then call impl_run_checkers.  */
4068 
4069 void
run_checkers()4070 run_checkers ()
4071 {
4072   /* Save input_location.  */
4073   location_t saved_input_location = input_location;
4074 
4075   /* Handle -fdump-analyzer and -fdump-analyzer-stderr.  */
4076   FILE *dump_fout = NULL;
4077   /* Track if we're responsible for closing dump_fout.  */
4078   bool owns_dump_fout = false;
4079   if (flag_dump_analyzer_stderr)
4080     dump_fout = stderr;
4081   else if (flag_dump_analyzer)
4082     {
4083       char *dump_filename = concat (dump_base_name, ".analyzer.txt", NULL);
4084       dump_fout = fopen (dump_filename, "w");
4085       free (dump_filename);
4086       if (dump_fout)
4087 	owns_dump_fout = true;
4088     }
4089 
4090   {
4091     log_user the_logger (NULL);
4092     if (dump_fout)
4093       the_logger.set_logger (new logger (dump_fout, 0, 0,
4094 					 *global_dc->printer));
4095     LOG_SCOPE (the_logger.get_logger ());
4096 
4097     impl_run_checkers (the_logger.get_logger ());
4098 
4099     /* end of lifetime of the_logger (so that dump file is closed after the
4100        various dtors run).  */
4101   }
4102 
4103   if (owns_dump_fout)
4104     fclose (dump_fout);
4105 
4106   /* Restore input_location.  Subsequent passes may assume that input_location
4107      is some arbitrary value *not* in the block tree, which might be violated
4108      if we didn't restore it.  */
4109   input_location = saved_input_location;
4110 }
4111 
4112 } // namespace ana
4113 
4114 #endif /* #if ENABLE_ANALYZER */
4115