Disable tests for strdup/strndup on __hpux__
[official-gcc.git] / gcc / analyzer / checker-event.cc
blob3ff3aea6a8671975b5dbf7578c64a9c73b625056
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)
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 #define INCLUDE_MEMORY
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tree.h"
26 #include "function.h"
27 #include "basic-block.h"
28 #include "gimple.h"
29 #include "diagnostic-core.h"
30 #include "gimple-pretty-print.h"
31 #include "fold-const.h"
32 #include "diagnostic-path.h"
33 #include "options.h"
34 #include "cgraph.h"
35 #include "cfg.h"
36 #include "digraph.h"
37 #include "diagnostic-event-id.h"
38 #include "analyzer/analyzer.h"
39 #include "analyzer/analyzer-logging.h"
40 #include "analyzer/sm.h"
41 #include "sbitmap.h"
42 #include "bitmap.h"
43 #include "ordered-hash-map.h"
44 #include "analyzer/call-string.h"
45 #include "analyzer/program-point.h"
46 #include "analyzer/store.h"
47 #include "analyzer/region-model.h"
48 #include "analyzer/program-state.h"
49 #include "analyzer/checker-path.h"
50 #include "gimple-iterator.h"
51 #include "inlining-iterator.h"
52 #include "analyzer/supergraph.h"
53 #include "analyzer/pending-diagnostic.h"
54 #include "analyzer/diagnostic-manager.h"
55 #include "analyzer/constraint-manager.h"
56 #include "analyzer/checker-event.h"
57 #include "analyzer/exploded-graph.h"
58 #include "diagnostic-format-sarif.h"
59 #include "tree-logical-location.h"
61 #if ENABLE_ANALYZER
63 namespace ana {
65 /* Get a string for EK. */
67 const char *
68 event_kind_to_string (enum event_kind ek)
70 switch (ek)
72 default:
73 gcc_unreachable ();
74 case EK_DEBUG:
75 return "EK_DEBUG";
76 case EK_CUSTOM:
77 return "EK_CUSTOM";
78 case EK_STMT:
79 return "EK_STMT";
80 case EK_REGION_CREATION:
81 return "EK_REGION_CREATION";
82 case EK_FUNCTION_ENTRY:
83 return "EK_FUNCTION_ENTRY";
84 case EK_STATE_CHANGE:
85 return "EK_STATE_CHANGE";
86 case EK_START_CFG_EDGE:
87 return "EK_START_CFG_EDGE";
88 case EK_END_CFG_EDGE:
89 return "EK_END_CFG_EDGE";
90 case EK_CALL_EDGE:
91 return "EK_CALL_EDGE";
92 case EK_RETURN_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";
98 case EK_INLINED_CALL:
99 return "EK_INLINED_CALL";
100 case EK_SETJMP:
101 return "EK_SETJMP";
102 case EK_REWIND_FROM_LONGJMP:
103 return "EK_REWIND_FROM_LONGJMP";
104 case EK_REWIND_TO_SETJMP:
105 return "EK_REWIND_TO_SETJMP";
106 case EK_WARNING:
107 return "EK_WARNING";
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
144 return meaning ();
147 /* Implementation of diagnostic_event::maybe_add_sarif_properties
148 for checker_event. */
150 void
151 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). */
173 void
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",
182 m_original_depth);
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)",
190 get_location ());
193 /* Dump this event to stderr (for debugging/logging purposes). */
195 DEBUG_FUNCTION void
196 checker_event::debug () const
198 pretty_printer pp;
199 pp_format_decoder (&pp) = default_tree_printer;
200 pp_show_color (&pp) = pp_show_color (global_dc->printer);
201 pp.buffer->stream = stderr;
202 dump (&pp);
203 pp_newline (&pp);
204 pp_flush (&pp);
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). */
222 void
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
236 debug_event.
237 Use the saved string as the event's description. */
239 label_text
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. */
251 label_text
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)),
265 m_stmt (stmt),
266 m_dst_state (dst_state)
270 /* Implementation of diagnostic_event::get_desc vfunc for
271 statement_event.
272 Use the statement's dump form as the event's description. */
274 label_text
275 statement_event::get_desc (bool) const
277 pretty_printer pp;
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
291 implementations. */
293 label_text
294 region_creation_event_memory_space::get_desc (bool) const
296 switch (m_mem_space)
298 default:
299 return label_text::borrow ("region created here");
300 case MEMSPACE_STACK:
301 return label_text::borrow ("region created on stack here");
302 case MEMSPACE_HEAP:
303 return label_text::borrow ("region created on heap here");
307 label_text
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,
315 hwi,
316 "capacity: %wu byte",
317 "capacity: %wu bytes",
318 hwi);
320 else
321 return make_label_text (can_colorize,
322 "capacity: %qE bytes", m_capacity);
325 label_text
326 region_creation_event_allocation_size::get_desc (bool can_colorize) const
328 if (m_capacity)
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",
335 m_capacity);
336 else
337 return make_label_text (can_colorize,
338 "allocated %qE bytes here",
339 m_capacity);
341 return make_label_text (can_colorize, "allocated here");
344 label_text
345 region_creation_event_debug::get_desc (bool) const
347 pretty_printer pp;
348 pp_format_decoder (&pp) = default_tree_printer;
349 pp_string (&pp, "region creation: ");
350 m_reg->dump_to_pp (&pp, true);
351 if (m_capacity)
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. */
372 label_text
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
379 function entry. */
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,
392 const gimple *stmt,
393 int stack_depth,
394 const state_machine &sm,
395 const svalue *sval,
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,
403 node->m_fun->decl,
404 stack_depth)),
405 m_node (node), m_stmt (stmt), m_sm (sm),
406 m_sval (sval), m_from (from), m_to (to),
407 m_origin (origin),
408 m_dst_state (dst_state),
409 m_enode (enode)
413 /* Implementation of diagnostic_event::get_desc vfunc for
414 state_change_event.
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
419 diagnostic).
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. */
424 label_text
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. */
446 if (m_origin)
447 return make_label_text
448 (can_colorize,
449 "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
450 custom_desc.get (),
451 var,
452 m_from->get_name (),
453 m_to->get_name (),
454 origin,
455 pp_formatted_text (&meaning_pp));
456 else
457 return make_label_text
458 (can_colorize,
459 "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
460 custom_desc.get (),
461 var,
462 m_from->get_name (),
463 m_to->get_name (),
464 pp_formatted_text (&meaning_pp));
466 else
467 return custom_desc;
471 /* Fallback description. */
472 if (m_sval)
474 label_text sval_desc = m_sval->get_desc ();
475 if (m_origin)
477 label_text origin_desc = m_origin->get_desc ();
478 return make_label_text
479 (can_colorize,
480 "state of %qs: %qs -> %qs (origin: %qs)",
481 sval_desc.get (),
482 m_from->get_name (),
483 m_to->get_name (),
484 origin_desc.get ());
486 else
487 return make_label_text
488 (can_colorize,
489 "state of %qs: %qs -> %qs (NULL origin)",
490 sval_desc.get (),
491 m_from->get_name (),
492 m_to->get_name ());
494 else
496 gcc_assert (m_origin == NULL);
497 return make_label_text
498 (can_colorize,
499 "global state: %qs -> %qs",
500 m_from->get_name (),
501 m_to->get_name ());
505 /* Implementation of diagnostic_event::get_meaning vfunc for
506 state change events: delegate to the pending_diagnostic to
507 get any meaning. */
509 diagnostic_event::meaning
510 state_change_event::get_meaning () const
512 if (m_pending_diagnostic)
514 region_model *model = m_dst_state.m_region_model;
515 tree var = model->get_representative_tree (m_sval);
516 tree origin = model->get_representative_tree (m_origin);
517 return m_pending_diagnostic->get_meaning_for_state_change
518 (evdesc::state_change (false, var, origin,
519 m_from, m_to, m_emission_id, *this));
521 else
522 return meaning ();
525 /* class superedge_event : public checker_event. */
527 /* Implementation of diagnostic_event::maybe_add_sarif_properties
528 for superedge_event. */
530 void
531 superedge_event::maybe_add_sarif_properties (sarif_object &thread_flow_loc_obj)
532 const
534 checker_event::maybe_add_sarif_properties (thread_flow_loc_obj);
535 sarif_property_bag &props = thread_flow_loc_obj.get_or_create_properties ();
536 #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
537 if (m_sedge)
538 props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
539 #undef PROPERTY_PREFIX
542 /* Get the callgraph_superedge for this superedge_event, which must be
543 for an interprocedural edge, rather than a CFG edge. */
545 const callgraph_superedge&
546 superedge_event::get_callgraph_superedge () const
548 gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
549 return *m_sedge->dyn_cast_callgraph_superedge ();
552 /* Determine if this event should be filtered at the given verbosity
553 level. */
555 bool
556 superedge_event::should_filter_p (int verbosity) const
558 switch (m_sedge->m_kind)
560 case SUPEREDGE_CFG_EDGE:
562 if (verbosity < 2)
563 return true;
565 if (verbosity < 4)
567 /* Filter events with empty descriptions. This ought to filter
568 FALLTHRU, but retain true/false/switch edges. */
569 label_text desc = get_desc (false);
570 gcc_assert (desc.get ());
571 if (desc.get ()[0] == '\0')
572 return true;
575 break;
577 default:
578 break;
580 return false;
583 /* superedge_event's ctor. */
585 superedge_event::superedge_event (enum event_kind kind,
586 const exploded_edge &eedge,
587 const event_loc_info &loc_info)
588 : checker_event (kind, loc_info),
589 m_eedge (eedge), m_sedge (eedge.m_sedge),
590 m_var (NULL_TREE), m_critical_state (0)
592 /* Note that m_sedge can be nullptr for e.g. jumps through
593 function pointers. */
596 /* class cfg_edge_event : public superedge_event. */
598 /* Get the cfg_superedge for this cfg_edge_event. */
600 const cfg_superedge &
601 cfg_edge_event::get_cfg_superedge () const
603 return *m_sedge->dyn_cast_cfg_superedge ();
606 /* cfg_edge_event's ctor. */
608 cfg_edge_event::cfg_edge_event (enum event_kind kind,
609 const exploded_edge &eedge,
610 const event_loc_info &loc_info)
611 : superedge_event (kind, eedge, loc_info)
613 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
616 /* Implementation of diagnostic_event::get_meaning vfunc for
617 CFG edge events. */
619 diagnostic_event::meaning
620 cfg_edge_event::get_meaning () const
622 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
623 if (cfg_sedge.true_value_p ())
624 return meaning (VERB_branch, PROPERTY_true);
625 else if (cfg_sedge.false_value_p ())
626 return meaning (VERB_branch, PROPERTY_false);
627 else
628 return meaning ();
631 /* class start_cfg_edge_event : public cfg_edge_event. */
633 /* Implementation of diagnostic_event::get_desc vfunc for
634 start_cfg_edge_event.
636 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
638 "taking 'true' edge SN:7 -> SN:8".
640 Otherwise, generate strings using the label of the underlying CFG if
641 any, such as:
642 "following 'true' branch..." or
643 "following 'case 3' branch..."
644 "following 'default' branch..."
646 For conditionals, attempt to supply a description of the condition that
647 holds, such as:
648 "following 'false' branch (when 'ptr' is non-NULL)..."
650 Failing that, return an empty description (which will lead to this event
651 being filtered). */
653 label_text
654 start_cfg_edge_event::get_desc (bool can_colorize) const
656 bool user_facing = !flag_analyzer_verbose_edges;
657 label_text edge_desc (m_sedge->get_description (user_facing));
658 if (user_facing)
660 if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
662 label_text cond_desc = maybe_describe_condition (can_colorize);
663 label_text result;
664 if (cond_desc.get ())
665 return make_label_text (can_colorize,
666 "following %qs branch (%s)...",
667 edge_desc.get (), cond_desc.get ());
668 else
669 return make_label_text (can_colorize,
670 "following %qs branch...",
671 edge_desc.get ());
673 else
674 return label_text::borrow ("");
676 else
678 if (strlen (edge_desc.get ()) > 0)
679 return make_label_text (can_colorize,
680 "taking %qs edge SN:%i -> SN:%i",
681 edge_desc.get (),
682 m_sedge->m_src->m_index,
683 m_sedge->m_dest->m_index);
684 else
685 return make_label_text (can_colorize,
686 "taking edge SN:%i -> SN:%i",
687 m_sedge->m_src->m_index,
688 m_sedge->m_dest->m_index);
692 /* Attempt to generate a description of any condition that holds at this edge.
694 The intent is to make the user-facing messages more clear, especially for
695 cases where there's a single or double-negative, such as
696 when describing the false branch of an inverted condition.
698 For example, rather than printing just:
700 | if (!ptr)
703 | (1) following 'false' branch...
705 it's clearer to spell out the condition that holds:
707 | if (!ptr)
710 | (1) following 'false' branch (when 'ptr' is non-NULL)...
711 ^^^^^^^^^^^^^^^^^^^^^^
713 In the above example, this function would generate the highlighted
714 string: "when 'ptr' is non-NULL".
716 If the edge is not a condition, or it's not clear that a description of
717 the condition would be helpful to the user, return NULL. */
719 label_text
720 start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
722 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
724 if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
726 const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
727 if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
729 enum tree_code op = gimple_cond_code (cond_stmt);
730 tree lhs = gimple_cond_lhs (cond_stmt);
731 tree rhs = gimple_cond_rhs (cond_stmt);
732 if (cfg_sedge.false_value_p ())
733 op = invert_tree_comparison (op, false /* honor_nans */);
734 return maybe_describe_condition (can_colorize,
735 lhs, op, rhs);
738 return label_text::borrow (NULL);
741 /* Subroutine of maybe_describe_condition above.
743 Attempt to generate a user-facing description of the condition
744 LHS OP RHS, but only if it is likely to make it easier for the
745 user to understand a condition. */
747 label_text
748 start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
749 tree lhs,
750 enum tree_code op,
751 tree rhs)
753 /* In theory we could just build a tree via
754 fold_build2 (op, boolean_type_node, lhs, rhs)
755 and print it with %qE on it, but this leads to warts such as
756 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
758 /* Special-case: describe testing the result of strcmp, as figuring
759 out what the "true" or "false" path is can be confusing to the user. */
760 if (TREE_CODE (lhs) == SSA_NAME
761 && zerop (rhs))
763 if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
764 if (is_special_named_call_p (call, "strcmp", 2))
766 if (op == EQ_EXPR)
767 return label_text::borrow ("when the strings are equal");
768 if (op == NE_EXPR)
769 return label_text::borrow ("when the strings are non-equal");
773 /* Only attempt to generate text for sufficiently simple expressions. */
774 if (!should_print_expr_p (lhs))
775 return label_text::borrow (NULL);
776 if (!should_print_expr_p (rhs))
777 return label_text::borrow (NULL);
779 /* Special cases for pointer comparisons against NULL. */
780 if (POINTER_TYPE_P (TREE_TYPE (lhs))
781 && POINTER_TYPE_P (TREE_TYPE (rhs))
782 && zerop (rhs))
784 if (op == EQ_EXPR)
785 return make_label_text (can_colorize, "when %qE is NULL",
786 lhs);
787 if (op == NE_EXPR)
788 return make_label_text (can_colorize, "when %qE is non-NULL",
789 lhs);
792 return make_label_text (can_colorize, "when %<%E %s %E%>",
793 lhs, op_symbol_code (op), rhs);
796 /* Subroutine of maybe_describe_condition.
798 Return true if EXPR is we will get suitable user-facing output
799 from %E on it. */
801 bool
802 start_cfg_edge_event::should_print_expr_p (tree expr)
804 if (TREE_CODE (expr) == SSA_NAME)
806 if (SSA_NAME_VAR (expr))
807 return should_print_expr_p (SSA_NAME_VAR (expr));
808 else
809 return false;
812 if (DECL_P (expr))
813 return true;
815 if (CONSTANT_CLASS_P (expr))
816 return true;
818 return false;
821 /* class call_event : public superedge_event. */
823 /* call_event's ctor. */
825 call_event::call_event (const exploded_edge &eedge,
826 const event_loc_info &loc_info)
827 : superedge_event (EK_CALL_EDGE, eedge, loc_info)
829 if (eedge.m_sedge)
830 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
832 m_src_snode = eedge.m_src->get_supernode ();
833 m_dest_snode = eedge.m_dest->get_supernode ();
836 /* Implementation of diagnostic_event::get_desc vfunc for
837 call_event.
839 If this call event passes critical state for an sm-based warning,
840 allow the diagnostic to generate a precise description, such as:
842 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
844 Otherwise, generate a description of the form
845 "calling 'foo' from 'bar'". */
847 label_text
848 call_event::get_desc (bool can_colorize) const
850 if (m_critical_state && m_pending_diagnostic)
852 gcc_assert (m_var);
853 tree var = fixup_tree_for_diagnostic (m_var);
854 label_text custom_desc
855 = m_pending_diagnostic->describe_call_with_state
856 (evdesc::call_with_state (can_colorize,
857 m_src_snode->m_fun->decl,
858 m_dest_snode->m_fun->decl,
859 var,
860 m_critical_state));
861 if (custom_desc.get ())
862 return custom_desc;
865 return make_label_text (can_colorize,
866 "calling %qE from %qE",
867 get_callee_fndecl (),
868 get_caller_fndecl ());
871 /* Implementation of diagnostic_event::get_meaning vfunc for
872 function call events. */
874 diagnostic_event::meaning
875 call_event::get_meaning () const
877 return meaning (VERB_call, NOUN_function);
880 /* Override of checker_event::is_call_p for calls. */
882 bool
883 call_event::is_call_p () const
885 return true;
888 tree
889 call_event::get_caller_fndecl () const
891 return m_src_snode->m_fun->decl;
894 tree
895 call_event::get_callee_fndecl () const
897 return m_dest_snode->m_fun->decl;
900 /* class return_event : public superedge_event. */
902 /* return_event's ctor. */
904 return_event::return_event (const exploded_edge &eedge,
905 const event_loc_info &loc_info)
906 : superedge_event (EK_RETURN_EDGE, eedge, loc_info)
908 if (eedge.m_sedge)
909 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
911 m_src_snode = eedge.m_src->get_supernode ();
912 m_dest_snode = eedge.m_dest->get_supernode ();
915 /* Implementation of diagnostic_event::get_desc vfunc for
916 return_event.
918 If this return event returns critical state for an sm-based warning,
919 allow the diagnostic to generate a precise description, such as:
921 "possible of NULL to 'foo' from 'bar'"
923 Otherwise, generate a description of the form
924 "returning to 'foo' from 'bar'. */
926 label_text
927 return_event::get_desc (bool can_colorize) const
929 /* For greatest precision-of-wording, if this is returning the
930 state involved in the pending diagnostic, give the pending
931 diagnostic a chance to describe this return (in terms of
932 itself). */
933 if (m_critical_state && m_pending_diagnostic)
935 label_text custom_desc
936 = m_pending_diagnostic->describe_return_of_state
937 (evdesc::return_of_state (can_colorize,
938 m_dest_snode->m_fun->decl,
939 m_src_snode->m_fun->decl,
940 m_critical_state));
941 if (custom_desc.get ())
942 return custom_desc;
944 return make_label_text (can_colorize,
945 "returning to %qE from %qE",
946 m_dest_snode->m_fun->decl,
947 m_src_snode->m_fun->decl);
950 /* Implementation of diagnostic_event::get_meaning vfunc for
951 function return events. */
953 diagnostic_event::meaning
954 return_event::get_meaning () const
956 return meaning (VERB_return, NOUN_function);
959 /* Override of checker_event::is_return_p for returns. */
961 bool
962 return_event::is_return_p () const
964 return true;
967 /* class start_consolidated_cfg_edges_event : public checker_event. */
969 label_text
970 start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
972 return make_label_text (can_colorize,
973 "following %qs branch...",
974 m_edge_sense ? "true" : "false");
977 /* Implementation of diagnostic_event::get_meaning vfunc for
978 start_consolidated_cfg_edges_event. */
980 diagnostic_event::meaning
981 start_consolidated_cfg_edges_event::get_meaning () const
983 return meaning (VERB_branch,
984 (m_edge_sense ? PROPERTY_true : PROPERTY_false));
987 /* class inlined_call_event : public checker_event. */
989 label_text
990 inlined_call_event::get_desc (bool can_colorize) const
992 return make_label_text (can_colorize,
993 "inlined call to %qE from %qE",
994 m_apparent_callee_fndecl,
995 m_apparent_caller_fndecl);
998 /* Implementation of diagnostic_event::get_meaning vfunc for
999 reconstructed inlined function calls. */
1001 diagnostic_event::meaning
1002 inlined_call_event::get_meaning () const
1004 return meaning (VERB_call, NOUN_function);
1007 /* class setjmp_event : public checker_event. */
1009 /* Implementation of diagnostic_event::get_desc vfunc for
1010 setjmp_event. */
1012 label_text
1013 setjmp_event::get_desc (bool can_colorize) const
1015 return make_label_text (can_colorize,
1016 "%qs called here",
1017 get_user_facing_name (m_setjmp_call));
1020 /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1022 Record this setjmp's event ID into the path, so that rewind events can
1023 use it. */
1025 void
1026 setjmp_event::prepare_for_emission (checker_path *path,
1027 pending_diagnostic *pd,
1028 diagnostic_event_id_t emission_id)
1030 checker_event::prepare_for_emission (path, pd, emission_id);
1031 path->record_setjmp_event (m_enode, emission_id);
1034 /* class rewind_event : public checker_event. */
1036 /* Get the fndecl containing the site of the longjmp call. */
1038 tree
1039 rewind_event::get_longjmp_caller () const
1041 return m_eedge->m_src->get_function ()->decl;
1044 /* Get the fndecl containing the site of the setjmp call. */
1046 tree
1047 rewind_event::get_setjmp_caller () const
1049 return m_eedge->m_dest->get_function ()->decl;
1052 /* rewind_event's ctor. */
1054 rewind_event::rewind_event (const exploded_edge *eedge,
1055 enum event_kind kind,
1056 const event_loc_info &loc_info,
1057 const rewind_info_t *rewind_info)
1058 : checker_event (kind, loc_info),
1059 m_rewind_info (rewind_info),
1060 m_eedge (eedge)
1062 gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1065 /* class rewind_from_longjmp_event : public rewind_event. */
1067 /* Implementation of diagnostic_event::get_desc vfunc for
1068 rewind_from_longjmp_event. */
1070 label_text
1071 rewind_from_longjmp_event::get_desc (bool can_colorize) const
1073 const char *src_name
1074 = get_user_facing_name (m_rewind_info->get_longjmp_call ());
1076 if (get_longjmp_caller () == get_setjmp_caller ())
1077 /* Special-case: purely intraprocedural rewind. */
1078 return make_label_text (can_colorize,
1079 "rewinding within %qE from %qs...",
1080 get_longjmp_caller (),
1081 src_name);
1082 else
1083 return make_label_text (can_colorize,
1084 "rewinding from %qs in %qE...",
1085 src_name,
1086 get_longjmp_caller ());
1089 /* class rewind_to_setjmp_event : public rewind_event. */
1091 /* Implementation of diagnostic_event::get_desc vfunc for
1092 rewind_to_setjmp_event. */
1094 label_text
1095 rewind_to_setjmp_event::get_desc (bool can_colorize) const
1097 const char *dst_name
1098 = get_user_facing_name (m_rewind_info->get_setjmp_call ());
1100 /* If we can, identify the ID of the setjmp_event. */
1101 if (m_original_setjmp_event_id.known_p ())
1103 if (get_longjmp_caller () == get_setjmp_caller ())
1104 /* Special-case: purely intraprocedural rewind. */
1105 return make_label_text (can_colorize,
1106 "...to %qs (saved at %@)",
1107 dst_name,
1108 &m_original_setjmp_event_id);
1109 else
1110 return make_label_text (can_colorize,
1111 "...to %qs in %qE (saved at %@)",
1112 dst_name,
1113 get_setjmp_caller (),
1114 &m_original_setjmp_event_id);
1116 else
1118 if (get_longjmp_caller () == get_setjmp_caller ())
1119 /* Special-case: purely intraprocedural rewind. */
1120 return make_label_text (can_colorize,
1121 "...to %qs",
1122 dst_name,
1123 get_setjmp_caller ());
1124 else
1125 return make_label_text (can_colorize,
1126 "...to %qs in %qE",
1127 dst_name,
1128 get_setjmp_caller ());
1132 /* Implementation of checker_event::prepare_for_emission vfunc for
1133 rewind_to_setjmp_event.
1135 Attempt to look up the setjmp event ID that recorded the jmp_buf
1136 for this rewind. */
1138 void
1139 rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1140 pending_diagnostic *pd,
1141 diagnostic_event_id_t emission_id)
1143 checker_event::prepare_for_emission (path, pd, emission_id);
1144 path->get_setjmp_event (m_rewind_info->get_enode_origin (),
1145 &m_original_setjmp_event_id);
1148 /* class warning_event : public checker_event. */
1150 /* Implementation of diagnostic_event::get_desc vfunc for
1151 warning_event.
1153 If the pending diagnostic implements describe_final_event, use it,
1154 generating a precise description e.g.
1155 "second 'free' here; first 'free' was at (7)"
1157 Otherwise generate a generic description. */
1159 label_text
1160 warning_event::get_desc (bool can_colorize) const
1162 if (m_pending_diagnostic)
1164 tree var = fixup_tree_for_diagnostic (m_var);
1165 label_text ev_desc
1166 = m_pending_diagnostic->describe_final_event
1167 (evdesc::final_event (can_colorize, var, m_state, *this));
1168 if (ev_desc.get ())
1170 if (m_sm && flag_analyzer_verbose_state_changes)
1172 if (var)
1173 return make_label_text (can_colorize,
1174 "%s (%qE is in state %qs)",
1175 ev_desc.get (),
1176 var, m_state->get_name ());
1177 else
1178 return make_label_text (can_colorize,
1179 "%s (in global state %qs)",
1180 ev_desc.get (),
1181 m_state->get_name ());
1183 else
1184 return ev_desc;
1188 if (m_sm)
1190 if (m_var)
1191 return make_label_text (can_colorize,
1192 "here (%qE is in state %qs)",
1193 m_var, m_state->get_name ());
1194 else
1195 return make_label_text (can_colorize,
1196 "here (in global state %qs)",
1197 m_state->get_name ());
1199 else
1200 return label_text::borrow ("here");
1203 /* Implementation of diagnostic_event::get_meaning vfunc for
1204 warning_event. */
1206 diagnostic_event::meaning
1207 warning_event::get_meaning () const
1209 return meaning (VERB_danger, NOUN_unknown);
1212 } // namespace ana
1214 #endif /* #if ENABLE_ANALYZER */