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