xref: /netbsd-src/external/gpl3/gcc/dist/gcc/analyzer/checker-path.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
2    Copyright (C) 2019-2022 Free Software Foundation, Inc.
3    Contributed by David Malcolm <dmalcolm@redhat.com>.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11 
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20 
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "basic-block.h"
27 #include "gimple.h"
28 #include "gimple-pretty-print.h"
29 #include "fold-const.h"
30 #include "function.h"
31 #include "diagnostic-path.h"
32 #include "options.h"
33 #include "cgraph.h"
34 #include "function.h"
35 #include "cfg.h"
36 #include "digraph.h"
37 #include "alloc-pool.h"
38 #include "fibonacci_heap.h"
39 #include "diagnostic-event-id.h"
40 #include "shortest-paths.h"
41 #include "json.h"
42 #include "analyzer/analyzer.h"
43 #include "analyzer/analyzer-logging.h"
44 #include "analyzer/sm.h"
45 #include "sbitmap.h"
46 #include "bitmap.h"
47 #include "tristate.h"
48 #include "ordered-hash-map.h"
49 #include "selftest.h"
50 #include "analyzer/call-string.h"
51 #include "analyzer/program-point.h"
52 #include "analyzer/store.h"
53 #include "analyzer/region-model.h"
54 #include "analyzer/program-state.h"
55 #include "analyzer/checker-path.h"
56 #include "gimple-iterator.h"
57 #include "analyzer/supergraph.h"
58 #include "analyzer/pending-diagnostic.h"
59 #include "analyzer/diagnostic-manager.h"
60 #include "analyzer/constraint-manager.h"
61 #include "analyzer/diagnostic-manager.h"
62 #include "analyzer/checker-path.h"
63 #include "analyzer/exploded-graph.h"
64 
65 #if ENABLE_ANALYZER
66 
67 namespace ana {
68 
69 /* Get a string for EK.  */
70 
71 const char *
event_kind_to_string(enum event_kind ek)72 event_kind_to_string (enum event_kind ek)
73 {
74   switch (ek)
75     {
76     default:
77       gcc_unreachable ();
78     case EK_DEBUG:
79       return "EK_DEBUG";
80     case EK_CUSTOM:
81       return "EK_CUSTOM";
82     case EK_STMT:
83       return "EK_STMT";
84     case EK_REGION_CREATION:
85       return "EK_REGION_CREATION";
86     case EK_FUNCTION_ENTRY:
87       return "EK_FUNCTION_ENTRY";
88     case EK_STATE_CHANGE:
89       return "EK_STATE_CHANGE";
90     case EK_START_CFG_EDGE:
91       return "EK_START_CFG_EDGE";
92     case EK_END_CFG_EDGE:
93       return "EK_END_CFG_EDGE";
94     case EK_CALL_EDGE:
95       return "EK_CALL_EDGE";
96     case EK_RETURN_EDGE:
97       return "EK_RETURN_EDGE";
98     case EK_START_CONSOLIDATED_CFG_EDGES:
99       return "EK_START_CONSOLIDATED_CFG_EDGES";
100     case EK_END_CONSOLIDATED_CFG_EDGES:
101       return "EK_END_CONSOLIDATED_CFG_EDGES";
102     case EK_SETJMP:
103       return "EK_SETJMP";
104     case EK_REWIND_FROM_LONGJMP:
105       return "EK_REWIND_FROM_LONGJMP";
106     case EK_REWIND_TO_SETJMP:
107       return "EK_REWIND_TO_SETJMP";
108     case EK_WARNING:
109       return "EK_WARNING";
110     }
111 }
112 
113 /* class checker_event : public diagnostic_event.  */
114 
115 /* Dump this event to PP (for debugging/logging purposes).  */
116 
117 void
dump(pretty_printer * pp) const118 checker_event::dump (pretty_printer *pp) const
119 {
120   label_text event_desc (get_desc (false));
121   pp_printf (pp, "\"%s\" (depth %i, m_loc=%x)",
122 	     event_desc.m_buffer,
123 	     get_stack_depth (),
124 	     get_location ());
125   event_desc.maybe_free ();
126 }
127 
128 /* Hook for being notified when this event has its final id EMISSION_ID
129    and is about to emitted for PD.
130 
131    Base implementation of checker_event::prepare_for_emission vfunc;
132    subclasses that override this should chain up to it.
133 
134    Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
135    side-effects of the call to get_desc take place before
136    pending_diagnostic::emit is called.
137 
138    For example, state_change_event::get_desc can call
139    pending_diagnostic::describe_state_change; free_of_non_heap can use this
140    to tweak the message (TODO: would be neater to simply capture the
141    pertinent data within the sm-state).  */
142 
143 void
prepare_for_emission(checker_path *,pending_diagnostic * pd,diagnostic_event_id_t emission_id)144 checker_event::prepare_for_emission (checker_path *,
145 				     pending_diagnostic *pd,
146 				     diagnostic_event_id_t emission_id)
147 {
148   m_pending_diagnostic = pd;
149   m_emission_id = emission_id;
150 
151   label_text desc = get_desc (false);
152   desc.maybe_free ();
153 }
154 
155 /* class debug_event : public checker_event.  */
156 
157 /* Implementation of diagnostic_event::get_desc vfunc for
158    debug_event.
159    Use the saved string as the event's description.  */
160 
161 label_text
get_desc(bool) const162 debug_event::get_desc (bool) const
163 {
164   return label_text::borrow (m_desc);
165 }
166 
167 /* class precanned_custom_event : public custom_event.  */
168 
169 /* Implementation of diagnostic_event::get_desc vfunc for
170    precanned_custom_event.
171    Use the saved string as the event's description.  */
172 
173 label_text
get_desc(bool) const174 precanned_custom_event::get_desc (bool) const
175 {
176   return label_text::borrow (m_desc);
177 }
178 
179 /* class statement_event : public checker_event.  */
180 
181 /* statement_event's ctor.  */
182 
statement_event(const gimple * stmt,tree fndecl,int depth,const program_state & dst_state)183 statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
184 				  const program_state &dst_state)
185 : checker_event (EK_STMT, gimple_location (stmt), fndecl, depth),
186   m_stmt (stmt),
187   m_dst_state (dst_state)
188 {
189 }
190 
191 /* Implementation of diagnostic_event::get_desc vfunc for
192    statement_event.
193    Use the statement's dump form as the event's description.  */
194 
195 label_text
get_desc(bool) const196 statement_event::get_desc (bool) const
197 {
198   pretty_printer pp;
199   pp_string (&pp, "stmt: ");
200   pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
201   return label_text::take (xstrdup (pp_formatted_text (&pp)));
202 }
203 
204 /* class region_creation_event : public checker_event.  */
205 
region_creation_event(const region * reg,location_t loc,tree fndecl,int depth)206 region_creation_event::region_creation_event (const region *reg,
207 					      location_t loc,
208 					      tree fndecl,
209 					      int depth)
210 : checker_event (EK_REGION_CREATION, loc, fndecl, depth),
211   m_reg (reg)
212 {
213 }
214 
215 /* Implementation of diagnostic_event::get_desc vfunc for
216    region_creation_event.  */
217 
218 label_text
get_desc(bool) const219 region_creation_event::get_desc (bool) const
220 {
221   switch (m_reg->get_memory_space ())
222     {
223     default:
224       return label_text::borrow ("region created here");
225     case MEMSPACE_STACK:
226       return label_text::borrow ("region created on stack here");
227     case MEMSPACE_HEAP:
228       return label_text::borrow ("region created on heap here");
229     }
230 }
231 
232 /* class function_entry_event : public checker_event.  */
233 
234 /* Implementation of diagnostic_event::get_desc vfunc for
235    function_entry_event.
236 
237    Use a string such as "entry to 'foo'" as the event's description.  */
238 
239 label_text
get_desc(bool can_colorize) const240 function_entry_event::get_desc (bool can_colorize) const
241 {
242   return make_label_text (can_colorize, "entry to %qE", m_fndecl);
243 }
244 
245 /* class state_change_event : public checker_event.  */
246 
247 /* state_change_event's ctor.  */
248 
state_change_event(const supernode * node,const gimple * stmt,int stack_depth,const state_machine & sm,const svalue * sval,state_machine::state_t from,state_machine::state_t to,const svalue * origin,const program_state & dst_state)249 state_change_event::state_change_event (const supernode *node,
250 					const gimple *stmt,
251 					int stack_depth,
252 					const state_machine &sm,
253 					const svalue *sval,
254 					state_machine::state_t from,
255 					state_machine::state_t to,
256 					const svalue *origin,
257 					const program_state &dst_state)
258 : checker_event (EK_STATE_CHANGE,
259 		 stmt->location, node->m_fun->decl,
260 		 stack_depth),
261   m_node (node), m_stmt (stmt), m_sm (sm),
262   m_sval (sval), m_from (from), m_to (to),
263   m_origin (origin),
264   m_dst_state (dst_state)
265 {
266 }
267 
268 /* Implementation of diagnostic_event::get_desc vfunc for
269    state_change_event.
270 
271    Attempt to generate a nicer human-readable description.
272    For greatest precision-of-wording, give the pending diagnostic
273    a chance to describe this state change (in terms of the
274    diagnostic).
275    Note that we only have a pending_diagnostic set on the event once
276    the diagnostic is about to being emitted, so the description for
277    an event can change.  */
278 
279 label_text
get_desc(bool can_colorize) const280 state_change_event::get_desc (bool can_colorize) const
281 {
282   if (m_pending_diagnostic)
283     {
284       region_model *model = m_dst_state.m_region_model;
285       tree var = model->get_representative_tree (m_sval);
286       tree origin = model->get_representative_tree (m_origin);
287       label_text custom_desc
288 	= m_pending_diagnostic->describe_state_change
289 	    (evdesc::state_change (can_colorize, var, origin,
290 				   m_from, m_to, m_emission_id, *this));
291       if (custom_desc.m_buffer)
292 	{
293 	  if (flag_analyzer_verbose_state_changes)
294 	    {
295 	      /* Append debug version.  */
296 	      label_text result;
297 	      if (m_origin)
298 		result = make_label_text
299 		  (can_colorize,
300 		   "%s (state of %qE: %qs -> %qs, origin: %qE)",
301 		   custom_desc.m_buffer,
302 		   var,
303 		   m_from->get_name (),
304 		   m_to->get_name (),
305 		   origin);
306 	      else
307 		result = make_label_text
308 		  (can_colorize,
309 		   "%s (state of %qE: %qs -> %qs, NULL origin)",
310 		   custom_desc.m_buffer,
311 		   var,
312 		   m_from->get_name (),
313 		   m_to->get_name ());
314 	      custom_desc.maybe_free ();
315 	      return result;
316 	    }
317 	  else
318 	    return custom_desc;
319 	}
320     }
321 
322   /* Fallback description.  */
323   if (m_sval)
324     {
325       label_text sval_desc = m_sval->get_desc ();
326       label_text result;
327       if (m_origin)
328 	{
329 	  label_text origin_desc = m_origin->get_desc ();
330 	  result = make_label_text
331 	    (can_colorize,
332 	     "state of %qs: %qs -> %qs (origin: %qs)",
333 	     sval_desc.m_buffer,
334 	     m_from->get_name (),
335 	     m_to->get_name (),
336 	     origin_desc.m_buffer);
337 	  origin_desc.maybe_free ();
338 	}
339       else
340 	result = make_label_text
341 	  (can_colorize,
342 	   "state of %qs: %qs -> %qs (NULL origin)",
343 	   sval_desc.m_buffer,
344 	   m_from->get_name (),
345 	   m_to->get_name ());
346       sval_desc.maybe_free ();
347       return result;
348     }
349   else
350     {
351       gcc_assert (m_origin == NULL);
352       return make_label_text
353 	(can_colorize,
354 	 "global state: %qs -> %qs",
355 	 m_from->get_name (),
356 	 m_to->get_name ());
357     }
358 }
359 
360 /* class superedge_event : public checker_event.  */
361 
362 /* Get the callgraph_superedge for this superedge_event, which must be
363    for an interprocedural edge, rather than a CFG edge.  */
364 
365 const callgraph_superedge&
get_callgraph_superedge() const366 superedge_event::get_callgraph_superedge () const
367 {
368   gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
369   return *m_sedge->dyn_cast_callgraph_superedge ();
370 }
371 
372 /* Determine if this event should be filtered at the given verbosity
373    level.  */
374 
375 bool
should_filter_p(int verbosity) const376 superedge_event::should_filter_p (int verbosity) const
377 {
378   switch (m_sedge->m_kind)
379     {
380     case SUPEREDGE_CFG_EDGE:
381       {
382 	if (verbosity < 2)
383 	  return true;
384 
385 	if (verbosity < 4)
386 	  {
387 	    /* Filter events with empty descriptions.  This ought to filter
388 	       FALLTHRU, but retain true/false/switch edges.  */
389 	    label_text desc = get_desc (false);
390 	    gcc_assert (desc.m_buffer);
391 	    if (desc.m_buffer[0] == '\0')
392 	      return true;
393 	    desc.maybe_free ();
394 	  }
395       }
396       break;
397 
398     default:
399       break;
400     }
401   return false;
402 }
403 
404 /* superedge_event's ctor.  */
405 
superedge_event(enum event_kind kind,const exploded_edge & eedge,location_t loc,tree fndecl,int depth)406 superedge_event::superedge_event (enum event_kind kind,
407 				  const exploded_edge &eedge,
408 				  location_t loc, tree fndecl, int depth)
409 : checker_event (kind, loc, fndecl, depth),
410   m_eedge (eedge), m_sedge (eedge.m_sedge),
411   m_var (NULL_TREE), m_critical_state (0)
412 {
413 }
414 
415 /* class cfg_edge_event : public superedge_event.  */
416 
417 /* Get the cfg_superedge for this cfg_edge_event.  */
418 
419 const cfg_superedge &
get_cfg_superedge() const420 cfg_edge_event::get_cfg_superedge () const
421 {
422   return *m_sedge->dyn_cast_cfg_superedge ();
423 }
424 
425 /* cfg_edge_event's ctor.  */
426 
cfg_edge_event(enum event_kind kind,const exploded_edge & eedge,location_t loc,tree fndecl,int depth)427 cfg_edge_event::cfg_edge_event (enum event_kind kind,
428 				const exploded_edge &eedge,
429 				location_t loc, tree fndecl, int depth)
430 : superedge_event (kind, eedge, loc, fndecl, depth)
431 {
432   gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
433 }
434 
435 /* class start_cfg_edge_event : public cfg_edge_event.  */
436 
437 /* Implementation of diagnostic_event::get_desc vfunc for
438    start_cfg_edge_event.
439 
440    If -fanalyzer-verbose-edges, then generate low-level descriptions, such
441    as
442      "taking 'true' edge SN:7 -> SN:8".
443 
444    Otherwise, generate strings using the label of the underlying CFG if
445    any, such as:
446      "following 'true' branch..." or
447      "following 'case 3' branch..."
448      "following 'default' branch..."
449 
450    For conditionals, attempt to supply a description of the condition that
451    holds, such as:
452      "following 'false' branch (when 'ptr' is non-NULL)..."
453 
454    Failing that, return an empty description (which will lead to this event
455    being filtered).  */
456 
457 label_text
get_desc(bool can_colorize) const458 start_cfg_edge_event::get_desc (bool can_colorize) const
459 {
460   bool user_facing = !flag_analyzer_verbose_edges;
461   char *edge_desc = m_sedge->get_description (user_facing);
462   if (user_facing)
463     {
464       if (edge_desc && strlen (edge_desc) > 0)
465 	{
466 	  label_text cond_desc = maybe_describe_condition (can_colorize);
467 	  label_text result;
468 	  if (cond_desc.m_buffer)
469 	    {
470 	      result = make_label_text (can_colorize,
471 					"following %qs branch (%s)...",
472 					edge_desc, cond_desc.m_buffer);
473 	      cond_desc.maybe_free ();
474 	    }
475 	  else
476 	    {
477 	      result = make_label_text (can_colorize,
478 					"following %qs branch...",
479 					edge_desc);
480 	    }
481 	  free (edge_desc);
482 	  return result;
483 	}
484       else
485 	{
486 	  free (edge_desc);
487 	  return label_text::borrow ("");
488 	}
489     }
490   else
491     {
492       if (strlen (edge_desc) > 0)
493 	{
494 	  label_text result
495 	    = make_label_text (can_colorize,
496 			       "taking %qs edge SN:%i -> SN:%i",
497 			       edge_desc,
498 			       m_sedge->m_src->m_index,
499 			       m_sedge->m_dest->m_index);
500 	  free (edge_desc);
501 	  return result;
502 	}
503       else
504 	{
505 	  free (edge_desc);
506 	  return make_label_text (can_colorize,
507 				  "taking edge SN:%i -> SN:%i",
508 				  m_sedge->m_src->m_index,
509 				  m_sedge->m_dest->m_index);
510 	}
511     }
512 }
513 
514 /* Attempt to generate a description of any condition that holds at this edge.
515 
516    The intent is to make the user-facing messages more clear, especially for
517    cases where there's a single or double-negative, such as
518    when describing the false branch of an inverted condition.
519 
520    For example, rather than printing just:
521 
522       |  if (!ptr)
523       |     ~
524       |     |
525       |     (1) following 'false' branch...
526 
527    it's clearer to spell out the condition that holds:
528 
529       |  if (!ptr)
530       |     ~
531       |     |
532       |     (1) following 'false' branch (when 'ptr' is non-NULL)...
533                                           ^^^^^^^^^^^^^^^^^^^^^^
534 
535    In the above example, this function would generate the highlighted
536    string: "when 'ptr' is non-NULL".
537 
538    If the edge is not a condition, or it's not clear that a description of
539    the condition would be helpful to the user, return NULL.  */
540 
541 label_text
maybe_describe_condition(bool can_colorize) const542 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
543 {
544   const cfg_superedge& cfg_sedge = get_cfg_superedge ();
545 
546   if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
547     {
548       const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
549       if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
550 	{
551 	  enum tree_code op = gimple_cond_code (cond_stmt);
552 	  tree lhs = gimple_cond_lhs (cond_stmt);
553 	  tree rhs = gimple_cond_rhs (cond_stmt);
554 	  if (cfg_sedge.false_value_p ())
555 	    op = invert_tree_comparison (op, false /* honor_nans */);
556 	  return maybe_describe_condition (can_colorize,
557 					   lhs, op, rhs);
558 	}
559     }
560   return label_text::borrow (NULL);
561 }
562 
563 /* Subroutine of maybe_describe_condition above.
564 
565    Attempt to generate a user-facing description of the condition
566    LHS OP RHS, but only if it is likely to make it easier for the
567    user to understand a condition.  */
568 
569 label_text
maybe_describe_condition(bool can_colorize,tree lhs,enum tree_code op,tree rhs)570 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
571 						tree lhs,
572 						enum tree_code op,
573 						tree rhs)
574 {
575   /* In theory we could just build a tree via
576        fold_build2 (op, boolean_type_node, lhs, rhs)
577      and print it with %qE on it, but this leads to warts such as
578      parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'.  */
579 
580   /* Special-case: describe testing the result of strcmp, as figuring
581      out what the "true" or "false" path is can be confusing to the user.  */
582   if (TREE_CODE (lhs) == SSA_NAME
583       && zerop (rhs))
584     {
585       if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
586 	if (is_special_named_call_p (call, "strcmp", 2))
587 	  {
588 	    if (op == EQ_EXPR)
589 	      return label_text::borrow ("when the strings are equal");
590 	    if (op == NE_EXPR)
591 	      return label_text::borrow ("when the strings are non-equal");
592 	  }
593     }
594 
595   /* Only attempt to generate text for sufficiently simple expressions.  */
596   if (!should_print_expr_p (lhs))
597     return label_text::borrow (NULL);
598   if (!should_print_expr_p (rhs))
599     return label_text::borrow (NULL);
600 
601   /* Special cases for pointer comparisons against NULL.  */
602   if (POINTER_TYPE_P (TREE_TYPE (lhs))
603       && POINTER_TYPE_P (TREE_TYPE (rhs))
604       && zerop (rhs))
605     {
606       if (op == EQ_EXPR)
607 	return make_label_text (can_colorize, "when %qE is NULL",
608 				lhs);
609       if (op == NE_EXPR)
610 	return make_label_text (can_colorize, "when %qE is non-NULL",
611 				lhs);
612     }
613 
614   return make_label_text (can_colorize, "when %<%E %s %E%>",
615 			  lhs, op_symbol_code (op), rhs);
616 }
617 
618 /* Subroutine of maybe_describe_condition.
619 
620    Return true if EXPR is we will get suitable user-facing output
621    from %E on it.  */
622 
623 bool
should_print_expr_p(tree expr)624 start_cfg_edge_event::should_print_expr_p (tree expr)
625 {
626   if (TREE_CODE (expr) == SSA_NAME)
627     {
628       if (SSA_NAME_VAR (expr))
629 	return should_print_expr_p (SSA_NAME_VAR (expr));
630       else
631 	return false;
632     }
633 
634   if (DECL_P (expr))
635     return true;
636 
637   if (CONSTANT_CLASS_P (expr))
638     return true;
639 
640   return false;
641 }
642 
643 /* class call_event : public superedge_event.  */
644 
645 /* call_event's ctor.  */
646 
call_event(const exploded_edge & eedge,location_t loc,tree fndecl,int depth)647 call_event::call_event (const exploded_edge &eedge,
648 			location_t loc, tree fndecl, int depth)
649 : superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth)
650 {
651   if (eedge.m_sedge)
652     gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
653 
654    m_src_snode = eedge.m_src->get_supernode ();
655    m_dest_snode = eedge.m_dest->get_supernode ();
656 }
657 
658 /* Implementation of diagnostic_event::get_desc vfunc for
659    call_event.
660 
661    If this call event passes critical state for an sm-based warning,
662    allow the diagnostic to generate a precise description, such as:
663 
664      "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
665 
666    Otherwise, generate a description of the form
667    "calling 'foo' from 'bar'".  */
668 
669 label_text
get_desc(bool can_colorize) const670 call_event::get_desc (bool can_colorize) const
671 {
672   if (m_critical_state && m_pending_diagnostic)
673     {
674       gcc_assert (m_var);
675       tree var = fixup_tree_for_diagnostic (m_var);
676       label_text custom_desc
677 	= m_pending_diagnostic->describe_call_with_state
678 	    (evdesc::call_with_state (can_colorize,
679 				      m_src_snode->m_fun->decl,
680 				      m_dest_snode->m_fun->decl,
681 				      var,
682 				      m_critical_state));
683       if (custom_desc.m_buffer)
684 	return custom_desc;
685     }
686 
687   return make_label_text (can_colorize,
688 			  "calling %qE from %qE",
689 			  m_dest_snode->m_fun->decl,
690 			  m_src_snode->m_fun->decl);
691 }
692 
693 /* Override of checker_event::is_call_p for calls.  */
694 
695 bool
is_call_p() const696 call_event::is_call_p () const
697 {
698   return true;
699 }
700 
701 /* class return_event : public superedge_event.  */
702 
703 /* return_event's ctor.  */
704 
return_event(const exploded_edge & eedge,location_t loc,tree fndecl,int depth)705 return_event::return_event (const exploded_edge &eedge,
706 			    location_t loc, tree fndecl, int depth)
707 : superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth)
708 {
709   if (eedge.m_sedge)
710     gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
711 
712   m_src_snode = eedge.m_src->get_supernode ();
713   m_dest_snode = eedge.m_dest->get_supernode ();
714 }
715 
716 /* Implementation of diagnostic_event::get_desc vfunc for
717    return_event.
718 
719    If this return event returns critical state for an sm-based warning,
720    allow the diagnostic to generate a precise description, such as:
721 
722       "possible of NULL to 'foo' from 'bar'"
723 
724    Otherwise, generate a description of the form
725    "returning to 'foo' from 'bar'.  */
726 
727 label_text
get_desc(bool can_colorize) const728 return_event::get_desc (bool can_colorize) const
729 {
730   /*  For greatest precision-of-wording, if this is returning the
731       state involved in the pending diagnostic, give the pending
732       diagnostic a chance to describe this return (in terms of
733       itself).  */
734   if (m_critical_state && m_pending_diagnostic)
735     {
736       label_text custom_desc
737 	= m_pending_diagnostic->describe_return_of_state
738 	    (evdesc::return_of_state (can_colorize,
739 				      m_dest_snode->m_fun->decl,
740 				      m_src_snode->m_fun->decl,
741 				      m_critical_state));
742       if (custom_desc.m_buffer)
743 	return custom_desc;
744     }
745   return make_label_text (can_colorize,
746 			  "returning to %qE from %qE",
747 			  m_dest_snode->m_fun->decl,
748 			  m_src_snode->m_fun->decl);
749 }
750 
751 /* Override of checker_event::is_return_p for returns.  */
752 
753 bool
is_return_p() const754 return_event::is_return_p () const
755 {
756   return true;
757 }
758 
759 /* class start_consolidated_cfg_edges_event : public checker_event.  */
760 
761 label_text
get_desc(bool can_colorize) const762 start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
763 {
764   return make_label_text (can_colorize,
765 			  "following %qs branch...",
766 			  m_edge_sense ? "true" : "false");
767 }
768 
769 /* class setjmp_event : public checker_event.  */
770 
771 /* Implementation of diagnostic_event::get_desc vfunc for
772    setjmp_event.  */
773 
774 label_text
get_desc(bool can_colorize) const775 setjmp_event::get_desc (bool can_colorize) const
776 {
777   return make_label_text (can_colorize,
778 			  "%qs called here",
779 			  get_user_facing_name (m_setjmp_call));
780 }
781 
782 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
783 
784    Record this setjmp's event ID into the path, so that rewind events can
785    use it.  */
786 
787 void
prepare_for_emission(checker_path * path,pending_diagnostic * pd,diagnostic_event_id_t emission_id)788 setjmp_event::prepare_for_emission (checker_path *path,
789 				    pending_diagnostic *pd,
790 				    diagnostic_event_id_t emission_id)
791 {
792   checker_event::prepare_for_emission (path, pd, emission_id);
793   path->record_setjmp_event (m_enode, emission_id);
794 }
795 
796 /* class rewind_event : public checker_event.  */
797 
798 /* Get the fndecl containing the site of the longjmp call.  */
799 
800 tree
get_longjmp_caller() const801 rewind_event::get_longjmp_caller () const
802 {
803   return m_eedge->m_src->get_function ()->decl;
804 }
805 
806 /* Get the fndecl containing the site of the setjmp call.  */
807 
808 tree
get_setjmp_caller() const809 rewind_event::get_setjmp_caller () const
810 {
811   return m_eedge->m_dest->get_function ()->decl;
812 }
813 
814 /* rewind_event's ctor.  */
815 
rewind_event(const exploded_edge * eedge,enum event_kind kind,location_t loc,tree fndecl,int depth,const rewind_info_t * rewind_info)816 rewind_event::rewind_event (const exploded_edge *eedge,
817 			    enum event_kind kind,
818 			    location_t loc, tree fndecl, int depth,
819 			    const rewind_info_t *rewind_info)
820 : checker_event (kind, loc, fndecl, depth),
821   m_rewind_info (rewind_info),
822   m_eedge (eedge)
823 {
824   gcc_assert (m_eedge->m_custom_info == m_rewind_info);
825 }
826 
827 /* class rewind_from_longjmp_event : public rewind_event.  */
828 
829 /* Implementation of diagnostic_event::get_desc vfunc for
830    rewind_from_longjmp_event.  */
831 
832 label_text
get_desc(bool can_colorize) const833 rewind_from_longjmp_event::get_desc (bool can_colorize) const
834 {
835   const char *src_name
836     = get_user_facing_name (m_rewind_info->get_longjmp_call ());
837 
838   if (get_longjmp_caller () == get_setjmp_caller ())
839     /* Special-case: purely intraprocedural rewind.  */
840     return make_label_text (can_colorize,
841 			    "rewinding within %qE from %qs...",
842 			    get_longjmp_caller (),
843 			    src_name);
844   else
845     return make_label_text (can_colorize,
846 			    "rewinding from %qs in %qE...",
847 			    src_name,
848 			    get_longjmp_caller ());
849 }
850 
851 /* class rewind_to_setjmp_event : public rewind_event.  */
852 
853 /* Implementation of diagnostic_event::get_desc vfunc for
854    rewind_to_setjmp_event.  */
855 
856 label_text
get_desc(bool can_colorize) const857 rewind_to_setjmp_event::get_desc (bool can_colorize) const
858 {
859   const char *dst_name
860     = get_user_facing_name (m_rewind_info->get_setjmp_call ());
861 
862   /* If we can, identify the ID of the setjmp_event.  */
863   if (m_original_setjmp_event_id.known_p ())
864     {
865       if (get_longjmp_caller () == get_setjmp_caller ())
866 	/* Special-case: purely intraprocedural rewind.  */
867 	return make_label_text (can_colorize,
868 				"...to %qs (saved at %@)",
869 				dst_name,
870 				&m_original_setjmp_event_id);
871       else
872 	return make_label_text (can_colorize,
873 				"...to %qs in %qE (saved at %@)",
874 				dst_name,
875 				get_setjmp_caller (),
876 				&m_original_setjmp_event_id);
877     }
878   else
879     {
880       if (get_longjmp_caller () == get_setjmp_caller ())
881 	/* Special-case: purely intraprocedural rewind.  */
882 	return make_label_text (can_colorize,
883 				"...to %qs",
884 				dst_name,
885 				get_setjmp_caller ());
886       else
887 	return make_label_text (can_colorize,
888 				"...to %qs in %qE",
889 				dst_name,
890 				get_setjmp_caller ());
891     }
892 }
893 
894 /* Implementation of checker_event::prepare_for_emission vfunc for
895    rewind_to_setjmp_event.
896 
897    Attempt to look up the setjmp event ID that recorded the jmp_buf
898    for this rewind.  */
899 
900 void
prepare_for_emission(checker_path * path,pending_diagnostic * pd,diagnostic_event_id_t emission_id)901 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
902 					      pending_diagnostic *pd,
903 					      diagnostic_event_id_t emission_id)
904 {
905   checker_event::prepare_for_emission (path, pd, emission_id);
906   path->get_setjmp_event (m_rewind_info->get_enode_origin (),
907 			  &m_original_setjmp_event_id);
908 }
909 
910 /* class warning_event : public checker_event.  */
911 
912 /* Implementation of diagnostic_event::get_desc vfunc for
913    warning_event.
914 
915    If the pending diagnostic implements describe_final_event, use it,
916    generating a precise description e.g.
917      "second 'free' here; first 'free' was at (7)"
918 
919    Otherwise generate a generic description.  */
920 
921 label_text
get_desc(bool can_colorize) const922 warning_event::get_desc (bool can_colorize) const
923 {
924   if (m_pending_diagnostic)
925     {
926       tree var = fixup_tree_for_diagnostic (m_var);
927       label_text ev_desc
928 	= m_pending_diagnostic->describe_final_event
929 	    (evdesc::final_event (can_colorize, var, m_state));
930       if (ev_desc.m_buffer)
931 	{
932 	  if (m_sm && flag_analyzer_verbose_state_changes)
933 	    {
934 	      label_text result;
935 	      if (var)
936 		result = make_label_text (can_colorize,
937 					  "%s (%qE is in state %qs)",
938 					  ev_desc.m_buffer,
939 					  var, m_state->get_name ());
940 	      else
941 		result = make_label_text (can_colorize,
942 					  "%s (in global state %qs)",
943 					  ev_desc.m_buffer,
944 					  m_state->get_name ());
945 	      ev_desc.maybe_free ();
946 	      return result;
947 	    }
948 	  else
949 	    return ev_desc;
950 	}
951     }
952 
953   if (m_sm)
954     {
955       if (m_var)
956 	return make_label_text (can_colorize,
957 				"here (%qE is in state %qs)",
958 				m_var, m_state->get_name ());
959       else
960 	return make_label_text (can_colorize,
961 				"here (in global state %qs)",
962 				m_state->get_name ());
963     }
964   else
965     return label_text::borrow ("here");
966 }
967 
968 /* Print a single-line representation of this path to PP.  */
969 
970 void
dump(pretty_printer * pp) const971 checker_path::dump (pretty_printer *pp) const
972 {
973   pp_character (pp, '[');
974 
975   checker_event *e;
976   int i;
977   FOR_EACH_VEC_ELT (m_events, i, e)
978     {
979       if (i > 0)
980 	pp_string (pp, ", ");
981       label_text event_desc (e->get_desc (false));
982       pp_printf (pp, "\"%s\"", event_desc.m_buffer);
983       event_desc.maybe_free ();
984     }
985   pp_character (pp, ']');
986 }
987 
988 /* Print a multiline form of this path to LOGGER, prefixing it with DESC.  */
989 
990 void
maybe_log(logger * logger,const char * desc) const991 checker_path::maybe_log (logger *logger, const char *desc) const
992 {
993   if (!logger)
994     return;
995   logger->start_log_line ();
996   logger->log_partial ("%s: ", desc);
997   dump (logger->get_printer ());
998   logger->end_log_line ();
999   for (unsigned i = 0; i < m_events.length (); i++)
1000     {
1001       logger->start_log_line ();
1002       logger->log_partial ("%s[%i]: %s ", desc, i,
1003 			   event_kind_to_string (m_events[i]->m_kind));
1004       m_events[i]->dump (logger->get_printer ());
1005       logger->end_log_line ();
1006     }
1007 }
1008 
1009 /* Print a multiline form of this path to STDERR.  */
1010 
1011 DEBUG_FUNCTION void
debug() const1012 checker_path::debug () const
1013 {
1014   checker_event *e;
1015   int i;
1016   FOR_EACH_VEC_ELT (m_events, i, e)
1017     {
1018       label_text event_desc (e->get_desc (false));
1019       fprintf (stderr,
1020 	       "[%i]: %s \"%s\"\n",
1021 	       i,
1022 	       event_kind_to_string (m_events[i]->m_kind),
1023 	       event_desc.m_buffer);
1024       event_desc.maybe_free ();
1025     }
1026 }
1027 
1028 /* Add region_creation_event instance to this path for REG,
1029    describing whether REG is on the stack or heap.  */
1030 
1031 void
add_region_creation_event(const region * reg,location_t loc,tree fndecl,int depth)1032 checker_path::add_region_creation_event (const region *reg,
1033 					 location_t loc,
1034 					 tree fndecl, int depth)
1035 {
1036   add_event (new region_creation_event (reg, loc, fndecl, depth));
1037 }
1038 
1039 /* Add a warning_event to the end of this path.  */
1040 
1041 void
add_final_event(const state_machine * sm,const exploded_node * enode,const gimple * stmt,tree var,state_machine::state_t state)1042 checker_path::add_final_event (const state_machine *sm,
1043 			       const exploded_node *enode, const gimple *stmt,
1044 			       tree var, state_machine::state_t state)
1045 {
1046   checker_event *end_of_path
1047     = new warning_event (get_stmt_location (stmt, enode->get_function ()),
1048 			 enode->get_function ()->decl,
1049 			 enode->get_stack_depth (),
1050 			 sm, var, state);
1051   add_event (end_of_path);
1052 }
1053 
1054 void
fixup_locations(pending_diagnostic * pd)1055 checker_path::fixup_locations (pending_diagnostic *pd)
1056 {
1057   for (checker_event *e : m_events)
1058     e->set_location (pd->fixup_location (e->get_location ()));
1059 }
1060 
1061 /* Return true if there is a (start_cfg_edge_event, end_cfg_edge_event) pair
1062    at (IDX, IDX + 1).  */
1063 
1064 bool
cfg_edge_pair_at_p(unsigned idx) const1065 checker_path::cfg_edge_pair_at_p (unsigned idx) const
1066 {
1067   if (m_events.length () < idx + 1)
1068     return false;
1069   return (m_events[idx]->m_kind == EK_START_CFG_EDGE
1070 	  && m_events[idx + 1]->m_kind == EK_END_CFG_EDGE);
1071 }
1072 
1073 } // namespace ana
1074 
1075 #endif /* #if ENABLE_ANALYZER */
1076