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