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>.
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)
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/>. */
22 #define INCLUDE_MEMORY
23 #define INCLUDE_VECTOR
25 #include "coretypes.h"
28 #include "basic-block.h"
30 #include "diagnostic-core.h"
31 #include "gimple-pretty-print.h"
32 #include "fold-const.h"
33 #include "diagnostic-path.h"
38 #include "diagnostic-event-id.h"
39 #include "analyzer/analyzer.h"
40 #include "analyzer/analyzer-logging.h"
41 #include "analyzer/sm.h"
44 #include "ordered-hash-map.h"
45 #include "analyzer/call-string.h"
46 #include "analyzer/program-point.h"
47 #include "analyzer/store.h"
48 #include "analyzer/region-model.h"
49 #include "analyzer/program-state.h"
50 #include "analyzer/checker-path.h"
51 #include "gimple-iterator.h"
52 #include "inlining-iterator.h"
53 #include "analyzer/supergraph.h"
54 #include "analyzer/pending-diagnostic.h"
55 #include "analyzer/diagnostic-manager.h"
56 #include "analyzer/constraint-manager.h"
57 #include "analyzer/checker-event.h"
58 #include "analyzer/exploded-graph.h"
59 #include "diagnostic-format-sarif.h"
60 #include "tree-logical-location.h"
66 /* Get a string for EK. */
69 event_kind_to_string (enum event_kind ek
)
81 case EK_REGION_CREATION
:
82 return "EK_REGION_CREATION";
83 case EK_FUNCTION_ENTRY
:
84 return "EK_FUNCTION_ENTRY";
86 return "EK_STATE_CHANGE";
87 case EK_START_CFG_EDGE
:
88 return "EK_START_CFG_EDGE";
90 return "EK_END_CFG_EDGE";
92 return "EK_CALL_EDGE";
94 return "EK_RETURN_EDGE";
95 case EK_START_CONSOLIDATED_CFG_EDGES
:
96 return "EK_START_CONSOLIDATED_CFG_EDGES";
97 case EK_END_CONSOLIDATED_CFG_EDGES
:
98 return "EK_END_CONSOLIDATED_CFG_EDGES";
100 return "EK_INLINED_CALL";
103 case EK_REWIND_FROM_LONGJMP
:
104 return "EK_REWIND_FROM_LONGJMP";
105 case EK_REWIND_TO_SETJMP
:
106 return "EK_REWIND_TO_SETJMP";
112 /* class checker_event : public diagnostic_event. */
114 /* checker_event's ctor. */
116 checker_event::checker_event (enum event_kind kind
,
117 const event_loc_info
&loc_info
)
118 : m_kind (kind
), m_loc (loc_info
.m_loc
),
119 m_original_fndecl (loc_info
.m_fndecl
),
120 m_effective_fndecl (loc_info
.m_fndecl
),
121 m_original_depth (loc_info
.m_depth
),
122 m_effective_depth (loc_info
.m_depth
),
123 m_pending_diagnostic (NULL
), m_emission_id (),
124 m_logical_loc (loc_info
.m_fndecl
)
126 /* Update effective fndecl and depth if inlining has been recorded. */
127 if (flag_analyzer_undo_inlining
)
129 inlining_info
info (m_loc
);
130 if (info
.get_inner_fndecl ())
132 m_effective_fndecl
= info
.get_inner_fndecl ();
133 m_effective_depth
+= info
.get_extra_frames ();
134 m_logical_loc
= tree_logical_location (m_effective_fndecl
);
139 /* No-op implementation of diagnostic_event::get_meaning vfunc for
140 checker_event: checker events have no meaning by default. */
142 diagnostic_event::meaning
143 checker_event::get_meaning () const
148 /* Implementation of diagnostic_event::maybe_add_sarif_properties
149 for checker_event. */
153 maybe_add_sarif_properties (sarif_object
&thread_flow_loc_obj
) const
155 sarif_property_bag
&props
= thread_flow_loc_obj
.get_or_create_properties ();
156 #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
157 props
.set (PROPERTY_PREFIX
"emission_id",
158 diagnostic_event_id_to_json (m_emission_id
));
159 props
.set_string (PROPERTY_PREFIX
"kind", event_kind_to_string (m_kind
));
161 if (m_original_fndecl
!= m_effective_fndecl
)
163 tree_logical_location
logical_loc (m_original_fndecl
);
164 props
.set (PROPERTY_PREFIX
"original_fndecl",
165 make_sarif_logical_location_object (logical_loc
));
167 if (m_original_depth
!= m_effective_depth
)
168 props
.set_integer (PROPERTY_PREFIX
"original_depth", m_original_depth
);
169 #undef PROPERTY_PREFIX
172 /* Dump this event to PP (for debugging/logging purposes). */
175 checker_event::dump (pretty_printer
*pp
) const
177 label_text
event_desc (get_desc (false));
178 pp_printf (pp
, "\"%s\" (depth %i",
179 event_desc
.get (), m_effective_depth
);
181 if (m_effective_depth
!= m_original_depth
)
182 pp_printf (pp
, " corrected from %i",
184 if (m_effective_fndecl
)
186 pp_printf (pp
, ", fndecl %qE", m_effective_fndecl
);
187 if (m_effective_fndecl
!= m_original_fndecl
)
188 pp_printf (pp
, " corrected from %qE", m_original_fndecl
);
190 pp_printf (pp
, ", m_loc=%x)",
194 /* Dump this event to stderr (for debugging/logging purposes). */
197 checker_event::debug () const
200 pp_format_decoder (&pp
) = default_tree_printer
;
201 pp_show_color (&pp
) = pp_show_color (global_dc
->printer
);
202 pp
.set_output_stream (stderr
);
208 /* Hook for being notified when this event has its final id EMISSION_ID
209 and is about to emitted for PD.
211 Base implementation of checker_event::prepare_for_emission vfunc;
212 subclasses that override this should chain up to it.
214 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
215 side-effects of the call to get_desc take place before
216 pending_diagnostic::emit is called.
218 For example, state_change_event::get_desc can call
219 pending_diagnostic::describe_state_change; free_of_non_heap can use this
220 to tweak the message (TODO: would be neater to simply capture the
221 pertinent data within the sm-state). */
224 checker_event::prepare_for_emission (checker_path
*,
225 pending_diagnostic
*pd
,
226 diagnostic_event_id_t emission_id
)
228 m_pending_diagnostic
= pd
;
229 m_emission_id
= emission_id
;
231 label_text desc
= get_desc (false);
234 /* class debug_event : public checker_event. */
236 /* Implementation of diagnostic_event::get_desc vfunc for
238 Use the saved string as the event's description. */
241 debug_event::get_desc (bool) const
243 return label_text::borrow (m_desc
);
246 /* class precanned_custom_event : public custom_event. */
248 /* Implementation of diagnostic_event::get_desc vfunc for
249 precanned_custom_event.
250 Use the saved string as the event's description. */
253 precanned_custom_event::get_desc (bool) const
255 return label_text::borrow (m_desc
);
258 /* class statement_event : public checker_event. */
260 /* statement_event's ctor. */
262 statement_event::statement_event (const gimple
*stmt
, tree fndecl
, int depth
,
263 const program_state
&dst_state
)
264 : checker_event (EK_STMT
,
265 event_loc_info (gimple_location (stmt
), fndecl
, depth
)),
267 m_dst_state (dst_state
)
271 /* Implementation of diagnostic_event::get_desc vfunc for
273 Use the statement's dump form as the event's description. */
276 statement_event::get_desc (bool) const
279 pp_string (&pp
, "stmt: ");
280 pp_gimple_stmt_1 (&pp
, m_stmt
, 0, (dump_flags_t
)0);
281 return label_text::take (xstrdup (pp_formatted_text (&pp
)));
284 /* class region_creation_event : public checker_event. */
286 region_creation_event::region_creation_event (const event_loc_info
&loc_info
)
287 : checker_event (EK_REGION_CREATION
, loc_info
)
291 /* The various region_creation_event subclasses' get_desc
295 region_creation_event_memory_space::get_desc (bool) const
300 return label_text::borrow ("region created here");
302 return label_text::borrow ("region created on stack here");
304 return label_text::borrow ("region created on heap here");
309 region_creation_event_capacity::get_desc (bool can_colorize
) const
311 gcc_assert (m_capacity
);
312 if (TREE_CODE (m_capacity
) == INTEGER_CST
)
314 unsigned HOST_WIDE_INT hwi
= tree_to_uhwi (m_capacity
);
315 return make_label_text_n (can_colorize
,
317 "capacity: %wu byte",
318 "capacity: %wu bytes",
322 return make_label_text (can_colorize
,
323 "capacity: %qE bytes", m_capacity
);
327 region_creation_event_allocation_size::get_desc (bool can_colorize
) const
331 if (TREE_CODE (m_capacity
) == INTEGER_CST
)
332 return make_label_text_n (can_colorize
,
333 tree_to_uhwi (m_capacity
),
334 "allocated %E byte here",
335 "allocated %E bytes here",
338 return make_label_text (can_colorize
,
339 "allocated %qE bytes here",
342 return make_label_text (can_colorize
, "allocated here");
346 region_creation_event_debug::get_desc (bool) const
349 pp_format_decoder (&pp
) = default_tree_printer
;
350 pp_string (&pp
, "region creation: ");
351 m_reg
->dump_to_pp (&pp
, true);
353 pp_printf (&pp
, " capacity: %qE", m_capacity
);
354 return label_text::take (xstrdup (pp_formatted_text (&pp
)));
357 /* class function_entry_event : public checker_event. */
359 function_entry_event::function_entry_event (const program_point
&dst_point
)
360 : checker_event (EK_FUNCTION_ENTRY
,
361 event_loc_info (dst_point
.get_supernode
362 ()->get_start_location (),
363 dst_point
.get_fndecl (),
364 dst_point
.get_stack_depth ()))
368 /* Implementation of diagnostic_event::get_desc vfunc for
369 function_entry_event.
371 Use a string such as "entry to 'foo'" as the event's description. */
374 function_entry_event::get_desc (bool can_colorize
) const
376 return make_label_text (can_colorize
, "entry to %qE", m_effective_fndecl
);
379 /* Implementation of diagnostic_event::get_meaning vfunc for
382 diagnostic_event::meaning
383 function_entry_event::get_meaning () const
385 return meaning (VERB_enter
, NOUN_function
);
388 /* class state_change_event : public checker_event. */
390 /* state_change_event's ctor. */
392 state_change_event::state_change_event (const supernode
*node
,
395 const state_machine
&sm
,
397 state_machine::state_t from
,
398 state_machine::state_t to
,
399 const svalue
*origin
,
400 const program_state
&dst_state
,
401 const exploded_node
*enode
)
402 : checker_event (EK_STATE_CHANGE
,
403 event_loc_info (stmt
->location
,
406 m_node (node
), m_stmt (stmt
), m_sm (sm
),
407 m_sval (sval
), m_from (from
), m_to (to
),
409 m_dst_state (dst_state
),
414 /* Implementation of diagnostic_event::get_desc vfunc for
417 Attempt to generate a nicer human-readable description.
418 For greatest precision-of-wording, give the pending diagnostic
419 a chance to describe this state change (in terms of the
421 Note that we only have a pending_diagnostic set on the event once
422 the diagnostic is about to being emitted, so the description for
423 an event can change. */
426 state_change_event::get_desc (bool can_colorize
) const
428 if (m_pending_diagnostic
)
430 region_model
*model
= m_dst_state
.m_region_model
;
431 tree var
= model
->get_representative_tree (m_sval
);
432 tree origin
= model
->get_representative_tree (m_origin
);
433 label_text custom_desc
434 = m_pending_diagnostic
->describe_state_change
435 (evdesc::state_change (can_colorize
, var
, origin
,
436 m_from
, m_to
, m_emission_id
, *this));
437 if (custom_desc
.get ())
439 if (flag_analyzer_verbose_state_changes
)
441 /* Get any "meaning" of event. */
442 diagnostic_event::meaning meaning
= get_meaning ();
443 pretty_printer meaning_pp
;
444 meaning
.dump_to_pp (&meaning_pp
);
446 /* Append debug version. */
450 return make_label_text
452 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
458 pp_formatted_text (&meaning_pp
));
460 return make_label_text
462 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
467 pp_formatted_text (&meaning_pp
));
472 return make_label_text
474 "%s (state: %qs -> %qs, origin: %qE, meaning: %s)",
479 pp_formatted_text (&meaning_pp
));
481 return make_label_text
483 "%s (state: %qs -> %qs, NULL origin, meaning: %s)",
487 pp_formatted_text (&meaning_pp
));
495 /* Fallback description. */
498 label_text sval_desc
= m_sval
->get_desc ();
501 label_text origin_desc
= m_origin
->get_desc ();
502 return make_label_text
504 "state of %qs: %qs -> %qs (origin: %qs)",
511 return make_label_text
513 "state of %qs: %qs -> %qs (NULL origin)",
520 gcc_assert (m_origin
== NULL
);
521 return make_label_text
523 "global state: %qs -> %qs",
529 /* Implementation of diagnostic_event::get_meaning vfunc for
530 state change events: delegate to the pending_diagnostic to
533 diagnostic_event::meaning
534 state_change_event::get_meaning () const
536 if (m_pending_diagnostic
)
538 region_model
*model
= m_dst_state
.m_region_model
;
539 tree var
= model
->get_representative_tree (m_sval
);
540 tree origin
= model
->get_representative_tree (m_origin
);
541 return m_pending_diagnostic
->get_meaning_for_state_change
542 (evdesc::state_change (false, var
, origin
,
543 m_from
, m_to
, m_emission_id
, *this));
549 /* class superedge_event : public checker_event. */
551 /* Implementation of diagnostic_event::maybe_add_sarif_properties
552 for superedge_event. */
555 superedge_event::maybe_add_sarif_properties (sarif_object
&thread_flow_loc_obj
)
558 checker_event::maybe_add_sarif_properties (thread_flow_loc_obj
);
559 sarif_property_bag
&props
= thread_flow_loc_obj
.get_or_create_properties ();
560 #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
562 props
.set (PROPERTY_PREFIX
"superedge", m_sedge
->to_json ());
563 #undef PROPERTY_PREFIX
566 /* Get the callgraph_superedge for this superedge_event, which must be
567 for an interprocedural edge, rather than a CFG edge. */
569 const callgraph_superedge
&
570 superedge_event::get_callgraph_superedge () const
572 gcc_assert (m_sedge
->m_kind
!= SUPEREDGE_CFG_EDGE
);
573 return *m_sedge
->dyn_cast_callgraph_superedge ();
576 /* Determine if this event should be filtered at the given verbosity
580 superedge_event::should_filter_p (int verbosity
) const
582 switch (m_sedge
->m_kind
)
584 case SUPEREDGE_CFG_EDGE
:
591 /* Filter events with empty descriptions. This ought to filter
592 FALLTHRU, but retain true/false/switch edges. */
593 label_text desc
= get_desc (false);
594 gcc_assert (desc
.get ());
595 if (desc
.get ()[0] == '\0')
607 /* superedge_event's ctor. */
609 superedge_event::superedge_event (enum event_kind kind
,
610 const exploded_edge
&eedge
,
611 const event_loc_info
&loc_info
)
612 : checker_event (kind
, loc_info
),
613 m_eedge (eedge
), m_sedge (eedge
.m_sedge
),
614 m_var (NULL_TREE
), m_critical_state (0)
616 /* Note that m_sedge can be nullptr for e.g. jumps through
617 function pointers. */
620 /* class cfg_edge_event : public superedge_event. */
622 /* Get the cfg_superedge for this cfg_edge_event. */
624 const cfg_superedge
&
625 cfg_edge_event::get_cfg_superedge () const
627 return *m_sedge
->dyn_cast_cfg_superedge ();
630 /* cfg_edge_event's ctor. */
632 cfg_edge_event::cfg_edge_event (enum event_kind kind
,
633 const exploded_edge
&eedge
,
634 const event_loc_info
&loc_info
)
635 : superedge_event (kind
, eedge
, loc_info
)
637 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CFG_EDGE
);
640 /* Implementation of diagnostic_event::get_meaning vfunc for
643 diagnostic_event::meaning
644 cfg_edge_event::get_meaning () const
646 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
647 if (cfg_sedge
.true_value_p ())
648 return meaning (VERB_branch
, PROPERTY_true
);
649 else if (cfg_sedge
.false_value_p ())
650 return meaning (VERB_branch
, PROPERTY_false
);
655 /* class start_cfg_edge_event : public cfg_edge_event. */
657 /* Implementation of diagnostic_event::get_desc vfunc for
658 start_cfg_edge_event.
660 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
662 "taking 'true' edge SN:7 -> SN:8".
664 Otherwise, generate strings using the label of the underlying CFG if
666 "following 'true' branch..." or
667 "following 'case 3' branch..."
668 "following 'default' branch..."
670 For conditionals, attempt to supply a description of the condition that
672 "following 'false' branch (when 'ptr' is non-NULL)..."
674 Failing that, return an empty description (which will lead to this event
678 start_cfg_edge_event::get_desc (bool can_colorize
) const
680 bool user_facing
= !flag_analyzer_verbose_edges
;
681 label_text
edge_desc (m_sedge
->get_description (user_facing
));
684 if (edge_desc
.get () && strlen (edge_desc
.get ()) > 0)
686 label_text cond_desc
= maybe_describe_condition (can_colorize
);
688 if (cond_desc
.get ())
689 return make_label_text (can_colorize
,
690 "following %qs branch (%s)...",
691 edge_desc
.get (), cond_desc
.get ());
693 return make_label_text (can_colorize
,
694 "following %qs branch...",
698 return label_text::borrow ("");
702 if (strlen (edge_desc
.get ()) > 0)
703 return make_label_text (can_colorize
,
704 "taking %qs edge SN:%i -> SN:%i",
706 m_sedge
->m_src
->m_index
,
707 m_sedge
->m_dest
->m_index
);
709 return make_label_text (can_colorize
,
710 "taking edge SN:%i -> SN:%i",
711 m_sedge
->m_src
->m_index
,
712 m_sedge
->m_dest
->m_index
);
716 /* Attempt to generate a description of any condition that holds at this edge.
718 The intent is to make the user-facing messages more clear, especially for
719 cases where there's a single or double-negative, such as
720 when describing the false branch of an inverted condition.
722 For example, rather than printing just:
727 | (1) following 'false' branch...
729 it's clearer to spell out the condition that holds:
734 | (1) following 'false' branch (when 'ptr' is non-NULL)...
735 ^^^^^^^^^^^^^^^^^^^^^^
737 In the above example, this function would generate the highlighted
738 string: "when 'ptr' is non-NULL".
740 If the edge is not a condition, or it's not clear that a description of
741 the condition would be helpful to the user, return NULL. */
744 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
) const
746 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
748 if (cfg_sedge
.true_value_p () || cfg_sedge
.false_value_p ())
750 const gimple
*last_stmt
= m_sedge
->m_src
->get_last_stmt ();
751 if (const gcond
*cond_stmt
= dyn_cast
<const gcond
*> (last_stmt
))
753 enum tree_code op
= gimple_cond_code (cond_stmt
);
754 tree lhs
= gimple_cond_lhs (cond_stmt
);
755 tree rhs
= gimple_cond_rhs (cond_stmt
);
756 if (cfg_sedge
.false_value_p ())
757 op
= invert_tree_comparison (op
, false /* honor_nans */);
758 return maybe_describe_condition (can_colorize
,
762 return label_text::borrow (NULL
);
765 /* Subroutine of maybe_describe_condition above.
767 Attempt to generate a user-facing description of the condition
768 LHS OP RHS, but only if it is likely to make it easier for the
769 user to understand a condition. */
772 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
,
777 /* In theory we could just build a tree via
778 fold_build2 (op, boolean_type_node, lhs, rhs)
779 and print it with %qE on it, but this leads to warts such as
780 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
782 /* Special-case: describe testing the result of strcmp, as figuring
783 out what the "true" or "false" path is can be confusing to the user. */
784 if (TREE_CODE (lhs
) == SSA_NAME
787 if (gcall
*call
= dyn_cast
<gcall
*> (SSA_NAME_DEF_STMT (lhs
)))
788 if (is_special_named_call_p (call
, "strcmp", 2))
791 return label_text::borrow ("when the strings are equal");
793 return label_text::borrow ("when the strings are non-equal");
797 /* Only attempt to generate text for sufficiently simple expressions. */
798 if (!should_print_expr_p (lhs
))
799 return label_text::borrow (NULL
);
800 if (!should_print_expr_p (rhs
))
801 return label_text::borrow (NULL
);
803 /* Special cases for pointer comparisons against NULL. */
804 if (POINTER_TYPE_P (TREE_TYPE (lhs
))
805 && POINTER_TYPE_P (TREE_TYPE (rhs
))
809 return make_label_text (can_colorize
, "when %qE is NULL",
812 return make_label_text (can_colorize
, "when %qE is non-NULL",
816 return make_label_text (can_colorize
, "when %<%E %s %E%>",
817 lhs
, op_symbol_code (op
), rhs
);
820 /* Subroutine of maybe_describe_condition.
822 Return true if EXPR is we will get suitable user-facing output
826 start_cfg_edge_event::should_print_expr_p (tree expr
)
828 if (TREE_CODE (expr
) == SSA_NAME
)
830 if (SSA_NAME_VAR (expr
))
831 return should_print_expr_p (SSA_NAME_VAR (expr
));
839 if (CONSTANT_CLASS_P (expr
))
845 /* class call_event : public superedge_event. */
847 /* call_event's ctor. */
849 call_event::call_event (const exploded_edge
&eedge
,
850 const event_loc_info
&loc_info
)
851 : superedge_event (EK_CALL_EDGE
, eedge
, loc_info
)
854 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CALL
);
856 m_src_snode
= eedge
.m_src
->get_supernode ();
857 m_dest_snode
= eedge
.m_dest
->get_supernode ();
860 /* Implementation of diagnostic_event::get_desc vfunc for
863 If this call event passes critical state for an sm-based warning,
864 allow the diagnostic to generate a precise description, such as:
866 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
868 Otherwise, generate a description of the form
869 "calling 'foo' from 'bar'". */
872 call_event::get_desc (bool can_colorize
) const
874 if (m_critical_state
&& m_pending_diagnostic
)
877 tree var
= fixup_tree_for_diagnostic (m_var
);
878 label_text custom_desc
879 = m_pending_diagnostic
->describe_call_with_state
880 (evdesc::call_with_state (can_colorize
,
881 m_src_snode
->m_fun
->decl
,
882 m_dest_snode
->m_fun
->decl
,
885 if (custom_desc
.get ())
889 return make_label_text (can_colorize
,
890 "calling %qE from %qE",
891 get_callee_fndecl (),
892 get_caller_fndecl ());
895 /* Implementation of diagnostic_event::get_meaning vfunc for
896 function call events. */
898 diagnostic_event::meaning
899 call_event::get_meaning () const
901 return meaning (VERB_call
, NOUN_function
);
904 /* Override of checker_event::is_call_p for calls. */
907 call_event::is_call_p () const
913 call_event::get_caller_fndecl () const
915 return m_src_snode
->m_fun
->decl
;
919 call_event::get_callee_fndecl () const
921 return m_dest_snode
->m_fun
->decl
;
924 /* class return_event : public superedge_event. */
926 /* return_event's ctor. */
928 return_event::return_event (const exploded_edge
&eedge
,
929 const event_loc_info
&loc_info
)
930 : superedge_event (EK_RETURN_EDGE
, eedge
, loc_info
)
933 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_RETURN
);
935 m_src_snode
= eedge
.m_src
->get_supernode ();
936 m_dest_snode
= eedge
.m_dest
->get_supernode ();
939 /* Implementation of diagnostic_event::get_desc vfunc for
942 If this return event returns critical state for an sm-based warning,
943 allow the diagnostic to generate a precise description, such as:
945 "possible of NULL to 'foo' from 'bar'"
947 Otherwise, generate a description of the form
948 "returning to 'foo' from 'bar'. */
951 return_event::get_desc (bool can_colorize
) const
953 /* For greatest precision-of-wording, if this is returning the
954 state involved in the pending diagnostic, give the pending
955 diagnostic a chance to describe this return (in terms of
957 if (m_critical_state
&& m_pending_diagnostic
)
959 label_text custom_desc
960 = m_pending_diagnostic
->describe_return_of_state
961 (evdesc::return_of_state (can_colorize
,
962 m_dest_snode
->m_fun
->decl
,
963 m_src_snode
->m_fun
->decl
,
965 if (custom_desc
.get ())
968 return make_label_text (can_colorize
,
969 "returning to %qE from %qE",
970 m_dest_snode
->m_fun
->decl
,
971 m_src_snode
->m_fun
->decl
);
974 /* Implementation of diagnostic_event::get_meaning vfunc for
975 function return events. */
977 diagnostic_event::meaning
978 return_event::get_meaning () const
980 return meaning (VERB_return
, NOUN_function
);
983 /* Override of checker_event::is_return_p for returns. */
986 return_event::is_return_p () const
991 /* class start_consolidated_cfg_edges_event : public checker_event. */
994 start_consolidated_cfg_edges_event::get_desc (bool can_colorize
) const
996 return make_label_text (can_colorize
,
997 "following %qs branch...",
998 m_edge_sense
? "true" : "false");
1001 /* Implementation of diagnostic_event::get_meaning vfunc for
1002 start_consolidated_cfg_edges_event. */
1004 diagnostic_event::meaning
1005 start_consolidated_cfg_edges_event::get_meaning () const
1007 return meaning (VERB_branch
,
1008 (m_edge_sense
? PROPERTY_true
: PROPERTY_false
));
1011 /* class inlined_call_event : public checker_event. */
1014 inlined_call_event::get_desc (bool can_colorize
) const
1016 return make_label_text (can_colorize
,
1017 "inlined call to %qE from %qE",
1018 m_apparent_callee_fndecl
,
1019 m_apparent_caller_fndecl
);
1022 /* Implementation of diagnostic_event::get_meaning vfunc for
1023 reconstructed inlined function calls. */
1025 diagnostic_event::meaning
1026 inlined_call_event::get_meaning () const
1028 return meaning (VERB_call
, NOUN_function
);
1031 /* class setjmp_event : public checker_event. */
1033 /* Implementation of diagnostic_event::get_desc vfunc for
1037 setjmp_event::get_desc (bool can_colorize
) const
1039 return make_label_text (can_colorize
,
1041 get_user_facing_name (m_setjmp_call
));
1044 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1046 Record this setjmp's event ID into the path, so that rewind events can
1050 setjmp_event::prepare_for_emission (checker_path
*path
,
1051 pending_diagnostic
*pd
,
1052 diagnostic_event_id_t emission_id
)
1054 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1055 path
->record_setjmp_event (m_enode
, emission_id
);
1058 /* class rewind_event : public checker_event. */
1060 /* Get the fndecl containing the site of the longjmp call. */
1063 rewind_event::get_longjmp_caller () const
1065 return m_eedge
->m_src
->get_function ()->decl
;
1068 /* Get the fndecl containing the site of the setjmp call. */
1071 rewind_event::get_setjmp_caller () const
1073 return m_eedge
->m_dest
->get_function ()->decl
;
1076 /* rewind_event's ctor. */
1078 rewind_event::rewind_event (const exploded_edge
*eedge
,
1079 enum event_kind kind
,
1080 const event_loc_info
&loc_info
,
1081 const rewind_info_t
*rewind_info
)
1082 : checker_event (kind
, loc_info
),
1083 m_rewind_info (rewind_info
),
1086 gcc_assert (m_eedge
->m_custom_info
.get () == m_rewind_info
);
1089 /* class rewind_from_longjmp_event : public rewind_event. */
1091 /* Implementation of diagnostic_event::get_desc vfunc for
1092 rewind_from_longjmp_event. */
1095 rewind_from_longjmp_event::get_desc (bool can_colorize
) const
1097 const char *src_name
1098 = get_user_facing_name (m_rewind_info
->get_longjmp_call ());
1100 if (get_longjmp_caller () == get_setjmp_caller ())
1101 /* Special-case: purely intraprocedural rewind. */
1102 return make_label_text (can_colorize
,
1103 "rewinding within %qE from %qs...",
1104 get_longjmp_caller (),
1107 return make_label_text (can_colorize
,
1108 "rewinding from %qs in %qE...",
1110 get_longjmp_caller ());
1113 /* class rewind_to_setjmp_event : public rewind_event. */
1115 /* Implementation of diagnostic_event::get_desc vfunc for
1116 rewind_to_setjmp_event. */
1119 rewind_to_setjmp_event::get_desc (bool can_colorize
) const
1121 const char *dst_name
1122 = get_user_facing_name (m_rewind_info
->get_setjmp_call ());
1124 /* If we can, identify the ID of the setjmp_event. */
1125 if (m_original_setjmp_event_id
.known_p ())
1127 if (get_longjmp_caller () == get_setjmp_caller ())
1128 /* Special-case: purely intraprocedural rewind. */
1129 return make_label_text (can_colorize
,
1130 "...to %qs (saved at %@)",
1132 &m_original_setjmp_event_id
);
1134 return make_label_text (can_colorize
,
1135 "...to %qs in %qE (saved at %@)",
1137 get_setjmp_caller (),
1138 &m_original_setjmp_event_id
);
1142 if (get_longjmp_caller () == get_setjmp_caller ())
1143 /* Special-case: purely intraprocedural rewind. */
1144 return make_label_text (can_colorize
,
1147 get_setjmp_caller ());
1149 return make_label_text (can_colorize
,
1152 get_setjmp_caller ());
1156 /* Implementation of checker_event::prepare_for_emission vfunc for
1157 rewind_to_setjmp_event.
1159 Attempt to look up the setjmp event ID that recorded the jmp_buf
1163 rewind_to_setjmp_event::prepare_for_emission (checker_path
*path
,
1164 pending_diagnostic
*pd
,
1165 diagnostic_event_id_t emission_id
)
1167 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1168 path
->get_setjmp_event (m_rewind_info
->get_enode_origin (),
1169 &m_original_setjmp_event_id
);
1172 /* class warning_event : public checker_event. */
1174 /* Implementation of diagnostic_event::get_desc vfunc for
1177 If the pending diagnostic implements describe_final_event, use it,
1178 generating a precise description e.g.
1179 "second 'free' here; first 'free' was at (7)"
1181 Otherwise generate a generic description. */
1184 warning_event::get_desc (bool can_colorize
) const
1186 if (m_pending_diagnostic
)
1188 tree var
= fixup_tree_for_diagnostic (m_var
);
1190 = m_pending_diagnostic
->describe_final_event
1191 (evdesc::final_event (can_colorize
, var
, m_state
, *this));
1194 if (m_sm
&& flag_analyzer_verbose_state_changes
)
1197 return make_label_text (can_colorize
,
1198 "%s (%qE is in state %qs)",
1200 var
, m_state
->get_name ());
1202 return make_label_text (can_colorize
,
1203 "%s (in global state %qs)",
1205 m_state
->get_name ());
1215 return make_label_text (can_colorize
,
1216 "here (%qE is in state %qs)",
1217 m_var
, m_state
->get_name ());
1219 return make_label_text (can_colorize
,
1220 "here (in global state %qs)",
1221 m_state
->get_name ());
1224 return label_text::borrow ("here");
1227 /* Implementation of diagnostic_event::get_meaning vfunc for
1230 diagnostic_event::meaning
1231 warning_event::get_meaning () const
1233 return meaning (VERB_danger
, NOUN_unknown
);
1238 #endif /* #if ENABLE_ANALYZER */