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