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