1/* Subclasses of diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2023 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
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
59#if ENABLE_ANALYZER
60
61namespace ana {
62
63/* Get a string for EK. */
64
65const char *
66event_kind_to_string (enum event_kind ek)
67{
68 switch (ek)
69 {
70 default:
71 gcc_unreachable ();
72 case EK_DEBUG:
73 return "EK_DEBUG";
74 case EK_CUSTOM:
75 return "EK_CUSTOM";
76 case EK_STMT:
77 return "EK_STMT";
78 case EK_REGION_CREATION:
79 return "EK_REGION_CREATION";
80 case EK_FUNCTION_ENTRY:
81 return "EK_FUNCTION_ENTRY";
82 case EK_STATE_CHANGE:
83 return "EK_STATE_CHANGE";
84 case EK_START_CFG_EDGE:
85 return "EK_START_CFG_EDGE";
86 case EK_END_CFG_EDGE:
87 return "EK_END_CFG_EDGE";
88 case EK_CALL_EDGE:
89 return "EK_CALL_EDGE";
90 case EK_RETURN_EDGE:
91 return "EK_RETURN_EDGE";
92 case EK_START_CONSOLIDATED_CFG_EDGES:
93 return "EK_START_CONSOLIDATED_CFG_EDGES";
94 case EK_END_CONSOLIDATED_CFG_EDGES:
95 return "EK_END_CONSOLIDATED_CFG_EDGES";
96 case EK_INLINED_CALL:
97 return "EK_INLINED_CALL";
98 case EK_SETJMP:
99 return "EK_SETJMP";
100 case EK_REWIND_FROM_LONGJMP:
101 return "EK_REWIND_FROM_LONGJMP";
102 case EK_REWIND_TO_SETJMP:
103 return "EK_REWIND_TO_SETJMP";
104 case EK_WARNING:
105 return "EK_WARNING";
106 }
107}
108
109/* A class for fixing up fndecls and stack depths in checker_event, based
110 on inlining records.
111
112 The early inliner runs before the analyzer, which can lead to confusing
113 output.
114
115 Tne base fndecl and depth within a checker_event are from call strings
116 in program_points, which reflect the call strings after inlining.
117 This class lets us offset the depth and fix up the reported fndecl and
118 stack depth to better reflect the user's original code. */
119
120class inlining_info
121{
122public:
123 inlining_info (location_t loc)
124 {
125 inlining_iterator iter (loc);
126 m_inner_fndecl = iter.get_fndecl ();
127 int num_frames = 0;
128 while (!iter.done_p ())
129 {
130 m_outer_fndecl = iter.get_fndecl ();
131 num_frames++;
132 iter.next ();
133 }
134 if (num_frames > 1)
135 m_extra_frames = num_frames - 1;
136 else
137 m_extra_frames = 0;
138 }
139
140 tree get_inner_fndecl () const { return m_inner_fndecl; }
141 int get_extra_frames () const { return m_extra_frames; }
142
143private:
144 tree m_outer_fndecl;
145 tree m_inner_fndecl;
146 int m_extra_frames;
147};
148
149/* class checker_event : public diagnostic_event. */
150
151/* checker_event's ctor. */
152
153checker_event::checker_event (enum event_kind kind,
154 const event_loc_info &loc_info)
155: m_kind (kind), m_loc (loc_info.m_loc),
156 m_original_fndecl (loc_info.m_fndecl),
157 m_effective_fndecl (loc_info.m_fndecl),
158 m_original_depth (loc_info.m_depth),
159 m_effective_depth (loc_info.m_depth),
160 m_pending_diagnostic (NULL), m_emission_id (),
161 m_logical_loc (loc_info.m_fndecl)
162{
163 /* Update effective fndecl and depth if inlining has been recorded. */
164 if (flag_analyzer_undo_inlining)
165 {
166 inlining_info info (m_loc);
167 if (info.get_inner_fndecl ())
168 {
169 m_effective_fndecl = info.get_inner_fndecl ();
170 m_effective_depth += info.get_extra_frames ();
171 m_logical_loc = tree_logical_location (m_effective_fndecl);
172 }
173 }
174}
175
176/* No-op implementation of diagnostic_event::get_meaning vfunc for
177 checker_event: checker events have no meaning by default. */
178
179diagnostic_event::meaning
180checker_event::get_meaning () const
181{
182 return meaning ();
183}
184
185/* Dump this event to PP (for debugging/logging purposes). */
186
187void
188checker_event::dump (pretty_printer *pp) const
189{
190 label_text event_desc (get_desc (can_colorize: false));
191 pp_printf (pp, "\"%s\" (depth %i",
192 event_desc.get (), m_effective_depth);
193
194 if (m_effective_depth != m_original_depth)
195 pp_printf (pp, " corrected from %i",
196 m_original_depth);
197 if (m_effective_fndecl)
198 {
199 pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
200 if (m_effective_fndecl != m_original_fndecl)
201 pp_printf (pp, " corrected from %qE", m_original_fndecl);
202 }
203 pp_printf (pp, ", m_loc=%x)",
204 get_location ());
205}
206
207/* Dump this event to stderr (for debugging/logging purposes). */
208
209DEBUG_FUNCTION void
210checker_event::debug () const
211{
212 pretty_printer pp;
213 pp_format_decoder (&pp) = default_tree_printer;
214 pp_show_color (&pp) = pp_show_color (global_dc->printer);
215 pp.buffer->stream = stderr;
216 dump (pp: &pp);
217 pp_newline (&pp);
218 pp_flush (&pp);
219}
220
221/* Hook for being notified when this event has its final id EMISSION_ID
222 and is about to emitted for PD.
223
224 Base implementation of checker_event::prepare_for_emission vfunc;
225 subclasses that override this should chain up to it.
226
227 Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
228 side-effects of the call to get_desc take place before
229 pending_diagnostic::emit is called.
230
231 For example, state_change_event::get_desc can call
232 pending_diagnostic::describe_state_change; free_of_non_heap can use this
233 to tweak the message (TODO: would be neater to simply capture the
234 pertinent data within the sm-state). */
235
236void
237checker_event::prepare_for_emission (checker_path *,
238 pending_diagnostic *pd,
239 diagnostic_event_id_t emission_id)
240{
241 m_pending_diagnostic = pd;
242 m_emission_id = emission_id;
243
244 label_text desc = get_desc (can_colorize: false);
245}
246
247/* class debug_event : public checker_event. */
248
249/* Implementation of diagnostic_event::get_desc vfunc for
250 debug_event.
251 Use the saved string as the event's description. */
252
253label_text
254debug_event::get_desc (bool) const
255{
256 return label_text::borrow (buffer: m_desc);
257}
258
259/* class precanned_custom_event : public custom_event. */
260
261/* Implementation of diagnostic_event::get_desc vfunc for
262 precanned_custom_event.
263 Use the saved string as the event's description. */
264
265label_text
266precanned_custom_event::get_desc (bool) const
267{
268 return label_text::borrow (buffer: m_desc);
269}
270
271/* class statement_event : public checker_event. */
272
273/* statement_event's ctor. */
274
275statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
276 const program_state &dst_state)
277: checker_event (EK_STMT,
278 event_loc_info (gimple_location (g: stmt), fndecl, depth)),
279 m_stmt (stmt),
280 m_dst_state (dst_state)
281{
282}
283
284/* Implementation of diagnostic_event::get_desc vfunc for
285 statement_event.
286 Use the statement's dump form as the event's description. */
287
288label_text
289statement_event::get_desc (bool) const
290{
291 pretty_printer pp;
292 pp_string (&pp, "stmt: ");
293 pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
294 return label_text::take (buffer: xstrdup (pp_formatted_text (&pp)));
295}
296
297/* class region_creation_event : public checker_event. */
298
299region_creation_event::region_creation_event (const event_loc_info &loc_info)
300: checker_event (EK_REGION_CREATION, loc_info)
301{
302}
303
304/* The various region_creation_event subclasses' get_desc
305 implementations. */
306
307label_text
308region_creation_event_memory_space::get_desc (bool) const
309{
310 switch (m_mem_space)
311 {
312 default:
313 return label_text::borrow (buffer: "region created here");
314 case MEMSPACE_STACK:
315 return label_text::borrow (buffer: "region created on stack here");
316 case MEMSPACE_HEAP:
317 return label_text::borrow (buffer: "region created on heap here");
318 }
319}
320
321label_text
322region_creation_event_capacity::get_desc (bool can_colorize) const
323{
324 gcc_assert (m_capacity);
325 if (TREE_CODE (m_capacity) == INTEGER_CST)
326 {
327 unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
328 return make_label_text_n (can_colorize,
329 n: hwi,
330 singular_fmt: "capacity: %wu byte",
331 plural_fmt: "capacity: %wu bytes",
332 hwi);
333 }
334 else
335 return make_label_text (can_colorize,
336 fmt: "capacity: %qE bytes", m_capacity);
337}
338
339label_text
340region_creation_event_allocation_size::get_desc (bool can_colorize) const
341{
342 if (m_capacity)
343 {
344 if (TREE_CODE (m_capacity) == INTEGER_CST)
345 return make_label_text_n (can_colorize,
346 n: tree_to_uhwi (m_capacity),
347 singular_fmt: "allocated %E byte here",
348 plural_fmt: "allocated %E bytes here",
349 m_capacity);
350 else
351 return make_label_text (can_colorize,
352 fmt: "allocated %qE bytes here",
353 m_capacity);
354 }
355 return make_label_text (can_colorize, fmt: "allocated here");
356}
357
358label_text
359region_creation_event_debug::get_desc (bool) const
360{
361 pretty_printer pp;
362 pp_format_decoder (&pp) = default_tree_printer;
363 pp_string (&pp, "region creation: ");
364 m_reg->dump_to_pp (pp: &pp, simple: true);
365 if (m_capacity)
366 pp_printf (&pp, " capacity: %qE", m_capacity);
367 return label_text::take (buffer: xstrdup (pp_formatted_text (&pp)));
368}
369
370/* class function_entry_event : public checker_event. */
371
372function_entry_event::function_entry_event (const program_point &dst_point)
373: checker_event (EK_FUNCTION_ENTRY,
374 event_loc_info (dst_point.get_supernode
375 ()->get_start_location (),
376 dst_point.get_fndecl (),
377 dst_point.get_stack_depth ()))
378{
379}
380
381/* Implementation of diagnostic_event::get_desc vfunc for
382 function_entry_event.
383
384 Use a string such as "entry to 'foo'" as the event's description. */
385
386label_text
387function_entry_event::get_desc (bool can_colorize) const
388{
389 return make_label_text (can_colorize, fmt: "entry to %qE", m_effective_fndecl);
390}
391
392/* Implementation of diagnostic_event::get_meaning vfunc for
393 function entry. */
394
395diagnostic_event::meaning
396function_entry_event::get_meaning () const
397{
398 return meaning (VERB_enter, NOUN_function);
399}
400
401/* class state_change_event : public checker_event. */
402
403/* state_change_event's ctor. */
404
405state_change_event::state_change_event (const supernode *node,
406 const gimple *stmt,
407 int stack_depth,
408 const state_machine &sm,
409 const svalue *sval,
410 state_machine::state_t from,
411 state_machine::state_t to,
412 const svalue *origin,
413 const program_state &dst_state,
414 const exploded_node *enode)
415: checker_event (EK_STATE_CHANGE,
416 event_loc_info (stmt->location,
417 node->m_fun->decl,
418 stack_depth)),
419 m_node (node), m_stmt (stmt), m_sm (sm),
420 m_sval (sval), m_from (from), m_to (to),
421 m_origin (origin),
422 m_dst_state (dst_state),
423 m_enode (enode)
424{
425}
426
427/* Implementation of diagnostic_event::get_desc vfunc for
428 state_change_event.
429
430 Attempt to generate a nicer human-readable description.
431 For greatest precision-of-wording, give the pending diagnostic
432 a chance to describe this state change (in terms of the
433 diagnostic).
434 Note that we only have a pending_diagnostic set on the event once
435 the diagnostic is about to being emitted, so the description for
436 an event can change. */
437
438label_text
439state_change_event::get_desc (bool can_colorize) const
440{
441 if (m_pending_diagnostic)
442 {
443 region_model *model = m_dst_state.m_region_model;
444 tree var = model->get_representative_tree (sval: m_sval);
445 tree origin = model->get_representative_tree (sval: m_origin);
446 label_text custom_desc
447 = m_pending_diagnostic->describe_state_change
448 (evdesc::state_change (can_colorize, var, origin,
449 m_from, m_to, m_emission_id, *this));
450 if (custom_desc.get ())
451 {
452 if (flag_analyzer_verbose_state_changes)
453 {
454 /* Get any "meaning" of event. */
455 diagnostic_event::meaning meaning = get_meaning ();
456 pretty_printer meaning_pp;
457 meaning.dump_to_pp (pp: &meaning_pp);
458
459 /* Append debug version. */
460 if (m_origin)
461 return make_label_text
462 (can_colorize,
463 fmt: "%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
464 custom_desc.get (),
465 var,
466 m_from->get_name (),
467 m_to->get_name (),
468 origin,
469 pp_formatted_text (&meaning_pp));
470 else
471 return make_label_text
472 (can_colorize,
473 fmt: "%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
474 custom_desc.get (),
475 var,
476 m_from->get_name (),
477 m_to->get_name (),
478 pp_formatted_text (&meaning_pp));
479 }
480 else
481 return custom_desc;
482 }
483 }
484
485 /* Fallback description. */
486 if (m_sval)
487 {
488 label_text sval_desc = m_sval->get_desc ();
489 if (m_origin)
490 {
491 label_text origin_desc = m_origin->get_desc ();
492 return make_label_text
493 (can_colorize,
494 fmt: "state of %qs: %qs -> %qs (origin: %qs)",
495 sval_desc.get (),
496 m_from->get_name (),
497 m_to->get_name (),
498 origin_desc.get ());
499 }
500 else
501 return make_label_text
502 (can_colorize,
503 fmt: "state of %qs: %qs -> %qs (NULL origin)",
504 sval_desc.get (),
505 m_from->get_name (),
506 m_to->get_name ());
507 }
508 else
509 {
510 gcc_assert (m_origin == NULL);
511 return make_label_text
512 (can_colorize,
513 fmt: "global state: %qs -> %qs",
514 m_from->get_name (),
515 m_to->get_name ());
516 }
517}
518
519/* Implementation of diagnostic_event::get_meaning vfunc for
520 state change events: delegate to the pending_diagnostic to
521 get any meaning. */
522
523diagnostic_event::meaning
524state_change_event::get_meaning () const
525{
526 if (m_pending_diagnostic)
527 {
528 region_model *model = m_dst_state.m_region_model;
529 tree var = model->get_representative_tree (sval: m_sval);
530 tree origin = model->get_representative_tree (sval: m_origin);
531 return m_pending_diagnostic->get_meaning_for_state_change
532 (evdesc::state_change (false, var, origin,
533 m_from, m_to, m_emission_id, *this));
534 }
535 else
536 return meaning ();
537}
538
539/* class superedge_event : public checker_event. */
540
541/* Get the callgraph_superedge for this superedge_event, which must be
542 for an interprocedural edge, rather than a CFG edge. */
543
544const callgraph_superedge&
545superedge_event::get_callgraph_superedge () const
546{
547 gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
548 return *m_sedge->dyn_cast_callgraph_superedge ();
549}
550
551/* Determine if this event should be filtered at the given verbosity
552 level. */
553
554bool
555superedge_event::should_filter_p (int verbosity) const
556{
557 switch (m_sedge->m_kind)
558 {
559 case SUPEREDGE_CFG_EDGE:
560 {
561 if (verbosity < 2)
562 return true;
563
564 if (verbosity < 4)
565 {
566 /* Filter events with empty descriptions. This ought to filter
567 FALLTHRU, but retain true/false/switch edges. */
568 label_text desc = get_desc (can_colorize: false);
569 gcc_assert (desc.get ());
570 if (desc.get ()[0] == '\0')
571 return true;
572 }
573 }
574 break;
575
576 default:
577 break;
578 }
579 return false;
580}
581
582/* superedge_event's ctor. */
583
584superedge_event::superedge_event (enum event_kind kind,
585 const exploded_edge &eedge,
586 const event_loc_info &loc_info)
587: checker_event (kind, loc_info),
588 m_eedge (eedge), m_sedge (eedge.m_sedge),
589 m_var (NULL_TREE), m_critical_state (0)
590{
591}
592
593/* class cfg_edge_event : public superedge_event. */
594
595/* Get the cfg_superedge for this cfg_edge_event. */
596
597const cfg_superedge &
598cfg_edge_event::get_cfg_superedge () const
599{
600 return *m_sedge->dyn_cast_cfg_superedge ();
601}
602
603/* cfg_edge_event's ctor. */
604
605cfg_edge_event::cfg_edge_event (enum event_kind kind,
606 const exploded_edge &eedge,
607 const event_loc_info &loc_info)
608: superedge_event (kind, eedge, loc_info)
609{
610 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
611}
612
613/* Implementation of diagnostic_event::get_meaning vfunc for
614 CFG edge events. */
615
616diagnostic_event::meaning
617cfg_edge_event::get_meaning () const
618{
619 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
620 if (cfg_sedge.true_value_p ())
621 return meaning (VERB_branch, PROPERTY_true);
622 else if (cfg_sedge.false_value_p ())
623 return meaning (VERB_branch, PROPERTY_false);
624 else
625 return meaning ();
626}
627
628/* class start_cfg_edge_event : public cfg_edge_event. */
629
630/* Implementation of diagnostic_event::get_desc vfunc for
631 start_cfg_edge_event.
632
633 If -fanalyzer-verbose-edges, then generate low-level descriptions, such
634 as
635 "taking 'true' edge SN:7 -> SN:8".
636
637 Otherwise, generate strings using the label of the underlying CFG if
638 any, such as:
639 "following 'true' branch..." or
640 "following 'case 3' branch..."
641 "following 'default' branch..."
642
643 For conditionals, attempt to supply a description of the condition that
644 holds, such as:
645 "following 'false' branch (when 'ptr' is non-NULL)..."
646
647 Failing that, return an empty description (which will lead to this event
648 being filtered). */
649
650label_text
651start_cfg_edge_event::get_desc (bool can_colorize) const
652{
653 bool user_facing = !flag_analyzer_verbose_edges;
654 label_text edge_desc (m_sedge->get_description (user_facing));
655 if (user_facing)
656 {
657 if (edge_desc.get () && strlen (s: edge_desc.get ()) > 0)
658 {
659 label_text cond_desc = maybe_describe_condition (can_colorize);
660 label_text result;
661 if (cond_desc.get ())
662 return make_label_text (can_colorize,
663 fmt: "following %qs branch (%s)...",
664 edge_desc.get (), cond_desc.get ());
665 else
666 return make_label_text (can_colorize,
667 fmt: "following %qs branch...",
668 edge_desc.get ());
669 }
670 else
671 return label_text::borrow (buffer: "");
672 }
673 else
674 {
675 if (strlen (s: edge_desc.get ()) > 0)
676 return make_label_text (can_colorize,
677 fmt: "taking %qs edge SN:%i -> SN:%i",
678 edge_desc.get (),
679 m_sedge->m_src->m_index,
680 m_sedge->m_dest->m_index);
681 else
682 return make_label_text (can_colorize,
683 fmt: "taking edge SN:%i -> SN:%i",
684 m_sedge->m_src->m_index,
685 m_sedge->m_dest->m_index);
686 }
687}
688
689/* Attempt to generate a description of any condition that holds at this edge.
690
691 The intent is to make the user-facing messages more clear, especially for
692 cases where there's a single or double-negative, such as
693 when describing the false branch of an inverted condition.
694
695 For example, rather than printing just:
696
697 | if (!ptr)
698 | ~
699 | |
700 | (1) following 'false' branch...
701
702 it's clearer to spell out the condition that holds:
703
704 | if (!ptr)
705 | ~
706 | |
707 | (1) following 'false' branch (when 'ptr' is non-NULL)...
708 ^^^^^^^^^^^^^^^^^^^^^^
709
710 In the above example, this function would generate the highlighted
711 string: "when 'ptr' is non-NULL".
712
713 If the edge is not a condition, or it's not clear that a description of
714 the condition would be helpful to the user, return NULL. */
715
716label_text
717start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
718{
719 const cfg_superedge& cfg_sedge = get_cfg_superedge ();
720
721 if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
722 {
723 const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
724 if (const gcond *cond_stmt = dyn_cast <const gcond *> (p: last_stmt))
725 {
726 enum tree_code op = gimple_cond_code (gs: cond_stmt);
727 tree lhs = gimple_cond_lhs (gs: cond_stmt);
728 tree rhs = gimple_cond_rhs (gs: cond_stmt);
729 if (cfg_sedge.false_value_p ())
730 op = invert_tree_comparison (op, false /* honor_nans */);
731 return maybe_describe_condition (can_colorize,
732 lhs, op, rhs);
733 }
734 }
735 return label_text::borrow (NULL);
736}
737
738/* Subroutine of maybe_describe_condition above.
739
740 Attempt to generate a user-facing description of the condition
741 LHS OP RHS, but only if it is likely to make it easier for the
742 user to understand a condition. */
743
744label_text
745start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
746 tree lhs,
747 enum tree_code op,
748 tree rhs)
749{
750 /* In theory we could just build a tree via
751 fold_build2 (op, boolean_type_node, lhs, rhs)
752 and print it with %qE on it, but this leads to warts such as
753 parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
754
755 /* Special-case: describe testing the result of strcmp, as figuring
756 out what the "true" or "false" path is can be confusing to the user. */
757 if (TREE_CODE (lhs) == SSA_NAME
758 && zerop (rhs))
759 {
760 if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
761 if (is_special_named_call_p (call, funcname: "strcmp", num_args: 2))
762 {
763 if (op == EQ_EXPR)
764 return label_text::borrow (buffer: "when the strings are equal");
765 if (op == NE_EXPR)
766 return label_text::borrow (buffer: "when the strings are non-equal");
767 }
768 }
769
770 /* Only attempt to generate text for sufficiently simple expressions. */
771 if (!should_print_expr_p (lhs))
772 return label_text::borrow (NULL);
773 if (!should_print_expr_p (rhs))
774 return label_text::borrow (NULL);
775
776 /* Special cases for pointer comparisons against NULL. */
777 if (POINTER_TYPE_P (TREE_TYPE (lhs))
778 && POINTER_TYPE_P (TREE_TYPE (rhs))
779 && zerop (rhs))
780 {
781 if (op == EQ_EXPR)
782 return make_label_text (can_colorize, fmt: "when %qE is NULL",
783 lhs);
784 if (op == NE_EXPR)
785 return make_label_text (can_colorize, fmt: "when %qE is non-NULL",
786 lhs);
787 }
788
789 return make_label_text (can_colorize, fmt: "when %<%E %s %E%>",
790 lhs, op_symbol_code (op), rhs);
791}
792
793/* Subroutine of maybe_describe_condition.
794
795 Return true if EXPR is we will get suitable user-facing output
796 from %E on it. */
797
798bool
799start_cfg_edge_event::should_print_expr_p (tree expr)
800{
801 if (TREE_CODE (expr) == SSA_NAME)
802 {
803 if (SSA_NAME_VAR (expr))
804 return should_print_expr_p (SSA_NAME_VAR (expr));
805 else
806 return false;
807 }
808
809 if (DECL_P (expr))
810 return true;
811
812 if (CONSTANT_CLASS_P (expr))
813 return true;
814
815 return false;
816}
817
818/* class call_event : public superedge_event. */
819
820/* call_event's ctor. */
821
822call_event::call_event (const exploded_edge &eedge,
823 const event_loc_info &loc_info)
824: superedge_event (EK_CALL_EDGE, eedge, loc_info)
825{
826 if (eedge.m_sedge)
827 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
828
829 m_src_snode = eedge.m_src->get_supernode ();
830 m_dest_snode = eedge.m_dest->get_supernode ();
831}
832
833/* Implementation of diagnostic_event::get_desc vfunc for
834 call_event.
835
836 If this call event passes critical state for an sm-based warning,
837 allow the diagnostic to generate a precise description, such as:
838
839 "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
840
841 Otherwise, generate a description of the form
842 "calling 'foo' from 'bar'". */
843
844label_text
845call_event::get_desc (bool can_colorize) const
846{
847 if (m_critical_state && m_pending_diagnostic)
848 {
849 gcc_assert (m_var);
850 tree var = fixup_tree_for_diagnostic (m_var);
851 label_text custom_desc
852 = m_pending_diagnostic->describe_call_with_state
853 (evdesc::call_with_state (can_colorize,
854 m_src_snode->m_fun->decl,
855 m_dest_snode->m_fun->decl,
856 var,
857 m_critical_state));
858 if (custom_desc.get ())
859 return custom_desc;
860 }
861
862 return make_label_text (can_colorize,
863 fmt: "calling %qE from %qE",
864 get_callee_fndecl (),
865 get_caller_fndecl ());
866}
867
868/* Implementation of diagnostic_event::get_meaning vfunc for
869 function call events. */
870
871diagnostic_event::meaning
872call_event::get_meaning () const
873{
874 return meaning (VERB_call, NOUN_function);
875}
876
877/* Override of checker_event::is_call_p for calls. */
878
879bool
880call_event::is_call_p () const
881{
882 return true;
883}
884
885tree
886call_event::get_caller_fndecl () const
887{
888 return m_src_snode->m_fun->decl;
889}
890
891tree
892call_event::get_callee_fndecl () const
893{
894 return m_dest_snode->m_fun->decl;
895}
896
897/* class return_event : public superedge_event. */
898
899/* return_event's ctor. */
900
901return_event::return_event (const exploded_edge &eedge,
902 const event_loc_info &loc_info)
903: superedge_event (EK_RETURN_EDGE, eedge, loc_info)
904{
905 if (eedge.m_sedge)
906 gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
907
908 m_src_snode = eedge.m_src->get_supernode ();
909 m_dest_snode = eedge.m_dest->get_supernode ();
910}
911
912/* Implementation of diagnostic_event::get_desc vfunc for
913 return_event.
914
915 If this return event returns critical state for an sm-based warning,
916 allow the diagnostic to generate a precise description, such as:
917
918 "possible of NULL to 'foo' from 'bar'"
919
920 Otherwise, generate a description of the form
921 "returning to 'foo' from 'bar'. */
922
923label_text
924return_event::get_desc (bool can_colorize) const
925{
926 /* For greatest precision-of-wording, if this is returning the
927 state involved in the pending diagnostic, give the pending
928 diagnostic a chance to describe this return (in terms of
929 itself). */
930 if (m_critical_state && m_pending_diagnostic)
931 {
932 label_text custom_desc
933 = m_pending_diagnostic->describe_return_of_state
934 (evdesc::return_of_state (can_colorize,
935 m_dest_snode->m_fun->decl,
936 m_src_snode->m_fun->decl,
937 m_critical_state));
938 if (custom_desc.get ())
939 return custom_desc;
940 }
941 return make_label_text (can_colorize,
942 fmt: "returning to %qE from %qE",
943 m_dest_snode->m_fun->decl,
944 m_src_snode->m_fun->decl);
945}
946
947/* Implementation of diagnostic_event::get_meaning vfunc for
948 function return events. */
949
950diagnostic_event::meaning
951return_event::get_meaning () const
952{
953 return meaning (VERB_return, NOUN_function);
954}
955
956/* Override of checker_event::is_return_p for returns. */
957
958bool
959return_event::is_return_p () const
960{
961 return true;
962}
963
964/* class start_consolidated_cfg_edges_event : public checker_event. */
965
966label_text
967start_consolidated_cfg_edges_event::get_desc (bool can_colorize) const
968{
969 return make_label_text (can_colorize,
970 fmt: "following %qs branch...",
971 m_edge_sense ? "true" : "false");
972}
973
974/* Implementation of diagnostic_event::get_meaning vfunc for
975 start_consolidated_cfg_edges_event. */
976
977diagnostic_event::meaning
978start_consolidated_cfg_edges_event::get_meaning () const
979{
980 return meaning (VERB_branch,
981 (m_edge_sense ? PROPERTY_true : PROPERTY_false));
982}
983
984/* class inlined_call_event : public checker_event. */
985
986label_text
987inlined_call_event::get_desc (bool can_colorize) const
988{
989 return make_label_text (can_colorize,
990 fmt: "inlined call to %qE from %qE",
991 m_apparent_callee_fndecl,
992 m_apparent_caller_fndecl);
993}
994
995/* Implementation of diagnostic_event::get_meaning vfunc for
996 reconstructed inlined function calls. */
997
998diagnostic_event::meaning
999inlined_call_event::get_meaning () const
1000{
1001 return meaning (VERB_call, NOUN_function);
1002}
1003
1004/* class setjmp_event : public checker_event. */
1005
1006/* Implementation of diagnostic_event::get_desc vfunc for
1007 setjmp_event. */
1008
1009label_text
1010setjmp_event::get_desc (bool can_colorize) const
1011{
1012 return make_label_text (can_colorize,
1013 fmt: "%qs called here",
1014 get_user_facing_name (call: m_setjmp_call));
1015}
1016
1017/* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
1018
1019 Record this setjmp's event ID into the path, so that rewind events can
1020 use it. */
1021
1022void
1023setjmp_event::prepare_for_emission (checker_path *path,
1024 pending_diagnostic *pd,
1025 diagnostic_event_id_t emission_id)
1026{
1027 checker_event::prepare_for_emission (path, pd, emission_id);
1028 path->record_setjmp_event (enode: m_enode, setjmp_emission_id: emission_id);
1029}
1030
1031/* class rewind_event : public checker_event. */
1032
1033/* Get the fndecl containing the site of the longjmp call. */
1034
1035tree
1036rewind_event::get_longjmp_caller () const
1037{
1038 return m_eedge->m_src->get_function ()->decl;
1039}
1040
1041/* Get the fndecl containing the site of the setjmp call. */
1042
1043tree
1044rewind_event::get_setjmp_caller () const
1045{
1046 return m_eedge->m_dest->get_function ()->decl;
1047}
1048
1049/* rewind_event's ctor. */
1050
1051rewind_event::rewind_event (const exploded_edge *eedge,
1052 enum event_kind kind,
1053 const event_loc_info &loc_info,
1054 const rewind_info_t *rewind_info)
1055: checker_event (kind, loc_info),
1056 m_rewind_info (rewind_info),
1057 m_eedge (eedge)
1058{
1059 gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
1060}
1061
1062/* class rewind_from_longjmp_event : public rewind_event. */
1063
1064/* Implementation of diagnostic_event::get_desc vfunc for
1065 rewind_from_longjmp_event. */
1066
1067label_text
1068rewind_from_longjmp_event::get_desc (bool can_colorize) const
1069{
1070 const char *src_name
1071 = get_user_facing_name (call: m_rewind_info->get_longjmp_call ());
1072
1073 if (get_longjmp_caller () == get_setjmp_caller ())
1074 /* Special-case: purely intraprocedural rewind. */
1075 return make_label_text (can_colorize,
1076 fmt: "rewinding within %qE from %qs...",
1077 get_longjmp_caller (),
1078 src_name);
1079 else
1080 return make_label_text (can_colorize,
1081 fmt: "rewinding from %qs in %qE...",
1082 src_name,
1083 get_longjmp_caller ());
1084}
1085
1086/* class rewind_to_setjmp_event : public rewind_event. */
1087
1088/* Implementation of diagnostic_event::get_desc vfunc for
1089 rewind_to_setjmp_event. */
1090
1091label_text
1092rewind_to_setjmp_event::get_desc (bool can_colorize) const
1093{
1094 const char *dst_name
1095 = get_user_facing_name (call: m_rewind_info->get_setjmp_call ());
1096
1097 /* If we can, identify the ID of the setjmp_event. */
1098 if (m_original_setjmp_event_id.known_p ())
1099 {
1100 if (get_longjmp_caller () == get_setjmp_caller ())
1101 /* Special-case: purely intraprocedural rewind. */
1102 return make_label_text (can_colorize,
1103 fmt: "...to %qs (saved at %@)",
1104 dst_name,
1105 &m_original_setjmp_event_id);
1106 else
1107 return make_label_text (can_colorize,
1108 fmt: "...to %qs in %qE (saved at %@)",
1109 dst_name,
1110 get_setjmp_caller (),
1111 &m_original_setjmp_event_id);
1112 }
1113 else
1114 {
1115 if (get_longjmp_caller () == get_setjmp_caller ())
1116 /* Special-case: purely intraprocedural rewind. */
1117 return make_label_text (can_colorize,
1118 fmt: "...to %qs",
1119 dst_name,
1120 get_setjmp_caller ());
1121 else
1122 return make_label_text (can_colorize,
1123 fmt: "...to %qs in %qE",
1124 dst_name,
1125 get_setjmp_caller ());
1126 }
1127}
1128
1129/* Implementation of checker_event::prepare_for_emission vfunc for
1130 rewind_to_setjmp_event.
1131
1132 Attempt to look up the setjmp event ID that recorded the jmp_buf
1133 for this rewind. */
1134
1135void
1136rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
1137 pending_diagnostic *pd,
1138 diagnostic_event_id_t emission_id)
1139{
1140 checker_event::prepare_for_emission (path, pd, emission_id);
1141 path->get_setjmp_event (enode: m_rewind_info->get_enode_origin (),
1142 out_emission_id: &m_original_setjmp_event_id);
1143}
1144
1145/* class warning_event : public checker_event. */
1146
1147/* Implementation of diagnostic_event::get_desc vfunc for
1148 warning_event.
1149
1150 If the pending diagnostic implements describe_final_event, use it,
1151 generating a precise description e.g.
1152 "second 'free' here; first 'free' was at (7)"
1153
1154 Otherwise generate a generic description. */
1155
1156label_text
1157warning_event::get_desc (bool can_colorize) const
1158{
1159 if (m_pending_diagnostic)
1160 {
1161 tree var = fixup_tree_for_diagnostic (m_var);
1162 label_text ev_desc
1163 = m_pending_diagnostic->describe_final_event
1164 (evdesc::final_event (can_colorize, var, m_state, *this));
1165 if (ev_desc.get ())
1166 {
1167 if (m_sm && flag_analyzer_verbose_state_changes)
1168 {
1169 if (var)
1170 return make_label_text (can_colorize,
1171 fmt: "%s (%qE is in state %qs)",
1172 ev_desc.get (),
1173 var, m_state->get_name ());
1174 else
1175 return make_label_text (can_colorize,
1176 fmt: "%s (in global state %qs)",
1177 ev_desc.get (),
1178 m_state->get_name ());
1179 }
1180 else
1181 return ev_desc;
1182 }
1183 }
1184
1185 if (m_sm)
1186 {
1187 if (m_var)
1188 return make_label_text (can_colorize,
1189 fmt: "here (%qE is in state %qs)",
1190 m_var, m_state->get_name ());
1191 else
1192 return make_label_text (can_colorize,
1193 fmt: "here (in global state %qs)",
1194 m_state->get_name ());
1195 }
1196 else
1197 return label_text::borrow (buffer: "here");
1198}
1199
1200/* Implementation of diagnostic_event::get_meaning vfunc for
1201 warning_event. */
1202
1203diagnostic_event::meaning
1204warning_event::get_meaning () const
1205{
1206 return meaning (VERB_danger, NOUN_unknown);
1207}
1208
1209} // namespace ana
1210
1211#endif /* #if ENABLE_ANALYZER */
1212

source code of gcc/analyzer/checker-event.cc