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
24 #include "coretypes.h"
27 #include "basic-block.h"
29 #include "diagnostic-core.h"
30 #include "gimple-pretty-print.h"
31 #include "fold-const.h"
32 #include "diagnostic-path.h"
37 #include "diagnostic-event-id.h"
38 #include "analyzer/analyzer.h"
39 #include "analyzer/analyzer-logging.h"
40 #include "analyzer/sm.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"
65 /* Get a string for EK. */
68 event_kind_to_string (enum event_kind ek
)
80 case EK_REGION_CREATION
:
81 return "EK_REGION_CREATION";
82 case EK_FUNCTION_ENTRY
:
83 return "EK_FUNCTION_ENTRY";
85 return "EK_STATE_CHANGE";
86 case EK_START_CFG_EDGE
:
87 return "EK_START_CFG_EDGE";
89 return "EK_END_CFG_EDGE";
91 return "EK_CALL_EDGE";
93 return "EK_RETURN_EDGE";
94 case EK_START_CONSOLIDATED_CFG_EDGES
:
95 return "EK_START_CONSOLIDATED_CFG_EDGES";
96 case EK_END_CONSOLIDATED_CFG_EDGES
:
97 return "EK_END_CONSOLIDATED_CFG_EDGES";
99 return "EK_INLINED_CALL";
102 case EK_REWIND_FROM_LONGJMP
:
103 return "EK_REWIND_FROM_LONGJMP";
104 case EK_REWIND_TO_SETJMP
:
105 return "EK_REWIND_TO_SETJMP";
111 /* class checker_event : public diagnostic_event. */
113 /* checker_event's ctor. */
115 checker_event::checker_event (enum event_kind kind
,
116 const event_loc_info
&loc_info
)
117 : m_kind (kind
), m_loc (loc_info
.m_loc
),
118 m_original_fndecl (loc_info
.m_fndecl
),
119 m_effective_fndecl (loc_info
.m_fndecl
),
120 m_original_depth (loc_info
.m_depth
),
121 m_effective_depth (loc_info
.m_depth
),
122 m_pending_diagnostic (NULL
), m_emission_id (),
123 m_logical_loc (loc_info
.m_fndecl
)
125 /* Update effective fndecl and depth if inlining has been recorded. */
126 if (flag_analyzer_undo_inlining
)
128 inlining_info
info (m_loc
);
129 if (info
.get_inner_fndecl ())
131 m_effective_fndecl
= info
.get_inner_fndecl ();
132 m_effective_depth
+= info
.get_extra_frames ();
133 m_logical_loc
= tree_logical_location (m_effective_fndecl
);
138 /* No-op implementation of diagnostic_event::get_meaning vfunc for
139 checker_event: checker events have no meaning by default. */
141 diagnostic_event::meaning
142 checker_event::get_meaning () const
147 /* Implementation of diagnostic_event::maybe_add_sarif_properties
148 for checker_event. */
152 maybe_add_sarif_properties (sarif_object
&thread_flow_loc_obj
) const
154 sarif_property_bag
&props
= thread_flow_loc_obj
.get_or_create_properties ();
155 #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
156 props
.set (PROPERTY_PREFIX
"emission_id",
157 diagnostic_event_id_to_json (m_emission_id
));
158 props
.set_string (PROPERTY_PREFIX
"kind", event_kind_to_string (m_kind
));
160 if (m_original_fndecl
!= m_effective_fndecl
)
162 tree_logical_location
logical_loc (m_original_fndecl
);
163 props
.set (PROPERTY_PREFIX
"original_fndecl",
164 make_sarif_logical_location_object (logical_loc
));
166 if (m_original_depth
!= m_effective_depth
)
167 props
.set_integer (PROPERTY_PREFIX
"original_depth", m_original_depth
);
168 #undef PROPERTY_PREFIX
171 /* Dump this event to PP (for debugging/logging purposes). */
174 checker_event::dump (pretty_printer
*pp
) const
176 label_text
event_desc (get_desc (false));
177 pp_printf (pp
, "\"%s\" (depth %i",
178 event_desc
.get (), m_effective_depth
);
180 if (m_effective_depth
!= m_original_depth
)
181 pp_printf (pp
, " corrected from %i",
183 if (m_effective_fndecl
)
185 pp_printf (pp
, ", fndecl %qE", m_effective_fndecl
);
186 if (m_effective_fndecl
!= m_original_fndecl
)
187 pp_printf (pp
, " corrected from %qE", m_original_fndecl
);
189 pp_printf (pp
, ", m_loc=%x)",
193 /* Dump this event to stderr (for debugging/logging purposes). */
196 checker_event::debug () const
199 pp_format_decoder (&pp
) = default_tree_printer
;
200 pp_show_color (&pp
) = pp_show_color (global_dc
->printer
);
201 pp
.buffer
->stream
= stderr
;
207 /* Hook for being notified when this event has its final id EMISSION_ID
208 and is about to emitted for PD.
210 Base implementation of checker_event::prepare_for_emission vfunc;
211 subclasses that override this should chain up to it.
213 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
214 side-effects of the call to get_desc take place before
215 pending_diagnostic::emit is called.
217 For example, state_change_event::get_desc can call
218 pending_diagnostic::describe_state_change; free_of_non_heap can use this
219 to tweak the message (TODO: would be neater to simply capture the
220 pertinent data within the sm-state). */
223 checker_event::prepare_for_emission (checker_path
*,
224 pending_diagnostic
*pd
,
225 diagnostic_event_id_t emission_id
)
227 m_pending_diagnostic
= pd
;
228 m_emission_id
= emission_id
;
230 label_text desc
= get_desc (false);
233 /* class debug_event : public checker_event. */
235 /* Implementation of diagnostic_event::get_desc vfunc for
237 Use the saved string as the event's description. */
240 debug_event::get_desc (bool) const
242 return label_text::borrow (m_desc
);
245 /* class precanned_custom_event : public custom_event. */
247 /* Implementation of diagnostic_event::get_desc vfunc for
248 precanned_custom_event.
249 Use the saved string as the event's description. */
252 precanned_custom_event::get_desc (bool) const
254 return label_text::borrow (m_desc
);
257 /* class statement_event : public checker_event. */
259 /* statement_event's ctor. */
261 statement_event::statement_event (const gimple
*stmt
, tree fndecl
, int depth
,
262 const program_state
&dst_state
)
263 : checker_event (EK_STMT
,
264 event_loc_info (gimple_location (stmt
), fndecl
, depth
)),
266 m_dst_state (dst_state
)
270 /* Implementation of diagnostic_event::get_desc vfunc for
272 Use the statement's dump form as the event's description. */
275 statement_event::get_desc (bool) const
278 pp_string (&pp
, "stmt: ");
279 pp_gimple_stmt_1 (&pp
, m_stmt
, 0, (dump_flags_t
)0);
280 return label_text::take (xstrdup (pp_formatted_text (&pp
)));
283 /* class region_creation_event : public checker_event. */
285 region_creation_event::region_creation_event (const event_loc_info
&loc_info
)
286 : checker_event (EK_REGION_CREATION
, loc_info
)
290 /* The various region_creation_event subclasses' get_desc
294 region_creation_event_memory_space::get_desc (bool) const
299 return label_text::borrow ("region created here");
301 return label_text::borrow ("region created on stack here");
303 return label_text::borrow ("region created on heap here");
308 region_creation_event_capacity::get_desc (bool can_colorize
) const
310 gcc_assert (m_capacity
);
311 if (TREE_CODE (m_capacity
) == INTEGER_CST
)
313 unsigned HOST_WIDE_INT hwi
= tree_to_uhwi (m_capacity
);
314 return make_label_text_n (can_colorize
,
316 "capacity: %wu byte",
317 "capacity: %wu bytes",
321 return make_label_text (can_colorize
,
322 "capacity: %qE bytes", m_capacity
);
326 region_creation_event_allocation_size::get_desc (bool can_colorize
) const
330 if (TREE_CODE (m_capacity
) == INTEGER_CST
)
331 return make_label_text_n (can_colorize
,
332 tree_to_uhwi (m_capacity
),
333 "allocated %E byte here",
334 "allocated %E bytes here",
337 return make_label_text (can_colorize
,
338 "allocated %qE bytes here",
341 return make_label_text (can_colorize
, "allocated here");
345 region_creation_event_debug::get_desc (bool) const
348 pp_format_decoder (&pp
) = default_tree_printer
;
349 pp_string (&pp
, "region creation: ");
350 m_reg
->dump_to_pp (&pp
, true);
352 pp_printf (&pp
, " capacity: %qE", m_capacity
);
353 return label_text::take (xstrdup (pp_formatted_text (&pp
)));
356 /* class function_entry_event : public checker_event. */
358 function_entry_event::function_entry_event (const program_point
&dst_point
)
359 : checker_event (EK_FUNCTION_ENTRY
,
360 event_loc_info (dst_point
.get_supernode
361 ()->get_start_location (),
362 dst_point
.get_fndecl (),
363 dst_point
.get_stack_depth ()))
367 /* Implementation of diagnostic_event::get_desc vfunc for
368 function_entry_event.
370 Use a string such as "entry to 'foo'" as the event's description. */
373 function_entry_event::get_desc (bool can_colorize
) const
375 return make_label_text (can_colorize
, "entry to %qE", m_effective_fndecl
);
378 /* Implementation of diagnostic_event::get_meaning vfunc for
381 diagnostic_event::meaning
382 function_entry_event::get_meaning () const
384 return meaning (VERB_enter
, NOUN_function
);
387 /* class state_change_event : public checker_event. */
389 /* state_change_event's ctor. */
391 state_change_event::state_change_event (const supernode
*node
,
394 const state_machine
&sm
,
396 state_machine::state_t from
,
397 state_machine::state_t to
,
398 const svalue
*origin
,
399 const program_state
&dst_state
,
400 const exploded_node
*enode
)
401 : checker_event (EK_STATE_CHANGE
,
402 event_loc_info (stmt
->location
,
405 m_node (node
), m_stmt (stmt
), m_sm (sm
),
406 m_sval (sval
), m_from (from
), m_to (to
),
408 m_dst_state (dst_state
),
413 /* Implementation of diagnostic_event::get_desc vfunc for
416 Attempt to generate a nicer human-readable description.
417 For greatest precision-of-wording, give the pending diagnostic
418 a chance to describe this state change (in terms of the
420 Note that we only have a pending_diagnostic set on the event once
421 the diagnostic is about to being emitted, so the description for
422 an event can change. */
425 state_change_event::get_desc (bool can_colorize
) const
427 if (m_pending_diagnostic
)
429 region_model
*model
= m_dst_state
.m_region_model
;
430 tree var
= model
->get_representative_tree (m_sval
);
431 tree origin
= model
->get_representative_tree (m_origin
);
432 label_text custom_desc
433 = m_pending_diagnostic
->describe_state_change
434 (evdesc::state_change (can_colorize
, var
, origin
,
435 m_from
, m_to
, m_emission_id
, *this));
436 if (custom_desc
.get ())
438 if (flag_analyzer_verbose_state_changes
)
440 /* Get any "meaning" of event. */
441 diagnostic_event::meaning meaning
= get_meaning ();
442 pretty_printer meaning_pp
;
443 meaning
.dump_to_pp (&meaning_pp
);
445 /* Append debug version. */
449 return make_label_text
451 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
457 pp_formatted_text (&meaning_pp
));
459 return make_label_text
461 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
466 pp_formatted_text (&meaning_pp
));
471 return make_label_text
473 "%s (state: %qs -> %qs, origin: %qE, meaning: %s)",
478 pp_formatted_text (&meaning_pp
));
480 return make_label_text
482 "%s (state: %qs -> %qs, NULL origin, meaning: %s)",
486 pp_formatted_text (&meaning_pp
));
494 /* Fallback description. */
497 label_text sval_desc
= m_sval
->get_desc ();
500 label_text origin_desc
= m_origin
->get_desc ();
501 return make_label_text
503 "state of %qs: %qs -> %qs (origin: %qs)",
510 return make_label_text
512 "state of %qs: %qs -> %qs (NULL origin)",
519 gcc_assert (m_origin
== NULL
);
520 return make_label_text
522 "global state: %qs -> %qs",
528 /* Implementation of diagnostic_event::get_meaning vfunc for
529 state change events: delegate to the pending_diagnostic to
532 diagnostic_event::meaning
533 state_change_event::get_meaning () const
535 if (m_pending_diagnostic
)
537 region_model
*model
= m_dst_state
.m_region_model
;
538 tree var
= model
->get_representative_tree (m_sval
);
539 tree origin
= model
->get_representative_tree (m_origin
);
540 return m_pending_diagnostic
->get_meaning_for_state_change
541 (evdesc::state_change (false, var
, origin
,
542 m_from
, m_to
, m_emission_id
, *this));
548 /* class superedge_event : public checker_event. */
550 /* Implementation of diagnostic_event::maybe_add_sarif_properties
551 for superedge_event. */
554 superedge_event::maybe_add_sarif_properties (sarif_object
&thread_flow_loc_obj
)
557 checker_event::maybe_add_sarif_properties (thread_flow_loc_obj
);
558 sarif_property_bag
&props
= thread_flow_loc_obj
.get_or_create_properties ();
559 #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
561 props
.set (PROPERTY_PREFIX
"superedge", m_sedge
->to_json ());
562 #undef PROPERTY_PREFIX
565 /* Get the callgraph_superedge for this superedge_event, which must be
566 for an interprocedural edge, rather than a CFG edge. */
568 const callgraph_superedge
&
569 superedge_event::get_callgraph_superedge () const
571 gcc_assert (m_sedge
->m_kind
!= SUPEREDGE_CFG_EDGE
);
572 return *m_sedge
->dyn_cast_callgraph_superedge ();
575 /* Determine if this event should be filtered at the given verbosity
579 superedge_event::should_filter_p (int verbosity
) const
581 switch (m_sedge
->m_kind
)
583 case SUPEREDGE_CFG_EDGE
:
590 /* Filter events with empty descriptions. This ought to filter
591 FALLTHRU, but retain true/false/switch edges. */
592 label_text desc
= get_desc (false);
593 gcc_assert (desc
.get ());
594 if (desc
.get ()[0] == '\0')
606 /* superedge_event's ctor. */
608 superedge_event::superedge_event (enum event_kind kind
,
609 const exploded_edge
&eedge
,
610 const event_loc_info
&loc_info
)
611 : checker_event (kind
, loc_info
),
612 m_eedge (eedge
), m_sedge (eedge
.m_sedge
),
613 m_var (NULL_TREE
), m_critical_state (0)
615 /* Note that m_sedge can be nullptr for e.g. jumps through
616 function pointers. */
619 /* class cfg_edge_event : public superedge_event. */
621 /* Get the cfg_superedge for this cfg_edge_event. */
623 const cfg_superedge
&
624 cfg_edge_event::get_cfg_superedge () const
626 return *m_sedge
->dyn_cast_cfg_superedge ();
629 /* cfg_edge_event's ctor. */
631 cfg_edge_event::cfg_edge_event (enum event_kind kind
,
632 const exploded_edge
&eedge
,
633 const event_loc_info
&loc_info
)
634 : superedge_event (kind
, eedge
, loc_info
)
636 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CFG_EDGE
);
639 /* Implementation of diagnostic_event::get_meaning vfunc for
642 diagnostic_event::meaning
643 cfg_edge_event::get_meaning () const
645 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
646 if (cfg_sedge
.true_value_p ())
647 return meaning (VERB_branch
, PROPERTY_true
);
648 else if (cfg_sedge
.false_value_p ())
649 return meaning (VERB_branch
, PROPERTY_false
);
654 /* class start_cfg_edge_event : public cfg_edge_event. */
656 /* Implementation of diagnostic_event::get_desc vfunc for
657 start_cfg_edge_event.
659 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
661 "taking 'true' edge SN:7 -> SN:8".
663 Otherwise, generate strings using the label of the underlying CFG if
665 "following 'true' branch..." or
666 "following 'case 3' branch..."
667 "following 'default' branch..."
669 For conditionals, attempt to supply a description of the condition that
671 "following 'false' branch (when 'ptr' is non-NULL)..."
673 Failing that, return an empty description (which will lead to this event
677 start_cfg_edge_event::get_desc (bool can_colorize
) const
679 bool user_facing
= !flag_analyzer_verbose_edges
;
680 label_text
edge_desc (m_sedge
->get_description (user_facing
));
683 if (edge_desc
.get () && strlen (edge_desc
.get ()) > 0)
685 label_text cond_desc
= maybe_describe_condition (can_colorize
);
687 if (cond_desc
.get ())
688 return make_label_text (can_colorize
,
689 "following %qs branch (%s)...",
690 edge_desc
.get (), cond_desc
.get ());
692 return make_label_text (can_colorize
,
693 "following %qs branch...",
697 return label_text::borrow ("");
701 if (strlen (edge_desc
.get ()) > 0)
702 return make_label_text (can_colorize
,
703 "taking %qs edge SN:%i -> SN:%i",
705 m_sedge
->m_src
->m_index
,
706 m_sedge
->m_dest
->m_index
);
708 return make_label_text (can_colorize
,
709 "taking edge SN:%i -> SN:%i",
710 m_sedge
->m_src
->m_index
,
711 m_sedge
->m_dest
->m_index
);
715 /* Attempt to generate a description of any condition that holds at this edge.
717 The intent is to make the user-facing messages more clear, especially for
718 cases where there's a single or double-negative, such as
719 when describing the false branch of an inverted condition.
721 For example, rather than printing just:
726 | (1) following 'false' branch...
728 it's clearer to spell out the condition that holds:
733 | (1) following 'false' branch (when 'ptr' is non-NULL)...
734 ^^^^^^^^^^^^^^^^^^^^^^
736 In the above example, this function would generate the highlighted
737 string: "when 'ptr' is non-NULL".
739 If the edge is not a condition, or it's not clear that a description of
740 the condition would be helpful to the user, return NULL. */
743 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
) const
745 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
747 if (cfg_sedge
.true_value_p () || cfg_sedge
.false_value_p ())
749 const gimple
*last_stmt
= m_sedge
->m_src
->get_last_stmt ();
750 if (const gcond
*cond_stmt
= dyn_cast
<const gcond
*> (last_stmt
))
752 enum tree_code op
= gimple_cond_code (cond_stmt
);
753 tree lhs
= gimple_cond_lhs (cond_stmt
);
754 tree rhs
= gimple_cond_rhs (cond_stmt
);
755 if (cfg_sedge
.false_value_p ())
756 op
= invert_tree_comparison (op
, false /* honor_nans */);
757 return maybe_describe_condition (can_colorize
,
761 return label_text::borrow (NULL
);
764 /* Subroutine of maybe_describe_condition above.
766 Attempt to generate a user-facing description of the condition
767 LHS OP RHS, but only if it is likely to make it easier for the
768 user to understand a condition. */
771 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
,
776 /* In theory we could just build a tree via
777 fold_build2 (op, boolean_type_node, lhs, rhs)
778 and print it with %qE on it, but this leads to warts such as
779 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
781 /* Special-case: describe testing the result of strcmp, as figuring
782 out what the "true" or "false" path is can be confusing to the user. */
783 if (TREE_CODE (lhs
) == SSA_NAME
786 if (gcall
*call
= dyn_cast
<gcall
*> (SSA_NAME_DEF_STMT (lhs
)))
787 if (is_special_named_call_p (call
, "strcmp", 2))
790 return label_text::borrow ("when the strings are equal");
792 return label_text::borrow ("when the strings are non-equal");
796 /* Only attempt to generate text for sufficiently simple expressions. */
797 if (!should_print_expr_p (lhs
))
798 return label_text::borrow (NULL
);
799 if (!should_print_expr_p (rhs
))
800 return label_text::borrow (NULL
);
802 /* Special cases for pointer comparisons against NULL. */
803 if (POINTER_TYPE_P (TREE_TYPE (lhs
))
804 && POINTER_TYPE_P (TREE_TYPE (rhs
))
808 return make_label_text (can_colorize
, "when %qE is NULL",
811 return make_label_text (can_colorize
, "when %qE is non-NULL",
815 return make_label_text (can_colorize
, "when %<%E %s %E%>",
816 lhs
, op_symbol_code (op
), rhs
);
819 /* Subroutine of maybe_describe_condition.
821 Return true if EXPR is we will get suitable user-facing output
825 start_cfg_edge_event::should_print_expr_p (tree expr
)
827 if (TREE_CODE (expr
) == SSA_NAME
)
829 if (SSA_NAME_VAR (expr
))
830 return should_print_expr_p (SSA_NAME_VAR (expr
));
838 if (CONSTANT_CLASS_P (expr
))
844 /* class call_event : public superedge_event. */
846 /* call_event's ctor. */
848 call_event::call_event (const exploded_edge
&eedge
,
849 const event_loc_info
&loc_info
)
850 : superedge_event (EK_CALL_EDGE
, eedge
, loc_info
)
853 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CALL
);
855 m_src_snode
= eedge
.m_src
->get_supernode ();
856 m_dest_snode
= eedge
.m_dest
->get_supernode ();
859 /* Implementation of diagnostic_event::get_desc vfunc for
862 If this call event passes critical state for an sm-based warning,
863 allow the diagnostic to generate a precise description, such as:
865 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
867 Otherwise, generate a description of the form
868 "calling 'foo' from 'bar'". */
871 call_event::get_desc (bool can_colorize
) const
873 if (m_critical_state
&& m_pending_diagnostic
)
876 tree var
= fixup_tree_for_diagnostic (m_var
);
877 label_text custom_desc
878 = m_pending_diagnostic
->describe_call_with_state
879 (evdesc::call_with_state (can_colorize
,
880 m_src_snode
->m_fun
->decl
,
881 m_dest_snode
->m_fun
->decl
,
884 if (custom_desc
.get ())
888 return make_label_text (can_colorize
,
889 "calling %qE from %qE",
890 get_callee_fndecl (),
891 get_caller_fndecl ());
894 /* Implementation of diagnostic_event::get_meaning vfunc for
895 function call events. */
897 diagnostic_event::meaning
898 call_event::get_meaning () const
900 return meaning (VERB_call
, NOUN_function
);
903 /* Override of checker_event::is_call_p for calls. */
906 call_event::is_call_p () const
912 call_event::get_caller_fndecl () const
914 return m_src_snode
->m_fun
->decl
;
918 call_event::get_callee_fndecl () const
920 return m_dest_snode
->m_fun
->decl
;
923 /* class return_event : public superedge_event. */
925 /* return_event's ctor. */
927 return_event::return_event (const exploded_edge
&eedge
,
928 const event_loc_info
&loc_info
)
929 : superedge_event (EK_RETURN_EDGE
, eedge
, loc_info
)
932 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_RETURN
);
934 m_src_snode
= eedge
.m_src
->get_supernode ();
935 m_dest_snode
= eedge
.m_dest
->get_supernode ();
938 /* Implementation of diagnostic_event::get_desc vfunc for
941 If this return event returns critical state for an sm-based warning,
942 allow the diagnostic to generate a precise description, such as:
944 "possible of NULL to 'foo' from 'bar'"
946 Otherwise, generate a description of the form
947 "returning to 'foo' from 'bar'. */
950 return_event::get_desc (bool can_colorize
) const
952 /* For greatest precision-of-wording, if this is returning the
953 state involved in the pending diagnostic, give the pending
954 diagnostic a chance to describe this return (in terms of
956 if (m_critical_state
&& m_pending_diagnostic
)
958 label_text custom_desc
959 = m_pending_diagnostic
->describe_return_of_state
960 (evdesc::return_of_state (can_colorize
,
961 m_dest_snode
->m_fun
->decl
,
962 m_src_snode
->m_fun
->decl
,
964 if (custom_desc
.get ())
967 return make_label_text (can_colorize
,
968 "returning to %qE from %qE",
969 m_dest_snode
->m_fun
->decl
,
970 m_src_snode
->m_fun
->decl
);
973 /* Implementation of diagnostic_event::get_meaning vfunc for
974 function return events. */
976 diagnostic_event::meaning
977 return_event::get_meaning () const
979 return meaning (VERB_return
, NOUN_function
);
982 /* Override of checker_event::is_return_p for returns. */
985 return_event::is_return_p () const
990 /* class start_consolidated_cfg_edges_event : public checker_event. */
993 start_consolidated_cfg_edges_event::get_desc (bool can_colorize
) const
995 return make_label_text (can_colorize
,
996 "following %qs branch...",
997 m_edge_sense
? "true" : "false");
1000 /* Implementation of diagnostic_event::get_meaning vfunc for
1001 start_consolidated_cfg_edges_event. */
1003 diagnostic_event::meaning
1004 start_consolidated_cfg_edges_event::get_meaning () const
1006 return meaning (VERB_branch
,
1007 (m_edge_sense
? PROPERTY_true
: PROPERTY_false
));
1010 /* class inlined_call_event : public checker_event. */
1013 inlined_call_event::get_desc (bool can_colorize
) const
1015 return make_label_text (can_colorize
,
1016 "inlined call to %qE from %qE",
1017 m_apparent_callee_fndecl
,
1018 m_apparent_caller_fndecl
);
1021 /* Implementation of diagnostic_event::get_meaning vfunc for
1022 reconstructed inlined function calls. */
1024 diagnostic_event::meaning
1025 inlined_call_event::get_meaning () const
1027 return meaning (VERB_call
, NOUN_function
);
1030 /* class setjmp_event : public checker_event. */
1032 /* Implementation of diagnostic_event::get_desc vfunc for
1036 setjmp_event::get_desc (bool can_colorize
) const
1038 return make_label_text (can_colorize
,
1040 get_user_facing_name (m_setjmp_call
));
1043 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1045 Record this setjmp's event ID into the path, so that rewind events can
1049 setjmp_event::prepare_for_emission (checker_path
*path
,
1050 pending_diagnostic
*pd
,
1051 diagnostic_event_id_t emission_id
)
1053 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1054 path
->record_setjmp_event (m_enode
, emission_id
);
1057 /* class rewind_event : public checker_event. */
1059 /* Get the fndecl containing the site of the longjmp call. */
1062 rewind_event::get_longjmp_caller () const
1064 return m_eedge
->m_src
->get_function ()->decl
;
1067 /* Get the fndecl containing the site of the setjmp call. */
1070 rewind_event::get_setjmp_caller () const
1072 return m_eedge
->m_dest
->get_function ()->decl
;
1075 /* rewind_event's ctor. */
1077 rewind_event::rewind_event (const exploded_edge
*eedge
,
1078 enum event_kind kind
,
1079 const event_loc_info
&loc_info
,
1080 const rewind_info_t
*rewind_info
)
1081 : checker_event (kind
, loc_info
),
1082 m_rewind_info (rewind_info
),
1085 gcc_assert (m_eedge
->m_custom_info
.get () == m_rewind_info
);
1088 /* class rewind_from_longjmp_event : public rewind_event. */
1090 /* Implementation of diagnostic_event::get_desc vfunc for
1091 rewind_from_longjmp_event. */
1094 rewind_from_longjmp_event::get_desc (bool can_colorize
) const
1096 const char *src_name
1097 = get_user_facing_name (m_rewind_info
->get_longjmp_call ());
1099 if (get_longjmp_caller () == get_setjmp_caller ())
1100 /* Special-case: purely intraprocedural rewind. */
1101 return make_label_text (can_colorize
,
1102 "rewinding within %qE from %qs...",
1103 get_longjmp_caller (),
1106 return make_label_text (can_colorize
,
1107 "rewinding from %qs in %qE...",
1109 get_longjmp_caller ());
1112 /* class rewind_to_setjmp_event : public rewind_event. */
1114 /* Implementation of diagnostic_event::get_desc vfunc for
1115 rewind_to_setjmp_event. */
1118 rewind_to_setjmp_event::get_desc (bool can_colorize
) const
1120 const char *dst_name
1121 = get_user_facing_name (m_rewind_info
->get_setjmp_call ());
1123 /* If we can, identify the ID of the setjmp_event. */
1124 if (m_original_setjmp_event_id
.known_p ())
1126 if (get_longjmp_caller () == get_setjmp_caller ())
1127 /* Special-case: purely intraprocedural rewind. */
1128 return make_label_text (can_colorize
,
1129 "...to %qs (saved at %@)",
1131 &m_original_setjmp_event_id
);
1133 return make_label_text (can_colorize
,
1134 "...to %qs in %qE (saved at %@)",
1136 get_setjmp_caller (),
1137 &m_original_setjmp_event_id
);
1141 if (get_longjmp_caller () == get_setjmp_caller ())
1142 /* Special-case: purely intraprocedural rewind. */
1143 return make_label_text (can_colorize
,
1146 get_setjmp_caller ());
1148 return make_label_text (can_colorize
,
1151 get_setjmp_caller ());
1155 /* Implementation of checker_event::prepare_for_emission vfunc for
1156 rewind_to_setjmp_event.
1158 Attempt to look up the setjmp event ID that recorded the jmp_buf
1162 rewind_to_setjmp_event::prepare_for_emission (checker_path
*path
,
1163 pending_diagnostic
*pd
,
1164 diagnostic_event_id_t emission_id
)
1166 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1167 path
->get_setjmp_event (m_rewind_info
->get_enode_origin (),
1168 &m_original_setjmp_event_id
);
1171 /* class warning_event : public checker_event. */
1173 /* Implementation of diagnostic_event::get_desc vfunc for
1176 If the pending diagnostic implements describe_final_event, use it,
1177 generating a precise description e.g.
1178 "second 'free' here; first 'free' was at (7)"
1180 Otherwise generate a generic description. */
1183 warning_event::get_desc (bool can_colorize
) const
1185 if (m_pending_diagnostic
)
1187 tree var
= fixup_tree_for_diagnostic (m_var
);
1189 = m_pending_diagnostic
->describe_final_event
1190 (evdesc::final_event (can_colorize
, var
, m_state
, *this));
1193 if (m_sm
&& flag_analyzer_verbose_state_changes
)
1196 return make_label_text (can_colorize
,
1197 "%s (%qE is in state %qs)",
1199 var
, m_state
->get_name ());
1201 return make_label_text (can_colorize
,
1202 "%s (in global state %qs)",
1204 m_state
->get_name ());
1214 return make_label_text (can_colorize
,
1215 "here (%qE is in state %qs)",
1216 m_var
, m_state
->get_name ());
1218 return make_label_text (can_colorize
,
1219 "here (in global state %qs)",
1220 m_state
->get_name ());
1223 return label_text::borrow ("here");
1226 /* Implementation of diagnostic_event::get_meaning vfunc for
1229 diagnostic_event::meaning
1230 warning_event::get_meaning () const
1232 return meaning (VERB_danger
, NOUN_unknown
);
1237 #endif /* #if ENABLE_ANALYZER */