Branch data Line data Source code
1 : : /* Subclasses of diagnostics::paths::event for analyzer diagnostics.
2 : : Copyright (C) 2019-2025 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 "analyzer/common.h"
22 : :
23 : : #include "gimple-pretty-print.h"
24 : : #include "sbitmap.h"
25 : : #include "ordered-hash-map.h"
26 : : #include "fold-const.h"
27 : : #include "gimple-iterator.h"
28 : : #include "inlining-iterator.h"
29 : : #include "tree-logical-location.h"
30 : : #include "diagnostics/sarif-sink.h"
31 : : #include "diagnostics/state-graphs.h"
32 : :
33 : : #include "analyzer/analyzer-logging.h"
34 : : #include "analyzer/sm.h"
35 : : #include "analyzer/call-string.h"
36 : : #include "analyzer/program-point.h"
37 : : #include "analyzer/store.h"
38 : : #include "analyzer/region-model.h"
39 : : #include "analyzer/program-state.h"
40 : : #include "analyzer/checker-path.h"
41 : : #include "analyzer/supergraph.h"
42 : : #include "analyzer/pending-diagnostic.h"
43 : : #include "analyzer/diagnostic-manager.h"
44 : : #include "analyzer/constraint-manager.h"
45 : : #include "analyzer/checker-event.h"
46 : : #include "analyzer/exploded-graph.h"
47 : :
48 : : #if ENABLE_ANALYZER
49 : :
50 : : namespace ana {
51 : :
52 : : /* Get a string for EK. */
53 : :
54 : : const char *
55 : 81 : event_kind_to_string (enum event_kind ek)
56 : : {
57 : 81 : switch (ek)
58 : : {
59 : 0 : default:
60 : 0 : gcc_unreachable ();
61 : : case event_kind::debug:
62 : : return "debug";
63 : 0 : case event_kind::custom:
64 : 0 : return "custom";
65 : 0 : case event_kind::stmt:
66 : 0 : return "stmt";
67 : 12 : case event_kind::region_creation:
68 : 12 : return "region_creation";
69 : 4 : case event_kind::function_entry:
70 : 4 : return "function_entry";
71 : 20 : case event_kind::state_change:
72 : 20 : return "state_change";
73 : 10 : case event_kind::start_cfg_edge:
74 : 10 : return "start_cfg_edge";
75 : 10 : case event_kind::end_cfg_edge:
76 : 10 : return "end_cfg_edge";
77 : 0 : case event_kind::catch_:
78 : 0 : return "catch";
79 : 3 : case event_kind::call_edge:
80 : 3 : return "call_edge";
81 : 3 : case event_kind::return_edge:
82 : 3 : return "return_edge";
83 : 0 : case event_kind::start_consolidated_cfg_edges:
84 : 0 : return "start_consolidated_cfg_edges";
85 : 0 : case event_kind::end_consolidated_cfg_edges:
86 : 0 : return "end_consolidated_cfg_edges";
87 : 0 : case event_kind::inlined_call:
88 : 0 : return "inlined_call";
89 : 0 : case event_kind::setjmp_:
90 : 0 : return "setjmp";
91 : 0 : case event_kind::rewind_from_longjmp:
92 : 0 : return "rewind_from_longjmp";
93 : 0 : case event_kind::rewind_to_setjmp:
94 : 0 : return "rewind_to_setjmp";
95 : 0 : case event_kind::throw_:
96 : 0 : return "throw";
97 : 0 : case event_kind::unwind:
98 : 0 : return "unwind";
99 : 19 : case event_kind::warning:
100 : 19 : return "warning";
101 : : }
102 : : }
103 : :
104 : : /* class checker_event : public diagnostics::paths::event. */
105 : :
106 : : /* checker_event's ctor. */
107 : :
108 : 59828 : checker_event::checker_event (enum event_kind kind,
109 : 59828 : const event_loc_info &loc_info)
110 : 59828 : : m_path (nullptr),
111 : 59828 : m_kind (kind), m_loc (loc_info.m_loc),
112 : 59828 : m_original_fndecl (loc_info.m_fndecl),
113 : 59828 : m_effective_fndecl (loc_info.m_fndecl),
114 : 59828 : m_original_depth (loc_info.m_depth),
115 : 59828 : m_effective_depth (loc_info.m_depth),
116 : 59828 : m_pending_diagnostic (nullptr), m_emission_id (),
117 : : m_logical_loc
118 : 59828 : (tree_logical_location_manager::key_from_tree (loc_info.m_fndecl))
119 : : {
120 : : /* Update effective fndecl and depth if inlining has been recorded. */
121 : 59828 : if (flag_analyzer_undo_inlining)
122 : : {
123 : 59800 : inlining_info info (m_loc);
124 : 59800 : if (info.get_inner_fndecl ())
125 : : {
126 : 44927 : m_effective_fndecl = info.get_inner_fndecl ();
127 : 44927 : m_effective_depth += info.get_extra_frames ();
128 : 44927 : m_logical_loc
129 : 44927 : = tree_logical_location_manager::key_from_tree (m_effective_fndecl);
130 : : }
131 : : }
132 : 59828 : }
133 : :
134 : : /* No-op implementation of diagnostics::paths::event::get_meaning vfunc for
135 : : checker_event: checker events have no meaning by default. */
136 : :
137 : : diagnostics::paths::event::meaning
138 : 92 : checker_event::get_meaning () const
139 : : {
140 : 92 : return diagnostics::paths::event::meaning ();
141 : : }
142 : :
143 : : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
144 : : for checker_event. */
145 : :
146 : : void
147 : 81 : checker_event::
148 : : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
149 : : diagnostics::sarif_object &thread_flow_loc_obj) const
150 : : {
151 : 81 : auto &props = thread_flow_loc_obj.get_or_create_properties ();
152 : : #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
153 : 162 : props.set (PROPERTY_PREFIX "emission_id",
154 : 81 : diagnostic_event_id_to_json (m_emission_id));
155 : 81 : props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
156 : :
157 : 81 : if (m_original_fndecl != m_effective_fndecl)
158 : 0 : props.set_logical_location
159 : 0 : (PROPERTY_PREFIX "original_fndecl",
160 : : builder,
161 : 0 : tree_logical_location_manager::key_from_tree (m_original_fndecl));
162 : :
163 : 81 : if (m_original_depth != m_effective_depth)
164 : 0 : props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
165 : : #undef PROPERTY_PREFIX
166 : 81 : }
167 : :
168 : : /* Dump this event to PP (for debugging/logging purposes). */
169 : :
170 : : void
171 : 0 : checker_event::dump (pretty_printer *pp) const
172 : : {
173 : 0 : pp_character (pp, '"');
174 : 0 : print_desc (*pp);
175 : 0 : pp_printf (pp, "\" (depth %i", m_effective_depth);
176 : :
177 : 0 : if (m_effective_depth != m_original_depth)
178 : 0 : pp_printf (pp, " corrected from %i",
179 : : m_original_depth);
180 : 0 : if (m_effective_fndecl)
181 : : {
182 : 0 : pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
183 : 0 : if (m_effective_fndecl != m_original_fndecl)
184 : 0 : pp_printf (pp, " corrected from %qE", m_original_fndecl);
185 : : }
186 : 0 : pp_printf (pp, ", m_loc=%llx)",
187 : 0 : (unsigned long long) get_location ());
188 : 0 : }
189 : :
190 : : /* Dump this event to stderr (for debugging/logging purposes). */
191 : :
192 : : DEBUG_FUNCTION void
193 : 0 : checker_event::debug () const
194 : : {
195 : 0 : tree_dump_pretty_printer pp (stderr);
196 : 0 : dump (&pp);
197 : 0 : pp_newline (&pp);
198 : 0 : }
199 : :
200 : : /* Hook for being notified when this event has its final id EMISSION_ID
201 : : and is about to emitted for PD.
202 : :
203 : : Base implementation of checker_event::prepare_for_emission vfunc;
204 : : subclasses that override this should chain up to it.
205 : :
206 : : Record PD and EMISSION_ID, and call the print_desc vfunc, so that any
207 : : side-effects of the call to print_desc take place before
208 : : pending_diagnostic::emit is called.
209 : :
210 : : For example, state_change_event::print_desc can call
211 : : pending_diagnostic::describe_state_change; free_of_non_heap can use this
212 : : to tweak the message (TODO: would be neater to simply capture the
213 : : pertinent data within the sm-state). */
214 : :
215 : : void
216 : 17146 : checker_event::prepare_for_emission (checker_path *path,
217 : : pending_diagnostic *pd,
218 : : diagnostics::paths::event_id_t emission_id)
219 : : {
220 : 17146 : m_path = path;
221 : 17146 : m_pending_diagnostic = pd;
222 : 17146 : m_emission_id = emission_id;
223 : :
224 : 17146 : auto pp = global_dc->clone_printer ();
225 : 17146 : print_desc (*pp.get ());
226 : 17146 : }
227 : :
228 : : std::unique_ptr<diagnostics::digraphs::digraph>
229 : 28 : checker_event::maybe_make_diagnostic_state_graph (bool debug) const
230 : : {
231 : 28 : const program_state *state = get_program_state ();
232 : 28 : if (!state)
233 : 0 : return nullptr;
234 : :
235 : 28 : gcc_assert (m_path);
236 : 28 : const extrinsic_state &ext_state = m_path->get_ext_state ();
237 : :
238 : 28 : auto result = state->make_diagnostic_state_graph (ext_state);
239 : :
240 : 28 : if (debug)
241 : : {
242 : 27 : pretty_printer pp;
243 : 27 : text_art::theme *theme = global_dc->get_diagram_theme ();
244 : 27 : text_art::dump_to_pp (*state, theme, &pp);
245 : 27 : result->set_attr (STATE_GRAPH_PREFIX,
246 : : "analyzer/program_state/",
247 : : pp_formatted_text (&pp));
248 : 27 : }
249 : :
250 : 28 : return result;
251 : 28 : }
252 : :
253 : : /* class debug_event : public checker_event. */
254 : :
255 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
256 : : debug_event.
257 : : Use the saved string as the event's description. */
258 : :
259 : : void
260 : 0 : debug_event::print_desc (pretty_printer &pp) const
261 : : {
262 : 0 : pp_string (&pp, m_desc);
263 : 0 : }
264 : :
265 : : /* class precanned_custom_event : public custom_event. */
266 : :
267 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
268 : : precanned_custom_event.
269 : : Use the saved string as the event's description. */
270 : :
271 : : void
272 : 40 : precanned_custom_event::print_desc (pretty_printer &pp) const
273 : : {
274 : 40 : pp_string (&pp, m_desc);
275 : 40 : }
276 : :
277 : : /* class statement_event : public checker_event. */
278 : :
279 : : /* statement_event's ctor. */
280 : :
281 : 18788 : statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
282 : 18788 : const program_state &dst_state)
283 : : : checker_event (event_kind::stmt,
284 : 18788 : event_loc_info (gimple_location (stmt), fndecl, depth)),
285 : 18788 : m_stmt (stmt),
286 : 18788 : m_dst_state (dst_state)
287 : : {
288 : 18788 : }
289 : :
290 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
291 : : statement_event.
292 : : Use the statement's dump form as the event's description. */
293 : :
294 : : void
295 : 0 : statement_event::print_desc (pretty_printer &pp) const
296 : : {
297 : 0 : pp_string (&pp, "stmt: ");
298 : 0 : pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
299 : 0 : }
300 : :
301 : : /* class region_creation_event : public checker_event. */
302 : :
303 : 1539 : region_creation_event::region_creation_event (const event_loc_info &loc_info)
304 : 1539 : : checker_event (event_kind::region_creation, loc_info)
305 : : {
306 : 1539 : }
307 : :
308 : : /* The various region_creation_event subclasses' print_desc
309 : : implementations. */
310 : :
311 : : void
312 : 1184 : region_creation_event_memory_space::print_desc (pretty_printer &pp) const
313 : : {
314 : 1184 : switch (m_mem_space)
315 : : {
316 : 28 : default:
317 : 28 : pp_string (&pp, "region created here");
318 : 28 : return;
319 : 1058 : case MEMSPACE_STACK:
320 : 1058 : pp_string (&pp, "region created on stack here");
321 : 1058 : return;
322 : 98 : case MEMSPACE_HEAP:
323 : 98 : pp_string (&pp, "region created on heap here");
324 : 98 : return;
325 : : }
326 : : }
327 : :
328 : : void
329 : 1600 : region_creation_event_capacity::print_desc (pretty_printer &pp) const
330 : : {
331 : 1600 : gcc_assert (m_capacity);
332 : 1600 : if (TREE_CODE (m_capacity) == INTEGER_CST)
333 : : {
334 : 1404 : unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
335 : 1404 : return pp_printf_n (&pp,
336 : : hwi,
337 : : "capacity: %wu byte",
338 : : "capacity: %wu bytes",
339 : 1404 : hwi);
340 : : }
341 : : else
342 : 196 : return pp_printf (&pp, "capacity: %qE bytes", m_capacity);
343 : : }
344 : :
345 : : void
346 : 182 : region_creation_event_allocation_size::print_desc (pretty_printer &pp) const
347 : : {
348 : 182 : if (m_capacity)
349 : : {
350 : 174 : if (TREE_CODE (m_capacity) == INTEGER_CST)
351 : 118 : pp_printf_n (&pp,
352 : : tree_to_uhwi (m_capacity),
353 : : "allocated %E byte here",
354 : : "allocated %E bytes here",
355 : : m_capacity);
356 : : else
357 : 56 : pp_printf (&pp,
358 : : "allocated %qE bytes here",
359 : : m_capacity);
360 : : }
361 : 182 : pp_printf (&pp, "allocated here");
362 : 182 : }
363 : :
364 : : void
365 : 0 : region_creation_event_debug::print_desc (pretty_printer &pp) const
366 : : {
367 : 0 : pp_string (&pp, "region creation: ");
368 : 0 : m_reg->dump_to_pp (&pp, true);
369 : 0 : if (m_capacity)
370 : 0 : pp_printf (&pp, " capacity: %qE", m_capacity);
371 : 0 : }
372 : :
373 : : /* class function_entry_event : public checker_event. */
374 : :
375 : 5235 : function_entry_event::function_entry_event (const program_point &dst_point,
376 : 5235 : const program_state &state)
377 : : : checker_event (event_kind::function_entry,
378 : 5235 : event_loc_info (dst_point.get_supernode
379 : : ()->get_start_location (),
380 : : dst_point.get_fndecl (),
381 : 5235 : dst_point.get_stack_depth ())),
382 : 10470 : m_state (state)
383 : : {
384 : 5235 : }
385 : :
386 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
387 : : function_entry_event.
388 : :
389 : : Use a string such as "entry to 'foo'" as the event's description. */
390 : :
391 : : void
392 : 2828 : function_entry_event::print_desc (pretty_printer &pp) const
393 : : {
394 : 2828 : pp_printf (&pp, "entry to %qE", m_effective_fndecl);
395 : 2828 : }
396 : :
397 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
398 : : function entry. */
399 : :
400 : : diagnostics::paths::event::meaning
401 : 203 : function_entry_event::get_meaning () const
402 : : {
403 : 203 : return meaning (verb::enter, noun::function);
404 : : }
405 : :
406 : : /* class state_change_event : public checker_event. */
407 : :
408 : : /* state_change_event's ctor. */
409 : :
410 : 4728 : state_change_event::state_change_event (const supernode *node,
411 : : const gimple *stmt,
412 : : int stack_depth,
413 : : const state_machine &sm,
414 : : const svalue *sval,
415 : : state_machine::state_t from,
416 : : state_machine::state_t to,
417 : : const svalue *origin,
418 : : const program_state &dst_state,
419 : 4728 : const exploded_node *enode)
420 : : : checker_event (event_kind::state_change,
421 : 9456 : event_loc_info (stmt->location,
422 : 4728 : node->m_fun->decl,
423 : 4728 : stack_depth)),
424 : 4728 : m_node (node), m_stmt (stmt), m_sm (sm),
425 : 4728 : m_sval (sval), m_from (from), m_to (to),
426 : 4728 : m_origin (origin),
427 : 4728 : m_dst_state (dst_state),
428 : 4728 : m_enode (enode)
429 : : {
430 : 4728 : }
431 : :
432 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
433 : : state_change_event.
434 : :
435 : : Attempt to generate a nicer human-readable description.
436 : : For greatest precision-of-wording, give the pending diagnostic
437 : : a chance to describe this state change (in terms of the
438 : : diagnostic).
439 : : Note that we only have a pending_diagnostic set on the event once
440 : : the diagnostic is about to being emitted, so the description for
441 : : an event can change. */
442 : :
443 : : void
444 : 4538 : state_change_event::print_desc (pretty_printer &pp) const
445 : : {
446 : 4538 : if (m_pending_diagnostic)
447 : : {
448 : 4538 : region_model *model = m_dst_state.m_region_model;
449 : 4538 : tree var = model->get_representative_tree (m_sval);
450 : 4538 : tree origin = model->get_representative_tree (m_origin);
451 : 4538 : evdesc::state_change evd (var, origin,
452 : 4538 : m_from, m_to, m_emission_id, *this);
453 : 4538 : if (m_pending_diagnostic->describe_state_change (pp, evd))
454 : : {
455 : 4536 : if (flag_analyzer_verbose_state_changes)
456 : : {
457 : : /* Append debugging information about this event. */
458 : :
459 : 144 : if (var)
460 : 136 : pp_printf (&pp, " (state of %qE: ", var);
461 : : else
462 : 8 : pp_string (&pp, " (state: ");
463 : :
464 : 144 : pp_printf (&pp, "%qs -> %qs, ",
465 : 144 : m_from->get_name (),
466 : 144 : m_to->get_name ());
467 : :
468 : 144 : if (m_origin)
469 : 0 : pp_printf (&pp, "origin: %qE", origin);
470 : : else
471 : 144 : pp_string (&pp, "NULL origin");
472 : :
473 : : /* Get any "meaning" of event. */
474 : 144 : diagnostics::paths::event::meaning meaning = get_meaning ();
475 : 144 : pp_string (&pp, ", meaning: ");
476 : 144 : meaning.dump_to_pp (&pp);
477 : 144 : pp_string (&pp, ")");
478 : : }
479 : 4536 : return;
480 : : }
481 : : }
482 : :
483 : : /* Fallback description. */
484 : 2 : if (m_sval)
485 : : {
486 : 2 : label_text sval_desc = m_sval->get_desc ();
487 : 2 : pp_printf (&pp,
488 : : "state of %qs: %qs -> %qs",
489 : : sval_desc.get (),
490 : 2 : m_from->get_name (),
491 : 2 : m_to->get_name ());
492 : 2 : if (m_origin)
493 : : {
494 : 0 : label_text origin_desc = m_origin->get_desc ();
495 : 0 : pp_printf (&pp, " (origin: %qs)",
496 : : origin_desc.get ());
497 : 0 : }
498 : : else
499 : 2 : pp_string (&pp, " (NULL origin)");
500 : 2 : }
501 : : else
502 : : {
503 : 0 : gcc_assert (m_origin == nullptr);
504 : 0 : pp_printf (&pp,
505 : : "global state: %qs -> %qs",
506 : 0 : m_from->get_name (),
507 : 0 : m_to->get_name ());
508 : : }
509 : : }
510 : :
511 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
512 : : state change events: delegate to the pending_diagnostic to
513 : : get any meaning. */
514 : :
515 : : diagnostics::paths::event::meaning
516 : 330 : state_change_event::get_meaning () const
517 : : {
518 : 330 : if (m_pending_diagnostic)
519 : : {
520 : 330 : region_model *model = m_dst_state.m_region_model;
521 : 330 : tree var = model->get_representative_tree (m_sval);
522 : 330 : tree origin = model->get_representative_tree (m_origin);
523 : 330 : evdesc::state_change evd (var, origin,
524 : 330 : m_from, m_to, m_emission_id, *this);
525 : 330 : return m_pending_diagnostic->get_meaning_for_state_change (evd);
526 : : }
527 : : else
528 : 0 : return meaning ();
529 : : }
530 : :
531 : : /* class superedge_event : public checker_event. */
532 : :
533 : : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
534 : : for superedge_event. */
535 : :
536 : : void
537 : 26 : superedge_event::
538 : : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
539 : : diagnostics::sarif_object &thread_flow_loc_obj)
540 : : const
541 : : {
542 : 26 : checker_event::maybe_add_sarif_properties (builder, thread_flow_loc_obj);
543 : 26 : auto &props = thread_flow_loc_obj.get_or_create_properties ();
544 : : #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
545 : 26 : if (m_sedge)
546 : 26 : props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
547 : : #undef PROPERTY_PREFIX
548 : 26 : }
549 : :
550 : : /* Get the callgraph_superedge for this superedge_event, which must be
551 : : for an interprocedural edge, rather than a CFG edge. */
552 : :
553 : : const callgraph_superedge&
554 : 1683 : superedge_event::get_callgraph_superedge () const
555 : : {
556 : 1683 : gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
557 : 1683 : return *m_sedge->dyn_cast_callgraph_superedge ();
558 : : }
559 : :
560 : : /* Determine if this event should be filtered at the given verbosity
561 : : level. */
562 : :
563 : : bool
564 : 11025 : superedge_event::should_filter_p (int verbosity) const
565 : : {
566 : 11025 : switch (m_sedge->m_kind)
567 : : {
568 : 11025 : case SUPEREDGE_CFG_EDGE:
569 : 11025 : {
570 : 11025 : if (verbosity < 2)
571 : : return true;
572 : :
573 : 10828 : if (verbosity < 4)
574 : : {
575 : : /* Filter events with empty descriptions. This ought to filter
576 : : FALLTHRU, but retain true/false/switch edges. */
577 : 10828 : auto pp = global_dc->clone_printer ();
578 : 10828 : print_desc (*pp.get ());
579 : 10828 : if (pp_formatted_text (pp.get ()) [0] == '\0')
580 : 8164 : return true;
581 : 10828 : }
582 : : }
583 : : break;
584 : :
585 : : default:
586 : : break;
587 : : }
588 : : return false;
589 : : }
590 : :
591 : : const program_state *
592 : 15 : superedge_event::get_program_state () const
593 : : {
594 : 15 : return &m_eedge.m_dest->get_state ();
595 : : }
596 : :
597 : : /* superedge_event's ctor. */
598 : :
599 : 24276 : superedge_event::superedge_event (enum event_kind kind,
600 : : const exploded_edge &eedge,
601 : 24276 : const event_loc_info &loc_info)
602 : : : checker_event (kind, loc_info),
603 : 24276 : m_eedge (eedge), m_sedge (eedge.m_sedge),
604 : 24276 : m_var (NULL_TREE), m_critical_state (0)
605 : : {
606 : : /* Note that m_sedge can be nullptr for e.g. jumps through
607 : : function pointers. */
608 : 24276 : }
609 : :
610 : : /* class cfg_edge_event : public superedge_event. */
611 : :
612 : : /* Get the cfg_superedge for this cfg_edge_event. */
613 : :
614 : : const cfg_superedge &
615 : 8206 : cfg_edge_event::get_cfg_superedge () const
616 : : {
617 : 8206 : return *m_sedge->dyn_cast_cfg_superedge ();
618 : : }
619 : :
620 : : /* cfg_edge_event's ctor. */
621 : :
622 : 22359 : cfg_edge_event::cfg_edge_event (enum event_kind kind,
623 : : const exploded_edge &eedge,
624 : 22359 : const event_loc_info &loc_info)
625 : 22359 : : superedge_event (kind, eedge, loc_info)
626 : : {
627 : 22359 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
628 : 22359 : }
629 : :
630 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
631 : : CFG edge events. */
632 : :
633 : : diagnostics::paths::event::meaning
634 : 282 : cfg_edge_event::get_meaning () const
635 : : {
636 : 282 : const cfg_superedge& cfg_sedge = get_cfg_superedge ();
637 : 282 : if (cfg_sedge.true_value_p ())
638 : 116 : return meaning (verb::branch, property::true_);
639 : 166 : else if (cfg_sedge.false_value_p ())
640 : 126 : return meaning (verb::branch, property::false_);
641 : : else
642 : 40 : return meaning ();
643 : : }
644 : :
645 : : /* class start_cfg_edge_event : public cfg_edge_event. */
646 : :
647 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
648 : : start_cfg_edge_event.
649 : :
650 : : If -fanalyzer-verbose-edges, then generate low-level descriptions, such
651 : : as
652 : : "taking 'true' edge SN:7 -> SN:8".
653 : :
654 : : Otherwise, generate strings using the label of the underlying CFG if
655 : : any, such as:
656 : : "following 'true' branch..." or
657 : : "following 'case 3' branch..."
658 : : "following 'default' branch..."
659 : :
660 : : For conditionals, attempt to supply a description of the condition that
661 : : holds, such as:
662 : : "following 'false' branch (when 'ptr' is non-NULL)..."
663 : :
664 : : Failing that, print nothing (which will lead to this event
665 : : being filtered). */
666 : :
667 : : void
668 : 15604 : start_cfg_edge_event::print_desc (pretty_printer &pp) const
669 : : {
670 : 15604 : bool user_facing = !flag_analyzer_verbose_edges;
671 : 15604 : label_text edge_desc (m_sedge->get_description (user_facing));
672 : 15604 : if (user_facing)
673 : : {
674 : 15604 : if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
675 : : {
676 : 7440 : label_text cond_desc = maybe_describe_condition (pp_show_color (&pp));
677 : 7440 : label_text result;
678 : 7440 : if (cond_desc.get ())
679 : 4031 : pp_printf (&pp,
680 : : "following %qs branch (%s)...",
681 : : edge_desc.get (), cond_desc.get ());
682 : : else
683 : 3409 : pp_printf (&pp,
684 : : "following %qs branch...",
685 : : edge_desc.get ());
686 : 11411 : }
687 : : }
688 : : else
689 : : {
690 : 0 : if (strlen (edge_desc.get ()) > 0)
691 : 0 : return pp_printf (&pp,
692 : : "taking %qs edge SN:%i -> SN:%i",
693 : : edge_desc.get (),
694 : 0 : m_sedge->m_src->m_index,
695 : 0 : m_sedge->m_dest->m_index);
696 : : else
697 : 0 : return pp_printf (&pp,
698 : : "taking edge SN:%i -> SN:%i",
699 : 0 : m_sedge->m_src->m_index,
700 : 0 : m_sedge->m_dest->m_index);
701 : : }
702 : 15604 : }
703 : :
704 : : /* Attempt to generate a description of any condition that holds at this edge.
705 : :
706 : : The intent is to make the user-facing messages more clear, especially for
707 : : cases where there's a single or double-negative, such as
708 : : when describing the false branch of an inverted condition.
709 : :
710 : : For example, rather than printing just:
711 : :
712 : : | if (!ptr)
713 : : | ~
714 : : | |
715 : : | (1) following 'false' branch...
716 : :
717 : : it's clearer to spell out the condition that holds:
718 : :
719 : : | if (!ptr)
720 : : | ~
721 : : | |
722 : : | (1) following 'false' branch (when 'ptr' is non-NULL)...
723 : : ^^^^^^^^^^^^^^^^^^^^^^
724 : :
725 : : In the above example, this function would generate the highlighted
726 : : string: "when 'ptr' is non-NULL".
727 : :
728 : : If the edge is not a condition, or it's not clear that a description of
729 : : the condition would be helpful to the user, return NULL. */
730 : :
731 : : label_text
732 : 7550 : start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
733 : : {
734 : 7550 : const cfg_superedge& cfg_sedge = get_cfg_superedge ();
735 : :
736 : 7550 : if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
737 : : {
738 : 7139 : const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
739 : 7139 : if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
740 : : {
741 : 7139 : enum tree_code op = gimple_cond_code (cond_stmt);
742 : 7139 : tree lhs = gimple_cond_lhs (cond_stmt);
743 : 7139 : tree rhs = gimple_cond_rhs (cond_stmt);
744 : 7139 : if (cfg_sedge.false_value_p ())
745 : 3345 : op = invert_tree_comparison (op, false /* honor_nans */);
746 : 7139 : return maybe_describe_condition (can_colorize,
747 : 7139 : lhs, op, rhs);
748 : : }
749 : : }
750 : 411 : return label_text::borrow (nullptr);
751 : : }
752 : :
753 : : /* Subroutine of maybe_describe_condition above.
754 : :
755 : : Attempt to generate a user-facing description of the condition
756 : : LHS OP RHS, but only if it is likely to make it easier for the
757 : : user to understand a condition. */
758 : :
759 : : label_text
760 : 7139 : start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
761 : : tree lhs,
762 : : enum tree_code op,
763 : : tree rhs)
764 : : {
765 : : /* In theory we could just build a tree via
766 : : fold_build2 (op, boolean_type_node, lhs, rhs)
767 : : and print it with %qE on it, but this leads to warts such as
768 : : parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
769 : :
770 : : /* Special-case: describe testing the result of strcmp, as figuring
771 : : out what the "true" or "false" path is can be confusing to the user. */
772 : 7139 : if (TREE_CODE (lhs) == SSA_NAME
773 : 7139 : && zerop (rhs))
774 : : {
775 : 5490 : if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
776 : 2140 : if (is_special_named_call_p (*call, "strcmp", 2))
777 : : {
778 : 60 : if (op == EQ_EXPR)
779 : 9 : return label_text::borrow ("when the strings are equal");
780 : 51 : if (op == NE_EXPR)
781 : 51 : return label_text::borrow ("when the strings are non-equal");
782 : : }
783 : : }
784 : :
785 : : /* Only attempt to generate text for sufficiently simple expressions. */
786 : 7079 : if (!should_print_expr_p (lhs))
787 : 2958 : return label_text::borrow (nullptr);
788 : 4121 : if (!should_print_expr_p (rhs))
789 : 58 : return label_text::borrow (nullptr);
790 : :
791 : : /* Special cases for pointer comparisons against NULL. */
792 : 6587 : if (POINTER_TYPE_P (TREE_TYPE (lhs))
793 : 1539 : && POINTER_TYPE_P (TREE_TYPE (rhs))
794 : 5602 : && zerop (rhs))
795 : : {
796 : 1470 : if (op == EQ_EXPR)
797 : 393 : return make_label_text (can_colorize, "when %qE is NULL",
798 : 393 : lhs);
799 : 1077 : if (op == NE_EXPR)
800 : 1077 : return make_label_text (can_colorize, "when %qE is non-NULL",
801 : 1077 : lhs);
802 : : }
803 : :
804 : 2593 : return make_label_text (can_colorize, "when %<%E %s %E%>",
805 : 2593 : lhs, op_symbol_code (op), rhs);
806 : : }
807 : :
808 : : /* Subroutine of maybe_describe_condition.
809 : :
810 : : Return true if EXPR is we will get suitable user-facing output
811 : : from %E on it. */
812 : :
813 : : bool
814 : 11200 : start_cfg_edge_event::should_print_expr_p (tree expr)
815 : : {
816 : 15653 : if (TREE_CODE (expr) == SSA_NAME)
817 : : {
818 : 7469 : if (SSA_NAME_VAR (expr))
819 : : return should_print_expr_p (SSA_NAME_VAR (expr));
820 : : else
821 : : return false;
822 : : }
823 : :
824 : 8184 : if (DECL_P (expr))
825 : : return true;
826 : :
827 : 3731 : if (CONSTANT_CLASS_P (expr))
828 : 3731 : return true;
829 : :
830 : : return false;
831 : : }
832 : :
833 : : /* class call_event : public superedge_event. */
834 : :
835 : : /* call_event's ctor. */
836 : :
837 : 1241 : call_event::call_event (const exploded_edge &eedge,
838 : 1241 : const event_loc_info &loc_info)
839 : 1241 : : superedge_event (event_kind::call_edge, eedge, loc_info)
840 : : {
841 : 1241 : if (eedge.m_sedge)
842 : 1208 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
843 : :
844 : 1241 : m_src_snode = eedge.m_src->get_supernode ();
845 : 1241 : m_dest_snode = eedge.m_dest->get_supernode ();
846 : 1241 : }
847 : :
848 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
849 : : call_event.
850 : :
851 : : If this call event passes critical state for an sm-based warning,
852 : : allow the diagnostic to generate a precise description, such as:
853 : :
854 : : "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
855 : :
856 : : Otherwise, generate a description of the form
857 : : "calling 'foo' from 'bar'". */
858 : :
859 : : void
860 : 1774 : call_event::print_desc (pretty_printer &pp) const
861 : : {
862 : 1774 : if (m_critical_state && m_pending_diagnostic)
863 : : {
864 : 351 : gcc_assert (m_var);
865 : 351 : tree var = fixup_tree_for_diagnostic (m_var);
866 : 351 : evdesc::call_with_state evd (m_src_snode->m_fun->decl,
867 : 351 : m_dest_snode->m_fun->decl,
868 : : var,
869 : 351 : m_critical_state);
870 : 351 : if (m_pending_diagnostic->describe_call_with_state (pp, evd))
871 : 150 : return;
872 : : }
873 : :
874 : 1624 : pp_printf (&pp,
875 : : "calling %qE from %qE",
876 : : get_callee_fndecl (),
877 : : get_caller_fndecl ());
878 : : }
879 : :
880 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
881 : : function call events. */
882 : :
883 : : diagnostics::paths::event::meaning
884 : 126 : call_event::get_meaning () const
885 : : {
886 : 126 : return meaning (verb::call, noun::function);
887 : : }
888 : :
889 : : /* Override of checker_event::is_call_p for calls. */
890 : :
891 : : bool
892 : 2111 : call_event::is_call_p () const
893 : : {
894 : 2111 : return true;
895 : : }
896 : :
897 : : tree
898 : 1692 : call_event::get_caller_fndecl () const
899 : : {
900 : 1692 : return m_src_snode->m_fun->decl;
901 : : }
902 : :
903 : : tree
904 : 1692 : call_event::get_callee_fndecl () const
905 : : {
906 : 1692 : return m_dest_snode->m_fun->decl;
907 : : }
908 : :
909 : : const program_state *
910 : 3 : call_event::get_program_state () const
911 : : {
912 : : /* Use the state at the source (at the caller),
913 : : rather than the one at the dest, which has a frame for the callee. */
914 : 3 : return &m_eedge.m_src->get_state ();
915 : : }
916 : :
917 : : /* class return_event : public superedge_event. */
918 : :
919 : : /* return_event's ctor. */
920 : :
921 : 676 : return_event::return_event (const exploded_edge &eedge,
922 : 676 : const event_loc_info &loc_info)
923 : 676 : : superedge_event (event_kind::return_edge, eedge, loc_info)
924 : : {
925 : 676 : if (eedge.m_sedge)
926 : 658 : gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
927 : :
928 : 676 : m_src_snode = eedge.m_src->get_supernode ();
929 : 676 : m_dest_snode = eedge.m_dest->get_supernode ();
930 : 676 : }
931 : :
932 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
933 : : return_event.
934 : :
935 : : If this return event returns critical state for an sm-based warning,
936 : : allow the diagnostic to generate a precise description, such as:
937 : :
938 : : "possible of NULL to 'foo' from 'bar'"
939 : :
940 : : Otherwise, generate a description of the form
941 : : "returning to 'foo' from 'bar'. */
942 : :
943 : : void
944 : 720 : return_event::print_desc (pretty_printer &pp) const
945 : : {
946 : : /* For greatest precision-of-wording, if this is returning the
947 : : state involved in the pending diagnostic, give the pending
948 : : diagnostic a chance to describe this return (in terms of
949 : : itself). */
950 : 720 : if (m_critical_state && m_pending_diagnostic)
951 : : {
952 : 104 : evdesc::return_of_state evd (m_dest_snode->m_fun->decl,
953 : 104 : m_src_snode->m_fun->decl,
954 : 104 : m_critical_state);
955 : 104 : if (m_pending_diagnostic->describe_return_of_state (pp, evd))
956 : 44 : return;
957 : : }
958 : 676 : pp_printf (&pp,
959 : : "returning to %qE from %qE",
960 : 676 : m_dest_snode->m_fun->decl,
961 : 676 : m_src_snode->m_fun->decl);
962 : : }
963 : :
964 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
965 : : function return events. */
966 : :
967 : : diagnostics::paths::event::meaning
968 : 54 : return_event::get_meaning () const
969 : : {
970 : 54 : return meaning (verb::return_, noun::function);
971 : : }
972 : :
973 : : /* Override of checker_event::is_return_p for returns. */
974 : :
975 : : bool
976 : 678 : return_event::is_return_p () const
977 : : {
978 : 678 : return true;
979 : : }
980 : :
981 : : /* class start_consolidated_cfg_edges_event : public checker_event. */
982 : :
983 : : void
984 : 165 : start_consolidated_cfg_edges_event::print_desc (pretty_printer &pp) const
985 : : {
986 : 165 : pp_printf (&pp,
987 : : "following %qs branch...",
988 : 165 : m_edge_sense ? "true" : "false");
989 : 165 : }
990 : :
991 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
992 : : start_consolidated_cfg_edges_event. */
993 : :
994 : : diagnostics::paths::event::meaning
995 : 0 : start_consolidated_cfg_edges_event::get_meaning () const
996 : : {
997 : 0 : return meaning (verb::branch,
998 : 0 : (m_edge_sense ? property::true_ : property::false_));
999 : : }
1000 : :
1001 : : /* class inlined_call_event : public checker_event. */
1002 : :
1003 : : void
1004 : 333 : inlined_call_event::print_desc (pretty_printer &pp) const
1005 : : {
1006 : 333 : pp_printf (&pp,
1007 : : "inlined call to %qE from %qE",
1008 : 333 : m_apparent_callee_fndecl,
1009 : 333 : m_apparent_caller_fndecl);
1010 : 333 : }
1011 : :
1012 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
1013 : : reconstructed inlined function calls. */
1014 : :
1015 : : diagnostics::paths::event::meaning
1016 : 72 : inlined_call_event::get_meaning () const
1017 : : {
1018 : 72 : return meaning (verb::call, noun::function);
1019 : : }
1020 : :
1021 : : /* class setjmp_event : public checker_event. */
1022 : :
1023 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1024 : : setjmp_event. */
1025 : :
1026 : : void
1027 : 40 : setjmp_event::print_desc (pretty_printer &pp) const
1028 : : {
1029 : 40 : pp_printf (&pp,
1030 : : "%qs called here",
1031 : : get_user_facing_name (m_setjmp_call));
1032 : 40 : }
1033 : :
1034 : : /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1035 : :
1036 : : Record this setjmp's event ID into the path, so that rewind events can
1037 : : use it. */
1038 : :
1039 : : void
1040 : 20 : setjmp_event::prepare_for_emission (checker_path *path,
1041 : : pending_diagnostic *pd,
1042 : : diagnostics::paths::event_id_t emission_id)
1043 : : {
1044 : 20 : checker_event::prepare_for_emission (path, pd, emission_id);
1045 : 20 : path->record_setjmp_event (m_enode, emission_id);
1046 : 20 : }
1047 : :
1048 : : /* class rewind_event : public checker_event. */
1049 : :
1050 : : /* Get the fndecl containing the site of the longjmp call. */
1051 : :
1052 : : tree
1053 : 90 : rewind_event::get_longjmp_caller () const
1054 : : {
1055 : 90 : return m_eedge->m_src->get_function ()->decl;
1056 : : }
1057 : :
1058 : : /* Get the fndecl containing the site of the setjmp call. */
1059 : :
1060 : : tree
1061 : 82 : rewind_event::get_setjmp_caller () const
1062 : : {
1063 : 82 : return m_eedge->m_dest->get_function ()->decl;
1064 : : }
1065 : :
1066 : : /* rewind_event's ctor. */
1067 : :
1068 : 30 : rewind_event::rewind_event (const exploded_edge *eedge,
1069 : : enum event_kind kind,
1070 : : const event_loc_info &loc_info,
1071 : 30 : const rewind_info_t *rewind_info)
1072 : : : checker_event (kind, loc_info),
1073 : 30 : m_rewind_info (rewind_info),
1074 : 30 : m_eedge (eedge)
1075 : : {
1076 : 30 : gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1077 : 30 : }
1078 : :
1079 : : /* class rewind_from_longjmp_event : public rewind_event. */
1080 : :
1081 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1082 : : rewind_from_longjmp_event. */
1083 : :
1084 : : void
1085 : 30 : rewind_from_longjmp_event::print_desc (pretty_printer &pp) const
1086 : : {
1087 : 30 : const char *src_name
1088 : 30 : = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1089 : :
1090 : 30 : if (get_longjmp_caller () == get_setjmp_caller ())
1091 : : /* Special-case: purely intraprocedural rewind. */
1092 : 8 : pp_printf (&pp,
1093 : : "rewinding within %qE from %qs...",
1094 : : get_longjmp_caller (),
1095 : : src_name);
1096 : : else
1097 : 22 : pp_printf (&pp,
1098 : : "rewinding from %qs in %qE...",
1099 : : src_name,
1100 : : get_longjmp_caller ());
1101 : 30 : }
1102 : :
1103 : : /* class rewind_to_setjmp_event : public rewind_event. */
1104 : :
1105 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1106 : : rewind_to_setjmp_event. */
1107 : :
1108 : : void
1109 : 30 : rewind_to_setjmp_event::print_desc (pretty_printer &pp) const
1110 : : {
1111 : 30 : const char *dst_name
1112 : 30 : = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1113 : :
1114 : : /* If we can, identify the ID of the setjmp_event. */
1115 : 30 : if (m_original_setjmp_event_id.known_p ())
1116 : : {
1117 : 15 : if (get_longjmp_caller () == get_setjmp_caller ())
1118 : : /* Special-case: purely intraprocedural rewind. */
1119 : 4 : pp_printf (&pp,
1120 : : "...to %qs (saved at %@)",
1121 : : dst_name,
1122 : : &m_original_setjmp_event_id);
1123 : : else
1124 : 11 : pp_printf (&pp,
1125 : : "...to %qs in %qE (saved at %@)",
1126 : : dst_name,
1127 : : get_setjmp_caller (),
1128 : : &m_original_setjmp_event_id);
1129 : : }
1130 : : else
1131 : : {
1132 : 15 : if (get_longjmp_caller () == get_setjmp_caller ())
1133 : : /* Special-case: purely intraprocedural rewind. */
1134 : 4 : pp_printf (&pp,
1135 : : "...to %qs",
1136 : : dst_name);
1137 : : else
1138 : 11 : pp_printf (&pp,
1139 : : "...to %qs in %qE",
1140 : : dst_name,
1141 : : get_setjmp_caller ());
1142 : : }
1143 : 30 : }
1144 : :
1145 : : /* Implementation of checker_event::prepare_for_emission vfunc for
1146 : : rewind_to_setjmp_event.
1147 : :
1148 : : Attempt to look up the setjmp event ID that recorded the jmp_buf
1149 : : for this rewind. */
1150 : :
1151 : : void
1152 : 15 : rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1153 : : pending_diagnostic *pd,
1154 : : diagnostics::paths::event_id_t emission_id)
1155 : : {
1156 : 15 : checker_event::prepare_for_emission (path, pd, emission_id);
1157 : 15 : path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1158 : : &m_original_setjmp_event_id);
1159 : 15 : }
1160 : :
1161 : : /* class throw_event : public checker_event. */
1162 : :
1163 : : /* class explicit_throw_event : public throw_event. */
1164 : : void
1165 : 126 : explicit_throw_event::print_desc (pretty_printer &pp) const
1166 : : {
1167 : 126 : if (m_is_rethrow)
1168 : : {
1169 : 18 : if (m_type)
1170 : 18 : pp_printf (&pp, "rethrowing exception of type %qT here...", m_type);
1171 : : else
1172 : 0 : pp_printf (&pp, "rethrowing exception here...");
1173 : : }
1174 : : else
1175 : : {
1176 : 108 : if (m_type)
1177 : 108 : pp_printf (&pp, "throwing exception of type %qT here...", m_type);
1178 : : else
1179 : 0 : pp_printf (&pp, "throwing exception here...");
1180 : : }
1181 : 126 : }
1182 : :
1183 : : /* class throw_from_call_to_external_fn_event : public throw_event. */
1184 : :
1185 : : void
1186 : 44 : throw_from_call_to_external_fn_event::print_desc (pretty_printer &pp) const
1187 : : {
1188 : 44 : if (m_fndecl)
1189 : 44 : pp_printf (&pp, "if %qD throws an exception...", m_fndecl);
1190 : : else
1191 : 0 : pp_printf (&pp, "if the called function throws an exception...");
1192 : 44 : }
1193 : :
1194 : : // class unwind_event : public checker_event
1195 : :
1196 : : void
1197 : 20 : unwind_event::print_desc (pretty_printer &pp) const
1198 : : {
1199 : 20 : if (m_num_frames > 1)
1200 : 12 : pp_printf (&pp, "unwinding %i stack frames", m_num_frames);
1201 : : else
1202 : 8 : pp_printf (&pp, "unwinding stack frame");
1203 : 20 : }
1204 : :
1205 : : /* class warning_event : public checker_event. */
1206 : :
1207 : : /* Implementation of diagnostics::paths::event::print_desc vfunc for
1208 : : warning_event.
1209 : :
1210 : : If the pending diagnostic implements describe_final_event, use it,
1211 : : generating a precise description e.g.
1212 : : "second 'free' here; first 'free' was at (7)"
1213 : :
1214 : : Otherwise generate a generic description. */
1215 : :
1216 : : void
1217 : 7894 : warning_event::print_desc (pretty_printer &pp) const
1218 : : {
1219 : 7894 : if (m_pending_diagnostic)
1220 : : {
1221 : 7894 : tree var = fixup_tree_for_diagnostic (m_var);
1222 : 7894 : evdesc::final_event evd (var, m_state, *this);
1223 : 7894 : if (m_pending_diagnostic->describe_final_event (pp, evd))
1224 : : {
1225 : 7318 : if (m_sm && flag_analyzer_verbose_state_changes)
1226 : : {
1227 : 72 : if (var)
1228 : 64 : pp_printf (&pp, " (%qE is in state %qs)",
1229 : 64 : var, m_state->get_name ());
1230 : : else
1231 : 8 : pp_printf (&pp, " (in global state %qs)",
1232 : 8 : m_state->get_name ());
1233 : : }
1234 : 7318 : return;
1235 : : }
1236 : : }
1237 : :
1238 : 576 : if (m_sm)
1239 : : {
1240 : 64 : if (m_var)
1241 : 64 : pp_printf (&pp, "here (%qE is in state %qs)",
1242 : 64 : m_var, m_state->get_name ());
1243 : : else
1244 : 0 : pp_printf (&pp, "here (in global state %qs)",
1245 : 0 : m_state->get_name ());
1246 : 64 : return;
1247 : : }
1248 : : else
1249 : 512 : pp_string (&pp, "here");
1250 : : }
1251 : :
1252 : : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
1253 : : warning_event. */
1254 : :
1255 : : diagnostics::paths::event::meaning
1256 : 219 : warning_event::get_meaning () const
1257 : : {
1258 : 219 : return meaning (verb::danger, noun::unknown);
1259 : : }
1260 : :
1261 : : const program_state *
1262 : 3 : warning_event::get_program_state () const
1263 : : {
1264 : 3 : if (m_program_state)
1265 : : return m_program_state.get ();
1266 : : else
1267 : 1 : return &m_enode->get_state ();
1268 : : }
1269 : :
1270 : : } // namespace ana
1271 : :
1272 : : #endif /* #if ENABLE_ANALYZER */
|