1 /* Classes for saving, deduplicating, and emitting analyzer diagnostics.
2    Copyright (C) 2019-2021 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 "pretty-print.h"
26 #include "gcc-rich-location.h"
27 #include "gimple-pretty-print.h"
28 #include "function.h"
29 #include "diagnostic-core.h"
30 #include "diagnostic-event-id.h"
31 #include "diagnostic-path.h"
32 #include "alloc-pool.h"
33 #include "fibonacci_heap.h"
34 #include "shortest-paths.h"
35 #include "sbitmap.h"
36 #include "bitmap.h"
37 #include "tristate.h"
38 #include "selftest.h"
39 #include "ordered-hash-map.h"
40 #include "json.h"
41 #include "analyzer/analyzer.h"
42 #include "analyzer/analyzer-logging.h"
43 #include "analyzer/sm.h"
44 #include "analyzer/pending-diagnostic.h"
45 #include "analyzer/diagnostic-manager.h"
46 #include "analyzer/call-string.h"
47 #include "analyzer/program-point.h"
48 #include "analyzer/store.h"
49 #include "analyzer/region-model.h"
50 #include "analyzer/constraint-manager.h"
51 #include "cfg.h"
52 #include "basic-block.h"
53 #include "gimple.h"
54 #include "gimple-iterator.h"
55 #include "cgraph.h"
56 #include "digraph.h"
57 #include "analyzer/supergraph.h"
58 #include "analyzer/program-state.h"
59 #include "analyzer/exploded-graph.h"
60 #include "analyzer/trimmed-graph.h"
61 #include "analyzer/feasible-graph.h"
62 #include "analyzer/checker-path.h"
63 #include "analyzer/reachability.h"
64 
65 #if ENABLE_ANALYZER
66 
67 namespace ana {
68 
69 class feasible_worklist;
70 
71 /* State for finding the shortest feasible exploded_path for a
72    saved_diagnostic.
73    This is shared between all diagnostics, so that we avoid repeating work.  */
74 
75 class epath_finder
76 {
77 public:
epath_finder(const exploded_graph & eg)78   epath_finder (const exploded_graph &eg)
79   : m_eg (eg),
80     m_sep (NULL)
81   {
82     /* This is shared by all diagnostics, but only needed if
83        !flag_analyzer_feasibility.  */
84     if (!flag_analyzer_feasibility)
85       m_sep = new shortest_exploded_paths (eg, eg.get_origin (),
86 					   SPS_FROM_GIVEN_ORIGIN);
87   }
88 
~epath_finder()89   ~epath_finder () { delete m_sep; }
90 
get_logger() const91   logger *get_logger () const { return m_eg.get_logger (); }
92 
93   exploded_path *get_best_epath (const exploded_node *target_enode,
94 				 const char *desc, unsigned diag_idx,
95 				 feasibility_problem **out_problem);
96 
97 private:
98   DISABLE_COPY_AND_ASSIGN(epath_finder);
99 
100   exploded_path *explore_feasible_paths (const exploded_node *target_enode,
101 					 const char *desc, unsigned diag_idx);
102   bool process_worklist_item (feasible_worklist *worklist,
103 			      const trimmed_graph &tg,
104 			      feasible_graph *fg,
105 			      const exploded_node *target_enode,
106 			      unsigned diag_idx,
107 			      exploded_path **out_best_path) const;
108   void dump_trimmed_graph (const exploded_node *target_enode,
109 			   const char *desc, unsigned diag_idx,
110 			   const trimmed_graph &tg,
111 			   const shortest_paths<eg_traits, exploded_path> &sep);
112   void dump_feasible_graph (const exploded_node *target_enode,
113 			    const char *desc, unsigned diag_idx,
114 			    const feasible_graph &fg);
115 
116   const exploded_graph &m_eg;
117   shortest_exploded_paths *m_sep;
118 };
119 
120 /* class epath_finder.  */
121 
122 /* Get the "best" exploded_path for reaching ENODE from the origin,
123    returning ownership of it to the caller.
124 
125    Ideally we want to report the shortest feasible path.
126    Return NULL if we could not find a feasible path
127    (when flag_analyzer_feasibility is true).
128 
129    If flag_analyzer_feasibility is false, then simply return the
130    shortest path.
131 
132    Use DESC and DIAG_IDX when logging.
133 
134    Write any feasibility_problem to *OUT_PROBLEM.  */
135 
136 exploded_path *
get_best_epath(const exploded_node * enode,const char * desc,unsigned diag_idx,feasibility_problem ** out_problem)137 epath_finder::get_best_epath (const exploded_node *enode,
138 			      const char *desc, unsigned diag_idx,
139 			      feasibility_problem **out_problem)
140 {
141   logger *logger = get_logger ();
142   LOG_SCOPE (logger);
143 
144   unsigned snode_idx = enode->get_supernode ()->m_index;
145   if (logger)
146     logger->log ("considering %qs at EN: %i, SN: %i (sd: %i)",
147 		 desc, enode->m_index, snode_idx, diag_idx);
148 
149   /* State-merging means that not every path in the egraph corresponds
150      to a feasible one w.r.t. states.
151 
152      We want to find the shortest feasible path from the origin to ENODE
153      in the egraph.  */
154 
155   if (flag_analyzer_feasibility)
156     {
157       /* Attempt to find the shortest feasible path using feasible_graph.  */
158       if (logger)
159 	logger->log ("trying to find shortest feasible path");
160       if (exploded_path *epath = explore_feasible_paths (enode, desc, diag_idx))
161 	{
162 	  if (logger)
163 	    logger->log ("accepting %qs at EN: %i, SN: %i (sd: %i)"
164 			 " with feasible path (length: %i)",
165 			 desc, enode->m_index, snode_idx, diag_idx,
166 			 epath->length ());
167 	  return epath;
168 	}
169       else
170 	{
171 	  if (logger)
172 	    logger->log ("rejecting %qs at EN: %i, SN: %i (sd: %i)"
173 			 " due to not finding feasible path",
174 			 desc, enode->m_index, snode_idx, diag_idx);
175 	  return NULL;
176 	}
177     }
178   else
179     {
180       /* As a crude approximation to shortest feasible path, simply find
181 	 the shortest path, and note whether it is feasible.
182 	 There could be longer feasible paths within the egraph, so this
183 	 approach would lead to diagnostics being falsely rejected
184 	 (PR analyzer/96374).  */
185       if (logger)
186 	logger->log ("trying to find shortest path ignoring feasibility");
187       gcc_assert (m_sep);
188       exploded_path *epath
189 	= new exploded_path (m_sep->get_shortest_path (enode));
190       if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg))
191 	{
192 	  if (logger)
193 	    logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i)"
194 			 " with feasible path (length: %i)",
195 			 desc, enode->m_index, snode_idx, diag_idx,
196 			 epath->length ());
197 	}
198       else
199 	{
200 	  if (logger)
201 	    logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i) (length: %i)"
202 			 " despite infeasible path (due to %qs)",
203 			 desc, enode->m_index, snode_idx, diag_idx,
204 			 epath->length (),
205 			 "-fno-analyzer-feasibility");
206 	}
207       return epath;
208     }
209 }
210 
211 /* A class for managing the worklist of feasible_nodes in
212    epath_finder::explore_feasible_paths, prioritizing them
213    so that shorter paths appear earlier in the queue.  */
214 
215 class feasible_worklist
216 {
217 public:
feasible_worklist(const shortest_paths<eg_traits,exploded_path> & sep)218   feasible_worklist (const shortest_paths<eg_traits, exploded_path> &sep)
219   : m_queue (key_t (*this, NULL)),
220     m_sep (sep)
221   {
222   }
223 
take_next()224   feasible_node *take_next () { return m_queue.extract_min (); }
225 
add_node(feasible_node * fnode)226   void add_node (feasible_node *fnode)
227   {
228     m_queue.insert (key_t (*this, fnode), fnode);
229   }
230 
231 private:
232   struct key_t
233   {
key_tana::feasible_worklist::key_t234     key_t (const feasible_worklist &w, feasible_node *fnode)
235     : m_worklist (w), m_fnode (fnode)
236     {}
237 
operator <ana::feasible_worklist::key_t238     bool operator< (const key_t &other) const
239     {
240       return cmp (*this, other) < 0;
241     }
242 
operator ==ana::feasible_worklist::key_t243     bool operator== (const key_t &other) const
244     {
245       return cmp (*this, other) == 0;
246     }
247 
operator >ana::feasible_worklist::key_t248     bool operator> (const key_t &other) const
249     {
250       return !(*this == other || *this < other);
251     }
252 
253   private:
cmpana::feasible_worklist::key_t254     static int cmp (const key_t &ka, const key_t &kb)
255     {
256       /* Choose the node for which if the remaining path were feasible,
257 	 it would be the shortest path (summing the length of the
258 	 known-feasible path so far with that of the remaining
259 	 possibly-feasible path).  */
260       int ca = ka.m_worklist.get_estimated_cost (ka.m_fnode);
261       int cb = kb.m_worklist.get_estimated_cost (kb.m_fnode);
262       return ca - cb;
263     }
264 
265     const feasible_worklist &m_worklist;
266     feasible_node *m_fnode;
267   };
268 
269   /* Get the estimated length of a path involving FNODE from
270      the origin to the target enode.
271      Sum the length of the known-feasible path so far with
272      that of the remaining possibly-feasible path.  */
273 
get_estimated_cost(const feasible_node * fnode) const274   int get_estimated_cost (const feasible_node *fnode) const
275   {
276     unsigned length_so_far = fnode->get_path_length ();
277     int shortest_remaining_path
278       = m_sep.get_shortest_distance (fnode->get_inner_node ());
279 
280     gcc_assert (shortest_remaining_path >= 0);
281     /* This should be true since we're only exploring nodes within
282        the trimmed graph (and we anticipate it being much smaller
283        than this, and thus not overflowing the sum).  */
284     gcc_assert (shortest_remaining_path < INT_MAX);
285 
286     return length_so_far + shortest_remaining_path;
287   }
288 
289   /* Priority queue, backed by a fibonacci_heap.  */
290   typedef fibonacci_heap<key_t, feasible_node> queue_t;
291   queue_t m_queue;
292   const shortest_paths<eg_traits, exploded_path> &m_sep;
293 };
294 
295 /* Attempt to find the shortest feasible path from the origin to
296    TARGET_ENODE by iteratively building a feasible_graph, in which
297    every path to a feasible_node is feasible by construction.
298 
299    We effectively explore the tree of feasible paths in order of shortest
300    path until we either find a feasible path to TARGET_ENODE, or hit
301    a limit and give up.
302 
303    Preliminaries:
304    - Find the shortest path from each node to the TARGET_ENODE (without
305    checking feasibility), so that we can prioritize our worklist.
306    - Construct a trimmed_graph: the subset of nodes/edges that
307    are on a path that eventually reaches TARGET_ENODE.  We will only need
308    to consider these when considering the shortest feasible path.
309 
310    Build a feasible_graph, in which every path to a feasible_node
311    is feasible by construction.
312    We use a worklist to flatten the exploration into an iteration.
313    Starting at the origin, find feasible out-edges within the trimmed graph.
314    At each stage, choose the node for which if the remaining path were feasible,
315    it would be the shortest path (summing the length of the known-feasible path
316    so far with that of the remaining possibly-feasible path).
317    This way, the first feasible path we find to TARGET_ENODE is the shortest.
318    We start by trying the shortest possible path, but if that fails,
319    we explore progressively longer paths, eventually trying iterations through
320    loops.  The exploration is captured in the feasible_graph, which can be
321    dumped as a .dot file to visualize the exploration.  The indices of the
322    feasible_nodes show the order in which they were created.
323 
324    This is something of a brute-force approach, but the trimmed_graph
325    hopefully keeps the complexity manageable.
326 
327    Terminate with failure when the number of infeasible edges exceeds
328    a threshold (--param=analyzer-max-infeasible-edges=).
329    This is guaranteed to eventually lead to terminatation, as
330    we can't keep creating feasible nodes without eventually
331    either reaching an infeasible edge, or reaching the
332    TARGET_ENODE.  Specifically, there can't be a cycle of
333    feasible edges that doesn't reach the target_enode without
334    an out-edge that either fails feasibility or gets closer
335    to the TARGET_ENODE: on each iteration we are either:
336    - effectively getting closer to the TARGET_ENODE (which can't
337      continue forever without reaching the target), or
338    - getting monotonically closer to the termination threshold.  */
339 
340 exploded_path *
explore_feasible_paths(const exploded_node * target_enode,const char * desc,unsigned diag_idx)341 epath_finder::explore_feasible_paths (const exploded_node *target_enode,
342 				      const char *desc, unsigned diag_idx)
343 {
344   logger *logger = get_logger ();
345   LOG_SCOPE (logger);
346 
347   /* Determine the shortest path to TARGET_ENODE from each node in
348      the exploded graph.  */
349   shortest_paths<eg_traits, exploded_path> sep
350     (m_eg, target_enode, SPS_TO_GIVEN_TARGET);
351 
352   /* Construct a trimmed_graph: the subset of nodes/edges that
353      are on a path that eventually reaches TARGET_ENODE.
354      We only need to consider these when considering the shortest
355      feasible path.  */
356   trimmed_graph tg (m_eg, target_enode);
357 
358   if (flag_dump_analyzer_feasibility)
359     dump_trimmed_graph (target_enode, desc, diag_idx, tg, sep);
360 
361   feasible_graph fg;
362   feasible_worklist worklist (sep);
363 
364   /* Populate the worklist with the origin node.  */
365   {
366     feasibility_state init_state (m_eg.get_engine ()->get_model_manager (),
367 				  m_eg.get_supergraph ());
368     feasible_node *origin = fg.add_node (m_eg.get_origin (), init_state, 0);
369     worklist.add_node (origin);
370   }
371 
372   /* Iteratively explore the tree of feasible paths in order of shortest
373      path until we either find a feasible path to TARGET_ENODE, or hit
374      a limit.  */
375 
376   /* Set this if we find a feasible path to TARGET_ENODE.  */
377   exploded_path *best_path = NULL;
378 
379   while (process_worklist_item (&worklist, tg, &fg, target_enode, diag_idx,
380 				&best_path))
381     {
382       /* Empty; the work is done within process_worklist_item.  */
383     }
384 
385   if (logger)
386     {
387       logger->log ("tg for sd: %i:", diag_idx);
388       logger->inc_indent ();
389       tg.log_stats (logger);
390       logger->dec_indent ();
391 
392       logger->log ("fg for sd: %i:", diag_idx);
393       logger->inc_indent ();
394       fg.log_stats (logger);
395       logger->dec_indent ();
396     }
397 
398   /* Dump the feasible_graph.  */
399   if (flag_dump_analyzer_feasibility)
400     dump_feasible_graph (target_enode, desc, diag_idx, fg);
401 
402   return best_path;
403 }
404 
405 /* Process the next item in WORKLIST, potentially adding new items
406    based on feasible out-edges, and extending FG accordingly.
407    Use TG to ignore out-edges that don't lead to TARGET_ENODE.
408    Return true if the worklist processing should continue.
409    Return false if the processing of the worklist should stop
410    (either due to reaching TARGET_ENODE, or hitting a limit).
411    Write to *OUT_BEST_PATH if stopping due to finding a feasible path
412    to TARGET_ENODE.  */
413 
414 bool
process_worklist_item(feasible_worklist * worklist,const trimmed_graph & tg,feasible_graph * fg,const exploded_node * target_enode,unsigned diag_idx,exploded_path ** out_best_path) const415 epath_finder::process_worklist_item (feasible_worklist *worklist,
416 				     const trimmed_graph &tg,
417 				     feasible_graph *fg,
418 				     const exploded_node *target_enode,
419 				     unsigned diag_idx,
420 				     exploded_path **out_best_path) const
421 {
422   logger *logger = get_logger ();
423 
424   feasible_node *fnode = worklist->take_next ();
425   if (!fnode)
426     {
427       if (logger)
428 	logger->log ("drained worklist for sd: %i"
429 		     " without finding feasible path",
430 		     diag_idx);
431       return false;
432     }
433 
434   log_scope s (logger, "fg worklist item",
435 	       "considering FN: %i (EN: %i) for sd: %i",
436 	       fnode->get_index (), fnode->get_inner_node ()->m_index,
437 	       diag_idx);
438 
439   /* Iterate through all out-edges from this item.  */
440   unsigned i;
441   exploded_edge *succ_eedge;
442   FOR_EACH_VEC_ELT (fnode->get_inner_node ()->m_succs, i, succ_eedge)
443     {
444       log_scope s (logger, "edge", "considering edge: EN:%i -> EN:%i",
445 		   succ_eedge->m_src->m_index,
446 		   succ_eedge->m_dest->m_index);
447       /* Reject edges that aren't in the trimmed graph.  */
448       if (!tg.contains_p (succ_eedge))
449 	{
450 	  if (logger)
451 	    logger->log ("rejecting: not in trimmed graph");
452 	  continue;
453 	}
454 
455       feasibility_state succ_state (fnode->get_state ());
456       rejected_constraint *rc = NULL;
457       if (succ_state.maybe_update_for_edge (logger, succ_eedge, &rc))
458 	{
459 	  gcc_assert (rc == NULL);
460 	  feasible_node *succ_fnode
461 	    = fg->add_node (succ_eedge->m_dest,
462 			    succ_state,
463 			    fnode->get_path_length () + 1);
464 	  if (logger)
465 	    logger->log ("accepting as FN: %i", succ_fnode->get_index ());
466 	  fg->add_edge (new feasible_edge (fnode, succ_fnode, succ_eedge));
467 
468 	  /* Have we reached TARGET_ENODE?  */
469 	  if (succ_fnode->get_inner_node () == target_enode)
470 	    {
471 	      if (logger)
472 		logger->log ("success: got feasible path to EN: %i (sd: %i)"
473 			     " (length: %i)",
474 			     target_enode->m_index, diag_idx,
475 			     succ_fnode->get_path_length ());
476 	      *out_best_path = fg->make_epath (succ_fnode);
477 	      /* Success: stop the worklist iteration.  */
478 	      return false;
479 	    }
480 	  else
481 	    worklist->add_node (succ_fnode);
482 	}
483       else
484 	{
485 	  if (logger)
486 	    logger->log ("infeasible");
487 	  gcc_assert (rc);
488 	  fg->add_feasibility_problem (fnode,
489 				       succ_eedge,
490 				       *rc);
491 	  delete rc;
492 
493 	  /* Give up if there have been too many infeasible edges.  */
494 	  if (fg->get_num_infeasible ()
495 	      > (unsigned)param_analyzer_max_infeasible_edges)
496 	    {
497 	      if (logger)
498 		logger->log ("too many infeasible edges (%i); giving up",
499 			     fg->get_num_infeasible ());
500 	      return false;
501 	    }
502 	}
503     }
504 
505   /* Continue the worklist iteration.  */
506   return true;
507 }
508 
509 /* Helper class for epath_finder::dump_trimmed_graph
510    to dump extra per-node information.
511    Use SEP to add the length of the shortest path from each
512    node to the target node to each node's dump.  */
513 
514 class dump_eg_with_shortest_path : public eg_traits::dump_args_t
515 {
516 public:
dump_eg_with_shortest_path(const exploded_graph & eg,const shortest_paths<eg_traits,exploded_path> & sep)517   dump_eg_with_shortest_path
518     (const exploded_graph &eg,
519      const shortest_paths<eg_traits, exploded_path> &sep)
520   : dump_args_t (eg),
521     m_sep (sep)
522   {
523   }
524 
dump_extra_info(const exploded_node * enode,pretty_printer * pp) const525   void dump_extra_info (const exploded_node *enode,
526 			pretty_printer *pp) const FINAL OVERRIDE
527   {
528     pp_printf (pp, "sp: %i", m_sep.get_shortest_path (enode).length ());
529     pp_newline (pp);
530   }
531 
532 private:
533   const shortest_paths<eg_traits, exploded_path> &m_sep;
534 };
535 
536 /* Dump TG to "BASE_NAME.DESC.DIAG_IDX.to-enN.tg.dot",
537    annotating each node with the length of the shortest path
538    from that node to TARGET_ENODE (using SEP).  */
539 
540 void
541 epath_finder::
dump_trimmed_graph(const exploded_node * target_enode,const char * desc,unsigned diag_idx,const trimmed_graph & tg,const shortest_paths<eg_traits,exploded_path> & sep)542 dump_trimmed_graph (const exploded_node *target_enode,
543 		    const char *desc, unsigned diag_idx,
544 		    const trimmed_graph &tg,
545 		    const shortest_paths<eg_traits, exploded_path> &sep)
546 {
547   auto_timevar tv (TV_ANALYZER_DUMP);
548   dump_eg_with_shortest_path inner_args (m_eg, sep);
549   trimmed_graph::dump_args_t args (inner_args);
550   pretty_printer pp;
551   pp_printf (&pp, "%s.%s.%i.to-en%i.tg.dot",
552 	     dump_base_name, desc, diag_idx, target_enode->m_index);
553   char *filename = xstrdup (pp_formatted_text (&pp));
554   tg.dump_dot (filename, NULL, args);
555   free (filename);
556 }
557 
558 /* Dump FG to "BASE_NAME.DESC.DIAG_IDX.to-enN.fg.dot".  */
559 
560 void
dump_feasible_graph(const exploded_node * target_enode,const char * desc,unsigned diag_idx,const feasible_graph & fg)561 epath_finder::dump_feasible_graph (const exploded_node *target_enode,
562 				   const char *desc, unsigned diag_idx,
563 				   const feasible_graph &fg)
564 {
565   auto_timevar tv (TV_ANALYZER_DUMP);
566   exploded_graph::dump_args_t inner_args (m_eg);
567   feasible_graph::dump_args_t args (inner_args);
568   pretty_printer pp;
569   pp_printf (&pp, "%s.%s.%i.to-en%i.fg.dot",
570 	     dump_base_name, desc, diag_idx, target_enode->m_index);
571   char *filename = xstrdup (pp_formatted_text (&pp));
572   fg.dump_dot (filename, NULL, args);
573   free (filename);
574 }
575 
576 /* class saved_diagnostic.  */
577 
578 /* saved_diagnostic's ctor.
579    Take ownership of D and STMT_FINDER.  */
580 
saved_diagnostic(const state_machine * sm,const exploded_node * enode,const supernode * snode,const gimple * stmt,stmt_finder * stmt_finder,tree var,const svalue * sval,state_machine::state_t state,pending_diagnostic * d,unsigned idx)581 saved_diagnostic::saved_diagnostic (const state_machine *sm,
582 				    const exploded_node *enode,
583 				    const supernode *snode, const gimple *stmt,
584 				    stmt_finder *stmt_finder,
585 				    tree var,
586 				    const svalue *sval,
587 				    state_machine::state_t state,
588 				    pending_diagnostic *d,
589 				    unsigned idx)
590 : m_sm (sm), m_enode (enode), m_snode (snode), m_stmt (stmt),
591  /* stmt_finder could be on-stack; we want our own copy that can
592     outlive that.  */
593   m_stmt_finder (stmt_finder ? stmt_finder->clone () : NULL),
594   m_var (var), m_sval (sval), m_state (state),
595   m_d (d), m_trailing_eedge (NULL),
596   m_idx (idx),
597   m_best_epath (NULL), m_problem (NULL)
598 {
599   gcc_assert (m_stmt || m_stmt_finder);
600 
601   /* We must have an enode in order to be able to look for paths
602      through the exploded_graph to this diagnostic.  */
603   gcc_assert (m_enode);
604 }
605 
606 /* saved_diagnostic's dtor.  */
607 
~saved_diagnostic()608 saved_diagnostic::~saved_diagnostic ()
609 {
610   delete m_stmt_finder;
611   delete m_d;
612   delete m_best_epath;
613   delete m_problem;
614 }
615 
616 bool
operator ==(const saved_diagnostic & other) const617 saved_diagnostic::operator== (const saved_diagnostic &other) const
618 {
619   return (m_sm == other.m_sm
620 	  /* We don't compare m_enode.  */
621 	  && m_snode == other.m_snode
622 	  && m_stmt == other.m_stmt
623 	  /* We don't compare m_stmt_finder.  */
624 	  && pending_diagnostic::same_tree_p (m_var, other.m_var)
625 	  && m_state == other.m_state
626 	  && m_d->equal_p (*other.m_d)
627 	  && m_trailing_eedge == other.m_trailing_eedge);
628 }
629 
630 /* Return a new json::object of the form
631    {"sm": optional str,
632     "enode": int,
633     "snode": int,
634     "sval": optional str,
635     "state": optional str,
636     "path_length": optional int,
637     "pending_diagnostic": str,
638     "idx": int}.  */
639 
640 json::object *
to_json() const641 saved_diagnostic::to_json () const
642 {
643   json::object *sd_obj = new json::object ();
644 
645   if (m_sm)
646     sd_obj->set ("sm", new json::string (m_sm->get_name ()));
647   sd_obj->set ("enode", new json::integer_number (m_enode->m_index));
648   sd_obj->set ("snode", new json::integer_number (m_snode->m_index));
649   if (m_sval)
650     sd_obj->set ("sval", m_sval->to_json ());
651   if (m_state)
652     sd_obj->set ("state", m_state->to_json ());
653   if (m_best_epath)
654     sd_obj->set ("path_length", new json::integer_number (get_epath_length ()));
655   sd_obj->set ("pending_diagnostic", new json::string (m_d->get_kind ()));
656   sd_obj->set ("idx", new json::integer_number (m_idx));
657 
658   /* We're not yet JSONifying the following fields:
659      const gimple *m_stmt;
660      stmt_finder *m_stmt_finder;
661      tree m_var;
662      exploded_edge *m_trailing_eedge;
663      enum status m_status;
664      feasibility_problem *m_problem;
665   */
666 
667   return sd_obj;
668 }
669 
670 /* Use PF to find the best exploded_path for this saved_diagnostic,
671    and store it in m_best_epath.
672    If m_stmt is still NULL, use m_stmt_finder on the epath to populate
673    m_stmt.
674    Return true if a best path was found.  */
675 
676 bool
calc_best_epath(epath_finder * pf)677 saved_diagnostic::calc_best_epath (epath_finder *pf)
678 {
679   logger *logger = pf->get_logger ();
680   LOG_SCOPE (logger);
681   delete m_best_epath;
682   delete m_problem;
683   m_problem = NULL;
684 
685   m_best_epath = pf->get_best_epath (m_enode, m_d->get_kind (), m_idx,
686 				     &m_problem);
687 
688   /* Handle failure to find a feasible path.  */
689   if (m_best_epath == NULL)
690     return false;
691 
692   gcc_assert (m_best_epath);
693   if (m_stmt == NULL)
694     {
695       gcc_assert (m_stmt_finder);
696       m_stmt = m_stmt_finder->find_stmt (*m_best_epath);
697     }
698   gcc_assert (m_stmt);
699 
700   return true;
701 }
702 
703 unsigned
get_epath_length() const704 saved_diagnostic::get_epath_length () const
705 {
706   gcc_assert (m_best_epath);
707   return m_best_epath->length ();
708 }
709 
710 /* Record that OTHER (and its duplicates) are duplicates
711    of this saved_diagnostic.  */
712 
713 void
add_duplicate(saved_diagnostic * other)714 saved_diagnostic::add_duplicate (saved_diagnostic *other)
715 {
716   gcc_assert (other);
717   m_duplicates.reserve (m_duplicates.length ()
718 			+ other->m_duplicates.length ()
719 			+ 1);
720   m_duplicates.splice (other->m_duplicates);
721   other->m_duplicates.truncate (0);
722   m_duplicates.safe_push (other);
723 }
724 
725 /* State for building a checker_path from a particular exploded_path.
726    In particular, this precomputes reachability information: the set of
727    source enodes for which a path be found to the diagnostic enode.  */
728 
729 class path_builder
730 {
731 public:
path_builder(const exploded_graph & eg,const exploded_path & epath,const feasibility_problem * problem,const saved_diagnostic & sd)732   path_builder (const exploded_graph &eg,
733 		const exploded_path &epath,
734 		const feasibility_problem *problem,
735 		const saved_diagnostic &sd)
736   : m_eg (eg),
737     m_diag_enode (epath.get_final_enode ()),
738     m_sd (sd),
739     m_reachability (eg, m_diag_enode),
740     m_feasibility_problem (problem)
741   {}
742 
get_diag_node() const743   const exploded_node *get_diag_node () const { return m_diag_enode; }
744 
get_pending_diagnostic() const745   pending_diagnostic *get_pending_diagnostic () const
746   {
747     return m_sd.m_d;
748   }
749 
reachable_from_p(const exploded_node * src_enode) const750   bool reachable_from_p (const exploded_node *src_enode) const
751   {
752     return m_reachability.reachable_from_p (src_enode);
753   }
754 
get_ext_state() const755   const extrinsic_state &get_ext_state () const { return m_eg.get_ext_state (); }
756 
get_feasibility_problem() const757   const feasibility_problem *get_feasibility_problem () const
758   {
759     return m_feasibility_problem;
760   }
761 
get_sm() const762   const state_machine *get_sm () const { return m_sd.m_sm; }
763 
764 private:
765   typedef reachability<eg_traits> enode_reachability;
766 
767   const exploded_graph &m_eg;
768 
769   /* The enode where the diagnostic occurs.  */
770   const exploded_node *m_diag_enode;
771 
772   const saved_diagnostic &m_sd;
773 
774   /* Precompute all enodes from which the diagnostic is reachable.  */
775   enode_reachability m_reachability;
776 
777   const feasibility_problem *m_feasibility_problem;
778 };
779 
780 /* class diagnostic_manager.  */
781 
782 /* diagnostic_manager's ctor.  */
783 
diagnostic_manager(logger * logger,engine * eng,int verbosity)784 diagnostic_manager::diagnostic_manager (logger *logger, engine *eng,
785 					int verbosity)
786 : log_user (logger), m_eng (eng), m_verbosity (verbosity)
787 {
788 }
789 
790 /* Queue pending_diagnostic D at ENODE for later emission.  */
791 
792 void
add_diagnostic(const state_machine * sm,exploded_node * enode,const supernode * snode,const gimple * stmt,stmt_finder * finder,tree var,const svalue * sval,state_machine::state_t state,pending_diagnostic * d)793 diagnostic_manager::add_diagnostic (const state_machine *sm,
794 				    exploded_node *enode,
795 				    const supernode *snode, const gimple *stmt,
796 				    stmt_finder *finder,
797 				    tree var,
798 				    const svalue *sval,
799 				    state_machine::state_t state,
800 				    pending_diagnostic *d)
801 {
802   LOG_FUNC (get_logger ());
803 
804   /* We must have an enode in order to be able to look for paths
805      through the exploded_graph to the diagnostic.  */
806   gcc_assert (enode);
807 
808   saved_diagnostic *sd
809     = new saved_diagnostic (sm, enode, snode, stmt, finder, var, sval,
810 			    state, d, m_saved_diagnostics.length ());
811   m_saved_diagnostics.safe_push (sd);
812   enode->add_diagnostic (sd);
813   if (get_logger ())
814     log ("adding saved diagnostic %i at SN %i to EN %i: %qs",
815 	 sd->get_index (),
816 	 snode->m_index, enode->m_index, d->get_kind ());
817 }
818 
819 /* Queue pending_diagnostic D at ENODE for later emission.  */
820 
821 void
add_diagnostic(exploded_node * enode,const supernode * snode,const gimple * stmt,stmt_finder * finder,pending_diagnostic * d)822 diagnostic_manager::add_diagnostic (exploded_node *enode,
823 				    const supernode *snode, const gimple *stmt,
824 				    stmt_finder *finder,
825 				    pending_diagnostic *d)
826 {
827   gcc_assert (enode);
828   add_diagnostic (NULL, enode, snode, stmt, finder, NULL_TREE, NULL, 0, d);
829 }
830 
831 /* Return a new json::object of the form
832    {"diagnostics"  : [obj for saved_diagnostic]}.  */
833 
834 json::object *
to_json() const835 diagnostic_manager::to_json () const
836 {
837   json::object *dm_obj = new json::object ();
838 
839   {
840     json::array *sd_arr = new json::array ();
841     int i;
842     saved_diagnostic *sd;
843     FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
844       sd_arr->append (sd->to_json ());
845     dm_obj->set ("diagnostics", sd_arr);
846   }
847 
848   return dm_obj;
849 }
850 
851 /* A class for identifying sets of duplicated pending_diagnostic.
852 
853    We want to find the simplest saved_diagnostic amongst those that share a
854    dedupe_key.  */
855 
856 class dedupe_key
857 {
858 public:
dedupe_key(const saved_diagnostic & sd)859   dedupe_key (const saved_diagnostic &sd)
860   : m_sd (sd), m_stmt (sd.m_stmt)
861   {
862     gcc_assert (m_stmt);
863   }
864 
hash() const865   hashval_t hash () const
866   {
867     inchash::hash hstate;
868     hstate.add_ptr (m_stmt);
869     // TODO: m_sd
870     return hstate.end ();
871   }
operator ==(const dedupe_key & other) const872   bool operator== (const dedupe_key &other) const
873   {
874     return (m_sd == other.m_sd
875 	    && m_stmt == other.m_stmt);
876   }
877 
get_location() const878   location_t get_location () const
879   {
880     return m_stmt->location;
881   }
882 
883   /* A qsort comparator for use by dedupe_winners::emit_best
884      to sort them into location_t order.  */
885 
886   static int
comparator(const void * p1,const void * p2)887   comparator (const void *p1, const void *p2)
888   {
889     const dedupe_key *pk1 = *(const dedupe_key * const *)p1;
890     const dedupe_key *pk2 = *(const dedupe_key * const *)p2;
891 
892     location_t loc1 = pk1->get_location ();
893     location_t loc2 = pk2->get_location ();
894 
895     if (int cmp = linemap_compare_locations (line_table, loc2, loc1))
896       return cmp;
897     if (int cmp = ((int)pk1->m_sd.get_epath_length ()
898 		   - (int)pk2->m_sd.get_epath_length ()))
899       return cmp;
900     if (int cmp = strcmp (pk1->m_sd.m_d->get_kind (),
901 			  pk2->m_sd.m_d->get_kind ()))
902       return cmp;
903     return 0;
904   }
905 
906   const saved_diagnostic &m_sd;
907   const gimple *m_stmt;
908 };
909 
910 /* Traits for use by dedupe_winners.  */
911 
912 class dedupe_hash_map_traits
913 {
914 public:
915   typedef const dedupe_key *key_type;
916   typedef saved_diagnostic *value_type;
917   typedef saved_diagnostic *compare_type;
918 
hash(const key_type & v)919   static inline hashval_t hash (const key_type &v)
920   {
921     return v->hash ();
922   }
equal_keys(const key_type & k1,const key_type & k2)923   static inline bool equal_keys (const key_type &k1, const key_type &k2)
924   {
925     return *k1 == *k2;
926   }
927   template <typename T>
remove(T &)928   static inline void remove (T &)
929   {
930     // TODO
931   }
932   template <typename T>
mark_deleted(T & entry)933   static inline void mark_deleted (T &entry)
934   {
935     entry.m_key = reinterpret_cast<key_type> (1);
936   }
937   template <typename T>
mark_empty(T & entry)938   static inline void mark_empty (T &entry)
939   {
940     entry.m_key = NULL;
941   }
942   template <typename T>
is_deleted(const T & entry)943   static inline bool is_deleted (const T &entry)
944   {
945     return entry.m_key == reinterpret_cast<key_type> (1);
946   }
947   template <typename T>
is_empty(const T & entry)948   static inline bool is_empty (const T &entry)
949   {
950     return entry.m_key == NULL;
951   }
952   static const bool empty_zero_p = true;
953 };
954 
955 /* A class for deduplicating diagnostics and finding (and emitting) the
956    best saved_diagnostic within each partition.  */
957 
958 class dedupe_winners
959 {
960 public:
~dedupe_winners()961   ~dedupe_winners ()
962   {
963     /* Delete all keys, but not the saved_diagnostics.  */
964     for (map_t::iterator iter = m_map.begin ();
965 	 iter != m_map.end ();
966 	 ++iter)
967       delete (*iter).first;
968   }
969 
970   /* Determine an exploded_path for SD using PF and, if it's feasible,
971      determine if SD is the best seen so far for its dedupe_key.
972      Record the winning SD for each dedupe_key.  */
973 
add(logger * logger,epath_finder * pf,saved_diagnostic * sd)974   void add (logger *logger,
975 	    epath_finder *pf,
976 	    saved_diagnostic *sd)
977   {
978     /* Determine best epath for SD.  */
979     if (!sd->calc_best_epath (pf))
980       return;
981 
982     dedupe_key *key = new dedupe_key (*sd);
983     if (saved_diagnostic **slot = m_map.get (key))
984       {
985 	if (logger)
986 	  logger->log ("already have this dedupe_key");
987 
988 	saved_diagnostic *cur_best_sd = *slot;
989 
990 	if (sd->get_epath_length () < cur_best_sd->get_epath_length ())
991 	  {
992 	    /* We've got a shorter path for the key; replace
993 	       the current candidate, marking it as a duplicate of SD.  */
994 	    if (logger)
995 	      logger->log ("length %i is better than existing length %i;"
996 			   " taking over this dedupe_key",
997 			   sd->get_epath_length (),
998 			   cur_best_sd->get_epath_length ());
999 	    sd->add_duplicate (cur_best_sd);
1000 	    *slot = sd;
1001 	  }
1002 	else
1003 	  /* We haven't beaten the current best candidate; add SD
1004 	     as a duplicate of it.  */
1005 	  {
1006 	    if (logger)
1007 	      logger->log ("length %i isn't better than existing length %i;"
1008 			   " dropping this candidate",
1009 			   sd->get_epath_length (),
1010 			   cur_best_sd->get_epath_length ());
1011 	    cur_best_sd->add_duplicate (sd);
1012 	  }
1013 	delete key;
1014       }
1015     else
1016       {
1017 	/* This is the first candidate for this key.  */
1018 	m_map.put (key, sd);
1019 	if (logger)
1020 	  logger->log ("first candidate for this dedupe_key");
1021       }
1022   }
1023 
1024  /* Emit the simplest diagnostic within each set.  */
1025 
emit_best(diagnostic_manager * dm,const exploded_graph & eg)1026   void emit_best (diagnostic_manager *dm,
1027 		  const exploded_graph &eg)
1028   {
1029     LOG_SCOPE (dm->get_logger ());
1030 
1031     /* Get keys into a vec for sorting.  */
1032     auto_vec<const dedupe_key *> keys (m_map.elements ());
1033     for (map_t::iterator iter = m_map.begin ();
1034 	 iter != m_map.end ();
1035 	 ++iter)
1036       keys.quick_push ((*iter).first);
1037 
1038     dm->log ("# keys after de-duplication: %i", keys.length ());
1039 
1040     /* Sort into a good emission order.  */
1041     keys.qsort (dedupe_key::comparator);
1042 
1043     /* Emit the best saved_diagnostics for each key.  */
1044     int i;
1045     const dedupe_key *key;
1046     FOR_EACH_VEC_ELT (keys, i, key)
1047       {
1048 	saved_diagnostic **slot = m_map.get (key);
1049 	gcc_assert (*slot);
1050 	const saved_diagnostic *sd = *slot;
1051 	dm->emit_saved_diagnostic (eg, *sd);
1052       }
1053   }
1054 
1055 private:
1056   /* This maps from each dedupe_key to a current best saved_diagnostic.  */
1057 
1058   typedef hash_map<const dedupe_key *, saved_diagnostic *,
1059 		   dedupe_hash_map_traits> map_t;
1060   map_t m_map;
1061 };
1062 
1063 /* Emit all saved diagnostics.  */
1064 
1065 void
emit_saved_diagnostics(const exploded_graph & eg)1066 diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
1067 {
1068   LOG_SCOPE (get_logger ());
1069   auto_timevar tv (TV_ANALYZER_DIAGNOSTICS);
1070   log ("# saved diagnostics: %i", m_saved_diagnostics.length ());
1071   if (get_logger ())
1072     {
1073       unsigned i;
1074       saved_diagnostic *sd;
1075       FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1076 	log ("[%i] sd: %qs at EN: %i, SN: %i",
1077 	     i, sd->m_d->get_kind (), sd->m_enode->m_index,
1078 	     sd->m_snode->m_index);
1079     }
1080 
1081   if (m_saved_diagnostics.length () == 0)
1082     return;
1083 
1084   /* Compute the shortest_paths once, sharing it between all diagnostics.  */
1085   epath_finder pf (eg);
1086 
1087   /* Iterate through all saved diagnostics, adding them to a dedupe_winners
1088      instance.  This partitions the saved diagnostics by dedupe_key,
1089      generating exploded_paths for them, and retaining the best one in each
1090      partition.  */
1091   dedupe_winners best_candidates;
1092 
1093   int i;
1094   saved_diagnostic *sd;
1095   FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1096     best_candidates.add (get_logger (), &pf, sd);
1097 
1098   /* For each dedupe-key, call emit_saved_diagnostic on the "best"
1099      saved_diagnostic.  */
1100   best_candidates.emit_best (this, eg);
1101 }
1102 
1103 /* Given a saved_diagnostic SD with m_best_epath through EG,
1104    create an checker_path of suitable events and use it to call
1105    SD's underlying pending_diagnostic "emit" vfunc to emit a diagnostic.  */
1106 
1107 void
emit_saved_diagnostic(const exploded_graph & eg,const saved_diagnostic & sd)1108 diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
1109 					   const saved_diagnostic &sd)
1110 {
1111   LOG_SCOPE (get_logger ());
1112   log ("sd: %qs at SN: %i", sd.m_d->get_kind (), sd.m_snode->m_index);
1113   log ("num dupes: %i", sd.get_num_dupes ());
1114 
1115   pretty_printer *pp = global_dc->printer->clone ();
1116 
1117   const exploded_path *epath = sd.get_best_epath ();
1118   gcc_assert (epath);
1119 
1120   /* Precompute all enodes from which the diagnostic is reachable.  */
1121   path_builder pb (eg, *epath, sd.get_feasibility_problem (), sd);
1122 
1123   /* This is the diagnostic_path subclass that will be built for
1124      the diagnostic.  */
1125   checker_path emission_path;
1126 
1127   /* Populate emission_path with a full description of EPATH.  */
1128   build_emission_path (pb, *epath, &emission_path);
1129 
1130   /* Now prune it to just cover the most pertinent events.  */
1131   prune_path (&emission_path, sd.m_sm, sd.m_sval, sd.m_state);
1132 
1133   /* Add a final event to the path, covering the diagnostic itself.
1134      We use the final enode from the epath, which might be different from
1135      the sd.m_enode, as the dedupe code doesn't care about enodes, just
1136      snodes.  */
1137   emission_path.add_final_event (sd.m_sm, epath->get_final_enode (), sd.m_stmt,
1138 				 sd.m_var, sd.m_state);
1139 
1140   /* The "final" event might not be final; if the saved_diagnostic has a
1141      trailing eedge stashed, add any events for it.  This is for use
1142      in handling longjmp, to show where a longjmp is rewinding to.  */
1143   if (sd.m_trailing_eedge)
1144     add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path);
1145 
1146   emission_path.prepare_for_emission (sd.m_d);
1147 
1148   location_t loc = get_stmt_location (sd.m_stmt, sd.m_snode->m_fun);
1149 
1150   /* Allow the pending_diagnostic to fix up the primary location
1151      and any locations for events.  */
1152   loc = sd.m_d->fixup_location (loc);
1153   emission_path.fixup_locations (sd.m_d);
1154 
1155   gcc_rich_location rich_loc (loc);
1156   rich_loc.set_path (&emission_path);
1157 
1158   auto_diagnostic_group d;
1159   auto_cfun sentinel (sd.m_snode->m_fun);
1160   if (sd.m_d->emit (&rich_loc))
1161     {
1162       unsigned num_dupes = sd.get_num_dupes ();
1163       if (flag_analyzer_show_duplicate_count && num_dupes > 0)
1164 	inform_n (loc, num_dupes,
1165 		  "%i duplicate", "%i duplicates",
1166 		  num_dupes);
1167     }
1168   delete pp;
1169 }
1170 
1171 /* Emit a "path" of events to EMISSION_PATH describing the exploded path
1172    EPATH within EG.  */
1173 
1174 void
build_emission_path(const path_builder & pb,const exploded_path & epath,checker_path * emission_path) const1175 diagnostic_manager::build_emission_path (const path_builder &pb,
1176 					 const exploded_path &epath,
1177 					 checker_path *emission_path) const
1178 {
1179   LOG_SCOPE (get_logger ());
1180   for (unsigned i = 0; i < epath.m_edges.length (); i++)
1181     {
1182       const exploded_edge *eedge = epath.m_edges[i];
1183       add_events_for_eedge (pb, *eedge, emission_path);
1184     }
1185 }
1186 
1187 /* Subclass of state_change_visitor that creates state_change_event
1188    instances.  */
1189 
1190 class state_change_event_creator : public state_change_visitor
1191 {
1192 public:
state_change_event_creator(const path_builder & pb,const exploded_edge & eedge,checker_path * emission_path)1193   state_change_event_creator (const path_builder &pb,
1194 			      const exploded_edge &eedge,
1195 			      checker_path *emission_path)
1196     : m_pb (pb),
1197       m_eedge (eedge),
1198       m_emission_path (emission_path)
1199   {}
1200 
on_global_state_change(const state_machine & sm,state_machine::state_t src_sm_val,state_machine::state_t dst_sm_val)1201   bool on_global_state_change (const state_machine &sm,
1202 			       state_machine::state_t src_sm_val,
1203 			       state_machine::state_t dst_sm_val)
1204     FINAL OVERRIDE
1205   {
1206     if (&sm != m_pb.get_sm ())
1207       return false;
1208     const exploded_node *src_node = m_eedge.m_src;
1209     const program_point &src_point = src_node->get_point ();
1210     const int src_stack_depth = src_point.get_stack_depth ();
1211     const exploded_node *dst_node = m_eedge.m_dest;
1212     const gimple *stmt = src_point.get_stmt ();
1213     const supernode *supernode = src_point.get_supernode ();
1214     const program_state &dst_state = dst_node->get_state ();
1215 
1216     int stack_depth = src_stack_depth;
1217 
1218     m_emission_path->add_event (new state_change_event (supernode,
1219 							stmt,
1220 							stack_depth,
1221 							sm,
1222 							NULL,
1223 							src_sm_val,
1224 							dst_sm_val,
1225 							NULL,
1226 							dst_state));
1227     return false;
1228   }
1229 
on_state_change(const state_machine & sm,state_machine::state_t src_sm_val,state_machine::state_t dst_sm_val,const svalue * sval,const svalue * dst_origin_sval)1230   bool on_state_change (const state_machine &sm,
1231 			state_machine::state_t src_sm_val,
1232 			state_machine::state_t dst_sm_val,
1233 			const svalue *sval,
1234 			const svalue *dst_origin_sval) FINAL OVERRIDE
1235   {
1236     if (&sm != m_pb.get_sm ())
1237       return false;
1238     const exploded_node *src_node = m_eedge.m_src;
1239     const program_point &src_point = src_node->get_point ();
1240     const int src_stack_depth = src_point.get_stack_depth ();
1241     const exploded_node *dst_node = m_eedge.m_dest;
1242     const gimple *stmt = src_point.get_stmt ();
1243     const supernode *supernode = src_point.get_supernode ();
1244     const program_state &dst_state = dst_node->get_state ();
1245 
1246     int stack_depth = src_stack_depth;
1247 
1248     if (m_eedge.m_sedge
1249 	&& m_eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE)
1250       {
1251 	supernode = src_point.get_supernode ();
1252 	stmt = supernode->get_last_stmt ();
1253 	stack_depth = src_stack_depth;
1254       }
1255 
1256     /* Bulletproofing for state changes at calls/returns;
1257        TODO: is there a better way? */
1258     if (!stmt)
1259       return false;
1260 
1261     m_emission_path->add_event (new state_change_event (supernode,
1262 							stmt,
1263 							stack_depth,
1264 							sm,
1265 							sval,
1266 							src_sm_val,
1267 							dst_sm_val,
1268 							dst_origin_sval,
1269 							dst_state));
1270     return false;
1271   }
1272 
1273   const path_builder &m_pb;
1274   const exploded_edge &m_eedge;
1275   checker_path *m_emission_path;
1276 };
1277 
1278 /* Compare SRC_STATE and DST_STATE (which use EXT_STATE), and call
1279    VISITOR's on_state_change for every sm-state change that occurs
1280    to a tree, and on_global_state_change for every global state change
1281    that occurs.
1282 
1283    This determines the state changes that ought to be reported to
1284    the user: a combination of the effects of changes to sm_state_map
1285    (which maps svalues to sm-states), and of region_model changes
1286    (which map trees to svalues).
1287 
1288    Bail out early and return true if any call to on_global_state_change
1289    or on_state_change returns true, otherwise return false.
1290 
1291    This is split out to make it easier to experiment with changes to
1292    exploded_node granularity (so that we can observe what state changes
1293    lead to state_change_events being emitted).  */
1294 
1295 bool
for_each_state_change(const program_state & src_state,const program_state & dst_state,const extrinsic_state & ext_state,state_change_visitor * visitor)1296 for_each_state_change (const program_state &src_state,
1297 		       const program_state &dst_state,
1298 		       const extrinsic_state &ext_state,
1299 		       state_change_visitor *visitor)
1300 {
1301   gcc_assert (src_state.m_checker_states.length ()
1302 	      == ext_state.get_num_checkers ());
1303   gcc_assert (dst_state.m_checker_states.length ()
1304 	      == ext_state.get_num_checkers ());
1305   for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
1306     {
1307       const state_machine &sm = ext_state.get_sm (i);
1308       const sm_state_map &src_smap = *src_state.m_checker_states[i];
1309       const sm_state_map &dst_smap = *dst_state.m_checker_states[i];
1310 
1311       /* Add events for any global state changes.  */
1312       if (src_smap.get_global_state () != dst_smap.get_global_state ())
1313 	if (visitor->on_global_state_change (sm,
1314 					     src_smap.get_global_state (),
1315 					     dst_smap.get_global_state ()))
1316 	  return true;
1317 
1318       /* Add events for per-svalue state changes.  */
1319       for (sm_state_map::iterator_t iter = dst_smap.begin ();
1320 	   iter != dst_smap.end ();
1321 	   ++iter)
1322 	{
1323 	  const svalue *sval = (*iter).first;
1324 	  state_machine::state_t dst_sm_val = (*iter).second.m_state;
1325 	  state_machine::state_t src_sm_val
1326 	    = src_smap.get_state (sval, ext_state);
1327 	  if (dst_sm_val != src_sm_val)
1328 	    {
1329 	      const svalue *origin_sval = (*iter).second.m_origin;
1330 	      if (visitor->on_state_change (sm, src_sm_val, dst_sm_val,
1331 					    sval, origin_sval))
1332 		return true;
1333 	    }
1334 	}
1335     }
1336   return false;
1337 }
1338 
1339 /* An sm_context for adding state_change_event on assignments to NULL,
1340    where the default state isn't m_start.  Storing such state in the
1341    sm_state_map would lead to bloat of the exploded_graph, so we want
1342    to leave it as a default state, and inject state change events here
1343    when we have a diagnostic.
1344    Find transitions of constants, for handling on_zero_assignment.  */
1345 
1346 struct null_assignment_sm_context : public sm_context
1347 {
null_assignment_sm_contextana::null_assignment_sm_context1348   null_assignment_sm_context (int sm_idx,
1349 			      const state_machine &sm,
1350 			      const program_state *old_state,
1351 			      const program_state *new_state,
1352 			      const gimple *stmt,
1353 			      const program_point *point,
1354 			      checker_path *emission_path,
1355 			      const extrinsic_state &ext_state)
1356   : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state),
1357     m_stmt (stmt), m_point (point), m_emission_path (emission_path),
1358     m_ext_state (ext_state)
1359   {
1360   }
1361 
get_fndecl_for_callana::null_assignment_sm_context1362   tree get_fndecl_for_call (const gcall */*call*/) FINAL OVERRIDE
1363   {
1364     return NULL_TREE;
1365   }
1366 
get_stateana::null_assignment_sm_context1367   state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
1368 				    tree var) FINAL OVERRIDE
1369   {
1370     const svalue *var_old_sval
1371       = m_old_state->m_region_model->get_rvalue (var, NULL);
1372     const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
1373 
1374     state_machine::state_t current
1375       = old_smap->get_state (var_old_sval, m_ext_state);
1376 
1377     return current;
1378   }
1379 
set_next_stateana::null_assignment_sm_context1380   void set_next_state (const gimple *stmt,
1381 		       tree var,
1382 		       state_machine::state_t to,
1383 		       tree origin ATTRIBUTE_UNUSED) FINAL OVERRIDE
1384   {
1385     state_machine::state_t from = get_state (stmt, var);
1386     if (from != m_sm.get_start_state ())
1387       return;
1388 
1389     const svalue *var_new_sval
1390       = m_new_state->m_region_model->get_rvalue (var, NULL);
1391     const supernode *supernode = m_point->get_supernode ();
1392     int stack_depth = m_point->get_stack_depth ();
1393 
1394     m_emission_path->add_event (new state_change_event (supernode,
1395 							m_stmt,
1396 							stack_depth,
1397 							m_sm,
1398 							var_new_sval,
1399 							from, to,
1400 							NULL,
1401 							*m_new_state));
1402   }
1403 
warnana::null_assignment_sm_context1404   void warn (const supernode *, const gimple *,
1405 	     tree, pending_diagnostic *d) FINAL OVERRIDE
1406   {
1407     delete d;
1408   }
1409 
get_diagnostic_treeana::null_assignment_sm_context1410   tree get_diagnostic_tree (tree expr) FINAL OVERRIDE
1411   {
1412     return expr;
1413   }
1414 
get_global_stateana::null_assignment_sm_context1415   state_machine::state_t get_global_state () const FINAL OVERRIDE
1416   {
1417     return 0;
1418   }
1419 
set_global_stateana::null_assignment_sm_context1420   void set_global_state (state_machine::state_t) FINAL OVERRIDE
1421   {
1422     /* No-op.  */
1423   }
1424 
on_custom_transitionana::null_assignment_sm_context1425   void on_custom_transition (custom_transition *) FINAL OVERRIDE
1426   {
1427   }
1428 
is_zero_assignmentana::null_assignment_sm_context1429   tree is_zero_assignment (const gimple *stmt) FINAL OVERRIDE
1430   {
1431     const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
1432     if (!assign_stmt)
1433      return NULL_TREE;
1434     if (const svalue *sval
1435 	= m_new_state->m_region_model->get_gassign_result (assign_stmt, NULL))
1436       if (tree cst = sval->maybe_get_constant ())
1437 	if (::zerop(cst))
1438 	  return gimple_assign_lhs (assign_stmt);
1439     return NULL_TREE;
1440   }
1441 
1442   const program_state *m_old_state;
1443   const program_state *m_new_state;
1444   const gimple *m_stmt;
1445   const program_point *m_point;
1446   checker_path *m_emission_path;
1447   const extrinsic_state &m_ext_state;
1448 };
1449 
1450 /* Subroutine of diagnostic_manager::build_emission_path.
1451    Add any events for EEDGE to EMISSION_PATH.  */
1452 
1453 void
add_events_for_eedge(const path_builder & pb,const exploded_edge & eedge,checker_path * emission_path) const1454 diagnostic_manager::add_events_for_eedge (const path_builder &pb,
1455 					  const exploded_edge &eedge,
1456 					  checker_path *emission_path) const
1457 {
1458   const exploded_node *src_node = eedge.m_src;
1459   const program_point &src_point = src_node->get_point ();
1460   const exploded_node *dst_node = eedge.m_dest;
1461   const program_point &dst_point = dst_node->get_point ();
1462   const int dst_stack_depth = dst_point.get_stack_depth ();
1463   if (get_logger ())
1464     {
1465       get_logger ()->start_log_line ();
1466       pretty_printer *pp = get_logger ()->get_printer ();
1467       pp_printf (pp, "EN %i -> EN %i: ",
1468 		 eedge.m_src->m_index,
1469 		 eedge.m_dest->m_index);
1470       src_point.print (pp, format (false));
1471       pp_string (pp, "-> ");
1472       dst_point.print (pp, format (false));
1473       get_logger ()->end_log_line ();
1474     }
1475   const program_state &src_state = src_node->get_state ();
1476   const program_state &dst_state = dst_node->get_state ();
1477 
1478   /* Add state change events for the states that have changed.
1479      We add these before events for superedges, so that if we have a
1480      state_change_event due to following an edge, we'll get this sequence
1481      of events:
1482 
1483       | if (!ptr)
1484       |    ~
1485       |    |
1486       |    (1) assuming 'ptr' is non-NULL  (state_change_event)
1487       |    (2) following 'false' branch... (start_cfg_edge_event)
1488      ...
1489       | do_something (ptr);
1490       | ~~~~~~~~~~~~~^~~~~
1491       |              |
1492       |              (3) ...to here        (end_cfg_edge_event).  */
1493   state_change_event_creator visitor (pb, eedge, emission_path);
1494   for_each_state_change (src_state, dst_state, pb.get_ext_state (),
1495 			 &visitor);
1496 
1497   /* Allow non-standard edges to add events, e.g. when rewinding from
1498      longjmp to a setjmp.  */
1499   if (eedge.m_custom_info)
1500     eedge.m_custom_info->add_events_to_path (emission_path, eedge);
1501 
1502   /* Add events for superedges, function entries, and for statements.  */
1503   switch (dst_point.get_kind ())
1504     {
1505     default:
1506       break;
1507     case PK_BEFORE_SUPERNODE:
1508       if (src_point.get_kind () == PK_AFTER_SUPERNODE)
1509 	{
1510 	  if (eedge.m_sedge)
1511 	    add_events_for_superedge (pb, eedge, emission_path);
1512 	}
1513       /* Add function entry events.  */
1514       if (dst_point.get_supernode ()->entry_p ())
1515 	{
1516 	  emission_path->add_event
1517 	    (new function_entry_event
1518 	     (dst_point.get_supernode ()->get_start_location (),
1519 	      dst_point.get_fndecl (),
1520 	      dst_stack_depth));
1521 	}
1522       break;
1523     case PK_BEFORE_STMT:
1524       {
1525 	const gimple *stmt = dst_point.get_stmt ();
1526 	const gcall *call = dyn_cast <const gcall *> (stmt);
1527 	if (call && is_setjmp_call_p (call))
1528 	  emission_path->add_event
1529 	    (new setjmp_event (stmt->location,
1530 			       dst_node,
1531 			       dst_point.get_fndecl (),
1532 			       dst_stack_depth,
1533 			       call));
1534 	else
1535 	  emission_path->add_event
1536 	    (new statement_event (stmt,
1537 				  dst_point.get_fndecl (),
1538 				  dst_stack_depth, dst_state));
1539 
1540 	/* Create state change events for assignment to NULL.
1541 	   Iterate through the stmts in dst_enode, adding state change
1542 	   events for them.  */
1543 	if (dst_state.m_region_model)
1544 	  {
1545 	    program_state iter_state (dst_state);
1546 	    program_point iter_point (dst_point);
1547 	    while (1)
1548 	      {
1549 		const gimple *stmt = iter_point.get_stmt ();
1550 		if (const gassign *assign = dyn_cast<const gassign *> (stmt))
1551 		  {
1552 		    const extrinsic_state &ext_state = pb.get_ext_state ();
1553 		    program_state old_state (iter_state);
1554 		    iter_state.m_region_model->on_assignment (assign, NULL);
1555 		    for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
1556 		      {
1557 			const state_machine &sm = ext_state.get_sm (i);
1558 			null_assignment_sm_context sm_ctxt (i, sm,
1559 							    &old_state,
1560 							    &iter_state,
1561 							    stmt,
1562 							    &iter_point,
1563 							    emission_path,
1564 							    pb.get_ext_state ());
1565 			sm.on_stmt (&sm_ctxt, dst_point.get_supernode (), stmt);
1566 			// TODO: what about phi nodes?
1567 		      }
1568 		  }
1569 		iter_point.next_stmt ();
1570 		if (iter_point.get_kind () == PK_AFTER_SUPERNODE
1571 		    || (dst_node->m_succs.length () > 1
1572 			&& (iter_point
1573 			    == dst_node->m_succs[0]->m_dest->get_point ())))
1574 		  break;
1575 	      }
1576 	  }
1577       }
1578       break;
1579     }
1580 
1581   if (pb.get_feasibility_problem ()
1582       && &pb.get_feasibility_problem ()->m_eedge == &eedge)
1583     {
1584       pretty_printer pp;
1585       pp_format_decoder (&pp) = default_tree_printer;
1586       pp_string (&pp,
1587 		 "this path would have been rejected as infeasible"
1588 		 " at this edge: ");
1589       pb.get_feasibility_problem ()->dump_to_pp (&pp);
1590       emission_path->add_event (new custom_event
1591 				(dst_point.get_location (),
1592 				 dst_point.get_fndecl (),
1593 				 dst_stack_depth,
1594 				 pp_formatted_text (&pp)));
1595     }
1596 }
1597 
1598 /* Return true if EEDGE is a significant edge in the path to the diagnostic
1599    for PB.
1600 
1601    Consider all of the sibling out-eedges from the same source enode
1602    as EEDGE.
1603    If there's no path from the destinations of those eedges to the
1604    diagnostic enode, then we have to take this eedge and thus it's
1605    significant.
1606 
1607    Conversely if there is a path from the destination of any other sibling
1608    eedge to the diagnostic enode, then this edge is insignificant.
1609 
1610    Example 1: redundant if-else:
1611 
1612      (A) if (...)            A
1613      (B)   ...              / \
1614          else              B   C
1615      (C)   ...              \ /
1616      (D) [DIAGNOSTIC]        D
1617 
1618      D is reachable by either B or C, so neither of these edges
1619      are significant.
1620 
1621    Example 2: pertinent if-else:
1622 
1623      (A) if (...)                         A
1624      (B)   ...                           / \
1625          else                           B   C
1626      (C)   [NECESSARY CONDITION]        |   |
1627      (D) [POSSIBLE DIAGNOSTIC]          D1  D2
1628 
1629      D becomes D1 and D2 in the exploded graph, where the diagnostic occurs
1630      at D2.  D2 is only reachable via C, so the A -> C edge is significant.
1631 
1632    Example 3: redundant loop:
1633 
1634      (A) while (...)          +-->A
1635      (B)   ...                |  / \
1636      (C) ...                  +-B  C
1637      (D) [DIAGNOSTIC]              |
1638                                    D
1639 
1640      D is reachable from both B and C, so the A->C edge is not significant.  */
1641 
1642 bool
significant_edge_p(const path_builder & pb,const exploded_edge & eedge) const1643 diagnostic_manager::significant_edge_p (const path_builder &pb,
1644 					const exploded_edge &eedge) const
1645 {
1646   int i;
1647   exploded_edge *sibling;
1648   FOR_EACH_VEC_ELT (eedge.m_src->m_succs, i, sibling)
1649     {
1650       if (sibling == &eedge)
1651 	continue;
1652       if (pb.reachable_from_p (sibling->m_dest))
1653 	{
1654 	  if (get_logger ())
1655 	    get_logger ()->log ("  edge EN: %i -> EN: %i is insignificant as"
1656 				" EN: %i is also reachable via"
1657 				" EN: %i -> EN: %i",
1658 				eedge.m_src->m_index, eedge.m_dest->m_index,
1659 				pb.get_diag_node ()->m_index,
1660 				sibling->m_src->m_index,
1661 				sibling->m_dest->m_index);
1662 	  return false;
1663 	}
1664     }
1665 
1666   return true;
1667 }
1668 
1669 /* Subroutine of diagnostic_manager::add_events_for_eedge
1670    where EEDGE has an underlying superedge i.e. a CFG edge,
1671    or an interprocedural call/return.
1672    Add any events for the superedge to EMISSION_PATH.  */
1673 
1674 void
add_events_for_superedge(const path_builder & pb,const exploded_edge & eedge,checker_path * emission_path) const1675 diagnostic_manager::add_events_for_superedge (const path_builder &pb,
1676 					      const exploded_edge &eedge,
1677 					      checker_path *emission_path)
1678   const
1679 {
1680   gcc_assert (eedge.m_sedge);
1681 
1682   /* Give diagnostics an opportunity to override this function.  */
1683   pending_diagnostic *pd = pb.get_pending_diagnostic ();
1684   if (pd->maybe_add_custom_events_for_superedge (eedge, emission_path))
1685     return;
1686 
1687   /* Don't add events for insignificant edges at verbosity levels below 3.  */
1688   if (m_verbosity < 3)
1689     if (!significant_edge_p (pb, eedge))
1690       return;
1691 
1692   const exploded_node *src_node = eedge.m_src;
1693   const program_point &src_point = src_node->get_point ();
1694   const exploded_node *dst_node = eedge.m_dest;
1695   const program_point &dst_point = dst_node->get_point ();
1696   const int src_stack_depth = src_point.get_stack_depth ();
1697   const int dst_stack_depth = dst_point.get_stack_depth ();
1698   const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
1699 
1700   switch (eedge.m_sedge->m_kind)
1701     {
1702     case SUPEREDGE_CFG_EDGE:
1703       {
1704 	emission_path->add_event
1705 	  (new start_cfg_edge_event (eedge,
1706 			       (last_stmt
1707 				? last_stmt->location
1708 				: UNKNOWN_LOCATION),
1709 			       src_point.get_fndecl (),
1710 			       src_stack_depth));
1711 	emission_path->add_event
1712 	  (new end_cfg_edge_event (eedge,
1713 				   dst_point.get_supernode ()->get_start_location (),
1714 				   dst_point.get_fndecl (),
1715 				   dst_stack_depth));
1716       }
1717       break;
1718 
1719     case SUPEREDGE_CALL:
1720       {
1721 	emission_path->add_event
1722 	  (new call_event (eedge,
1723 			   (last_stmt
1724 			    ? last_stmt->location
1725 			    : UNKNOWN_LOCATION),
1726 			   src_point.get_fndecl (),
1727 			   src_stack_depth));
1728       }
1729       break;
1730 
1731     case SUPEREDGE_INTRAPROCEDURAL_CALL:
1732       {
1733 	/* TODO: add a subclass for this, or generate events for the
1734 	   summary.  */
1735 	emission_path->add_event
1736 	  (new debug_event ((last_stmt
1737 			     ? last_stmt->location
1738 			     : UNKNOWN_LOCATION),
1739 			    src_point.get_fndecl (),
1740 			    src_stack_depth,
1741 			    "call summary"));
1742       }
1743       break;
1744 
1745     case SUPEREDGE_RETURN:
1746       {
1747 	const return_superedge *return_edge
1748 	  = as_a <const return_superedge *> (eedge.m_sedge);
1749 
1750 	const gcall *call_stmt = return_edge->get_call_stmt ();
1751 	emission_path->add_event
1752 	  (new return_event (eedge,
1753 			     (call_stmt
1754 			      ? call_stmt->location
1755 			      : UNKNOWN_LOCATION),
1756 			     dst_point.get_fndecl (),
1757 			     dst_stack_depth));
1758       }
1759       break;
1760     }
1761 }
1762 
1763 /* Prune PATH, based on the verbosity level, to the most pertinent
1764    events for a diagnostic that involves VAR ending in state STATE
1765    (for state machine SM).
1766 
1767    PATH is updated in place, and the redundant checker_events are deleted.
1768 
1769    As well as deleting events, call record_critical_state on events in
1770    which state critical to the pending_diagnostic is being handled; see
1771    the comment for diagnostic_manager::prune_for_sm_diagnostic.  */
1772 
1773 void
prune_path(checker_path * path,const state_machine * sm,const svalue * sval,state_machine::state_t state) const1774 diagnostic_manager::prune_path (checker_path *path,
1775 				const state_machine *sm,
1776 				const svalue *sval,
1777 				state_machine::state_t state) const
1778 {
1779   LOG_FUNC (get_logger ());
1780   path->maybe_log (get_logger (), "path");
1781   prune_for_sm_diagnostic (path, sm, sval, state);
1782   prune_interproc_events (path);
1783   consolidate_conditions (path);
1784   finish_pruning (path);
1785   path->maybe_log (get_logger (), "pruned");
1786 }
1787 
1788 /* A cheap test to determine if EXPR can be the expression of interest in
1789    an sm-diagnostic, so that we can reject cases where we have a non-lvalue.
1790    We don't have always have a model when calling this, so we can't use
1791    tentative_region_model_context, so there can be false positives.  */
1792 
1793 static bool
can_be_expr_of_interest_p(tree expr)1794 can_be_expr_of_interest_p (tree expr)
1795 {
1796   if (!expr)
1797     return false;
1798 
1799   /* Reject constants.  */
1800   if (CONSTANT_CLASS_P (expr))
1801     return false;
1802 
1803   /* Otherwise assume that it can be an lvalue.  */
1804   return true;
1805 }
1806 
1807 /* First pass of diagnostic_manager::prune_path: apply verbosity level,
1808    pruning unrelated state change events.
1809 
1810    Iterate backwards through PATH, skipping state change events that aren't
1811    VAR but update the pertinent VAR when state-copying occurs.
1812 
1813    As well as deleting events, call record_critical_state on events in
1814    which state critical to the pending_diagnostic is being handled, so
1815    that the event's get_desc vfunc can potentially supply a more precise
1816    description of the event to the user.
1817    e.g. improving
1818      "calling 'foo' from 'bar'"
1819    to
1820      "passing possibly-NULL pointer 'ptr' to 'foo' from 'bar' as param 1"
1821    when the diagnostic relates to later dereferencing 'ptr'.  */
1822 
1823 void
prune_for_sm_diagnostic(checker_path * path,const state_machine * sm,const svalue * sval,state_machine::state_t state) const1824 diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
1825 					     const state_machine *sm,
1826 					     const svalue *sval,
1827 					     state_machine::state_t state) const
1828 {
1829   int idx = path->num_events () - 1;
1830   while (idx >= 0 && idx < (signed)path->num_events ())
1831     {
1832       checker_event *base_event = path->get_checker_event (idx);
1833       if (get_logger ())
1834 	{
1835 	  if (sm)
1836 	    {
1837 	      if (sval)
1838 		{
1839 		  label_text sval_desc = sval->get_desc ();
1840 		  log ("considering event %i (%s), with sval: %qs, state: %qs",
1841 		       idx, event_kind_to_string (base_event->m_kind),
1842 		       sval_desc.m_buffer, state->get_name ());
1843 		}
1844 	      else
1845 		log ("considering event %i (%s), with global state: %qs",
1846 		     idx, event_kind_to_string (base_event->m_kind),
1847 		     state->get_name ());
1848 	    }
1849 	  else
1850 	    log ("considering event %i", idx);
1851 	}
1852 
1853       switch (base_event->m_kind)
1854 	{
1855 	default:
1856 	  gcc_unreachable ();
1857 
1858 	case EK_DEBUG:
1859 	  if (m_verbosity < 4)
1860 	    {
1861 	      log ("filtering event %i: debug event", idx);
1862 	      path->delete_event (idx);
1863 	    }
1864 	  break;
1865 
1866 	case EK_CUSTOM:
1867 	  /* Don't filter custom events.  */
1868 	  break;
1869 
1870 	case EK_STMT:
1871 	  {
1872 	    if (m_verbosity < 4)
1873 	      {
1874 		log ("filtering event %i: statement event", idx);
1875 		path->delete_event (idx);
1876 	      }
1877 	  }
1878 	  break;
1879 
1880 	case EK_FUNCTION_ENTRY:
1881 	  if (m_verbosity < 1)
1882 	    {
1883 	      log ("filtering event %i: function entry", idx);
1884 	      path->delete_event (idx);
1885 	    }
1886 	  break;
1887 
1888 	case EK_STATE_CHANGE:
1889 	  {
1890 	    state_change_event *state_change = (state_change_event *)base_event;
1891 	    gcc_assert (state_change->m_dst_state.m_region_model);
1892 
1893 	    if (state_change->m_sval == sval)
1894 	      {
1895 		if (state_change->m_origin)
1896 		  {
1897 		    if (get_logger ())
1898 		      {
1899 			label_text sval_desc = sval->get_desc ();
1900 			label_text origin_sval_desc
1901 			  = state_change->m_origin->get_desc ();
1902 			log ("event %i:"
1903 			     " switching var of interest from %qs to %qs",
1904 			     idx, sval_desc.m_buffer,
1905 			     origin_sval_desc.m_buffer);
1906 		      }
1907 		    sval = state_change->m_origin;
1908 		  }
1909 		log ("event %i: switching state of interest from %qs to %qs",
1910 		     idx, state_change->m_to->get_name (),
1911 		     state_change->m_from->get_name ());
1912 		state = state_change->m_from;
1913 	      }
1914 	    else if (m_verbosity < 4)
1915 	      {
1916 		if (get_logger ())
1917 		  {
1918 		    if (state_change->m_sval)
1919 		      {
1920 			label_text change_sval_desc
1921 			  = state_change->m_sval->get_desc ();
1922 			if (sval)
1923 			  {
1924 			    label_text sval_desc = sval->get_desc ();
1925 			    log ("filtering event %i:"
1926 				 " state change to %qs unrelated to %qs",
1927 				 idx, change_sval_desc.m_buffer,
1928 				 sval_desc.m_buffer);
1929 			  }
1930 			else
1931 			  log ("filtering event %i: state change to %qs",
1932 			       idx, change_sval_desc.m_buffer);
1933 		      }
1934 		    else
1935 		      log ("filtering event %i: global state change", idx);
1936 		  }
1937 		path->delete_event (idx);
1938 	      }
1939 	  }
1940 	  break;
1941 
1942 	case EK_START_CFG_EDGE:
1943 	  {
1944 	    cfg_edge_event *event = (cfg_edge_event *)base_event;
1945 
1946 	    /* TODO: is this edge significant to var?
1947 	       See if var can be in other states in the dest, but not
1948 	       in other states in the src?
1949 	       Must have multiple sibling edges.  */
1950 
1951 	    if (event->should_filter_p (m_verbosity))
1952 	      {
1953 		log ("filtering events %i and %i: CFG edge", idx, idx + 1);
1954 		path->delete_event (idx);
1955 		/* Also delete the corresponding EK_END_CFG_EDGE.  */
1956 		gcc_assert (path->get_checker_event (idx)->m_kind
1957 			    == EK_END_CFG_EDGE);
1958 		path->delete_event (idx);
1959 	      }
1960 	  }
1961 	  break;
1962 
1963 	case EK_END_CFG_EDGE:
1964 	  /* These come in pairs with EK_START_CFG_EDGE events and are
1965 	     filtered when their start event is filtered.  */
1966 	  break;
1967 
1968 	case EK_CALL_EDGE:
1969 	  {
1970 	    call_event *event = (call_event *)base_event;
1971 	    const callgraph_superedge& cg_superedge
1972 	      = event->get_callgraph_superedge ();
1973 	    const region_model *callee_model
1974 	      = event->m_eedge.m_dest->get_state ().m_region_model;
1975 	    tree callee_var = callee_model->get_representative_tree (sval);
1976 	    /* We could just use caller_model->get_representative_tree (sval);
1977 	       to get the caller_var, but for now use
1978 	       map_expr_from_callee_to_caller so as to only record critical
1979 	       state for parms and the like.  */
1980 	    callsite_expr expr;
1981 	    tree caller_var
1982 	      = cg_superedge.map_expr_from_callee_to_caller (callee_var, &expr);
1983 	    if (caller_var)
1984 	      {
1985 		if (get_logger ())
1986 		  {
1987 		    label_text sval_desc = sval->get_desc ();
1988 		    log ("event %i:"
1989 			 " recording critical state for %qs at call"
1990 			 " from %qE in callee to %qE in caller",
1991 			 idx, sval_desc.m_buffer, callee_var, caller_var);
1992 		  }
1993 		if (expr.param_p ())
1994 		  event->record_critical_state (caller_var, state);
1995 	      }
1996 	  }
1997 	  break;
1998 
1999 	case EK_RETURN_EDGE:
2000 	  {
2001 	    if (sval)
2002 	      {
2003 		return_event *event = (return_event *)base_event;
2004 		const callgraph_superedge& cg_superedge
2005 		  = event->get_callgraph_superedge ();
2006 		const region_model *caller_model
2007 		  = event->m_eedge.m_dest->get_state ().m_region_model;
2008 		tree caller_var = caller_model->get_representative_tree (sval);
2009 		callsite_expr expr;
2010 		tree callee_var
2011 		  = cg_superedge.map_expr_from_caller_to_callee (caller_var,
2012 								 &expr);
2013 		if (callee_var)
2014 		  {
2015 		    if (get_logger ())
2016 		      {
2017 			label_text sval_desc = sval->get_desc ();
2018 			log ("event %i:"
2019 			     " recording critical state for %qs at return"
2020 			     " from %qE in caller to %qE in callee",
2021 			     idx, sval_desc.m_buffer, callee_var, callee_var);
2022 		      }
2023 		    if (expr.return_value_p ())
2024 		      event->record_critical_state (callee_var, state);
2025 		  }
2026 	      }
2027 	  }
2028 	  break;
2029 
2030 	case EK_SETJMP:
2031 	  /* TODO: only show setjmp_events that matter i.e. those for which
2032 	     there is a later rewind event using them.  */
2033 	case EK_REWIND_FROM_LONGJMP:
2034 	case EK_REWIND_TO_SETJMP:
2035 	  break;
2036 
2037 	case EK_WARNING:
2038 	  /* Always show the final "warning" event in the path.  */
2039 	  break;
2040 	}
2041       idx--;
2042     }
2043 }
2044 
2045 /* Subroutine of diagnostic_manager::prune_for_sm_diagnostic.
2046    If *EXPR is not suitable to be the expression of interest in
2047    an sm-diagnostic, set *EXPR to NULL and log.  */
2048 
2049 void
update_for_unsuitable_sm_exprs(tree * expr) const2050 diagnostic_manager::update_for_unsuitable_sm_exprs (tree *expr) const
2051 {
2052   gcc_assert (expr);
2053   if (*expr && !can_be_expr_of_interest_p (*expr))
2054     {
2055       log ("new var %qE is unsuitable; setting var to NULL", *expr);
2056       *expr = NULL_TREE;
2057     }
2058 }
2059 
2060 /* Second pass of diagnostic_manager::prune_path: remove redundant
2061    interprocedural information.
2062 
2063    For example, given:
2064      (1)- calling "f2" from "f1"
2065      (2)--- entry to "f2"
2066      (3)--- calling "f3" from "f2"
2067      (4)----- entry to "f3"
2068      (5)--- returning to "f2" to "f3"
2069      (6)- returning to "f1" to "f2"
2070    with no other intervening events, then none of these events are
2071    likely to be interesting to the user.
2072 
2073    Prune [..., call, function-entry, return, ...] triples repeatedly
2074    until nothing has changed.  For the example above, this would
2075    remove events (3, 4, 5), and then remove events (1, 2, 6).  */
2076 
2077 void
prune_interproc_events(checker_path * path) const2078 diagnostic_manager::prune_interproc_events (checker_path *path) const
2079 {
2080   bool changed = false;
2081   do
2082     {
2083       changed = false;
2084       int idx = (signed)path->num_events () - 1;
2085       while (idx >= 0)
2086 	{
2087 	  /* Prune [..., call, function-entry, return, ...] triples.  */
2088 	  if (idx + 2 < (signed)path->num_events ()
2089 	      && path->get_checker_event (idx)->is_call_p ()
2090 	      && path->get_checker_event (idx + 1)->is_function_entry_p ()
2091 	      && path->get_checker_event (idx + 2)->is_return_p ())
2092 	    {
2093 	      if (get_logger ())
2094 		{
2095 		  label_text desc
2096 		    (path->get_checker_event (idx)->get_desc (false));
2097 		  log ("filtering events %i-%i:"
2098 		       " irrelevant call/entry/return: %s",
2099 		       idx, idx + 2, desc.m_buffer);
2100 		  desc.maybe_free ();
2101 		}
2102 	      path->delete_event (idx + 2);
2103 	      path->delete_event (idx + 1);
2104 	      path->delete_event (idx);
2105 	      changed = true;
2106 	      idx--;
2107 	      continue;
2108 	    }
2109 
2110 	  /* Prune [..., call, return, ...] pairs
2111 	     (for -fanalyzer-verbosity=0).  */
2112 	  if (idx + 1 < (signed)path->num_events ()
2113 	      && path->get_checker_event (idx)->is_call_p ()
2114 	      && path->get_checker_event (idx + 1)->is_return_p ())
2115 	    {
2116 	      if (get_logger ())
2117 		{
2118 		  label_text desc
2119 		    (path->get_checker_event (idx)->get_desc (false));
2120 		  log ("filtering events %i-%i:"
2121 		       " irrelevant call/return: %s",
2122 		       idx, idx + 1, desc.m_buffer);
2123 		  desc.maybe_free ();
2124 		}
2125 	      path->delete_event (idx + 1);
2126 	      path->delete_event (idx);
2127 	      changed = true;
2128 	      idx--;
2129 	      continue;
2130 	    }
2131 
2132 	  idx--;
2133 	}
2134 
2135     }
2136   while (changed);
2137 }
2138 
2139 /* Return true iff event IDX within PATH is on the same line as REF_EXP_LOC.  */
2140 
2141 static bool
same_line_as_p(const expanded_location & ref_exp_loc,checker_path * path,unsigned idx)2142 same_line_as_p (const expanded_location &ref_exp_loc,
2143 		checker_path *path, unsigned idx)
2144 {
2145   const checker_event *ev = path->get_checker_event (idx);
2146   expanded_location idx_exp_loc = expand_location (ev->get_location ());
2147   gcc_assert (ref_exp_loc.file);
2148   if (idx_exp_loc.file == NULL)
2149     return false;
2150   if (strcmp (ref_exp_loc.file, idx_exp_loc.file))
2151     return false;
2152   return ref_exp_loc.line == idx_exp_loc.line;
2153 }
2154 
2155 /* This path-readability optimization reduces the verbosity of compound
2156    conditional statements (without needing to reconstruct the AST, which
2157    has already been lost).
2158 
2159    For example, it converts:
2160 
2161     |   61 |   if (cp[0] != '\0' && cp[0] != '#')
2162     |      |      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2163     |      |      |              |    |
2164     |      |      |              |    (6) ...to here
2165     |      |      |              (7) following ‘true’ branch...
2166     |      |      (5) following ‘true’ branch...
2167     |   62 |     {
2168     |   63 |       alias = cp++;
2169     |      |               ~~~~
2170     |      |                 |
2171     |      |                 (8) ...to here
2172 
2173    into:
2174 
2175     |   61 |   if (cp[0] != '\0' && cp[0] != '#')
2176     |      |      ~
2177     |      |      |
2178     |      |      (5) following ‘true’ branch...
2179     |   62 |     {
2180     |   63 |       alias = cp++;
2181     |      |               ~~~~
2182     |      |                 |
2183     |      |                 (6) ...to here
2184 
2185    by combining events 5-8 into new events 5-6.
2186 
2187    Find runs of consecutive (start_cfg_edge_event, end_cfg_edge_event) pairs
2188    in which all events apart from the final end_cfg_edge_event are on the same
2189    line, and for which either all the CFG edges are TRUE edges, or all are
2190    FALSE edges.
2191 
2192    Consolidate each such run into a
2193      (start_consolidated_cfg_edges_event, end_consolidated_cfg_edges_event)
2194    pair.  */
2195 
2196 void
consolidate_conditions(checker_path * path) const2197 diagnostic_manager::consolidate_conditions (checker_path *path) const
2198 {
2199   /* Don't simplify edges if we're debugging them.  */
2200   if (flag_analyzer_verbose_edges)
2201     return;
2202 
2203   for (int start_idx = 0;
2204        start_idx < (signed)path->num_events () - 1;
2205        start_idx++)
2206     {
2207       if (path->cfg_edge_pair_at_p (start_idx))
2208 	{
2209 	  const checker_event *old_start_ev
2210 	    = path->get_checker_event (start_idx);
2211 	  expanded_location start_exp_loc
2212 	    = expand_location (old_start_ev->get_location ());
2213 	  if (start_exp_loc.file == NULL)
2214 	    continue;
2215 	  if (!same_line_as_p (start_exp_loc, path, start_idx + 1))
2216 	    continue;
2217 
2218 	  /* Are we looking for a run of all TRUE edges, or all FALSE edges?  */
2219 	  gcc_assert (old_start_ev->m_kind == EK_START_CFG_EDGE);
2220 	  const start_cfg_edge_event *old_start_cfg_ev
2221 	    = (const start_cfg_edge_event *)old_start_ev;
2222 	  const cfg_superedge& first_cfg_sedge
2223 	    = old_start_cfg_ev->get_cfg_superedge ();
2224 	  bool edge_sense;
2225 	  if (first_cfg_sedge.true_value_p ())
2226 	    edge_sense = true;
2227 	  else if (first_cfg_sedge.false_value_p ())
2228 	    edge_sense = false;
2229 	  else
2230 	    continue;
2231 
2232 	  /* Find a run of CFG start/end event pairs from
2233 	       [start_idx, next_idx)
2234 	     where all apart from the final event are on the same line,
2235 	     and all are either TRUE or FALSE edges, matching the initial.  */
2236 	  int next_idx = start_idx + 2;
2237 	  while (path->cfg_edge_pair_at_p (next_idx)
2238 		 && same_line_as_p (start_exp_loc, path, next_idx))
2239 	    {
2240 	      const checker_event *iter_ev
2241 		= path->get_checker_event (next_idx);
2242 	      gcc_assert (iter_ev->m_kind == EK_START_CFG_EDGE);
2243 	      const start_cfg_edge_event *iter_cfg_ev
2244 		= (const start_cfg_edge_event *)iter_ev;
2245 	      const cfg_superedge& iter_cfg_sedge
2246 		= iter_cfg_ev->get_cfg_superedge ();
2247 	      if (edge_sense)
2248 		{
2249 		  if (!iter_cfg_sedge.true_value_p ())
2250 		    break;
2251 		}
2252 	      else
2253 		{
2254 		  if (!iter_cfg_sedge.false_value_p ())
2255 		    break;
2256 		}
2257 	      next_idx += 2;
2258 	    }
2259 
2260 	  /* If we have more than one pair in the run, consolidate.  */
2261 	  if (next_idx > start_idx + 2)
2262 	    {
2263 	      const checker_event *old_end_ev
2264 		= path->get_checker_event (next_idx - 1);
2265 	      log ("consolidating CFG edge events %i-%i into %i-%i",
2266 		   start_idx, next_idx - 1, start_idx, start_idx +1);
2267 	      start_consolidated_cfg_edges_event *new_start_ev
2268 		= new start_consolidated_cfg_edges_event
2269 		(old_start_ev->get_location (),
2270 		 old_start_ev->get_fndecl (),
2271 		 old_start_ev->get_stack_depth (),
2272 		 edge_sense);
2273 	      checker_event *new_end_ev
2274 		= new end_consolidated_cfg_edges_event
2275 		(old_end_ev->get_location (),
2276 		 old_end_ev->get_fndecl (),
2277 		 old_end_ev->get_stack_depth ());
2278 	      path->replace_event (start_idx, new_start_ev);
2279 	      path->replace_event (start_idx + 1, new_end_ev);
2280 	      path->delete_events (start_idx + 2, next_idx - (start_idx + 2));
2281 	    }
2282 	}
2283     }
2284 }
2285 
2286 /* Final pass of diagnostic_manager::prune_path.
2287 
2288    If all we're left with is in one function, then filter function entry
2289    events.  */
2290 
2291 void
finish_pruning(checker_path * path) const2292 diagnostic_manager::finish_pruning (checker_path *path) const
2293 {
2294   if (!path->interprocedural_p ())
2295     {
2296       int idx = path->num_events () - 1;
2297       while (idx >= 0 && idx < (signed)path->num_events ())
2298 	{
2299 	  checker_event *base_event = path->get_checker_event (idx);
2300 	  if (base_event->m_kind == EK_FUNCTION_ENTRY)
2301 	    {
2302 	      log ("filtering event %i:"
2303 		   " function entry for purely intraprocedural path", idx);
2304 	      path->delete_event (idx);
2305 	    }
2306 	  idx--;
2307 	}
2308     }
2309 }
2310 
2311 } // namespace ana
2312 
2313 #endif /* #if ENABLE_ANALYZER */
2314