d: Merge upstream dmd 56589f0f4, druntime 651389b5, phobos 1516ecad9.
[official-gcc.git] / gcc / analyzer / checker-path.cc
blob953e192cd55c6728922d2932025a23a466f58ce2
1 /* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
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.
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.
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/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "function.h"
26 #include "basic-block.h"
27 #include "gimple.h"
28 #include "diagnostic-core.h"
29 #include "gimple-pretty-print.h"
30 #include "fold-const.h"
31 #include "function.h"
32 #include "diagnostic-path.h"
33 #include "options.h"
34 #include "cgraph.h"
35 #include "function.h"
36 #include "cfg.h"
37 #include "digraph.h"
38 #include "alloc-pool.h"
39 #include "fibonacci_heap.h"
40 #include "diagnostic-event-id.h"
41 #include "shortest-paths.h"
42 #include "json.h"
43 #include "analyzer/analyzer.h"
44 #include "analyzer/analyzer-logging.h"
45 #include "analyzer/sm.h"
46 #include "sbitmap.h"
47 #include "bitmap.h"
48 #include "tristate.h"
49 #include "ordered-hash-map.h"
50 #include "selftest.h"
51 #include "analyzer/call-string.h"
52 #include "analyzer/program-point.h"
53 #include "analyzer/store.h"
54 #include "analyzer/region-model.h"
55 #include "analyzer/program-state.h"
56 #include "analyzer/checker-path.h"
57 #include "gimple-iterator.h"
58 #include "inlining-iterator.h"
59 #include "analyzer/supergraph.h"
60 #include "analyzer/pending-diagnostic.h"
61 #include "analyzer/diagnostic-manager.h"
62 #include "analyzer/constraint-manager.h"
63 #include "analyzer/diagnostic-manager.h"
64 #include "analyzer/checker-path.h"
65 #include "analyzer/exploded-graph.h"
67 #if ENABLE_ANALYZER
69 namespace ana {
71 /* Get a string for EK. */
73 const char *
74 event_kind_to_string (enum event_kind ek)
76 switch (ek)
78 default:
79 gcc_unreachable ();
80 case EK_DEBUG:
81 return "EK_DEBUG";
82 case EK_CUSTOM:
83 return "EK_CUSTOM";
84 case EK_STMT:
85 return "EK_STMT";
86 case EK_REGION_CREATION:
87 return "EK_REGION_CREATION";
88 case EK_FUNCTION_ENTRY:
89 return "EK_FUNCTION_ENTRY";
90 case EK_STATE_CHANGE:
91 return "EK_STATE_CHANGE";
92 case EK_START_CFG_EDGE:
93 return "EK_START_CFG_EDGE";
94 case EK_END_CFG_EDGE:
95 return "EK_END_CFG_EDGE";
96 case EK_CALL_EDGE:
97 return "EK_CALL_EDGE";
98 case EK_RETURN_EDGE:
99 return "EK_RETURN_EDGE";
100 case EK_START_CONSOLIDATED_CFG_EDGES:
101 return "EK_START_CONSOLIDATED_CFG_EDGES";
102 case EK_END_CONSOLIDATED_CFG_EDGES:
103 return "EK_END_CONSOLIDATED_CFG_EDGES";
104 case EK_INLINED_CALL:
105 return "EK_INLINED_CALL";
106 case EK_SETJMP:
107 return "EK_SETJMP";
108 case EK_REWIND_FROM_LONGJMP:
109 return "EK_REWIND_FROM_LONGJMP";
110 case EK_REWIND_TO_SETJMP:
111 return "EK_REWIND_TO_SETJMP";
112 case EK_WARNING:
113 return "EK_WARNING";
117 /* A class for fixing up fndecls and stack depths in checker_event, based
118 on inlining records.
120 The early inliner runs before the analyzer, which can lead to confusing
121 output.
123 Tne base fndecl and depth within a checker_event are from call strings
124 in program_points, which reflect the call strings after inlining.
125 This class lets us offset the depth and fix up the reported fndecl and
126 stack depth to better reflect the user's original code. */
128 class inlining_info
130 public:
131 inlining_info (location_t loc)
133 inlining_iterator iter (loc);
134 m_inner_fndecl = iter.get_fndecl ();
135 int num_frames = 0;
136 while (!iter.done_p ())
138 m_outer_fndecl = iter.get_fndecl ();
139 num_frames++;
140 iter.next ();
142 if (num_frames > 1)
143 m_extra_frames = num_frames - 1;
144 else
145 m_extra_frames = 0;
148 tree get_inner_fndecl () const { return m_inner_fndecl; }
149 int get_extra_frames () const { return m_extra_frames; }
151 private:
152 tree m_outer_fndecl;
153 tree m_inner_fndecl;
154 int m_extra_frames;
157 /* class checker_event : public diagnostic_event. */
159 /* checker_event's ctor. */
161 checker_event::checker_event (enum event_kind kind,
162 location_t loc, tree fndecl, int depth)
163 : m_kind (kind), m_loc (loc),
164 m_original_fndecl (fndecl), m_effective_fndecl (fndecl),
165 m_original_depth (depth), m_effective_depth (depth),
166 m_pending_diagnostic (NULL), m_emission_id (),
167 m_logical_loc (fndecl)
169 /* Update effective fndecl and depth if inlining has been recorded. */
170 if (flag_analyzer_undo_inlining)
172 inlining_info info (loc);
173 if (info.get_inner_fndecl ())
175 m_effective_fndecl = info.get_inner_fndecl ();
176 m_effective_depth += info.get_extra_frames ();
177 m_logical_loc = tree_logical_location (m_effective_fndecl);
182 /* No-op implementation of diagnostic_event::get_meaning vfunc for
183 checker_event: checker events have no meaning by default. */
185 diagnostic_event::meaning
186 checker_event::get_meaning () const
188 return meaning ();
191 /* Dump this event to PP (for debugging/logging purposes). */
193 void
194 checker_event::dump (pretty_printer *pp) const
196 label_text event_desc (get_desc (false));
197 pp_printf (pp, "\"%s\" (depth %i",
198 event_desc.m_buffer, m_effective_depth);
199 event_desc.maybe_free ();
201 if (m_effective_depth != m_original_depth)
202 pp_printf (pp, " corrected from %i",
203 m_original_depth);
204 if (m_effective_fndecl)
206 pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
207 if (m_effective_fndecl != m_original_fndecl)
208 pp_printf (pp, " corrected from %qE", m_original_fndecl);
210 pp_printf (pp, ", m_loc=%x)",
211 get_location ());
214 /* Hook for being notified when this event has its final id EMISSION_ID
215 and is about to emitted for PD.
217 Base implementation of checker_event::prepare_for_emission vfunc;
218 subclasses that override this should chain up to it.
220 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
221 side-effects of the call to get_desc take place before
222 pending_diagnostic::emit is called.
224 For example, state_change_event::get_desc can call
225 pending_diagnostic::describe_state_change; free_of_non_heap can use this
226 to tweak the message (TODO: would be neater to simply capture the
227 pertinent data within the sm-state). */
229 void
230 checker_event::prepare_for_emission (checker_path *,
231 pending_diagnostic *pd,
232 diagnostic_event_id_t emission_id)
234 m_pending_diagnostic = pd;
235 m_emission_id = emission_id;
237 label_text desc = get_desc (false);
238 desc.maybe_free ();
241 /* class debug_event : public checker_event. */
243 /* Implementation of diagnostic_event::get_desc vfunc for
244 debug_event.
245 Use the saved string as the event's description. */
247 label_text
248 debug_event::get_desc (bool) const
250 return label_text::borrow (m_desc);
253 /* class precanned_custom_event : public custom_event. */
255 /* Implementation of diagnostic_event::get_desc vfunc for
256 precanned_custom_event.
257 Use the saved string as the event's description. */
259 label_text
260 precanned_custom_event::get_desc (bool) const
262 return label_text::borrow (m_desc);
265 /* class statement_event : public checker_event. */
267 /* statement_event's ctor. */
269 statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
270 const program_state &dst_state)
271 : checker_event (EK_STMT, gimple_location (stmt), fndecl, depth),
272 m_stmt (stmt),
273 m_dst_state (dst_state)
277 /* Implementation of diagnostic_event::get_desc vfunc for
278 statement_event.
279 Use the statement's dump form as the event's description. */
281 label_text
282 statement_event::get_desc (bool) const
284 pretty_printer pp;
285 pp_string (&pp, "stmt: ");
286 pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
287 return label_text::take (xstrdup (pp_formatted_text (&pp)));
290 /* class region_creation_event : public checker_event. */
292 region_creation_event::region_creation_event (const region *reg,
293 location_t loc,
294 tree fndecl,
295 int depth)
296 : checker_event (EK_REGION_CREATION, loc, fndecl, depth),
297 m_reg (reg)
301 /* Implementation of diagnostic_event::get_desc vfunc for
302 region_creation_event. */
304 label_text
305 region_creation_event::get_desc (bool can_colorize) const
307 if (m_pending_diagnostic)
309 label_text custom_desc
310 = m_pending_diagnostic->describe_region_creation_event
311 (evdesc::region_creation (can_colorize, m_reg));
312 if (custom_desc.m_buffer)
313 return custom_desc;
316 switch (m_reg->get_memory_space ())
318 default:
319 return label_text::borrow ("region created here");
320 case MEMSPACE_STACK:
321 return label_text::borrow ("region created on stack here");
322 case MEMSPACE_HEAP:
323 return label_text::borrow ("region created on heap here");
327 /* class function_entry_event : public checker_event. */
329 /* Implementation of diagnostic_event::get_desc vfunc for
330 function_entry_event.
332 Use a string such as "entry to 'foo'" as the event's description. */
334 label_text
335 function_entry_event::get_desc (bool can_colorize) const
337 return make_label_text (can_colorize, "entry to %qE", m_effective_fndecl);
340 /* Implementation of diagnostic_event::get_meaning vfunc for
341 function entry. */
343 diagnostic_event::meaning
344 function_entry_event::get_meaning () const
346 return meaning (VERB_enter, NOUN_function);
349 /* class state_change_event : public checker_event. */
351 /* state_change_event's ctor. */
353 state_change_event::state_change_event (const supernode *node,
354 const gimple *stmt,
355 int stack_depth,
356 const state_machine &sm,
357 const svalue *sval,
358 state_machine::state_t from,
359 state_machine::state_t to,
360 const svalue *origin,
361 const program_state &dst_state)
362 : checker_event (EK_STATE_CHANGE,
363 stmt->location, node->m_fun->decl,
364 stack_depth),
365 m_node (node), m_stmt (stmt), m_sm (sm),
366 m_sval (sval), m_from (from), m_to (to),
367 m_origin (origin),
368 m_dst_state (dst_state)
372 /* Implementation of diagnostic_event::get_desc vfunc for
373 state_change_event.
375 Attempt to generate a nicer human-readable description.
376 For greatest precision-of-wording, give the pending diagnostic
377 a chance to describe this state change (in terms of the
378 diagnostic).
379 Note that we only have a pending_diagnostic set on the event once
380 the diagnostic is about to being emitted, so the description for
381 an event can change. */
383 label_text
384 state_change_event::get_desc (bool can_colorize) const
386 if (m_pending_diagnostic)
388 region_model *model = m_dst_state.m_region_model;
389 tree var = model->get_representative_tree (m_sval);
390 tree origin = model->get_representative_tree (m_origin);
391 label_text custom_desc
392 = m_pending_diagnostic->describe_state_change
393 (evdesc::state_change (can_colorize, var, origin,
394 m_from, m_to, m_emission_id, *this));
395 if (custom_desc.m_buffer)
397 if (flag_analyzer_verbose_state_changes)
399 /* Get any "meaning" of event. */
400 diagnostic_event::meaning meaning = get_meaning ();
401 pretty_printer meaning_pp;
402 meaning.dump_to_pp (&meaning_pp);
404 /* Append debug version. */
405 label_text result;
406 if (m_origin)
407 result = make_label_text
408 (can_colorize,
409 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
410 custom_desc.m_buffer,
411 var,
412 m_from->get_name (),
413 m_to->get_name (),
414 origin,
415 pp_formatted_text (&meaning_pp));
416 else
417 result = make_label_text
418 (can_colorize,
419 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
420 custom_desc.m_buffer,
421 var,
422 m_from->get_name (),
423 m_to->get_name (),
424 pp_formatted_text (&meaning_pp));
426 custom_desc.maybe_free ();
427 return result;
429 else
430 return custom_desc;
434 /* Fallback description. */
435 if (m_sval)
437 label_text sval_desc = m_sval->get_desc ();
438 label_text result;
439 if (m_origin)
441 label_text origin_desc = m_origin->get_desc ();
442 result = make_label_text
443 (can_colorize,
444 "state of %qs: %qs -> %qs (origin: %qs)",
445 sval_desc.m_buffer,
446 m_from->get_name (),
447 m_to->get_name (),
448 origin_desc.m_buffer);
449 origin_desc.maybe_free ();
451 else
452 result = make_label_text
453 (can_colorize,
454 "state of %qs: %qs -> %qs (NULL origin)",
455 sval_desc.m_buffer,
456 m_from->get_name (),
457 m_to->get_name ());
458 sval_desc.maybe_free ();
459 return result;
461 else
463 gcc_assert (m_origin == NULL);
464 return make_label_text
465 (can_colorize,
466 "global state: %qs -> %qs",
467 m_from->get_name (),
468 m_to->get_name ());
472 /* Implementation of diagnostic_event::get_meaning vfunc for
473 state change events: delegate to the pending_diagnostic to
474 get any meaning. */
476 diagnostic_event::meaning
477 state_change_event::get_meaning () const
479 if (m_pending_diagnostic)
481 region_model *model = m_dst_state.m_region_model;
482 tree var = model->get_representative_tree (m_sval);
483 tree origin = model->get_representative_tree (m_origin);
484 return m_pending_diagnostic->get_meaning_for_state_change
485 (evdesc::state_change (false, var, origin,
486 m_from, m_to, m_emission_id, *this));
488 else
489 return meaning ();
492 /* class superedge_event : public checker_event. */
494 /* Get the callgraph_superedge for this superedge_event, which must be
495 for an interprocedural edge, rather than a CFG edge. */
497 const callgraph_superedge&
498 superedge_event::get_callgraph_superedge () const
500 gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
501 return *m_sedge->dyn_cast_callgraph_superedge ();
504 /* Determine if this event should be filtered at the given verbosity
505 level. */
507 bool
508 superedge_event::should_filter_p (int verbosity) const
510 switch (m_sedge->m_kind)
512 case SUPEREDGE_CFG_EDGE:
514 if (verbosity < 2)
515 return true;
517 if (verbosity < 4)
519 /* Filter events with empty descriptions. This ought to filter
520 FALLTHRU, but retain true/false/switch edges. */
521 label_text desc = get_desc (false);
522 gcc_assert (desc.m_buffer);
523 if (desc.m_buffer[0] == '\0')
524 return true;
525 desc.maybe_free ();
528 break;
530 default:
531 break;
533 return false;
536 /* superedge_event's ctor. */
538 superedge_event::superedge_event (enum event_kind kind,
539 const exploded_edge &eedge,
540 location_t loc, tree fndecl, int depth)
541 : checker_event (kind, loc, fndecl, depth),
542 m_eedge (eedge), m_sedge (eedge.m_sedge),
543 m_var (NULL_TREE), m_critical_state (0)
547 /* class cfg_edge_event : public superedge_event. */
549 /* Get the cfg_superedge for this cfg_edge_event. */
551 const cfg_superedge &
552 cfg_edge_event::get_cfg_superedge () const
554 return *m_sedge->dyn_cast_cfg_superedge ();
557 /* cfg_edge_event's ctor. */
559 cfg_edge_event::cfg_edge_event (enum event_kind kind,
560 const exploded_edge &eedge,
561 location_t loc, tree fndecl, int depth)
562 : superedge_event (kind, eedge, loc, fndecl, depth)
564 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
567 /* Implementation of diagnostic_event::get_meaning vfunc for
568 CFG edge events. */
570 diagnostic_event::meaning
571 cfg_edge_event::get_meaning () const
573 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
574 if (cfg_sedge.true_value_p ())
575 return meaning (VERB_branch, PROPERTY_true);
576 else if (cfg_sedge.false_value_p ())
577 return meaning (VERB_branch, PROPERTY_false);
578 else
579 return meaning ();
582 /* class start_cfg_edge_event : public cfg_edge_event. */
584 /* Implementation of diagnostic_event::get_desc vfunc for
585 start_cfg_edge_event.
587 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
589 "taking 'true' edge SN:7 -> SN:8".
591 Otherwise, generate strings using the label of the underlying CFG if
592 any, such as:
593 "following 'true' branch..." or
594 "following 'case 3' branch..."
595 "following 'default' branch..."
597 For conditionals, attempt to supply a description of the condition that
598 holds, such as:
599 "following 'false' branch (when 'ptr' is non-NULL)..."
601 Failing that, return an empty description (which will lead to this event
602 being filtered). */
604 label_text
605 start_cfg_edge_event::get_desc (bool can_colorize) const
607 bool user_facing = !flag_analyzer_verbose_edges;
608 char *edge_desc = m_sedge->get_description (user_facing);
609 if (user_facing)
611 if (edge_desc && strlen (edge_desc) > 0)
613 label_text cond_desc = maybe_describe_condition (can_colorize);
614 label_text result;
615 if (cond_desc.m_buffer)
617 result = make_label_text (can_colorize,
618 "following %qs branch (%s)...",
619 edge_desc, cond_desc.m_buffer);
620 cond_desc.maybe_free ();
622 else
624 result = make_label_text (can_colorize,
625 "following %qs branch...",
626 edge_desc);
628 free (edge_desc);
629 return result;
631 else
633 free (edge_desc);
634 return label_text::borrow ("");
637 else
639 if (strlen (edge_desc) > 0)
641 label_text result
642 = make_label_text (can_colorize,
643 "taking %qs edge SN:%i -> SN:%i",
644 edge_desc,
645 m_sedge->m_src->m_index,
646 m_sedge->m_dest->m_index);
647 free (edge_desc);
648 return result;
650 else
652 free (edge_desc);
653 return make_label_text (can_colorize,
654 "taking edge SN:%i -> SN:%i",
655 m_sedge->m_src->m_index,
656 m_sedge->m_dest->m_index);
661 /* Attempt to generate a description of any condition that holds at this edge.
663 The intent is to make the user-facing messages more clear, especially for
664 cases where there's a single or double-negative, such as
665 when describing the false branch of an inverted condition.
667 For example, rather than printing just:
669 | if (!ptr)
672 | (1) following 'false' branch...
674 it's clearer to spell out the condition that holds:
676 | if (!ptr)
679 | (1) following 'false' branch (when 'ptr' is non-NULL)...
680 ^^^^^^^^^^^^^^^^^^^^^^
682 In the above example, this function would generate the highlighted
683 string: "when 'ptr' is non-NULL".
685 If the edge is not a condition, or it's not clear that a description of
686 the condition would be helpful to the user, return NULL. */
688 label_text
689 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
691 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
693 if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
695 const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
696 if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
698 enum tree_code op = gimple_cond_code (cond_stmt);
699 tree lhs = gimple_cond_lhs (cond_stmt);
700 tree rhs = gimple_cond_rhs (cond_stmt);
701 if (cfg_sedge.false_value_p ())
702 op = invert_tree_comparison (op, false /* honor_nans */);
703 return maybe_describe_condition (can_colorize,
704 lhs, op, rhs);
707 return label_text::borrow (NULL);
710 /* Subroutine of maybe_describe_condition above.
712 Attempt to generate a user-facing description of the condition
713 LHS OP RHS, but only if it is likely to make it easier for the
714 user to understand a condition. */
716 label_text
717 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
718 tree lhs,
719 enum tree_code op,
720 tree rhs)
722 /* In theory we could just build a tree via
723 fold_build2 (op, boolean_type_node, lhs, rhs)
724 and print it with %qE on it, but this leads to warts such as
725 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
727 /* Special-case: describe testing the result of strcmp, as figuring
728 out what the "true" or "false" path is can be confusing to the user. */
729 if (TREE_CODE (lhs) == SSA_NAME
730 && zerop (rhs))
732 if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
733 if (is_special_named_call_p (call, "strcmp", 2))
735 if (op == EQ_EXPR)
736 return label_text::borrow ("when the strings are equal");
737 if (op == NE_EXPR)
738 return label_text::borrow ("when the strings are non-equal");
742 /* Only attempt to generate text for sufficiently simple expressions. */
743 if (!should_print_expr_p (lhs))
744 return label_text::borrow (NULL);
745 if (!should_print_expr_p (rhs))
746 return label_text::borrow (NULL);
748 /* Special cases for pointer comparisons against NULL. */
749 if (POINTER_TYPE_P (TREE_TYPE (lhs))
750 && POINTER_TYPE_P (TREE_TYPE (rhs))
751 && zerop (rhs))
753 if (op == EQ_EXPR)
754 return make_label_text (can_colorize, "when %qE is NULL",
755 lhs);
756 if (op == NE_EXPR)
757 return make_label_text (can_colorize, "when %qE is non-NULL",
758 lhs);
761 return make_label_text (can_colorize, "when %<%E %s %E%>",
762 lhs, op_symbol_code (op), rhs);
765 /* Subroutine of maybe_describe_condition.
767 Return true if EXPR is we will get suitable user-facing output
768 from %E on it. */
770 bool
771 start_cfg_edge_event::should_print_expr_p (tree expr)
773 if (TREE_CODE (expr) == SSA_NAME)
775 if (SSA_NAME_VAR (expr))
776 return should_print_expr_p (SSA_NAME_VAR (expr));
777 else
778 return false;
781 if (DECL_P (expr))
782 return true;
784 if (CONSTANT_CLASS_P (expr))
785 return true;
787 return false;
790 /* class call_event : public superedge_event. */
792 /* call_event's ctor. */
794 call_event::call_event (const exploded_edge &eedge,
795 location_t loc, tree fndecl, int depth)
796 : superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth)
798 if (eedge.m_sedge)
799 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
801 m_src_snode = eedge.m_src->get_supernode ();
802 m_dest_snode = eedge.m_dest->get_supernode ();
805 /* Implementation of diagnostic_event::get_desc vfunc for
806 call_event.
808 If this call event passes critical state for an sm-based warning,
809 allow the diagnostic to generate a precise description, such as:
811 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
813 Otherwise, generate a description of the form
814 "calling 'foo' from 'bar'". */
816 label_text
817 call_event::get_desc (bool can_colorize) const
819 if (m_critical_state && m_pending_diagnostic)
821 gcc_assert (m_var);
822 tree var = fixup_tree_for_diagnostic (m_var);
823 label_text custom_desc
824 = m_pending_diagnostic->describe_call_with_state
825 (evdesc::call_with_state (can_colorize,
826 m_src_snode->m_fun->decl,
827 m_dest_snode->m_fun->decl,
828 var,
829 m_critical_state));
830 if (custom_desc.m_buffer)
831 return custom_desc;
834 return make_label_text (can_colorize,
835 "calling %qE from %qE",
836 get_callee_fndecl (),
837 get_caller_fndecl ());
840 /* Implementation of diagnostic_event::get_meaning vfunc for
841 function call events. */
843 diagnostic_event::meaning
844 call_event::get_meaning () const
846 return meaning (VERB_call, NOUN_function);
849 /* Override of checker_event::is_call_p for calls. */
851 bool
852 call_event::is_call_p () const
854 return true;
857 tree
858 call_event::get_caller_fndecl () const
860 return m_src_snode->m_fun->decl;
863 tree
864 call_event::get_callee_fndecl () const
866 return m_dest_snode->m_fun->decl;
869 /* class return_event : public superedge_event. */
871 /* return_event's ctor. */
873 return_event::return_event (const exploded_edge &eedge,
874 location_t loc, tree fndecl, int depth)
875 : superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth)
877 if (eedge.m_sedge)
878 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
880 m_src_snode = eedge.m_src->get_supernode ();
881 m_dest_snode = eedge.m_dest->get_supernode ();
884 /* Implementation of diagnostic_event::get_desc vfunc for
885 return_event.
887 If this return event returns critical state for an sm-based warning,
888 allow the diagnostic to generate a precise description, such as:
890 "possible of NULL to 'foo' from 'bar'"
892 Otherwise, generate a description of the form
893 "returning to 'foo' from 'bar'. */
895 label_text
896 return_event::get_desc (bool can_colorize) const
898 /* For greatest precision-of-wording, if this is returning the
899 state involved in the pending diagnostic, give the pending
900 diagnostic a chance to describe this return (in terms of
901 itself). */
902 if (m_critical_state && m_pending_diagnostic)
904 label_text custom_desc
905 = m_pending_diagnostic->describe_return_of_state
906 (evdesc::return_of_state (can_colorize,
907 m_dest_snode->m_fun->decl,
908 m_src_snode->m_fun->decl,
909 m_critical_state));
910 if (custom_desc.m_buffer)
911 return custom_desc;
913 return make_label_text (can_colorize,
914 "returning to %qE from %qE",
915 m_dest_snode->m_fun->decl,
916 m_src_snode->m_fun->decl);
919 /* Implementation of diagnostic_event::get_meaning vfunc for
920 function return events. */
922 diagnostic_event::meaning
923 return_event::get_meaning () const
925 return meaning (VERB_return, NOUN_function);
928 /* Override of checker_event::is_return_p for returns. */
930 bool
931 return_event::is_return_p () const
933 return true;
936 /* class start_consolidated_cfg_edges_event : public checker_event. */
938 label_text
939 start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
941 return make_label_text (can_colorize,
942 "following %qs branch...",
943 m_edge_sense ? "true" : "false");
946 /* Implementation of diagnostic_event::get_meaning vfunc for
947 start_consolidated_cfg_edges_event. */
949 diagnostic_event::meaning
950 start_consolidated_cfg_edges_event::get_meaning () const
952 return meaning (VERB_branch,
953 (m_edge_sense ? PROPERTY_true : PROPERTY_false));
956 /* class inlined_call_event : public checker_event. */
958 label_text
959 inlined_call_event::get_desc (bool can_colorize) const
961 return make_label_text (can_colorize,
962 "inlined call to %qE from %qE",
963 m_apparent_callee_fndecl,
964 m_apparent_caller_fndecl);
967 /* Implementation of diagnostic_event::get_meaning vfunc for
968 reconstructed inlined function calls. */
970 diagnostic_event::meaning
971 inlined_call_event::get_meaning () const
973 return meaning (VERB_call, NOUN_function);
976 /* class setjmp_event : public checker_event. */
978 /* Implementation of diagnostic_event::get_desc vfunc for
979 setjmp_event. */
981 label_text
982 setjmp_event::get_desc (bool can_colorize) const
984 return make_label_text (can_colorize,
985 "%qs called here",
986 get_user_facing_name (m_setjmp_call));
989 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
991 Record this setjmp's event ID into the path, so that rewind events can
992 use it. */
994 void
995 setjmp_event::prepare_for_emission (checker_path *path,
996 pending_diagnostic *pd,
997 diagnostic_event_id_t emission_id)
999 checker_event::prepare_for_emission (path, pd, emission_id);
1000 path->record_setjmp_event (m_enode, emission_id);
1003 /* class rewind_event : public checker_event. */
1005 /* Get the fndecl containing the site of the longjmp call. */
1007 tree
1008 rewind_event::get_longjmp_caller () const
1010 return m_eedge->m_src->get_function ()->decl;
1013 /* Get the fndecl containing the site of the setjmp call. */
1015 tree
1016 rewind_event::get_setjmp_caller () const
1018 return m_eedge->m_dest->get_function ()->decl;
1021 /* rewind_event's ctor. */
1023 rewind_event::rewind_event (const exploded_edge *eedge,
1024 enum event_kind kind,
1025 location_t loc, tree fndecl, int depth,
1026 const rewind_info_t *rewind_info)
1027 : checker_event (kind, loc, fndecl, depth),
1028 m_rewind_info (rewind_info),
1029 m_eedge (eedge)
1031 gcc_assert (m_eedge->m_custom_info == m_rewind_info);
1034 /* class rewind_from_longjmp_event : public rewind_event. */
1036 /* Implementation of diagnostic_event::get_desc vfunc for
1037 rewind_from_longjmp_event. */
1039 label_text
1040 rewind_from_longjmp_event::get_desc (bool can_colorize) const
1042 const char *src_name
1043 = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1045 if (get_longjmp_caller () == get_setjmp_caller ())
1046 /* Special-case: purely intraprocedural rewind. */
1047 return make_label_text (can_colorize,
1048 "rewinding within %qE from %qs...",
1049 get_longjmp_caller (),
1050 src_name);
1051 else
1052 return make_label_text (can_colorize,
1053 "rewinding from %qs in %qE...",
1054 src_name,
1055 get_longjmp_caller ());
1058 /* class rewind_to_setjmp_event : public rewind_event. */
1060 /* Implementation of diagnostic_event::get_desc vfunc for
1061 rewind_to_setjmp_event. */
1063 label_text
1064 rewind_to_setjmp_event::get_desc (bool can_colorize) const
1066 const char *dst_name
1067 = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1069 /* If we can, identify the ID of the setjmp_event. */
1070 if (m_original_setjmp_event_id.known_p ())
1072 if (get_longjmp_caller () == get_setjmp_caller ())
1073 /* Special-case: purely intraprocedural rewind. */
1074 return make_label_text (can_colorize,
1075 "...to %qs (saved at %@)",
1076 dst_name,
1077 &m_original_setjmp_event_id);
1078 else
1079 return make_label_text (can_colorize,
1080 "...to %qs in %qE (saved at %@)",
1081 dst_name,
1082 get_setjmp_caller (),
1083 &m_original_setjmp_event_id);
1085 else
1087 if (get_longjmp_caller () == get_setjmp_caller ())
1088 /* Special-case: purely intraprocedural rewind. */
1089 return make_label_text (can_colorize,
1090 "...to %qs",
1091 dst_name,
1092 get_setjmp_caller ());
1093 else
1094 return make_label_text (can_colorize,
1095 "...to %qs in %qE",
1096 dst_name,
1097 get_setjmp_caller ());
1101 /* Implementation of checker_event::prepare_for_emission vfunc for
1102 rewind_to_setjmp_event.
1104 Attempt to look up the setjmp event ID that recorded the jmp_buf
1105 for this rewind. */
1107 void
1108 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1109 pending_diagnostic *pd,
1110 diagnostic_event_id_t emission_id)
1112 checker_event::prepare_for_emission (path, pd, emission_id);
1113 path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1114 &m_original_setjmp_event_id);
1117 /* class warning_event : public checker_event. */
1119 /* Implementation of diagnostic_event::get_desc vfunc for
1120 warning_event.
1122 If the pending diagnostic implements describe_final_event, use it,
1123 generating a precise description e.g.
1124 "second 'free' here; first 'free' was at (7)"
1126 Otherwise generate a generic description. */
1128 label_text
1129 warning_event::get_desc (bool can_colorize) const
1131 if (m_pending_diagnostic)
1133 tree var = fixup_tree_for_diagnostic (m_var);
1134 label_text ev_desc
1135 = m_pending_diagnostic->describe_final_event
1136 (evdesc::final_event (can_colorize, var, m_state));
1137 if (ev_desc.m_buffer)
1139 if (m_sm && flag_analyzer_verbose_state_changes)
1141 label_text result;
1142 if (var)
1143 result = make_label_text (can_colorize,
1144 "%s (%qE is in state %qs)",
1145 ev_desc.m_buffer,
1146 var, m_state->get_name ());
1147 else
1148 result = make_label_text (can_colorize,
1149 "%s (in global state %qs)",
1150 ev_desc.m_buffer,
1151 m_state->get_name ());
1152 ev_desc.maybe_free ();
1153 return result;
1155 else
1156 return ev_desc;
1160 if (m_sm)
1162 if (m_var)
1163 return make_label_text (can_colorize,
1164 "here (%qE is in state %qs)",
1165 m_var, m_state->get_name ());
1166 else
1167 return make_label_text (can_colorize,
1168 "here (in global state %qs)",
1169 m_state->get_name ());
1171 else
1172 return label_text::borrow ("here");
1175 /* Implementation of diagnostic_event::get_meaning vfunc for
1176 warning_event. */
1178 diagnostic_event::meaning
1179 warning_event::get_meaning () const
1181 return meaning (VERB_danger, NOUN_unknown);
1184 /* Print a single-line representation of this path to PP. */
1186 void
1187 checker_path::dump (pretty_printer *pp) const
1189 pp_character (pp, '[');
1191 checker_event *e;
1192 int i;
1193 FOR_EACH_VEC_ELT (m_events, i, e)
1195 if (i > 0)
1196 pp_string (pp, ", ");
1197 label_text event_desc (e->get_desc (false));
1198 pp_printf (pp, "\"%s\"", event_desc.m_buffer);
1199 event_desc.maybe_free ();
1201 pp_character (pp, ']');
1204 /* Print a multiline form of this path to LOGGER, prefixing it with DESC. */
1206 void
1207 checker_path::maybe_log (logger *logger, const char *desc) const
1209 if (!logger)
1210 return;
1211 logger->start_log_line ();
1212 logger->log_partial ("%s: ", desc);
1213 dump (logger->get_printer ());
1214 logger->end_log_line ();
1215 for (unsigned i = 0; i < m_events.length (); i++)
1217 logger->start_log_line ();
1218 logger->log_partial ("%s[%i]: %s ", desc, i,
1219 event_kind_to_string (m_events[i]->m_kind));
1220 m_events[i]->dump (logger->get_printer ());
1221 logger->end_log_line ();
1225 /* Print a multiline form of this path to STDERR. */
1227 DEBUG_FUNCTION void
1228 checker_path::debug () const
1230 checker_event *e;
1231 int i;
1232 FOR_EACH_VEC_ELT (m_events, i, e)
1234 label_text event_desc (e->get_desc (false));
1235 fprintf (stderr,
1236 "[%i]: %s \"%s\"\n",
1238 event_kind_to_string (m_events[i]->m_kind),
1239 event_desc.m_buffer);
1240 event_desc.maybe_free ();
1244 /* Add region_creation_event instance to this path for REG,
1245 describing whether REG is on the stack or heap. */
1247 void
1248 checker_path::add_region_creation_event (const region *reg,
1249 location_t loc,
1250 tree fndecl, int depth)
1252 add_event (new region_creation_event (reg, loc, fndecl, depth));
1255 /* Add a warning_event to the end of this path. */
1257 void
1258 checker_path::add_final_event (const state_machine *sm,
1259 const exploded_node *enode, const gimple *stmt,
1260 tree var, state_machine::state_t state)
1262 checker_event *end_of_path
1263 = new warning_event (get_stmt_location (stmt, enode->get_function ()),
1264 enode->get_function ()->decl,
1265 enode->get_stack_depth (),
1266 sm, var, state);
1267 add_event (end_of_path);
1270 void
1271 checker_path::fixup_locations (pending_diagnostic *pd)
1273 for (checker_event *e : m_events)
1274 e->set_location (pd->fixup_location (e->get_location ()));
1277 /* Return true if there is a (start_cfg_edge_event, end_cfg_edge_event) pair
1278 at (IDX, IDX + 1). */
1280 bool
1281 checker_path::cfg_edge_pair_at_p (unsigned idx) const
1283 if (m_events.length () < idx + 1)
1284 return false;
1285 return (m_events[idx]->m_kind == EK_START_CFG_EDGE
1286 && m_events[idx + 1]->m_kind == EK_END_CFG_EDGE);
1289 /* Consider a call from "outer" to "middle" which calls "inner",
1290 where "inner" and "middle" have been inlined into "outer".
1292 We expect the stmt locations for the inlined stmts to have a
1293 chain like:
1295 [{fndecl: inner},
1296 {fndecl: middle, callsite: within middle to inner},
1297 {fndecl: outer, callsite: without outer to middle}]
1299 The location for the stmt will already be fixed up to reflect
1300 the two extra frames, so that we have e.g. this as input
1301 (for gcc.dg/analyzer/inlining-4.c):
1303 before[0]:
1304 EK_FUNCTION_ENTRY "entry to ‘outer’"
1305 (depth 1, fndecl ‘outer’, m_loc=511c4)
1306 before[1]:
1307 EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..."
1308 (depth 3 corrected from 1,
1309 fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f)
1310 before[2]:
1311 EK_END_CFG_EDGE "...to here"
1312 (depth 1, fndecl ‘outer’, m_loc=0)
1313 before[3]:
1314 EK_WARNING "here (‘<unknown>’ is in state ‘null’)"
1315 (depth 1, fndecl ‘outer’, m_loc=80000004)
1317 We want to add inlined_call_events showing the calls, so that
1318 the above becomes:
1320 after[0]:
1321 EK_FUNCTION_ENTRY "entry to ‘outer’"
1322 (depth 1, fndecl ‘outer’, m_loc=511c4)
1323 after[1]:
1324 EK_INLINED_CALL "inlined call to ‘middle’ from ‘outer’"
1325 (depth 1, fndecl ‘outer’, m_loc=53300)
1326 after[2]:
1327 EK_INLINED_CALL "inlined call to ‘inner’ from ‘middle’"
1328 (depth 2, fndecl ‘middle’, m_loc=4d2e0)
1329 after[3]:
1330 EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..."
1331 (depth 3 corrected from 1,
1332 fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f)
1333 after[4]: EK_END_CFG_EDGE "...to here"
1334 (depth 1, fndecl ‘outer’, m_loc=0)
1335 after[5]: EK_WARNING "here (‘<unknown>’ is in state ‘null’)"
1336 (depth 1, fndecl ‘outer’, m_loc=80000004)
1338 where we've added events between before[0] and before[1] to show
1339 the inlined calls leading to the effective stack depths, making
1340 the generated path much easier for a user to read.
1342 Note how in the above we have a branch (before[1] to before[2])
1343 where the locations were originally in different functions.
1344 Hence we have to add these events quite late when generating
1345 checker_path. */
1347 void
1348 checker_path::inject_any_inlined_call_events (logger *logger)
1350 LOG_SCOPE (logger);
1352 if (!flag_analyzer_undo_inlining)
1353 return;
1355 /* Build a copy of m_events with the new events inserted. */
1356 auto_vec<checker_event *> updated_events;
1358 maybe_log (logger, "before");
1360 hash_set<tree> blocks_in_prev_event;
1362 for (unsigned ev_idx = 0; ev_idx < m_events.length (); ev_idx++)
1364 checker_event *curr_event = m_events[ev_idx];
1365 location_t curr_loc = curr_event->get_location ();
1366 hash_set<tree> blocks_in_curr_event;
1368 if (logger)
1370 logger->start_log_line ();
1371 logger->log_partial ("event[%i]: %s ", ev_idx,
1372 event_kind_to_string (curr_event->m_kind));
1373 curr_event->dump (logger->get_printer ());
1374 logger->end_log_line ();
1375 for (inlining_iterator iter (curr_event->get_location ());
1376 !iter.done_p (); iter.next ())
1378 logger->start_log_line ();
1379 logger->log_partial (" %qE (%p), fndecl: %qE, callsite: 0x%x",
1380 iter.get_block (), iter.get_block (),
1381 iter.get_fndecl (), iter.get_callsite ());
1382 if (iter.get_callsite ())
1383 dump_location (logger->get_printer (), iter.get_callsite ());
1384 logger->end_log_line ();
1388 /* We want to add events to show inlined calls.
1390 We want to show changes relative to the previous event, omitting
1391 the commonality between the inlining chain.
1393 The chain is ordered from innermost frame to outermost frame;
1394 we want to walk it backwards to show the calls, so capture it
1395 in a vec. */
1396 struct chain_element { tree m_block; tree m_fndecl; };
1397 auto_vec<chain_element> elements;
1398 for (inlining_iterator iter (curr_loc); !iter.done_p (); iter.next ())
1400 chain_element ce;
1401 ce.m_block = iter.get_block ();
1402 ce.m_fndecl = iter.get_fndecl ();
1404 if (!blocks_in_prev_event.contains (ce.m_block))
1405 elements.safe_push (ce);
1406 blocks_in_curr_event.add (ce.m_block);
1409 /* Walk from outermost to innermost. */
1410 if (elements.length () > 0)
1412 int orig_stack_depth = curr_event->get_original_stack_depth ();
1413 for (unsigned element_idx = elements.length () - 1; element_idx > 0;
1414 element_idx--)
1416 const chain_element &ce = elements[element_idx];
1417 int stack_depth_adjustment
1418 = (blocks_in_curr_event.elements () - element_idx) - 1;
1419 if (location_t callsite = BLOCK_SOURCE_LOCATION (ce.m_block))
1420 updated_events.safe_push
1421 (new inlined_call_event (callsite,
1422 elements[element_idx - 1].m_fndecl,
1423 ce.m_fndecl,
1424 orig_stack_depth,
1425 stack_depth_adjustment));
1429 /* Ideally we'd use assignment here:
1430 blocks_in_prev_event = blocks_in_curr_event; */
1431 blocks_in_prev_event.empty ();
1432 for (auto iter : blocks_in_curr_event)
1433 blocks_in_prev_event.add (iter);
1435 /* Add the existing event. */
1436 updated_events.safe_push (curr_event);
1439 /* Replace m_events with updated_events. */
1440 m_events.truncate (0);
1441 m_events.safe_splice (updated_events);
1443 maybe_log (logger, " after");
1446 } // namespace ana
1448 #endif /* #if ENABLE_ANALYZER */