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)
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/>. */
23 #include "coretypes.h"
26 #include "basic-block.h"
28 #include "gimple-pretty-print.h"
29 #include "fold-const.h"
31 #include "diagnostic-path.h"
37 #include "alloc-pool.h"
38 #include "fibonacci_heap.h"
39 #include "diagnostic-event-id.h"
40 #include "shortest-paths.h"
42 #include "analyzer/analyzer.h"
43 #include "analyzer/analyzer-logging.h"
44 #include "analyzer/sm.h"
48 #include "ordered-hash-map.h"
50 #include "analyzer/call-string.h"
51 #include "analyzer/program-point.h"
52 #include "analyzer/store.h"
53 #include "analyzer/region-model.h"
54 #include "analyzer/program-state.h"
55 #include "analyzer/checker-path.h"
56 #include "gimple-iterator.h"
57 #include "analyzer/supergraph.h"
58 #include "analyzer/pending-diagnostic.h"
59 #include "analyzer/diagnostic-manager.h"
60 #include "analyzer/constraint-manager.h"
61 #include "analyzer/diagnostic-manager.h"
62 #include "analyzer/checker-path.h"
63 #include "analyzer/exploded-graph.h"
69 /* Get a string for EK. */
72 event_kind_to_string (enum event_kind ek
)
84 case EK_REGION_CREATION
:
85 return "EK_REGION_CREATION";
86 case EK_FUNCTION_ENTRY
:
87 return "EK_FUNCTION_ENTRY";
89 return "EK_STATE_CHANGE";
90 case EK_START_CFG_EDGE
:
91 return "EK_START_CFG_EDGE";
93 return "EK_END_CFG_EDGE";
95 return "EK_CALL_EDGE";
97 return "EK_RETURN_EDGE";
98 case EK_START_CONSOLIDATED_CFG_EDGES
:
99 return "EK_START_CONSOLIDATED_CFG_EDGES";
100 case EK_END_CONSOLIDATED_CFG_EDGES
:
101 return "EK_END_CONSOLIDATED_CFG_EDGES";
104 case EK_REWIND_FROM_LONGJMP
:
105 return "EK_REWIND_FROM_LONGJMP";
106 case EK_REWIND_TO_SETJMP
:
107 return "EK_REWIND_TO_SETJMP";
113 /* class checker_event : public diagnostic_event. */
115 /* No-op implementation of diagnostic_event::get_meaning vfunc for
116 checker_event: checker events have no meaning by default. */
118 diagnostic_event::meaning
119 checker_event::get_meaning () const
124 /* Dump this event to PP (for debugging/logging purposes). */
127 checker_event::dump (pretty_printer
*pp
) const
129 label_text
event_desc (get_desc (false));
130 pp_printf (pp
, "\"%s\" (depth %i, m_loc=%x)",
134 event_desc
.maybe_free ();
137 /* Hook for being notified when this event has its final id EMISSION_ID
138 and is about to emitted for PD.
140 Base implementation of checker_event::prepare_for_emission vfunc;
141 subclasses that override this should chain up to it.
143 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
144 side-effects of the call to get_desc take place before
145 pending_diagnostic::emit is called.
147 For example, state_change_event::get_desc can call
148 pending_diagnostic::describe_state_change; free_of_non_heap can use this
149 to tweak the message (TODO: would be neater to simply capture the
150 pertinent data within the sm-state). */
153 checker_event::prepare_for_emission (checker_path
*,
154 pending_diagnostic
*pd
,
155 diagnostic_event_id_t emission_id
)
157 m_pending_diagnostic
= pd
;
158 m_emission_id
= emission_id
;
160 label_text desc
= get_desc (false);
164 /* class debug_event : public checker_event. */
166 /* Implementation of diagnostic_event::get_desc vfunc for
168 Use the saved string as the event's description. */
171 debug_event::get_desc (bool) const
173 return label_text::borrow (m_desc
);
176 /* class precanned_custom_event : public custom_event. */
178 /* Implementation of diagnostic_event::get_desc vfunc for
179 precanned_custom_event.
180 Use the saved string as the event's description. */
183 precanned_custom_event::get_desc (bool) const
185 return label_text::borrow (m_desc
);
188 /* class statement_event : public checker_event. */
190 /* statement_event's ctor. */
192 statement_event::statement_event (const gimple
*stmt
, tree fndecl
, int depth
,
193 const program_state
&dst_state
)
194 : checker_event (EK_STMT
, gimple_location (stmt
), fndecl
, depth
),
196 m_dst_state (dst_state
)
200 /* Implementation of diagnostic_event::get_desc vfunc for
202 Use the statement's dump form as the event's description. */
205 statement_event::get_desc (bool) const
208 pp_string (&pp
, "stmt: ");
209 pp_gimple_stmt_1 (&pp
, m_stmt
, 0, (dump_flags_t
)0);
210 return label_text::take (xstrdup (pp_formatted_text (&pp
)));
213 /* class region_creation_event : public checker_event. */
215 region_creation_event::region_creation_event (const region
*reg
,
219 : checker_event (EK_REGION_CREATION
, loc
, fndecl
, depth
),
224 /* Implementation of diagnostic_event::get_desc vfunc for
225 region_creation_event. */
228 region_creation_event::get_desc (bool) const
230 switch (m_reg
->get_memory_space ())
233 return label_text::borrow ("region created here");
235 return label_text::borrow ("region created on stack here");
237 return label_text::borrow ("region created on heap here");
241 /* class function_entry_event : public checker_event. */
243 /* Implementation of diagnostic_event::get_desc vfunc for
244 function_entry_event.
246 Use a string such as "entry to 'foo'" as the event's description. */
249 function_entry_event::get_desc (bool can_colorize
) const
251 return make_label_text (can_colorize
, "entry to %qE", m_fndecl
);
254 /* Implementation of diagnostic_event::get_meaning vfunc for
257 diagnostic_event::meaning
258 function_entry_event::get_meaning () const
260 return meaning (VERB_enter
, NOUN_function
);
263 /* class state_change_event : public checker_event. */
265 /* state_change_event's ctor. */
267 state_change_event::state_change_event (const supernode
*node
,
270 const state_machine
&sm
,
272 state_machine::state_t from
,
273 state_machine::state_t to
,
274 const svalue
*origin
,
275 const program_state
&dst_state
)
276 : checker_event (EK_STATE_CHANGE
,
277 stmt
->location
, node
->m_fun
->decl
,
279 m_node (node
), m_stmt (stmt
), m_sm (sm
),
280 m_sval (sval
), m_from (from
), m_to (to
),
282 m_dst_state (dst_state
)
286 /* Implementation of diagnostic_event::get_desc vfunc for
289 Attempt to generate a nicer human-readable description.
290 For greatest precision-of-wording, give the pending diagnostic
291 a chance to describe this state change (in terms of the
293 Note that we only have a pending_diagnostic set on the event once
294 the diagnostic is about to being emitted, so the description for
295 an event can change. */
298 state_change_event::get_desc (bool can_colorize
) const
300 if (m_pending_diagnostic
)
302 region_model
*model
= m_dst_state
.m_region_model
;
303 tree var
= model
->get_representative_tree (m_sval
);
304 tree origin
= model
->get_representative_tree (m_origin
);
305 label_text custom_desc
306 = m_pending_diagnostic
->describe_state_change
307 (evdesc::state_change (can_colorize
, var
, origin
,
308 m_from
, m_to
, m_emission_id
, *this));
309 if (custom_desc
.m_buffer
)
311 if (flag_analyzer_verbose_state_changes
)
313 /* Get any "meaning" of event. */
314 diagnostic_event::meaning meaning
= get_meaning ();
315 pretty_printer meaning_pp
;
316 meaning
.dump_to_pp (&meaning_pp
);
318 /* Append debug version. */
321 result
= make_label_text
323 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
324 custom_desc
.m_buffer
,
329 pp_formatted_text (&meaning_pp
));
331 result
= make_label_text
333 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
334 custom_desc
.m_buffer
,
338 pp_formatted_text (&meaning_pp
));
340 custom_desc
.maybe_free ();
348 /* Fallback description. */
351 label_text sval_desc
= m_sval
->get_desc ();
355 label_text origin_desc
= m_origin
->get_desc ();
356 result
= make_label_text
358 "state of %qs: %qs -> %qs (origin: %qs)",
362 origin_desc
.m_buffer
);
363 origin_desc
.maybe_free ();
366 result
= make_label_text
368 "state of %qs: %qs -> %qs (NULL origin)",
372 sval_desc
.maybe_free ();
377 gcc_assert (m_origin
== NULL
);
378 return make_label_text
380 "global state: %qs -> %qs",
386 /* Implementation of diagnostic_event::get_meaning vfunc for
387 state change events: delegate to the pending_diagnostic to
390 diagnostic_event::meaning
391 state_change_event::get_meaning () const
393 if (m_pending_diagnostic
)
395 region_model
*model
= m_dst_state
.m_region_model
;
396 tree var
= model
->get_representative_tree (m_sval
);
397 tree origin
= model
->get_representative_tree (m_origin
);
398 return m_pending_diagnostic
->get_meaning_for_state_change
399 (evdesc::state_change (false, var
, origin
,
400 m_from
, m_to
, m_emission_id
, *this));
406 /* class superedge_event : public checker_event. */
408 /* Get the callgraph_superedge for this superedge_event, which must be
409 for an interprocedural edge, rather than a CFG edge. */
411 const callgraph_superedge
&
412 superedge_event::get_callgraph_superedge () const
414 gcc_assert (m_sedge
->m_kind
!= SUPEREDGE_CFG_EDGE
);
415 return *m_sedge
->dyn_cast_callgraph_superedge ();
418 /* Determine if this event should be filtered at the given verbosity
422 superedge_event::should_filter_p (int verbosity
) const
424 switch (m_sedge
->m_kind
)
426 case SUPEREDGE_CFG_EDGE
:
433 /* Filter events with empty descriptions. This ought to filter
434 FALLTHRU, but retain true/false/switch edges. */
435 label_text desc
= get_desc (false);
436 gcc_assert (desc
.m_buffer
);
437 if (desc
.m_buffer
[0] == '\0')
450 /* superedge_event's ctor. */
452 superedge_event::superedge_event (enum event_kind kind
,
453 const exploded_edge
&eedge
,
454 location_t loc
, tree fndecl
, int depth
)
455 : checker_event (kind
, loc
, fndecl
, depth
),
456 m_eedge (eedge
), m_sedge (eedge
.m_sedge
),
457 m_var (NULL_TREE
), m_critical_state (0)
461 /* class cfg_edge_event : public superedge_event. */
463 /* Get the cfg_superedge for this cfg_edge_event. */
465 const cfg_superedge
&
466 cfg_edge_event::get_cfg_superedge () const
468 return *m_sedge
->dyn_cast_cfg_superedge ();
471 /* cfg_edge_event's ctor. */
473 cfg_edge_event::cfg_edge_event (enum event_kind kind
,
474 const exploded_edge
&eedge
,
475 location_t loc
, tree fndecl
, int depth
)
476 : superedge_event (kind
, eedge
, loc
, fndecl
, depth
)
478 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CFG_EDGE
);
481 /* Implementation of diagnostic_event::get_meaning vfunc for
484 diagnostic_event::meaning
485 cfg_edge_event::get_meaning () const
487 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
488 if (cfg_sedge
.true_value_p ())
489 return meaning (VERB_branch
, PROPERTY_true
);
490 else if (cfg_sedge
.false_value_p ())
491 return meaning (VERB_branch
, PROPERTY_false
);
496 /* class start_cfg_edge_event : public cfg_edge_event. */
498 /* Implementation of diagnostic_event::get_desc vfunc for
499 start_cfg_edge_event.
501 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
503 "taking 'true' edge SN:7 -> SN:8".
505 Otherwise, generate strings using the label of the underlying CFG if
507 "following 'true' branch..." or
508 "following 'case 3' branch..."
509 "following 'default' branch..."
511 For conditionals, attempt to supply a description of the condition that
513 "following 'false' branch (when 'ptr' is non-NULL)..."
515 Failing that, return an empty description (which will lead to this event
519 start_cfg_edge_event::get_desc (bool can_colorize
) const
521 bool user_facing
= !flag_analyzer_verbose_edges
;
522 char *edge_desc
= m_sedge
->get_description (user_facing
);
525 if (edge_desc
&& strlen (edge_desc
) > 0)
527 label_text cond_desc
= maybe_describe_condition (can_colorize
);
529 if (cond_desc
.m_buffer
)
531 result
= make_label_text (can_colorize
,
532 "following %qs branch (%s)...",
533 edge_desc
, cond_desc
.m_buffer
);
534 cond_desc
.maybe_free ();
538 result
= make_label_text (can_colorize
,
539 "following %qs branch...",
548 return label_text::borrow ("");
553 if (strlen (edge_desc
) > 0)
556 = make_label_text (can_colorize
,
557 "taking %qs edge SN:%i -> SN:%i",
559 m_sedge
->m_src
->m_index
,
560 m_sedge
->m_dest
->m_index
);
567 return make_label_text (can_colorize
,
568 "taking edge SN:%i -> SN:%i",
569 m_sedge
->m_src
->m_index
,
570 m_sedge
->m_dest
->m_index
);
575 /* Attempt to generate a description of any condition that holds at this edge.
577 The intent is to make the user-facing messages more clear, especially for
578 cases where there's a single or double-negative, such as
579 when describing the false branch of an inverted condition.
581 For example, rather than printing just:
586 | (1) following 'false' branch...
588 it's clearer to spell out the condition that holds:
593 | (1) following 'false' branch (when 'ptr' is non-NULL)...
594 ^^^^^^^^^^^^^^^^^^^^^^
596 In the above example, this function would generate the highlighted
597 string: "when 'ptr' is non-NULL".
599 If the edge is not a condition, or it's not clear that a description of
600 the condition would be helpful to the user, return NULL. */
603 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
) const
605 const cfg_superedge
& cfg_sedge
= get_cfg_superedge ();
607 if (cfg_sedge
.true_value_p () || cfg_sedge
.false_value_p ())
609 const gimple
*last_stmt
= m_sedge
->m_src
->get_last_stmt ();
610 if (const gcond
*cond_stmt
= dyn_cast
<const gcond
*> (last_stmt
))
612 enum tree_code op
= gimple_cond_code (cond_stmt
);
613 tree lhs
= gimple_cond_lhs (cond_stmt
);
614 tree rhs
= gimple_cond_rhs (cond_stmt
);
615 if (cfg_sedge
.false_value_p ())
616 op
= invert_tree_comparison (op
, false /* honor_nans */);
617 return maybe_describe_condition (can_colorize
,
621 return label_text::borrow (NULL
);
624 /* Subroutine of maybe_describe_condition above.
626 Attempt to generate a user-facing description of the condition
627 LHS OP RHS, but only if it is likely to make it easier for the
628 user to understand a condition. */
631 start_cfg_edge_event::maybe_describe_condition (bool can_colorize
,
636 /* In theory we could just build a tree via
637 fold_build2 (op, boolean_type_node, lhs, rhs)
638 and print it with %qE on it, but this leads to warts such as
639 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
641 /* Special-case: describe testing the result of strcmp, as figuring
642 out what the "true" or "false" path is can be confusing to the user. */
643 if (TREE_CODE (lhs
) == SSA_NAME
646 if (gcall
*call
= dyn_cast
<gcall
*> (SSA_NAME_DEF_STMT (lhs
)))
647 if (is_special_named_call_p (call
, "strcmp", 2))
650 return label_text::borrow ("when the strings are equal");
652 return label_text::borrow ("when the strings are non-equal");
656 /* Only attempt to generate text for sufficiently simple expressions. */
657 if (!should_print_expr_p (lhs
))
658 return label_text::borrow (NULL
);
659 if (!should_print_expr_p (rhs
))
660 return label_text::borrow (NULL
);
662 /* Special cases for pointer comparisons against NULL. */
663 if (POINTER_TYPE_P (TREE_TYPE (lhs
))
664 && POINTER_TYPE_P (TREE_TYPE (rhs
))
668 return make_label_text (can_colorize
, "when %qE is NULL",
671 return make_label_text (can_colorize
, "when %qE is non-NULL",
675 return make_label_text (can_colorize
, "when %<%E %s %E%>",
676 lhs
, op_symbol_code (op
), rhs
);
679 /* Subroutine of maybe_describe_condition.
681 Return true if EXPR is we will get suitable user-facing output
685 start_cfg_edge_event::should_print_expr_p (tree expr
)
687 if (TREE_CODE (expr
) == SSA_NAME
)
689 if (SSA_NAME_VAR (expr
))
690 return should_print_expr_p (SSA_NAME_VAR (expr
));
698 if (CONSTANT_CLASS_P (expr
))
704 /* class call_event : public superedge_event. */
706 /* call_event's ctor. */
708 call_event::call_event (const exploded_edge
&eedge
,
709 location_t loc
, tree fndecl
, int depth
)
710 : superedge_event (EK_CALL_EDGE
, eedge
, loc
, fndecl
, depth
)
713 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_CALL
);
715 m_src_snode
= eedge
.m_src
->get_supernode ();
716 m_dest_snode
= eedge
.m_dest
->get_supernode ();
719 /* Implementation of diagnostic_event::get_desc vfunc for
722 If this call event passes critical state for an sm-based warning,
723 allow the diagnostic to generate a precise description, such as:
725 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
727 Otherwise, generate a description of the form
728 "calling 'foo' from 'bar'". */
731 call_event::get_desc (bool can_colorize
) const
733 if (m_critical_state
&& m_pending_diagnostic
)
736 tree var
= fixup_tree_for_diagnostic (m_var
);
737 label_text custom_desc
738 = m_pending_diagnostic
->describe_call_with_state
739 (evdesc::call_with_state (can_colorize
,
740 m_src_snode
->m_fun
->decl
,
741 m_dest_snode
->m_fun
->decl
,
744 if (custom_desc
.m_buffer
)
748 return make_label_text (can_colorize
,
749 "calling %qE from %qE",
750 get_callee_fndecl (),
751 get_caller_fndecl ());
754 /* Implementation of diagnostic_event::get_meaning vfunc for
755 function call events. */
757 diagnostic_event::meaning
758 call_event::get_meaning () const
760 return meaning (VERB_call
, NOUN_function
);
763 /* Override of checker_event::is_call_p for calls. */
766 call_event::is_call_p () const
772 call_event::get_caller_fndecl () const
774 return m_src_snode
->m_fun
->decl
;
778 call_event::get_callee_fndecl () const
780 return m_dest_snode
->m_fun
->decl
;
783 /* class return_event : public superedge_event. */
785 /* return_event's ctor. */
787 return_event::return_event (const exploded_edge
&eedge
,
788 location_t loc
, tree fndecl
, int depth
)
789 : superedge_event (EK_RETURN_EDGE
, eedge
, loc
, fndecl
, depth
)
792 gcc_assert (eedge
.m_sedge
->m_kind
== SUPEREDGE_RETURN
);
794 m_src_snode
= eedge
.m_src
->get_supernode ();
795 m_dest_snode
= eedge
.m_dest
->get_supernode ();
798 /* Implementation of diagnostic_event::get_desc vfunc for
801 If this return event returns critical state for an sm-based warning,
802 allow the diagnostic to generate a precise description, such as:
804 "possible of NULL to 'foo' from 'bar'"
806 Otherwise, generate a description of the form
807 "returning to 'foo' from 'bar'. */
810 return_event::get_desc (bool can_colorize
) const
812 /* For greatest precision-of-wording, if this is returning the
813 state involved in the pending diagnostic, give the pending
814 diagnostic a chance to describe this return (in terms of
816 if (m_critical_state
&& m_pending_diagnostic
)
818 label_text custom_desc
819 = m_pending_diagnostic
->describe_return_of_state
820 (evdesc::return_of_state (can_colorize
,
821 m_dest_snode
->m_fun
->decl
,
822 m_src_snode
->m_fun
->decl
,
824 if (custom_desc
.m_buffer
)
827 return make_label_text (can_colorize
,
828 "returning to %qE from %qE",
829 m_dest_snode
->m_fun
->decl
,
830 m_src_snode
->m_fun
->decl
);
833 /* Implementation of diagnostic_event::get_meaning vfunc for
834 function return events. */
836 diagnostic_event::meaning
837 return_event::get_meaning () const
839 return meaning (VERB_return
, NOUN_function
);
842 /* Override of checker_event::is_return_p for returns. */
845 return_event::is_return_p () const
850 /* class start_consolidated_cfg_edges_event : public checker_event. */
853 start_consolidated_cfg_edges_event::get_desc (bool can_colorize
) const
855 return make_label_text (can_colorize
,
856 "following %qs branch...",
857 m_edge_sense
? "true" : "false");
860 /* Implementation of diagnostic_event::get_meaning vfunc for
861 start_consolidated_cfg_edges_event. */
863 diagnostic_event::meaning
864 start_consolidated_cfg_edges_event::get_meaning () const
866 return meaning (VERB_branch
,
867 (m_edge_sense
? PROPERTY_true
: PROPERTY_false
));
870 /* class setjmp_event : public checker_event. */
872 /* Implementation of diagnostic_event::get_desc vfunc for
876 setjmp_event::get_desc (bool can_colorize
) const
878 return make_label_text (can_colorize
,
880 get_user_facing_name (m_setjmp_call
));
883 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
885 Record this setjmp's event ID into the path, so that rewind events can
889 setjmp_event::prepare_for_emission (checker_path
*path
,
890 pending_diagnostic
*pd
,
891 diagnostic_event_id_t emission_id
)
893 checker_event::prepare_for_emission (path
, pd
, emission_id
);
894 path
->record_setjmp_event (m_enode
, emission_id
);
897 /* class rewind_event : public checker_event. */
899 /* Get the fndecl containing the site of the longjmp call. */
902 rewind_event::get_longjmp_caller () const
904 return m_eedge
->m_src
->get_function ()->decl
;
907 /* Get the fndecl containing the site of the setjmp call. */
910 rewind_event::get_setjmp_caller () const
912 return m_eedge
->m_dest
->get_function ()->decl
;
915 /* rewind_event's ctor. */
917 rewind_event::rewind_event (const exploded_edge
*eedge
,
918 enum event_kind kind
,
919 location_t loc
, tree fndecl
, int depth
,
920 const rewind_info_t
*rewind_info
)
921 : checker_event (kind
, loc
, fndecl
, depth
),
922 m_rewind_info (rewind_info
),
925 gcc_assert (m_eedge
->m_custom_info
== m_rewind_info
);
928 /* class rewind_from_longjmp_event : public rewind_event. */
930 /* Implementation of diagnostic_event::get_desc vfunc for
931 rewind_from_longjmp_event. */
934 rewind_from_longjmp_event::get_desc (bool can_colorize
) const
937 = get_user_facing_name (m_rewind_info
->get_longjmp_call ());
939 if (get_longjmp_caller () == get_setjmp_caller ())
940 /* Special-case: purely intraprocedural rewind. */
941 return make_label_text (can_colorize
,
942 "rewinding within %qE from %qs...",
943 get_longjmp_caller (),
946 return make_label_text (can_colorize
,
947 "rewinding from %qs in %qE...",
949 get_longjmp_caller ());
952 /* class rewind_to_setjmp_event : public rewind_event. */
954 /* Implementation of diagnostic_event::get_desc vfunc for
955 rewind_to_setjmp_event. */
958 rewind_to_setjmp_event::get_desc (bool can_colorize
) const
961 = get_user_facing_name (m_rewind_info
->get_setjmp_call ());
963 /* If we can, identify the ID of the setjmp_event. */
964 if (m_original_setjmp_event_id
.known_p ())
966 if (get_longjmp_caller () == get_setjmp_caller ())
967 /* Special-case: purely intraprocedural rewind. */
968 return make_label_text (can_colorize
,
969 "...to %qs (saved at %@)",
971 &m_original_setjmp_event_id
);
973 return make_label_text (can_colorize
,
974 "...to %qs in %qE (saved at %@)",
976 get_setjmp_caller (),
977 &m_original_setjmp_event_id
);
981 if (get_longjmp_caller () == get_setjmp_caller ())
982 /* Special-case: purely intraprocedural rewind. */
983 return make_label_text (can_colorize
,
986 get_setjmp_caller ());
988 return make_label_text (can_colorize
,
991 get_setjmp_caller ());
995 /* Implementation of checker_event::prepare_for_emission vfunc for
996 rewind_to_setjmp_event.
998 Attempt to look up the setjmp event ID that recorded the jmp_buf
1002 rewind_to_setjmp_event::prepare_for_emission (checker_path
*path
,
1003 pending_diagnostic
*pd
,
1004 diagnostic_event_id_t emission_id
)
1006 checker_event::prepare_for_emission (path
, pd
, emission_id
);
1007 path
->get_setjmp_event (m_rewind_info
->get_enode_origin (),
1008 &m_original_setjmp_event_id
);
1011 /* class warning_event : public checker_event. */
1013 /* Implementation of diagnostic_event::get_desc vfunc for
1016 If the pending diagnostic implements describe_final_event, use it,
1017 generating a precise description e.g.
1018 "second 'free' here; first 'free' was at (7)"
1020 Otherwise generate a generic description. */
1023 warning_event::get_desc (bool can_colorize
) const
1025 if (m_pending_diagnostic
)
1027 tree var
= fixup_tree_for_diagnostic (m_var
);
1029 = m_pending_diagnostic
->describe_final_event
1030 (evdesc::final_event (can_colorize
, var
, m_state
));
1031 if (ev_desc
.m_buffer
)
1033 if (m_sm
&& flag_analyzer_verbose_state_changes
)
1037 result
= make_label_text (can_colorize
,
1038 "%s (%qE is in state %qs)",
1040 var
, m_state
->get_name ());
1042 result
= make_label_text (can_colorize
,
1043 "%s (in global state %qs)",
1045 m_state
->get_name ());
1046 ev_desc
.maybe_free ();
1057 return make_label_text (can_colorize
,
1058 "here (%qE is in state %qs)",
1059 m_var
, m_state
->get_name ());
1061 return make_label_text (can_colorize
,
1062 "here (in global state %qs)",
1063 m_state
->get_name ());
1066 return label_text::borrow ("here");
1069 /* Implementation of diagnostic_event::get_meaning vfunc for
1072 diagnostic_event::meaning
1073 warning_event::get_meaning () const
1075 return meaning (VERB_danger
, NOUN_unknown
);
1078 /* Print a single-line representation of this path to PP. */
1081 checker_path::dump (pretty_printer
*pp
) const
1083 pp_character (pp
, '[');
1087 FOR_EACH_VEC_ELT (m_events
, i
, e
)
1090 pp_string (pp
, ", ");
1091 label_text
event_desc (e
->get_desc (false));
1092 pp_printf (pp
, "\"%s\"", event_desc
.m_buffer
);
1093 event_desc
.maybe_free ();
1095 pp_character (pp
, ']');
1098 /* Print a multiline form of this path to LOGGER, prefixing it with DESC. */
1101 checker_path::maybe_log (logger
*logger
, const char *desc
) const
1105 logger
->start_log_line ();
1106 logger
->log_partial ("%s: ", desc
);
1107 dump (logger
->get_printer ());
1108 logger
->end_log_line ();
1109 for (unsigned i
= 0; i
< m_events
.length (); i
++)
1111 logger
->start_log_line ();
1112 logger
->log_partial ("%s[%i]: %s ", desc
, i
,
1113 event_kind_to_string (m_events
[i
]->m_kind
));
1114 m_events
[i
]->dump (logger
->get_printer ());
1115 logger
->end_log_line ();
1119 /* Print a multiline form of this path to STDERR. */
1122 checker_path::debug () const
1126 FOR_EACH_VEC_ELT (m_events
, i
, e
)
1128 label_text
event_desc (e
->get_desc (false));
1130 "[%i]: %s \"%s\"\n",
1132 event_kind_to_string (m_events
[i
]->m_kind
),
1133 event_desc
.m_buffer
);
1134 event_desc
.maybe_free ();
1138 /* Add region_creation_event instance to this path for REG,
1139 describing whether REG is on the stack or heap. */
1142 checker_path::add_region_creation_event (const region
*reg
,
1144 tree fndecl
, int depth
)
1146 add_event (new region_creation_event (reg
, loc
, fndecl
, depth
));
1149 /* Add a warning_event to the end of this path. */
1152 checker_path::add_final_event (const state_machine
*sm
,
1153 const exploded_node
*enode
, const gimple
*stmt
,
1154 tree var
, state_machine::state_t state
)
1156 checker_event
*end_of_path
1157 = new warning_event (get_stmt_location (stmt
, enode
->get_function ()),
1158 enode
->get_function ()->decl
,
1159 enode
->get_stack_depth (),
1161 add_event (end_of_path
);
1165 checker_path::fixup_locations (pending_diagnostic
*pd
)
1167 for (checker_event
*e
: m_events
)
1168 e
->set_location (pd
->fixup_location (e
->get_location ()));
1171 /* Return true if there is a (start_cfg_edge_event, end_cfg_edge_event) pair
1172 at (IDX, IDX + 1). */
1175 checker_path::cfg_edge_pair_at_p (unsigned idx
) const
1177 if (m_events
.length () < idx
+ 1)
1179 return (m_events
[idx
]->m_kind
== EK_START_CFG_EDGE
1180 && m_events
[idx
+ 1]->m_kind
== EK_END_CFG_EDGE
);
1185 #endif /* #if ENABLE_ANALYZER */