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