d: Merge upstream dmd 56589f0f4, druntime 651389b5, phobos 1516ecad9.
[official-gcc.git] / gcc / analyzer / diagnostic-manager.cc
blob4adfda1af65721db6ac5931b3c0178d3bfa352cf
1 /* Classes for saving, deduplicating, and emitting analyzer diagnostics.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
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 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "pretty-print.h"
26 #include "gcc-rich-location.h"
27 #include "gimple-pretty-print.h"
28 #include "function.h"
29 #include "diagnostic-core.h"
30 #include "diagnostic-event-id.h"
31 #include "diagnostic-path.h"
32 #include "alloc-pool.h"
33 #include "fibonacci_heap.h"
34 #include "shortest-paths.h"
35 #include "sbitmap.h"
36 #include "bitmap.h"
37 #include "tristate.h"
38 #include "selftest.h"
39 #include "ordered-hash-map.h"
40 #include "json.h"
41 #include "analyzer/analyzer.h"
42 #include "analyzer/analyzer-logging.h"
43 #include "analyzer/sm.h"
44 #include "analyzer/pending-diagnostic.h"
45 #include "analyzer/diagnostic-manager.h"
46 #include "analyzer/call-string.h"
47 #include "analyzer/program-point.h"
48 #include "analyzer/store.h"
49 #include "analyzer/region-model.h"
50 #include "analyzer/constraint-manager.h"
51 #include "cfg.h"
52 #include "basic-block.h"
53 #include "gimple.h"
54 #include "gimple-iterator.h"
55 #include "inlining-iterator.h"
56 #include "cgraph.h"
57 #include "digraph.h"
58 #include "analyzer/supergraph.h"
59 #include "analyzer/program-state.h"
60 #include "analyzer/exploded-graph.h"
61 #include "analyzer/trimmed-graph.h"
62 #include "analyzer/feasible-graph.h"
63 #include "analyzer/checker-path.h"
64 #include "analyzer/reachability.h"
66 #if ENABLE_ANALYZER
68 namespace ana {
70 class feasible_worklist;
72 /* State for finding the shortest feasible exploded_path for a
73 saved_diagnostic.
74 This is shared between all diagnostics, so that we avoid repeating work. */
76 class epath_finder
78 public:
79 epath_finder (const exploded_graph &eg)
80 : m_eg (eg),
81 m_sep (NULL)
83 /* This is shared by all diagnostics, but only needed if
84 !flag_analyzer_feasibility. */
85 if (!flag_analyzer_feasibility)
86 m_sep = new shortest_exploded_paths (eg, eg.get_origin (),
87 SPS_FROM_GIVEN_ORIGIN);
90 ~epath_finder () { delete m_sep; }
92 logger *get_logger () const { return m_eg.get_logger (); }
94 exploded_path *get_best_epath (const exploded_node *target_enode,
95 const char *desc, unsigned diag_idx,
96 feasibility_problem **out_problem);
98 private:
99 DISABLE_COPY_AND_ASSIGN(epath_finder);
101 exploded_path *explore_feasible_paths (const exploded_node *target_enode,
102 const char *desc, unsigned diag_idx);
103 bool process_worklist_item (feasible_worklist *worklist,
104 const trimmed_graph &tg,
105 feasible_graph *fg,
106 const exploded_node *target_enode,
107 unsigned diag_idx,
108 exploded_path **out_best_path) const;
109 void dump_trimmed_graph (const exploded_node *target_enode,
110 const char *desc, unsigned diag_idx,
111 const trimmed_graph &tg,
112 const shortest_paths<eg_traits, exploded_path> &sep);
113 void dump_feasible_graph (const exploded_node *target_enode,
114 const char *desc, unsigned diag_idx,
115 const feasible_graph &fg);
116 void dump_feasible_path (const exploded_node *target_enode,
117 unsigned diag_idx,
118 const feasible_graph &fg,
119 const feasible_node &fnode) const;
121 const exploded_graph &m_eg;
122 shortest_exploded_paths *m_sep;
125 /* class epath_finder. */
127 /* Get the "best" exploded_path for reaching ENODE from the origin,
128 returning ownership of it to the caller.
130 Ideally we want to report the shortest feasible path.
131 Return NULL if we could not find a feasible path
132 (when flag_analyzer_feasibility is true).
134 If flag_analyzer_feasibility is false, then simply return the
135 shortest path.
137 Use DESC and DIAG_IDX when logging.
139 Write any feasibility_problem to *OUT_PROBLEM. */
141 exploded_path *
142 epath_finder::get_best_epath (const exploded_node *enode,
143 const char *desc, unsigned diag_idx,
144 feasibility_problem **out_problem)
146 logger *logger = get_logger ();
147 LOG_SCOPE (logger);
149 unsigned snode_idx = enode->get_supernode ()->m_index;
150 if (logger)
151 logger->log ("considering %qs at EN: %i, SN: %i (sd: %i)",
152 desc, enode->m_index, snode_idx, diag_idx);
154 /* State-merging means that not every path in the egraph corresponds
155 to a feasible one w.r.t. states.
157 We want to find the shortest feasible path from the origin to ENODE
158 in the egraph. */
160 if (flag_analyzer_feasibility)
162 /* Attempt to find the shortest feasible path using feasible_graph. */
163 if (logger)
164 logger->log ("trying to find shortest feasible path");
165 if (exploded_path *epath = explore_feasible_paths (enode, desc, diag_idx))
167 if (logger)
168 logger->log ("accepting %qs at EN: %i, SN: %i (sd: %i)"
169 " with feasible path (length: %i)",
170 desc, enode->m_index, snode_idx, diag_idx,
171 epath->length ());
172 return epath;
174 else
176 if (logger)
177 logger->log ("rejecting %qs at EN: %i, SN: %i (sd: %i)"
178 " due to not finding feasible path",
179 desc, enode->m_index, snode_idx, diag_idx);
180 return NULL;
183 else
185 /* As a crude approximation to shortest feasible path, simply find
186 the shortest path, and note whether it is feasible.
187 There could be longer feasible paths within the egraph, so this
188 approach would lead to diagnostics being falsely rejected
189 (PR analyzer/96374). */
190 if (logger)
191 logger->log ("trying to find shortest path ignoring feasibility");
192 gcc_assert (m_sep);
193 exploded_path *epath
194 = new exploded_path (m_sep->get_shortest_path (enode));
195 if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg))
197 if (logger)
198 logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i)"
199 " with feasible path (length: %i)",
200 desc, enode->m_index, snode_idx, diag_idx,
201 epath->length ());
203 else
205 if (logger)
206 logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i) (length: %i)"
207 " despite infeasible path (due to %qs)",
208 desc, enode->m_index, snode_idx, diag_idx,
209 epath->length (),
210 "-fno-analyzer-feasibility");
212 return epath;
216 /* A class for managing the worklist of feasible_nodes in
217 epath_finder::explore_feasible_paths, prioritizing them
218 so that shorter paths appear earlier in the queue. */
220 class feasible_worklist
222 public:
223 feasible_worklist (const shortest_paths<eg_traits, exploded_path> &sep)
224 : m_queue (key_t (*this, NULL)),
225 m_sep (sep)
229 feasible_node *take_next () { return m_queue.extract_min (); }
231 void add_node (feasible_node *fnode)
233 m_queue.insert (key_t (*this, fnode), fnode);
236 private:
237 struct key_t
239 key_t (const feasible_worklist &w, feasible_node *fnode)
240 : m_worklist (w), m_fnode (fnode)
243 bool operator< (const key_t &other) const
245 return cmp (*this, other) < 0;
248 bool operator== (const key_t &other) const
250 return cmp (*this, other) == 0;
253 bool operator> (const key_t &other) const
255 return !(*this == other || *this < other);
258 private:
259 static int cmp (const key_t &ka, const key_t &kb)
261 /* Choose the node for which if the remaining path were feasible,
262 it would be the shortest path (summing the length of the
263 known-feasible path so far with that of the remaining
264 possibly-feasible path). */
265 int ca = ka.m_worklist.get_estimated_cost (ka.m_fnode);
266 int cb = kb.m_worklist.get_estimated_cost (kb.m_fnode);
267 return ca - cb;
270 const feasible_worklist &m_worklist;
271 feasible_node *m_fnode;
274 /* Get the estimated length of a path involving FNODE from
275 the origin to the target enode.
276 Sum the length of the known-feasible path so far with
277 that of the remaining possibly-feasible path. */
279 int get_estimated_cost (const feasible_node *fnode) const
281 unsigned length_so_far = fnode->get_path_length ();
282 int shortest_remaining_path
283 = m_sep.get_shortest_distance (fnode->get_inner_node ());
285 gcc_assert (shortest_remaining_path >= 0);
286 /* This should be true since we're only exploring nodes within
287 the trimmed graph (and we anticipate it being much smaller
288 than this, and thus not overflowing the sum). */
289 gcc_assert (shortest_remaining_path < INT_MAX);
291 return length_so_far + shortest_remaining_path;
294 /* Priority queue, backed by a fibonacci_heap. */
295 typedef fibonacci_heap<key_t, feasible_node> queue_t;
296 queue_t m_queue;
297 const shortest_paths<eg_traits, exploded_path> &m_sep;
300 /* When we're building the exploded graph we want to simplify
301 overly-complicated symbolic values down to "UNKNOWN" to try to avoid
302 state explosions and unbounded chains of exploration.
304 However, when we're building the feasibility graph for a diagnostic
305 (actually a tree), we don't want UNKNOWN values, as conditions on them
306 are also unknown: we don't want to have a contradiction such as a path
307 where (VAL != 0) and then (VAL == 0) along the same path.
309 Hence this is an RAII class for temporarily disabling complexity-checking
310 in the region_model_manager, for use within
311 epath_finder::explore_feasible_paths.
313 We also disable the creation of unknown_svalue instances during feasibility
314 checking, instead creating unique svalues, to avoid paradoxes in paths. */
316 class auto_checking_feasibility
318 public:
319 auto_checking_feasibility (region_model_manager *mgr) : m_mgr (mgr)
321 m_mgr->begin_checking_feasibility ();
323 ~auto_checking_feasibility ()
325 m_mgr->end_checking_feasibility ();
327 private:
328 region_model_manager *m_mgr;
331 /* Attempt to find the shortest feasible path from the origin to
332 TARGET_ENODE by iteratively building a feasible_graph, in which
333 every path to a feasible_node is feasible by construction.
335 We effectively explore the tree of feasible paths in order of shortest
336 path until we either find a feasible path to TARGET_ENODE, or hit
337 a limit and give up.
339 Preliminaries:
340 - Find the shortest path from each node to the TARGET_ENODE (without
341 checking feasibility), so that we can prioritize our worklist.
342 - Construct a trimmed_graph: the subset of nodes/edges that
343 are on a path that eventually reaches TARGET_ENODE. We will only need
344 to consider these when considering the shortest feasible path.
346 Build a feasible_graph, in which every path to a feasible_node
347 is feasible by construction.
348 We use a worklist to flatten the exploration into an iteration.
349 Starting at the origin, find feasible out-edges within the trimmed graph.
350 At each stage, choose the node for which if the remaining path were feasible,
351 it would be the shortest path (summing the length of the known-feasible path
352 so far with that of the remaining possibly-feasible path).
353 This way, the first feasible path we find to TARGET_ENODE is the shortest.
354 We start by trying the shortest possible path, but if that fails,
355 we explore progressively longer paths, eventually trying iterations through
356 loops. The exploration is captured in the feasible_graph, which can be
357 dumped as a .dot file to visualize the exploration. The indices of the
358 feasible_nodes show the order in which they were created.
360 This is something of a brute-force approach, but the trimmed_graph
361 hopefully keeps the complexity manageable.
363 Terminate with failure when the number of infeasible edges exceeds
364 a threshold (--param=analyzer-max-infeasible-edges=).
365 This is guaranteed to eventually lead to terminatation, as
366 we can't keep creating feasible nodes without eventually
367 either reaching an infeasible edge, or reaching the
368 TARGET_ENODE. Specifically, there can't be a cycle of
369 feasible edges that doesn't reach the target_enode without
370 an out-edge that either fails feasibility or gets closer
371 to the TARGET_ENODE: on each iteration we are either:
372 - effectively getting closer to the TARGET_ENODE (which can't
373 continue forever without reaching the target), or
374 - getting monotonically closer to the termination threshold. */
376 exploded_path *
377 epath_finder::explore_feasible_paths (const exploded_node *target_enode,
378 const char *desc, unsigned diag_idx)
380 logger *logger = get_logger ();
381 LOG_SCOPE (logger);
383 region_model_manager *mgr = m_eg.get_engine ()->get_model_manager ();
385 /* Determine the shortest path to TARGET_ENODE from each node in
386 the exploded graph. */
387 shortest_paths<eg_traits, exploded_path> sep
388 (m_eg, target_enode, SPS_TO_GIVEN_TARGET);
390 /* Construct a trimmed_graph: the subset of nodes/edges that
391 are on a path that eventually reaches TARGET_ENODE.
392 We only need to consider these when considering the shortest
393 feasible path. */
394 trimmed_graph tg (m_eg, target_enode);
396 if (flag_dump_analyzer_feasibility)
397 dump_trimmed_graph (target_enode, desc, diag_idx, tg, sep);
399 feasible_graph fg;
400 feasible_worklist worklist (sep);
402 /* Populate the worklist with the origin node. */
404 feasibility_state init_state (mgr, m_eg.get_supergraph ());
405 feasible_node *origin = fg.add_node (m_eg.get_origin (), init_state, 0);
406 worklist.add_node (origin);
409 /* Iteratively explore the tree of feasible paths in order of shortest
410 path until we either find a feasible path to TARGET_ENODE, or hit
411 a limit. */
413 /* Set this if we find a feasible path to TARGET_ENODE. */
414 exploded_path *best_path = NULL;
417 auto_checking_feasibility sentinel (mgr);
419 while (process_worklist_item (&worklist, tg, &fg, target_enode, diag_idx,
420 &best_path))
422 /* Empty; the work is done within process_worklist_item. */
426 if (logger)
428 logger->log ("tg for sd: %i:", diag_idx);
429 logger->inc_indent ();
430 tg.log_stats (logger);
431 logger->dec_indent ();
433 logger->log ("fg for sd: %i:", diag_idx);
434 logger->inc_indent ();
435 fg.log_stats (logger);
436 logger->dec_indent ();
439 /* Dump the feasible_graph. */
440 if (flag_dump_analyzer_feasibility)
441 dump_feasible_graph (target_enode, desc, diag_idx, fg);
443 return best_path;
446 /* Process the next item in WORKLIST, potentially adding new items
447 based on feasible out-edges, and extending FG accordingly.
448 Use TG to ignore out-edges that don't lead to TARGET_ENODE.
449 Return true if the worklist processing should continue.
450 Return false if the processing of the worklist should stop
451 (either due to reaching TARGET_ENODE, or hitting a limit).
452 Write to *OUT_BEST_PATH if stopping due to finding a feasible path
453 to TARGET_ENODE. */
455 bool
456 epath_finder::process_worklist_item (feasible_worklist *worklist,
457 const trimmed_graph &tg,
458 feasible_graph *fg,
459 const exploded_node *target_enode,
460 unsigned diag_idx,
461 exploded_path **out_best_path) const
463 logger *logger = get_logger ();
465 feasible_node *fnode = worklist->take_next ();
466 if (!fnode)
468 if (logger)
469 logger->log ("drained worklist for sd: %i"
470 " without finding feasible path",
471 diag_idx);
472 return false;
475 log_scope s (logger, "fg worklist item",
476 "considering FN: %i (EN: %i) for sd: %i",
477 fnode->get_index (), fnode->get_inner_node ()->m_index,
478 diag_idx);
480 /* Iterate through all out-edges from this item. */
481 unsigned i;
482 exploded_edge *succ_eedge;
483 FOR_EACH_VEC_ELT (fnode->get_inner_node ()->m_succs, i, succ_eedge)
485 log_scope s (logger, "edge", "considering edge: EN:%i -> EN:%i",
486 succ_eedge->m_src->m_index,
487 succ_eedge->m_dest->m_index);
488 /* Reject edges that aren't in the trimmed graph. */
489 if (!tg.contains_p (succ_eedge))
491 if (logger)
492 logger->log ("rejecting: not in trimmed graph");
493 continue;
496 feasibility_state succ_state (fnode->get_state ());
497 rejected_constraint *rc = NULL;
498 if (succ_state.maybe_update_for_edge (logger, succ_eedge, &rc))
500 gcc_assert (rc == NULL);
501 feasible_node *succ_fnode
502 = fg->add_node (succ_eedge->m_dest,
503 succ_state,
504 fnode->get_path_length () + 1);
505 if (logger)
506 logger->log ("accepting as FN: %i", succ_fnode->get_index ());
507 fg->add_edge (new feasible_edge (fnode, succ_fnode, succ_eedge));
509 /* Have we reached TARGET_ENODE? */
510 if (succ_fnode->get_inner_node () == target_enode)
512 if (logger)
513 logger->log ("success: got feasible path to EN: %i (sd: %i)"
514 " (length: %i)",
515 target_enode->m_index, diag_idx,
516 succ_fnode->get_path_length ());
517 *out_best_path = fg->make_epath (succ_fnode);
518 if (flag_dump_analyzer_feasibility)
519 dump_feasible_path (target_enode, diag_idx, *fg, *succ_fnode);
521 /* Success: stop the worklist iteration. */
522 return false;
524 else
525 worklist->add_node (succ_fnode);
527 else
529 if (logger)
530 logger->log ("infeasible");
531 gcc_assert (rc);
532 fg->add_feasibility_problem (fnode,
533 succ_eedge,
534 rc);
536 /* Give up if there have been too many infeasible edges. */
537 if (fg->get_num_infeasible ()
538 > (unsigned)param_analyzer_max_infeasible_edges)
540 if (logger)
541 logger->log ("too many infeasible edges (%i); giving up",
542 fg->get_num_infeasible ());
543 return false;
548 /* Continue the worklist iteration. */
549 return true;
552 /* Helper class for epath_finder::dump_trimmed_graph
553 to dump extra per-node information.
554 Use SEP to add the length of the shortest path from each
555 node to the target node to each node's dump. */
557 class dump_eg_with_shortest_path : public eg_traits::dump_args_t
559 public:
560 dump_eg_with_shortest_path
561 (const exploded_graph &eg,
562 const shortest_paths<eg_traits, exploded_path> &sep)
563 : dump_args_t (eg),
564 m_sep (sep)
568 void dump_extra_info (const exploded_node *enode,
569 pretty_printer *pp) const final override
571 pp_printf (pp, "sp: %i", m_sep.get_shortest_path (enode).length ());
572 pp_newline (pp);
575 private:
576 const shortest_paths<eg_traits, exploded_path> &m_sep;
579 /* Dump TG to "BASE_NAME.DESC.DIAG_IDX.to-enN.tg.dot",
580 annotating each node with the length of the shortest path
581 from that node to TARGET_ENODE (using SEP). */
583 void
584 epath_finder::
585 dump_trimmed_graph (const exploded_node *target_enode,
586 const char *desc, unsigned diag_idx,
587 const trimmed_graph &tg,
588 const shortest_paths<eg_traits, exploded_path> &sep)
590 auto_timevar tv (TV_ANALYZER_DUMP);
591 dump_eg_with_shortest_path inner_args (m_eg, sep);
592 trimmed_graph::dump_args_t args (inner_args);
593 pretty_printer pp;
594 pp_printf (&pp, "%s.%s.%i.to-en%i.tg.dot",
595 dump_base_name, desc, diag_idx, target_enode->m_index);
596 char *filename = xstrdup (pp_formatted_text (&pp));
597 tg.dump_dot (filename, NULL, args);
598 free (filename);
601 /* Dump FG to "BASE_NAME.DESC.DIAG_IDX.to-enN.fg.dot". */
603 void
604 epath_finder::dump_feasible_graph (const exploded_node *target_enode,
605 const char *desc, unsigned diag_idx,
606 const feasible_graph &fg)
608 auto_timevar tv (TV_ANALYZER_DUMP);
609 exploded_graph::dump_args_t inner_args (m_eg);
610 feasible_graph::dump_args_t args (inner_args);
611 pretty_printer pp;
612 pp_printf (&pp, "%s.%s.%i.to-en%i.fg.dot",
613 dump_base_name, desc, diag_idx, target_enode->m_index);
614 char *filename = xstrdup (pp_formatted_text (&pp));
615 fg.dump_dot (filename, NULL, args);
616 free (filename);
619 /* Dump the path to FNODE to "BASE_NAME.DIAG_IDX.to-enN.fpath.txt". */
621 void
622 epath_finder::dump_feasible_path (const exploded_node *target_enode,
623 unsigned diag_idx,
624 const feasible_graph &fg,
625 const feasible_node &fnode) const
627 auto_timevar tv (TV_ANALYZER_DUMP);
628 pretty_printer pp;
629 pp_printf (&pp, "%s.%i.to-en%i.fpath.txt",
630 dump_base_name, diag_idx, target_enode->m_index);
631 char *filename = xstrdup (pp_formatted_text (&pp));
632 fg.dump_feasible_path (fnode, filename);
633 free (filename);
636 /* class saved_diagnostic. */
638 /* saved_diagnostic's ctor.
639 Take ownership of D and STMT_FINDER. */
641 saved_diagnostic::saved_diagnostic (const state_machine *sm,
642 const exploded_node *enode,
643 const supernode *snode, const gimple *stmt,
644 stmt_finder *stmt_finder,
645 tree var,
646 const svalue *sval,
647 state_machine::state_t state,
648 pending_diagnostic *d,
649 unsigned idx)
650 : m_sm (sm), m_enode (enode), m_snode (snode), m_stmt (stmt),
651 /* stmt_finder could be on-stack; we want our own copy that can
652 outlive that. */
653 m_stmt_finder (stmt_finder ? stmt_finder->clone () : NULL),
654 m_var (var), m_sval (sval), m_state (state),
655 m_d (d), m_trailing_eedge (NULL),
656 m_idx (idx),
657 m_best_epath (NULL), m_problem (NULL),
658 m_notes ()
660 gcc_assert (m_stmt || m_stmt_finder);
662 /* We must have an enode in order to be able to look for paths
663 through the exploded_graph to this diagnostic. */
664 gcc_assert (m_enode);
667 /* saved_diagnostic's dtor. */
669 saved_diagnostic::~saved_diagnostic ()
671 delete m_stmt_finder;
672 delete m_d;
673 delete m_best_epath;
674 delete m_problem;
677 bool
678 saved_diagnostic::operator== (const saved_diagnostic &other) const
680 if (m_notes.length () != other.m_notes.length ())
681 return false;
682 for (unsigned i = 0; i < m_notes.length (); i++)
683 if (!m_notes[i]->equal_p (*other.m_notes[i]))
684 return false;
685 return (m_sm == other.m_sm
686 /* We don't compare m_enode. */
687 && m_snode == other.m_snode
688 && m_stmt == other.m_stmt
689 /* We don't compare m_stmt_finder. */
690 && pending_diagnostic::same_tree_p (m_var, other.m_var)
691 && m_state == other.m_state
692 && m_d->equal_p (*other.m_d)
693 && m_trailing_eedge == other.m_trailing_eedge);
696 /* Add PN to this diagnostic, taking ownership of it. */
698 void
699 saved_diagnostic::add_note (pending_note *pn)
701 gcc_assert (pn);
702 m_notes.safe_push (pn);
705 /* Return a new json::object of the form
706 {"sm": optional str,
707 "enode": int,
708 "snode": int,
709 "sval": optional str,
710 "state": optional str,
711 "path_length": optional int,
712 "pending_diagnostic": str,
713 "idx": int}. */
715 json::object *
716 saved_diagnostic::to_json () const
718 json::object *sd_obj = new json::object ();
720 if (m_sm)
721 sd_obj->set ("sm", new json::string (m_sm->get_name ()));
722 sd_obj->set ("enode", new json::integer_number (m_enode->m_index));
723 sd_obj->set ("snode", new json::integer_number (m_snode->m_index));
724 if (m_sval)
725 sd_obj->set ("sval", m_sval->to_json ());
726 if (m_state)
727 sd_obj->set ("state", m_state->to_json ());
728 if (m_best_epath)
729 sd_obj->set ("path_length", new json::integer_number (get_epath_length ()));
730 sd_obj->set ("pending_diagnostic", new json::string (m_d->get_kind ()));
731 sd_obj->set ("idx", new json::integer_number (m_idx));
733 /* We're not yet JSONifying the following fields:
734 const gimple *m_stmt;
735 stmt_finder *m_stmt_finder;
736 tree m_var;
737 exploded_edge *m_trailing_eedge;
738 enum status m_status;
739 feasibility_problem *m_problem;
740 auto_delete_vec <pending_note> m_notes;
743 return sd_obj;
746 /* Dump this to PP in a form suitable for use as an id in .dot output. */
748 void
749 saved_diagnostic::dump_dot_id (pretty_printer *pp) const
751 pp_printf (pp, "sd_%i", m_idx);
754 /* Dump this to PP in a form suitable for use as a node in .dot output. */
756 void
757 saved_diagnostic::dump_as_dot_node (pretty_printer *pp) const
759 dump_dot_id (pp);
760 pp_printf (pp,
761 " [shape=none,margin=0,style=filled,fillcolor=\"red\",label=\"");
762 pp_write_text_to_stream (pp);
764 /* Node label. */
765 pp_printf (pp, "DIAGNOSTIC: %s (sd: %i)\n",
766 m_d->get_kind (), m_idx);
767 if (m_sm)
769 pp_printf (pp, "sm: %s", m_sm->get_name ());
770 if (m_state)
772 pp_printf (pp, "; state: ");
773 m_state->dump_to_pp (pp);
775 pp_newline (pp);
777 if (m_stmt)
779 pp_string (pp, "stmt: ");
780 pp_gimple_stmt_1 (pp, m_stmt, 0, (dump_flags_t)0);
781 pp_newline (pp);
783 if (m_var)
784 pp_printf (pp, "var: %qE\n", m_var);
785 if (m_sval)
787 pp_string (pp, "sval: ");
788 m_sval->dump_to_pp (pp, true);
789 pp_newline (pp);
791 if (m_best_epath)
792 pp_printf (pp, "path length: %i\n", get_epath_length ());
794 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
795 pp_string (pp, "\"];\n\n");
797 /* Show links to duplicates. */
798 for (auto iter : m_duplicates)
800 dump_dot_id (pp);
801 pp_string (pp, " -> ");
802 iter->dump_dot_id (pp);
803 pp_string (pp, " [style=\"dotted\" arrowhead=\"none\"];");
804 pp_newline (pp);
808 /* Use PF to find the best exploded_path for this saved_diagnostic,
809 and store it in m_best_epath.
810 If m_stmt is still NULL, use m_stmt_finder on the epath to populate
811 m_stmt.
812 Return true if a best path was found. */
814 bool
815 saved_diagnostic::calc_best_epath (epath_finder *pf)
817 logger *logger = pf->get_logger ();
818 LOG_SCOPE (logger);
819 delete m_best_epath;
820 delete m_problem;
821 m_problem = NULL;
823 m_best_epath = pf->get_best_epath (m_enode, m_d->get_kind (), m_idx,
824 &m_problem);
826 /* Handle failure to find a feasible path. */
827 if (m_best_epath == NULL)
828 return false;
830 gcc_assert (m_best_epath);
831 if (m_stmt == NULL)
833 gcc_assert (m_stmt_finder);
834 m_stmt = m_stmt_finder->find_stmt (*m_best_epath);
836 gcc_assert (m_stmt);
838 return true;
841 unsigned
842 saved_diagnostic::get_epath_length () const
844 gcc_assert (m_best_epath);
845 return m_best_epath->length ();
848 /* Record that OTHER (and its duplicates) are duplicates
849 of this saved_diagnostic. */
851 void
852 saved_diagnostic::add_duplicate (saved_diagnostic *other)
854 gcc_assert (other);
855 m_duplicates.reserve (m_duplicates.length ()
856 + other->m_duplicates.length ()
857 + 1);
858 m_duplicates.splice (other->m_duplicates);
859 other->m_duplicates.truncate (0);
860 m_duplicates.safe_push (other);
863 /* Return true if this diagnostic supercedes OTHER, and that OTHER should
864 therefore not be emitted. */
866 bool
867 saved_diagnostic::supercedes_p (const saved_diagnostic &other) const
869 /* They should be at the same stmt. */
870 if (m_stmt != other.m_stmt)
871 return false;
872 return m_d->supercedes_p (*other.m_d);
875 /* Emit any pending notes owned by this diagnostic. */
877 void
878 saved_diagnostic::emit_any_notes () const
880 for (auto pn : m_notes)
881 pn->emit ();
884 /* State for building a checker_path from a particular exploded_path.
885 In particular, this precomputes reachability information: the set of
886 source enodes for which a path be found to the diagnostic enode. */
888 class path_builder
890 public:
891 path_builder (const exploded_graph &eg,
892 const exploded_path &epath,
893 const feasibility_problem *problem,
894 const saved_diagnostic &sd)
895 : m_eg (eg),
896 m_diag_enode (epath.get_final_enode ()),
897 m_sd (sd),
898 m_reachability (eg, m_diag_enode),
899 m_feasibility_problem (problem)
902 const exploded_node *get_diag_node () const { return m_diag_enode; }
904 pending_diagnostic *get_pending_diagnostic () const
906 return m_sd.m_d;
909 bool reachable_from_p (const exploded_node *src_enode) const
911 return m_reachability.reachable_from_p (src_enode);
914 const extrinsic_state &get_ext_state () const { return m_eg.get_ext_state (); }
916 const feasibility_problem *get_feasibility_problem () const
918 return m_feasibility_problem;
921 const state_machine *get_sm () const { return m_sd.m_sm; }
923 private:
924 typedef reachability<eg_traits> enode_reachability;
926 const exploded_graph &m_eg;
928 /* The enode where the diagnostic occurs. */
929 const exploded_node *m_diag_enode;
931 const saved_diagnostic &m_sd;
933 /* Precompute all enodes from which the diagnostic is reachable. */
934 enode_reachability m_reachability;
936 const feasibility_problem *m_feasibility_problem;
939 /* Determine the emission location for PD at STMT in FUN. */
941 static location_t
942 get_emission_location (const gimple *stmt, function *fun,
943 const pending_diagnostic &pd)
945 location_t loc = get_stmt_location (stmt, fun);
947 /* Allow the pending_diagnostic to fix up the location. */
948 loc = pd.fixup_location (loc);
950 return loc;
953 /* class diagnostic_manager. */
955 /* diagnostic_manager's ctor. */
957 diagnostic_manager::diagnostic_manager (logger *logger, engine *eng,
958 int verbosity)
959 : log_user (logger), m_eng (eng), m_verbosity (verbosity),
960 m_num_disabled_diagnostics (0)
964 /* Queue pending_diagnostic D at ENODE for later emission.
965 Return true/false signifying if the diagnostic was actually added.
966 Take ownership of D (or delete it). */
968 bool
969 diagnostic_manager::add_diagnostic (const state_machine *sm,
970 exploded_node *enode,
971 const supernode *snode, const gimple *stmt,
972 stmt_finder *finder,
973 tree var,
974 const svalue *sval,
975 state_machine::state_t state,
976 pending_diagnostic *d)
978 LOG_FUNC (get_logger ());
980 /* We must have an enode in order to be able to look for paths
981 through the exploded_graph to the diagnostic. */
982 gcc_assert (enode);
984 /* If this warning is ultimately going to be rejected by a -Wno-analyzer-*
985 flag, reject it now.
986 We can only do this for diagnostics where we already know the stmt,
987 and thus can determine the emission location. */
988 if (stmt)
990 location_t loc = get_emission_location (stmt, snode->m_fun, *d);
991 int option = d->get_controlling_option ();
992 if (!warning_enabled_at (loc, option))
994 if (get_logger ())
995 get_logger ()->log ("rejecting disabled warning %qs",
996 d->get_kind ());
997 delete d;
998 m_num_disabled_diagnostics++;
999 return false;
1003 saved_diagnostic *sd
1004 = new saved_diagnostic (sm, enode, snode, stmt, finder, var, sval,
1005 state, d, m_saved_diagnostics.length ());
1006 m_saved_diagnostics.safe_push (sd);
1007 enode->add_diagnostic (sd);
1008 if (get_logger ())
1009 log ("adding saved diagnostic %i at SN %i to EN %i: %qs",
1010 sd->get_index (),
1011 snode->m_index, enode->m_index, d->get_kind ());
1012 return true;
1015 /* Queue pending_diagnostic D at ENODE for later emission.
1016 Return true/false signifying if the diagnostic was actually added.
1017 Take ownership of D (or delete it). */
1019 bool
1020 diagnostic_manager::add_diagnostic (exploded_node *enode,
1021 const supernode *snode, const gimple *stmt,
1022 stmt_finder *finder,
1023 pending_diagnostic *d)
1025 gcc_assert (enode);
1026 return add_diagnostic (NULL, enode, snode, stmt, finder, NULL_TREE,
1027 NULL, 0, d);
1030 /* Add PN to the most recent saved_diagnostic. */
1032 void
1033 diagnostic_manager::add_note (pending_note *pn)
1035 LOG_FUNC (get_logger ());
1036 gcc_assert (pn);
1038 /* Get most recent saved_diagnostic. */
1039 gcc_assert (m_saved_diagnostics.length () > 0);
1040 saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1];
1041 sd->add_note (pn);
1044 /* Return a new json::object of the form
1045 {"diagnostics" : [obj for saved_diagnostic]}. */
1047 json::object *
1048 diagnostic_manager::to_json () const
1050 json::object *dm_obj = new json::object ();
1053 json::array *sd_arr = new json::array ();
1054 int i;
1055 saved_diagnostic *sd;
1056 FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1057 sd_arr->append (sd->to_json ());
1058 dm_obj->set ("diagnostics", sd_arr);
1061 return dm_obj;
1064 /* A class for identifying sets of duplicated pending_diagnostic.
1066 We want to find the simplest saved_diagnostic amongst those that share a
1067 dedupe_key. */
1069 class dedupe_key
1071 public:
1072 dedupe_key (const saved_diagnostic &sd)
1073 : m_sd (sd), m_stmt (sd.m_stmt)
1075 gcc_assert (m_stmt);
1078 hashval_t hash () const
1080 inchash::hash hstate;
1081 hstate.add_ptr (m_stmt);
1082 // TODO: m_sd
1083 return hstate.end ();
1085 bool operator== (const dedupe_key &other) const
1087 return (m_sd == other.m_sd
1088 && m_stmt == other.m_stmt);
1091 location_t get_location () const
1093 return m_stmt->location;
1096 /* A qsort comparator for use by dedupe_winners::emit_best
1097 to sort them into location_t order. */
1099 static int
1100 comparator (const void *p1, const void *p2)
1102 const dedupe_key *pk1 = *(const dedupe_key * const *)p1;
1103 const dedupe_key *pk2 = *(const dedupe_key * const *)p2;
1105 location_t loc1 = pk1->get_location ();
1106 location_t loc2 = pk2->get_location ();
1108 if (int cmp = linemap_compare_locations (line_table, loc2, loc1))
1109 return cmp;
1110 if (int cmp = ((int)pk1->m_sd.get_epath_length ()
1111 - (int)pk2->m_sd.get_epath_length ()))
1112 return cmp;
1113 if (int cmp = strcmp (pk1->m_sd.m_d->get_kind (),
1114 pk2->m_sd.m_d->get_kind ()))
1115 return cmp;
1116 return 0;
1119 const saved_diagnostic &m_sd;
1120 const gimple *m_stmt;
1123 /* Traits for use by dedupe_winners. */
1125 class dedupe_hash_map_traits
1127 public:
1128 typedef const dedupe_key *key_type;
1129 typedef saved_diagnostic *value_type;
1130 typedef saved_diagnostic *compare_type;
1132 static inline hashval_t hash (const key_type &v)
1134 return v->hash ();
1136 static inline bool equal_keys (const key_type &k1, const key_type &k2)
1138 return *k1 == *k2;
1140 template <typename T>
1141 static inline void remove (T &)
1143 // TODO
1145 template <typename T>
1146 static inline void mark_deleted (T &entry)
1148 entry.m_key = reinterpret_cast<key_type> (1);
1150 template <typename T>
1151 static inline void mark_empty (T &entry)
1153 entry.m_key = NULL;
1155 template <typename T>
1156 static inline bool is_deleted (const T &entry)
1158 return entry.m_key == reinterpret_cast<key_type> (1);
1160 template <typename T>
1161 static inline bool is_empty (const T &entry)
1163 return entry.m_key == NULL;
1165 static const bool empty_zero_p = true;
1168 /* A class for deduplicating diagnostics and finding (and emitting) the
1169 best saved_diagnostic within each partition. */
1171 class dedupe_winners
1173 public:
1174 ~dedupe_winners ()
1176 /* Delete all keys, but not the saved_diagnostics. */
1177 for (map_t::iterator iter = m_map.begin ();
1178 iter != m_map.end ();
1179 ++iter)
1180 delete (*iter).first;
1183 /* Determine an exploded_path for SD using PF and, if it's feasible,
1184 determine if SD is the best seen so far for its dedupe_key.
1185 Record the winning SD for each dedupe_key. */
1187 void add (logger *logger,
1188 epath_finder *pf,
1189 saved_diagnostic *sd)
1191 /* Determine best epath for SD. */
1192 if (!sd->calc_best_epath (pf))
1193 return;
1195 dedupe_key *key = new dedupe_key (*sd);
1196 if (saved_diagnostic **slot = m_map.get (key))
1198 if (logger)
1199 logger->log ("already have this dedupe_key");
1201 saved_diagnostic *cur_best_sd = *slot;
1203 if (sd->get_epath_length () < cur_best_sd->get_epath_length ())
1205 /* We've got a shorter path for the key; replace
1206 the current candidate, marking it as a duplicate of SD. */
1207 if (logger)
1208 logger->log ("length %i is better than existing length %i;"
1209 " taking over this dedupe_key",
1210 sd->get_epath_length (),
1211 cur_best_sd->get_epath_length ());
1212 sd->add_duplicate (cur_best_sd);
1213 *slot = sd;
1215 else
1216 /* We haven't beaten the current best candidate; add SD
1217 as a duplicate of it. */
1219 if (logger)
1220 logger->log ("length %i isn't better than existing length %i;"
1221 " dropping this candidate",
1222 sd->get_epath_length (),
1223 cur_best_sd->get_epath_length ());
1224 cur_best_sd->add_duplicate (sd);
1226 delete key;
1228 else
1230 /* This is the first candidate for this key. */
1231 m_map.put (key, sd);
1232 if (logger)
1233 logger->log ("first candidate for this dedupe_key");
1237 /* Handle interactions between the dedupe winners, so that some
1238 diagnostics can supercede others (of different kinds).
1240 We want use-after-free to supercede use-of-unitialized-value,
1241 so that if we have these at the same stmt, we don't emit
1242 a use-of-uninitialized, just the use-after-free. */
1244 void handle_interactions (diagnostic_manager *dm)
1246 LOG_SCOPE (dm->get_logger ());
1247 auto_vec<const dedupe_key *> superceded;
1248 for (auto outer : m_map)
1250 const saved_diagnostic *outer_sd = outer.second;
1251 for (auto inner : m_map)
1253 const saved_diagnostic *inner_sd = inner.second;
1254 if (inner_sd->supercedes_p (*outer_sd))
1256 superceded.safe_push (outer.first);
1257 if (dm->get_logger ())
1258 dm->log ("sd[%i] \"%s\" superceded by sd[%i] \"%s\"",
1259 outer_sd->get_index (), outer_sd->m_d->get_kind (),
1260 inner_sd->get_index (), inner_sd->m_d->get_kind ());
1261 break;
1265 for (auto iter : superceded)
1266 m_map.remove (iter);
1269 /* Emit the simplest diagnostic within each set. */
1271 void emit_best (diagnostic_manager *dm,
1272 const exploded_graph &eg)
1274 LOG_SCOPE (dm->get_logger ());
1276 /* Get keys into a vec for sorting. */
1277 auto_vec<const dedupe_key *> keys (m_map.elements ());
1278 for (map_t::iterator iter = m_map.begin ();
1279 iter != m_map.end ();
1280 ++iter)
1281 keys.quick_push ((*iter).first);
1283 dm->log ("# keys after de-duplication: %i", keys.length ());
1285 /* Sort into a good emission order. */
1286 keys.qsort (dedupe_key::comparator);
1288 /* Emit the best saved_diagnostics for each key. */
1289 int i;
1290 const dedupe_key *key;
1291 FOR_EACH_VEC_ELT (keys, i, key)
1293 saved_diagnostic **slot = m_map.get (key);
1294 gcc_assert (*slot);
1295 const saved_diagnostic *sd = *slot;
1296 dm->emit_saved_diagnostic (eg, *sd);
1300 private:
1301 /* This maps from each dedupe_key to a current best saved_diagnostic. */
1303 typedef hash_map<const dedupe_key *, saved_diagnostic *,
1304 dedupe_hash_map_traits> map_t;
1305 map_t m_map;
1308 /* Emit all saved diagnostics. */
1310 void
1311 diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
1313 LOG_SCOPE (get_logger ());
1314 auto_timevar tv (TV_ANALYZER_DIAGNOSTICS);
1315 log ("# saved diagnostics: %i", m_saved_diagnostics.length ());
1316 log ("# disabled diagnostics: %i", m_num_disabled_diagnostics);
1317 if (get_logger ())
1319 unsigned i;
1320 saved_diagnostic *sd;
1321 FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1322 log ("[%i] sd: %qs at EN: %i, SN: %i",
1323 i, sd->m_d->get_kind (), sd->m_enode->m_index,
1324 sd->m_snode->m_index);
1327 if (m_saved_diagnostics.length () == 0)
1328 return;
1330 /* Compute the shortest_paths once, sharing it between all diagnostics. */
1331 epath_finder pf (eg);
1333 /* Iterate through all saved diagnostics, adding them to a dedupe_winners
1334 instance. This partitions the saved diagnostics by dedupe_key,
1335 generating exploded_paths for them, and retaining the best one in each
1336 partition. */
1337 dedupe_winners best_candidates;
1339 int i;
1340 saved_diagnostic *sd;
1341 FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1342 best_candidates.add (get_logger (), &pf, sd);
1344 best_candidates.handle_interactions (this);
1346 /* For each dedupe-key, call emit_saved_diagnostic on the "best"
1347 saved_diagnostic. */
1348 best_candidates.emit_best (this, eg);
1351 /* Given a saved_diagnostic SD with m_best_epath through EG,
1352 create an checker_path of suitable events and use it to call
1353 SD's underlying pending_diagnostic "emit" vfunc to emit a diagnostic. */
1355 void
1356 diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
1357 const saved_diagnostic &sd)
1359 LOG_SCOPE (get_logger ());
1360 log ("sd: %qs at SN: %i", sd.m_d->get_kind (), sd.m_snode->m_index);
1361 log ("num dupes: %i", sd.get_num_dupes ());
1363 pretty_printer *pp = global_dc->printer->clone ();
1365 const exploded_path *epath = sd.get_best_epath ();
1366 gcc_assert (epath);
1368 /* Precompute all enodes from which the diagnostic is reachable. */
1369 path_builder pb (eg, *epath, sd.get_feasibility_problem (), sd);
1371 /* This is the diagnostic_path subclass that will be built for
1372 the diagnostic. */
1373 checker_path emission_path;
1375 /* Populate emission_path with a full description of EPATH. */
1376 build_emission_path (pb, *epath, &emission_path);
1378 /* Now prune it to just cover the most pertinent events. */
1379 prune_path (&emission_path, sd.m_sm, sd.m_sval, sd.m_state);
1381 /* Add a final event to the path, covering the diagnostic itself.
1382 We use the final enode from the epath, which might be different from
1383 the sd.m_enode, as the dedupe code doesn't care about enodes, just
1384 snodes. */
1385 emission_path.add_final_event (sd.m_sm, epath->get_final_enode (), sd.m_stmt,
1386 sd.m_var, sd.m_state);
1388 /* The "final" event might not be final; if the saved_diagnostic has a
1389 trailing eedge stashed, add any events for it. This is for use
1390 in handling longjmp, to show where a longjmp is rewinding to. */
1391 if (sd.m_trailing_eedge)
1392 add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path, NULL);
1394 emission_path.inject_any_inlined_call_events (get_logger ());
1396 emission_path.prepare_for_emission (sd.m_d);
1398 location_t loc
1399 = get_emission_location (sd.m_stmt, sd.m_snode->m_fun, *sd.m_d);
1401 /* Allow the pending_diagnostic to fix up the locations of events. */
1402 emission_path.fixup_locations (sd.m_d);
1404 gcc_rich_location rich_loc (loc);
1405 rich_loc.set_path (&emission_path);
1407 auto_diagnostic_group d;
1408 auto_cfun sentinel (sd.m_snode->m_fun);
1409 if (sd.m_d->emit (&rich_loc))
1411 sd.emit_any_notes ();
1413 unsigned num_dupes = sd.get_num_dupes ();
1414 if (flag_analyzer_show_duplicate_count && num_dupes > 0)
1415 inform_n (loc, num_dupes,
1416 "%i duplicate", "%i duplicates",
1417 num_dupes);
1418 if (flag_dump_analyzer_exploded_paths)
1420 auto_timevar tv (TV_ANALYZER_DUMP);
1421 pretty_printer pp;
1422 pp_printf (&pp, "%s.%i.%s.epath.txt",
1423 dump_base_name, sd.get_index (), sd.m_d->get_kind ());
1424 char *filename = xstrdup (pp_formatted_text (&pp));
1425 epath->dump_to_file (filename, eg.get_ext_state ());
1426 inform (loc, "exploded path written to %qs", filename);
1427 free (filename);
1430 delete pp;
1433 /* Emit a "path" of events to EMISSION_PATH describing the exploded path
1434 EPATH within EG. */
1436 void
1437 diagnostic_manager::build_emission_path (const path_builder &pb,
1438 const exploded_path &epath,
1439 checker_path *emission_path) const
1441 LOG_SCOPE (get_logger ());
1443 interesting_t interest;
1444 pb.get_pending_diagnostic ()->mark_interesting_stuff (&interest);
1446 /* Add region creation events for any globals of interest, at the
1447 beginning of the path. */
1449 for (auto reg : interest.m_region_creation)
1450 switch (reg->get_memory_space ())
1452 default:
1453 continue;
1454 case MEMSPACE_CODE:
1455 case MEMSPACE_GLOBALS:
1456 case MEMSPACE_READONLY_DATA:
1458 const region *base_reg = reg->get_base_region ();
1459 if (tree decl = base_reg->maybe_get_decl ())
1460 if (DECL_P (decl)
1461 && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
1463 emission_path->add_region_creation_event
1464 (reg,
1465 DECL_SOURCE_LOCATION (decl),
1466 NULL_TREE,
1473 /* Walk EPATH, adding events as appropriate. */
1474 for (unsigned i = 0; i < epath.m_edges.length (); i++)
1476 const exploded_edge *eedge = epath.m_edges[i];
1477 add_events_for_eedge (pb, *eedge, emission_path, &interest);
1479 add_event_on_final_node (epath.get_final_enode (), emission_path, &interest);
1482 /* Emit a region_creation_event when requested on the last statement in
1483 the path.
1485 If a region_creation_event should be emitted on the last statement of the
1486 path, we need to peek to the successors to get whether the final enode
1487 created a region.
1490 void
1491 diagnostic_manager::add_event_on_final_node (const exploded_node *final_enode,
1492 checker_path *emission_path,
1493 interesting_t *interest) const
1495 const program_point &src_point = final_enode->get_point ();
1496 const int src_stack_depth = src_point.get_stack_depth ();
1497 const program_state &src_state = final_enode->get_state ();
1498 const region_model *src_model = src_state.m_region_model;
1500 unsigned j;
1501 exploded_edge *e;
1502 FOR_EACH_VEC_ELT (final_enode->m_succs, j, e)
1504 exploded_node *dst = e->m_dest;
1505 const program_state &dst_state = dst->get_state ();
1506 const region_model *dst_model = dst_state.m_region_model;
1507 if (src_model->get_dynamic_extents ()
1508 != dst_model->get_dynamic_extents ())
1510 unsigned i;
1511 const region *reg;
1512 bool emitted = false;
1513 FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
1515 const region *base_reg = reg->get_base_region ();
1516 const svalue *old_extents
1517 = src_model->get_dynamic_extents (base_reg);
1518 const svalue *new_extents
1519 = dst_model->get_dynamic_extents (base_reg);
1520 if (old_extents == NULL && new_extents != NULL)
1521 switch (base_reg->get_kind ())
1523 default:
1524 break;
1525 case RK_HEAP_ALLOCATED:
1526 case RK_ALLOCA:
1527 emission_path->add_region_creation_event
1528 (reg,
1529 src_point.get_location (),
1530 src_point.get_fndecl (),
1531 src_stack_depth);
1532 emitted = true;
1533 break;
1536 if (emitted)
1537 break;
1542 /* Subclass of state_change_visitor that creates state_change_event
1543 instances. */
1545 class state_change_event_creator : public state_change_visitor
1547 public:
1548 state_change_event_creator (const path_builder &pb,
1549 const exploded_edge &eedge,
1550 checker_path *emission_path)
1551 : m_pb (pb),
1552 m_eedge (eedge),
1553 m_emission_path (emission_path)
1556 bool on_global_state_change (const state_machine &sm,
1557 state_machine::state_t src_sm_val,
1558 state_machine::state_t dst_sm_val)
1559 final override
1561 if (&sm != m_pb.get_sm ())
1562 return false;
1563 const exploded_node *src_node = m_eedge.m_src;
1564 const program_point &src_point = src_node->get_point ();
1565 const int src_stack_depth = src_point.get_stack_depth ();
1566 const exploded_node *dst_node = m_eedge.m_dest;
1567 const gimple *stmt = src_point.get_stmt ();
1568 const supernode *supernode = src_point.get_supernode ();
1569 const program_state &dst_state = dst_node->get_state ();
1571 int stack_depth = src_stack_depth;
1573 m_emission_path->add_event (new state_change_event (supernode,
1574 stmt,
1575 stack_depth,
1577 NULL,
1578 src_sm_val,
1579 dst_sm_val,
1580 NULL,
1581 dst_state));
1582 return false;
1585 bool on_state_change (const state_machine &sm,
1586 state_machine::state_t src_sm_val,
1587 state_machine::state_t dst_sm_val,
1588 const svalue *sval,
1589 const svalue *dst_origin_sval) final override
1591 if (&sm != m_pb.get_sm ())
1592 return false;
1593 const exploded_node *src_node = m_eedge.m_src;
1594 const program_point &src_point = src_node->get_point ();
1595 const int src_stack_depth = src_point.get_stack_depth ();
1596 const exploded_node *dst_node = m_eedge.m_dest;
1597 const gimple *stmt = src_point.get_stmt ();
1598 const supernode *supernode = src_point.get_supernode ();
1599 const program_state &dst_state = dst_node->get_state ();
1601 int stack_depth = src_stack_depth;
1603 if (m_eedge.m_sedge
1604 && m_eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE)
1606 supernode = src_point.get_supernode ();
1607 stmt = supernode->get_last_stmt ();
1608 stack_depth = src_stack_depth;
1611 /* Bulletproofing for state changes at calls/returns;
1612 TODO: is there a better way? */
1613 if (!stmt)
1614 return false;
1616 m_emission_path->add_event (new state_change_event (supernode,
1617 stmt,
1618 stack_depth,
1620 sval,
1621 src_sm_val,
1622 dst_sm_val,
1623 dst_origin_sval,
1624 dst_state));
1625 return false;
1628 const path_builder &m_pb;
1629 const exploded_edge &m_eedge;
1630 checker_path *m_emission_path;
1633 /* Compare SRC_STATE and DST_STATE (which use EXT_STATE), and call
1634 VISITOR's on_state_change for every sm-state change that occurs
1635 to a tree, and on_global_state_change for every global state change
1636 that occurs.
1638 This determines the state changes that ought to be reported to
1639 the user: a combination of the effects of changes to sm_state_map
1640 (which maps svalues to sm-states), and of region_model changes
1641 (which map trees to svalues).
1643 Bail out early and return true if any call to on_global_state_change
1644 or on_state_change returns true, otherwise return false.
1646 This is split out to make it easier to experiment with changes to
1647 exploded_node granularity (so that we can observe what state changes
1648 lead to state_change_events being emitted). */
1650 bool
1651 for_each_state_change (const program_state &src_state,
1652 const program_state &dst_state,
1653 const extrinsic_state &ext_state,
1654 state_change_visitor *visitor)
1656 gcc_assert (src_state.m_checker_states.length ()
1657 == ext_state.get_num_checkers ());
1658 gcc_assert (dst_state.m_checker_states.length ()
1659 == ext_state.get_num_checkers ());
1660 for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
1662 const state_machine &sm = ext_state.get_sm (i);
1663 const sm_state_map &src_smap = *src_state.m_checker_states[i];
1664 const sm_state_map &dst_smap = *dst_state.m_checker_states[i];
1666 /* Add events for any global state changes. */
1667 if (src_smap.get_global_state () != dst_smap.get_global_state ())
1668 if (visitor->on_global_state_change (sm,
1669 src_smap.get_global_state (),
1670 dst_smap.get_global_state ()))
1671 return true;
1673 /* Add events for per-svalue state changes. */
1674 for (sm_state_map::iterator_t iter = dst_smap.begin ();
1675 iter != dst_smap.end ();
1676 ++iter)
1678 const svalue *sval = (*iter).first;
1679 state_machine::state_t dst_sm_val = (*iter).second.m_state;
1680 state_machine::state_t src_sm_val
1681 = src_smap.get_state (sval, ext_state);
1682 if (dst_sm_val != src_sm_val)
1684 const svalue *origin_sval = (*iter).second.m_origin;
1685 if (visitor->on_state_change (sm, src_sm_val, dst_sm_val,
1686 sval, origin_sval))
1687 return true;
1691 return false;
1694 /* An sm_context for adding state_change_event on assignments to NULL,
1695 where the default state isn't m_start. Storing such state in the
1696 sm_state_map would lead to bloat of the exploded_graph, so we want
1697 to leave it as a default state, and inject state change events here
1698 when we have a diagnostic.
1699 Find transitions of constants, for handling on_zero_assignment. */
1701 struct null_assignment_sm_context : public sm_context
1703 null_assignment_sm_context (int sm_idx,
1704 const state_machine &sm,
1705 const program_state *old_state,
1706 const program_state *new_state,
1707 const gimple *stmt,
1708 const program_point *point,
1709 checker_path *emission_path,
1710 const extrinsic_state &ext_state)
1711 : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state),
1712 m_stmt (stmt), m_point (point), m_emission_path (emission_path),
1713 m_ext_state (ext_state)
1717 tree get_fndecl_for_call (const gcall */*call*/) final override
1719 return NULL_TREE;
1722 state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
1723 tree var) final override
1725 const svalue *var_old_sval
1726 = m_old_state->m_region_model->get_rvalue (var, NULL);
1727 const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
1729 state_machine::state_t current
1730 = old_smap->get_state (var_old_sval, m_ext_state);
1732 return current;
1735 state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
1736 const svalue *sval) final override
1738 const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
1739 state_machine::state_t current = old_smap->get_state (sval, m_ext_state);
1740 return current;
1743 void set_next_state (const gimple *stmt,
1744 tree var,
1745 state_machine::state_t to,
1746 tree origin ATTRIBUTE_UNUSED) final override
1748 state_machine::state_t from = get_state (stmt, var);
1749 if (from != m_sm.get_start_state ())
1750 return;
1752 const svalue *var_new_sval
1753 = m_new_state->m_region_model->get_rvalue (var, NULL);
1754 const supernode *supernode = m_point->get_supernode ();
1755 int stack_depth = m_point->get_stack_depth ();
1757 m_emission_path->add_event (new state_change_event (supernode,
1758 m_stmt,
1759 stack_depth,
1760 m_sm,
1761 var_new_sval,
1762 from, to,
1763 NULL,
1764 *m_new_state));
1767 void set_next_state (const gimple *stmt,
1768 const svalue *sval,
1769 state_machine::state_t to,
1770 tree origin ATTRIBUTE_UNUSED) final override
1772 state_machine::state_t from = get_state (stmt, sval);
1773 if (from != m_sm.get_start_state ())
1774 return;
1776 const supernode *supernode = m_point->get_supernode ();
1777 int stack_depth = m_point->get_stack_depth ();
1779 m_emission_path->add_event (new state_change_event (supernode,
1780 m_stmt,
1781 stack_depth,
1782 m_sm,
1783 sval,
1784 from, to,
1785 NULL,
1786 *m_new_state));
1789 void warn (const supernode *, const gimple *,
1790 tree, pending_diagnostic *d) final override
1792 delete d;
1794 void warn (const supernode *, const gimple *,
1795 const svalue *, pending_diagnostic *d) final override
1797 delete d;
1800 tree get_diagnostic_tree (tree expr) final override
1802 return expr;
1805 tree get_diagnostic_tree (const svalue *sval) final override
1807 return m_new_state->m_region_model->get_representative_tree (sval);
1810 state_machine::state_t get_global_state () const final override
1812 return 0;
1815 void set_global_state (state_machine::state_t) final override
1817 /* No-op. */
1820 void on_custom_transition (custom_transition *) final override
1824 tree is_zero_assignment (const gimple *stmt) final override
1826 const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
1827 if (!assign_stmt)
1828 return NULL_TREE;
1829 if (const svalue *sval
1830 = m_new_state->m_region_model->get_gassign_result (assign_stmt, NULL))
1831 if (tree cst = sval->maybe_get_constant ())
1832 if (::zerop(cst))
1833 return gimple_assign_lhs (assign_stmt);
1834 return NULL_TREE;
1837 const program_state *get_old_program_state () const final override
1839 return m_old_state;
1841 const program_state *get_new_program_state () const final override
1843 return m_new_state;
1846 const program_state *m_old_state;
1847 const program_state *m_new_state;
1848 const gimple *m_stmt;
1849 const program_point *m_point;
1850 checker_path *m_emission_path;
1851 const extrinsic_state &m_ext_state;
1854 /* Subroutine of diagnostic_manager::build_emission_path.
1855 Add any events for EEDGE to EMISSION_PATH. */
1857 void
1858 diagnostic_manager::add_events_for_eedge (const path_builder &pb,
1859 const exploded_edge &eedge,
1860 checker_path *emission_path,
1861 interesting_t *interest) const
1863 const exploded_node *src_node = eedge.m_src;
1864 const program_point &src_point = src_node->get_point ();
1865 const int src_stack_depth = src_point.get_stack_depth ();
1866 const exploded_node *dst_node = eedge.m_dest;
1867 const program_point &dst_point = dst_node->get_point ();
1868 const int dst_stack_depth = dst_point.get_stack_depth ();
1869 if (get_logger ())
1871 get_logger ()->start_log_line ();
1872 pretty_printer *pp = get_logger ()->get_printer ();
1873 pp_printf (pp, "EN %i -> EN %i: ",
1874 eedge.m_src->m_index,
1875 eedge.m_dest->m_index);
1876 src_point.print (pp, format (false));
1877 pp_string (pp, "-> ");
1878 dst_point.print (pp, format (false));
1879 get_logger ()->end_log_line ();
1881 const program_state &src_state = src_node->get_state ();
1882 const program_state &dst_state = dst_node->get_state ();
1884 /* Add state change events for the states that have changed.
1885 We add these before events for superedges, so that if we have a
1886 state_change_event due to following an edge, we'll get this sequence
1887 of events:
1889 | if (!ptr)
1892 | (1) assuming 'ptr' is non-NULL (state_change_event)
1893 | (2) following 'false' branch... (start_cfg_edge_event)
1895 | do_something (ptr);
1896 | ~~~~~~~~~~~~~^~~~~
1898 | (3) ...to here (end_cfg_edge_event). */
1899 state_change_event_creator visitor (pb, eedge, emission_path);
1900 for_each_state_change (src_state, dst_state, pb.get_ext_state (),
1901 &visitor);
1903 /* Allow non-standard edges to add events, e.g. when rewinding from
1904 longjmp to a setjmp. */
1905 if (eedge.m_custom_info)
1906 eedge.m_custom_info->add_events_to_path (emission_path, eedge);
1908 /* Add events for superedges, function entries, and for statements. */
1909 switch (dst_point.get_kind ())
1911 default:
1912 break;
1913 case PK_BEFORE_SUPERNODE:
1914 if (src_point.get_kind () == PK_AFTER_SUPERNODE)
1916 if (eedge.m_sedge)
1917 add_events_for_superedge (pb, eedge, emission_path);
1919 /* Add function entry events. */
1920 if (dst_point.get_supernode ()->entry_p ())
1922 emission_path->add_event
1923 (new function_entry_event
1924 (dst_point.get_supernode ()->get_start_location (),
1925 dst_point.get_fndecl (),
1926 dst_stack_depth));
1927 /* Create region_creation_events for on-stack regions within
1928 this frame. */
1929 if (interest)
1931 unsigned i;
1932 const region *reg;
1933 FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
1934 if (const frame_region *frame = reg->maybe_get_frame_region ())
1935 if (frame->get_fndecl () == dst_point.get_fndecl ())
1937 const region *base_reg = reg->get_base_region ();
1938 if (tree decl = base_reg->maybe_get_decl ())
1939 if (DECL_P (decl)
1940 && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
1942 emission_path->add_region_creation_event
1943 (reg,
1944 DECL_SOURCE_LOCATION (decl),
1945 dst_point.get_fndecl (),
1946 dst_stack_depth);
1951 break;
1952 case PK_BEFORE_STMT:
1954 const gimple *stmt = dst_point.get_stmt ();
1955 const gcall *call = dyn_cast <const gcall *> (stmt);
1956 if (call && is_setjmp_call_p (call))
1957 emission_path->add_event
1958 (new setjmp_event (stmt->location,
1959 dst_node,
1960 dst_point.get_fndecl (),
1961 dst_stack_depth,
1962 call));
1963 else
1964 emission_path->add_event
1965 (new statement_event (stmt,
1966 dst_point.get_fndecl (),
1967 dst_stack_depth, dst_state));
1969 /* Create state change events for assignment to NULL.
1970 Iterate through the stmts in dst_enode, adding state change
1971 events for them. */
1972 if (dst_state.m_region_model)
1974 program_state iter_state (dst_state);
1975 program_point iter_point (dst_point);
1976 while (1)
1978 const gimple *stmt = iter_point.get_stmt ();
1979 if (const gassign *assign = dyn_cast<const gassign *> (stmt))
1981 const extrinsic_state &ext_state = pb.get_ext_state ();
1982 program_state old_state (iter_state);
1983 iter_state.m_region_model->on_assignment (assign, NULL);
1984 for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
1986 const state_machine &sm = ext_state.get_sm (i);
1987 null_assignment_sm_context sm_ctxt (i, sm,
1988 &old_state,
1989 &iter_state,
1990 stmt,
1991 &iter_point,
1992 emission_path,
1993 pb.get_ext_state ());
1994 sm.on_stmt (&sm_ctxt, dst_point.get_supernode (), stmt);
1995 // TODO: what about phi nodes?
1998 iter_point.next_stmt ();
1999 if (iter_point.get_kind () == PK_AFTER_SUPERNODE
2000 || (dst_node->m_succs.length () > 1
2001 && (iter_point
2002 == dst_node->m_succs[0]->m_dest->get_point ())))
2003 break;
2008 break;
2011 /* Look for changes in dynamic extents, which will identify
2012 the creation of heap-based regions and alloca regions. */
2013 if (interest)
2015 const region_model *src_model = src_state.m_region_model;
2016 const region_model *dst_model = dst_state.m_region_model;
2017 if (src_model->get_dynamic_extents ()
2018 != dst_model->get_dynamic_extents ())
2020 unsigned i;
2021 const region *reg;
2022 FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
2024 const region *base_reg = reg->get_base_region ();
2025 const svalue *old_extents
2026 = src_model->get_dynamic_extents (base_reg);
2027 const svalue *new_extents
2028 = dst_model->get_dynamic_extents (base_reg);
2029 if (old_extents == NULL && new_extents != NULL)
2030 switch (base_reg->get_kind ())
2032 default:
2033 break;
2034 case RK_HEAP_ALLOCATED:
2035 case RK_ALLOCA:
2036 emission_path->add_region_creation_event
2037 (reg,
2038 src_point.get_location (),
2039 src_point.get_fndecl (),
2040 src_stack_depth);
2041 break;
2047 if (pb.get_feasibility_problem ()
2048 && &pb.get_feasibility_problem ()->m_eedge == &eedge)
2050 pretty_printer pp;
2051 pp_format_decoder (&pp) = default_tree_printer;
2052 pp_string (&pp,
2053 "this path would have been rejected as infeasible"
2054 " at this edge: ");
2055 pb.get_feasibility_problem ()->dump_to_pp (&pp);
2056 emission_path->add_event (new precanned_custom_event
2057 (dst_point.get_location (),
2058 dst_point.get_fndecl (),
2059 dst_stack_depth,
2060 pp_formatted_text (&pp)));
2064 /* Return true if EEDGE is a significant edge in the path to the diagnostic
2065 for PB.
2067 Consider all of the sibling out-eedges from the same source enode
2068 as EEDGE.
2069 If there's no path from the destinations of those eedges to the
2070 diagnostic enode, then we have to take this eedge and thus it's
2071 significant.
2073 Conversely if there is a path from the destination of any other sibling
2074 eedge to the diagnostic enode, then this edge is insignificant.
2076 Example 1: redundant if-else:
2078 (A) if (...) A
2079 (B) ... / \
2080 else B C
2081 (C) ... \ /
2082 (D) [DIAGNOSTIC] D
2084 D is reachable by either B or C, so neither of these edges
2085 are significant.
2087 Example 2: pertinent if-else:
2089 (A) if (...) A
2090 (B) ... / \
2091 else B C
2092 (C) [NECESSARY CONDITION] | |
2093 (D) [POSSIBLE DIAGNOSTIC] D1 D2
2095 D becomes D1 and D2 in the exploded graph, where the diagnostic occurs
2096 at D2. D2 is only reachable via C, so the A -> C edge is significant.
2098 Example 3: redundant loop:
2100 (A) while (...) +-->A
2101 (B) ... | / \
2102 (C) ... +-B C
2103 (D) [DIAGNOSTIC] |
2106 D is reachable from both B and C, so the A->C edge is not significant. */
2108 bool
2109 diagnostic_manager::significant_edge_p (const path_builder &pb,
2110 const exploded_edge &eedge) const
2112 int i;
2113 exploded_edge *sibling;
2114 FOR_EACH_VEC_ELT (eedge.m_src->m_succs, i, sibling)
2116 if (sibling == &eedge)
2117 continue;
2118 if (pb.reachable_from_p (sibling->m_dest))
2120 if (get_logger ())
2121 get_logger ()->log (" edge EN: %i -> EN: %i is insignificant as"
2122 " EN: %i is also reachable via"
2123 " EN: %i -> EN: %i",
2124 eedge.m_src->m_index, eedge.m_dest->m_index,
2125 pb.get_diag_node ()->m_index,
2126 sibling->m_src->m_index,
2127 sibling->m_dest->m_index);
2128 return false;
2132 return true;
2135 /* Subroutine of diagnostic_manager::add_events_for_eedge
2136 where EEDGE has an underlying superedge i.e. a CFG edge,
2137 or an interprocedural call/return.
2138 Add any events for the superedge to EMISSION_PATH. */
2140 void
2141 diagnostic_manager::add_events_for_superedge (const path_builder &pb,
2142 const exploded_edge &eedge,
2143 checker_path *emission_path)
2144 const
2146 gcc_assert (eedge.m_sedge);
2148 /* Give diagnostics an opportunity to override this function. */
2149 pending_diagnostic *pd = pb.get_pending_diagnostic ();
2150 if (pd->maybe_add_custom_events_for_superedge (eedge, emission_path))
2151 return;
2153 /* Don't add events for insignificant edges at verbosity levels below 3. */
2154 if (m_verbosity < 3)
2155 if (!significant_edge_p (pb, eedge))
2156 return;
2158 const exploded_node *src_node = eedge.m_src;
2159 const program_point &src_point = src_node->get_point ();
2160 const exploded_node *dst_node = eedge.m_dest;
2161 const program_point &dst_point = dst_node->get_point ();
2162 const int src_stack_depth = src_point.get_stack_depth ();
2163 const int dst_stack_depth = dst_point.get_stack_depth ();
2164 const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
2166 switch (eedge.m_sedge->m_kind)
2168 case SUPEREDGE_CFG_EDGE:
2170 emission_path->add_event
2171 (new start_cfg_edge_event (eedge,
2172 (last_stmt
2173 ? last_stmt->location
2174 : UNKNOWN_LOCATION),
2175 src_point.get_fndecl (),
2176 src_stack_depth));
2177 emission_path->add_event
2178 (new end_cfg_edge_event (eedge,
2179 dst_point.get_supernode ()->get_start_location (),
2180 dst_point.get_fndecl (),
2181 dst_stack_depth));
2183 break;
2185 case SUPEREDGE_CALL:
2186 pd->add_call_event (eedge, emission_path);
2187 break;
2189 case SUPEREDGE_INTRAPROCEDURAL_CALL:
2191 /* TODO: add a subclass for this, or generate events for the
2192 summary. */
2193 emission_path->add_event
2194 (new debug_event ((last_stmt
2195 ? last_stmt->location
2196 : UNKNOWN_LOCATION),
2197 src_point.get_fndecl (),
2198 src_stack_depth,
2199 "call summary"));
2201 break;
2203 case SUPEREDGE_RETURN:
2205 const return_superedge *return_edge
2206 = as_a <const return_superedge *> (eedge.m_sedge);
2208 const gcall *call_stmt = return_edge->get_call_stmt ();
2209 emission_path->add_event
2210 (new return_event (eedge,
2211 (call_stmt
2212 ? call_stmt->location
2213 : UNKNOWN_LOCATION),
2214 dst_point.get_fndecl (),
2215 dst_stack_depth));
2217 break;
2221 /* Prune PATH, based on the verbosity level, to the most pertinent
2222 events for a diagnostic that involves VAR ending in state STATE
2223 (for state machine SM).
2225 PATH is updated in place, and the redundant checker_events are deleted.
2227 As well as deleting events, call record_critical_state on events in
2228 which state critical to the pending_diagnostic is being handled; see
2229 the comment for diagnostic_manager::prune_for_sm_diagnostic. */
2231 void
2232 diagnostic_manager::prune_path (checker_path *path,
2233 const state_machine *sm,
2234 const svalue *sval,
2235 state_machine::state_t state) const
2237 LOG_FUNC (get_logger ());
2238 path->maybe_log (get_logger (), "path");
2239 prune_for_sm_diagnostic (path, sm, sval, state);
2240 prune_interproc_events (path);
2241 consolidate_conditions (path);
2242 finish_pruning (path);
2243 path->maybe_log (get_logger (), "pruned");
2246 /* A cheap test to determine if EXPR can be the expression of interest in
2247 an sm-diagnostic, so that we can reject cases where we have a non-lvalue.
2248 We don't have always have a model when calling this, so we can't use
2249 tentative_region_model_context, so there can be false positives. */
2251 static bool
2252 can_be_expr_of_interest_p (tree expr)
2254 if (!expr)
2255 return false;
2257 /* Reject constants. */
2258 if (CONSTANT_CLASS_P (expr))
2259 return false;
2261 /* Otherwise assume that it can be an lvalue. */
2262 return true;
2265 /* First pass of diagnostic_manager::prune_path: apply verbosity level,
2266 pruning unrelated state change events.
2268 Iterate backwards through PATH, skipping state change events that aren't
2269 VAR but update the pertinent VAR when state-copying occurs.
2271 As well as deleting events, call record_critical_state on events in
2272 which state critical to the pending_diagnostic is being handled, so
2273 that the event's get_desc vfunc can potentially supply a more precise
2274 description of the event to the user.
2275 e.g. improving
2276 "calling 'foo' from 'bar'"
2278 "passing possibly-NULL pointer 'ptr' to 'foo' from 'bar' as param 1"
2279 when the diagnostic relates to later dereferencing 'ptr'. */
2281 void
2282 diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
2283 const state_machine *sm,
2284 const svalue *sval,
2285 state_machine::state_t state) const
2287 int idx = path->num_events () - 1;
2288 while (idx >= 0 && idx < (signed)path->num_events ())
2290 checker_event *base_event = path->get_checker_event (idx);
2291 if (get_logger ())
2293 if (sm)
2295 if (sval)
2297 label_text sval_desc = sval->get_desc ();
2298 log ("considering event %i (%s), with sval: %qs, state: %qs",
2299 idx, event_kind_to_string (base_event->m_kind),
2300 sval_desc.m_buffer, state->get_name ());
2301 sval_desc.maybe_free ();
2303 else
2304 log ("considering event %i (%s), with global state: %qs",
2305 idx, event_kind_to_string (base_event->m_kind),
2306 state->get_name ());
2308 else
2309 log ("considering event %i", idx);
2312 switch (base_event->m_kind)
2314 default:
2315 gcc_unreachable ();
2317 case EK_DEBUG:
2318 if (m_verbosity < 4)
2320 log ("filtering event %i: debug event", idx);
2321 path->delete_event (idx);
2323 break;
2325 case EK_CUSTOM:
2326 /* Don't filter custom events. */
2327 break;
2329 case EK_STMT:
2331 if (m_verbosity < 4)
2333 log ("filtering event %i: statement event", idx);
2334 path->delete_event (idx);
2337 break;
2339 case EK_REGION_CREATION:
2340 /* Don't filter these. */
2341 break;
2343 case EK_FUNCTION_ENTRY:
2344 if (m_verbosity < 1)
2346 log ("filtering event %i: function entry", idx);
2347 path->delete_event (idx);
2349 break;
2351 case EK_STATE_CHANGE:
2353 state_change_event *state_change = (state_change_event *)base_event;
2354 gcc_assert (state_change->m_dst_state.m_region_model);
2356 if (state_change->m_sval == sval)
2358 if (state_change->m_origin)
2360 if (get_logger ())
2362 label_text sval_desc = sval->get_desc ();
2363 label_text origin_sval_desc
2364 = state_change->m_origin->get_desc ();
2365 log ("event %i:"
2366 " switching var of interest from %qs to %qs",
2367 idx, sval_desc.m_buffer,
2368 origin_sval_desc.m_buffer);
2369 sval_desc.maybe_free ();
2370 origin_sval_desc.maybe_free ();
2372 sval = state_change->m_origin;
2374 log ("event %i: switching state of interest from %qs to %qs",
2375 idx, state_change->m_to->get_name (),
2376 state_change->m_from->get_name ());
2377 state = state_change->m_from;
2379 else if (m_verbosity < 4)
2381 if (get_logger ())
2383 if (state_change->m_sval)
2385 label_text change_sval_desc
2386 = state_change->m_sval->get_desc ();
2387 if (sval)
2389 label_text sval_desc = sval->get_desc ();
2390 log ("filtering event %i:"
2391 " state change to %qs unrelated to %qs",
2392 idx, change_sval_desc.m_buffer,
2393 sval_desc.m_buffer);
2395 else
2396 log ("filtering event %i: state change to %qs",
2397 idx, change_sval_desc.m_buffer);
2398 change_sval_desc.maybe_free ();
2400 else
2401 log ("filtering event %i: global state change", idx);
2403 path->delete_event (idx);
2406 break;
2408 case EK_START_CFG_EDGE:
2410 cfg_edge_event *event = (cfg_edge_event *)base_event;
2412 /* TODO: is this edge significant to var?
2413 See if var can be in other states in the dest, but not
2414 in other states in the src?
2415 Must have multiple sibling edges. */
2417 if (event->should_filter_p (m_verbosity))
2419 log ("filtering events %i and %i: CFG edge", idx, idx + 1);
2420 path->delete_event (idx);
2421 /* Also delete the corresponding EK_END_CFG_EDGE. */
2422 gcc_assert (path->get_checker_event (idx)->m_kind
2423 == EK_END_CFG_EDGE);
2424 path->delete_event (idx);
2427 break;
2429 case EK_END_CFG_EDGE:
2430 /* These come in pairs with EK_START_CFG_EDGE events and are
2431 filtered when their start event is filtered. */
2432 break;
2434 case EK_CALL_EDGE:
2436 call_event *event = (call_event *)base_event;
2437 const region_model *callee_model
2438 = event->m_eedge.m_dest->get_state ().m_region_model;
2439 const region_model *caller_model
2440 = event->m_eedge.m_src->get_state ().m_region_model;
2441 tree callee_var = callee_model->get_representative_tree (sval);
2442 callsite_expr expr;
2444 tree caller_var;
2445 if(event->m_sedge)
2447 const callgraph_superedge& cg_superedge
2448 = event->get_callgraph_superedge ();
2449 if (cg_superedge.m_cedge)
2450 caller_var
2451 = cg_superedge.map_expr_from_callee_to_caller (callee_var,
2452 &expr);
2453 else
2454 caller_var = caller_model->get_representative_tree (sval);
2456 else
2457 caller_var = caller_model->get_representative_tree (sval);
2459 if (caller_var)
2461 if (get_logger ())
2463 label_text sval_desc = sval->get_desc ();
2464 log ("event %i:"
2465 " recording critical state for %qs at call"
2466 " from %qE in callee to %qE in caller",
2467 idx, sval_desc.m_buffer, callee_var, caller_var);
2468 sval_desc.maybe_free ();
2470 if (expr.param_p ())
2471 event->record_critical_state (caller_var, state);
2474 break;
2476 case EK_RETURN_EDGE:
2478 if (sval)
2480 return_event *event = (return_event *)base_event;
2481 const region_model *caller_model
2482 = event->m_eedge.m_dest->get_state ().m_region_model;
2483 tree caller_var = caller_model->get_representative_tree (sval);
2484 const region_model *callee_model
2485 = event->m_eedge.m_src->get_state ().m_region_model;
2486 callsite_expr expr;
2488 tree callee_var;
2489 if (event->m_sedge)
2491 const callgraph_superedge& cg_superedge
2492 = event->get_callgraph_superedge ();
2493 if (cg_superedge.m_cedge)
2494 callee_var
2495 = cg_superedge.map_expr_from_caller_to_callee (caller_var,
2496 &expr);
2497 else
2498 callee_var = callee_model->get_representative_tree (sval);
2500 else
2501 callee_var = callee_model->get_representative_tree (sval);
2503 if (callee_var)
2505 if (get_logger ())
2507 label_text sval_desc = sval->get_desc ();
2508 log ("event %i:"
2509 " recording critical state for %qs at return"
2510 " from %qE in caller to %qE in callee",
2511 idx, sval_desc.m_buffer, callee_var, callee_var);
2512 sval_desc.maybe_free ();
2514 if (expr.return_value_p ())
2515 event->record_critical_state (callee_var, state);
2519 break;
2521 case EK_INLINED_CALL:
2522 /* We don't expect to see these yet, as they're added later.
2523 We'd want to keep them around. */
2524 break;
2526 case EK_SETJMP:
2527 /* TODO: only show setjmp_events that matter i.e. those for which
2528 there is a later rewind event using them. */
2529 case EK_REWIND_FROM_LONGJMP:
2530 case EK_REWIND_TO_SETJMP:
2531 break;
2533 case EK_WARNING:
2534 /* Always show the final "warning" event in the path. */
2535 break;
2537 idx--;
2541 /* Subroutine of diagnostic_manager::prune_for_sm_diagnostic.
2542 If *EXPR is not suitable to be the expression of interest in
2543 an sm-diagnostic, set *EXPR to NULL and log. */
2545 void
2546 diagnostic_manager::update_for_unsuitable_sm_exprs (tree *expr) const
2548 gcc_assert (expr);
2549 if (*expr && !can_be_expr_of_interest_p (*expr))
2551 log ("new var %qE is unsuitable; setting var to NULL", *expr);
2552 *expr = NULL_TREE;
2556 /* Second pass of diagnostic_manager::prune_path: remove redundant
2557 interprocedural information.
2559 For example, given:
2560 (1)- calling "f2" from "f1"
2561 (2)--- entry to "f2"
2562 (3)--- calling "f3" from "f2"
2563 (4)----- entry to "f3"
2564 (5)--- returning to "f2" to "f3"
2565 (6)- returning to "f1" to "f2"
2566 with no other intervening events, then none of these events are
2567 likely to be interesting to the user.
2569 Prune [..., call, function-entry, return, ...] triples repeatedly
2570 until nothing has changed. For the example above, this would
2571 remove events (3, 4, 5), and then remove events (1, 2, 6). */
2573 void
2574 diagnostic_manager::prune_interproc_events (checker_path *path) const
2576 bool changed = false;
2579 changed = false;
2580 int idx = (signed)path->num_events () - 1;
2581 while (idx >= 0)
2583 /* Prune [..., call, function-entry, return, ...] triples. */
2584 if (idx + 2 < (signed)path->num_events ()
2585 && path->get_checker_event (idx)->is_call_p ()
2586 && path->get_checker_event (idx + 1)->is_function_entry_p ()
2587 && path->get_checker_event (idx + 2)->is_return_p ())
2589 if (get_logger ())
2591 label_text desc
2592 (path->get_checker_event (idx)->get_desc (false));
2593 log ("filtering events %i-%i:"
2594 " irrelevant call/entry/return: %s",
2595 idx, idx + 2, desc.m_buffer);
2596 desc.maybe_free ();
2598 path->delete_event (idx + 2);
2599 path->delete_event (idx + 1);
2600 path->delete_event (idx);
2601 changed = true;
2602 idx--;
2603 continue;
2606 /* Prune [..., call, return, ...] pairs
2607 (for -fanalyzer-verbosity=0). */
2608 if (idx + 1 < (signed)path->num_events ()
2609 && path->get_checker_event (idx)->is_call_p ()
2610 && path->get_checker_event (idx + 1)->is_return_p ())
2612 if (get_logger ())
2614 label_text desc
2615 (path->get_checker_event (idx)->get_desc (false));
2616 log ("filtering events %i-%i:"
2617 " irrelevant call/return: %s",
2618 idx, idx + 1, desc.m_buffer);
2619 desc.maybe_free ();
2621 path->delete_event (idx + 1);
2622 path->delete_event (idx);
2623 changed = true;
2624 idx--;
2625 continue;
2628 idx--;
2632 while (changed);
2635 /* Return true iff event IDX within PATH is on the same line as REF_EXP_LOC. */
2637 static bool
2638 same_line_as_p (const expanded_location &ref_exp_loc,
2639 checker_path *path, unsigned idx)
2641 const checker_event *ev = path->get_checker_event (idx);
2642 expanded_location idx_exp_loc = expand_location (ev->get_location ());
2643 gcc_assert (ref_exp_loc.file);
2644 if (idx_exp_loc.file == NULL)
2645 return false;
2646 if (strcmp (ref_exp_loc.file, idx_exp_loc.file))
2647 return false;
2648 return ref_exp_loc.line == idx_exp_loc.line;
2651 /* This path-readability optimization reduces the verbosity of compound
2652 conditional statements (without needing to reconstruct the AST, which
2653 has already been lost).
2655 For example, it converts:
2657 | 61 | if (cp[0] != '\0' && cp[0] != '#')
2658 | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2659 | | | | |
2660 | | | | (6) ...to here
2661 | | | (7) following ‘true’ branch...
2662 | | (5) following ‘true’ branch...
2663 | 62 | {
2664 | 63 | alias = cp++;
2665 | | ~~~~
2666 | | |
2667 | | (8) ...to here
2669 into:
2671 | 61 | if (cp[0] != '\0' && cp[0] != '#')
2672 | | ~
2673 | | |
2674 | | (5) following ‘true’ branch...
2675 | 62 | {
2676 | 63 | alias = cp++;
2677 | | ~~~~
2678 | | |
2679 | | (6) ...to here
2681 by combining events 5-8 into new events 5-6.
2683 Find runs of consecutive (start_cfg_edge_event, end_cfg_edge_event) pairs
2684 in which all events apart from the final end_cfg_edge_event are on the same
2685 line, and for which either all the CFG edges are TRUE edges, or all are
2686 FALSE edges.
2688 Consolidate each such run into a
2689 (start_consolidated_cfg_edges_event, end_consolidated_cfg_edges_event)
2690 pair. */
2692 void
2693 diagnostic_manager::consolidate_conditions (checker_path *path) const
2695 /* Don't simplify edges if we're debugging them. */
2696 if (flag_analyzer_verbose_edges)
2697 return;
2699 for (int start_idx = 0;
2700 start_idx < (signed)path->num_events () - 1;
2701 start_idx++)
2703 if (path->cfg_edge_pair_at_p (start_idx))
2705 const checker_event *old_start_ev
2706 = path->get_checker_event (start_idx);
2707 expanded_location start_exp_loc
2708 = expand_location (old_start_ev->get_location ());
2709 if (start_exp_loc.file == NULL)
2710 continue;
2711 if (!same_line_as_p (start_exp_loc, path, start_idx + 1))
2712 continue;
2714 /* Are we looking for a run of all TRUE edges, or all FALSE edges? */
2715 gcc_assert (old_start_ev->m_kind == EK_START_CFG_EDGE);
2716 const start_cfg_edge_event *old_start_cfg_ev
2717 = (const start_cfg_edge_event *)old_start_ev;
2718 const cfg_superedge& first_cfg_sedge
2719 = old_start_cfg_ev->get_cfg_superedge ();
2720 bool edge_sense;
2721 if (first_cfg_sedge.true_value_p ())
2722 edge_sense = true;
2723 else if (first_cfg_sedge.false_value_p ())
2724 edge_sense = false;
2725 else
2726 continue;
2728 /* Find a run of CFG start/end event pairs from
2729 [start_idx, next_idx)
2730 where all apart from the final event are on the same line,
2731 and all are either TRUE or FALSE edges, matching the initial. */
2732 int next_idx = start_idx + 2;
2733 while (path->cfg_edge_pair_at_p (next_idx)
2734 && same_line_as_p (start_exp_loc, path, next_idx))
2736 const checker_event *iter_ev
2737 = path->get_checker_event (next_idx);
2738 gcc_assert (iter_ev->m_kind == EK_START_CFG_EDGE);
2739 const start_cfg_edge_event *iter_cfg_ev
2740 = (const start_cfg_edge_event *)iter_ev;
2741 const cfg_superedge& iter_cfg_sedge
2742 = iter_cfg_ev->get_cfg_superedge ();
2743 if (edge_sense)
2745 if (!iter_cfg_sedge.true_value_p ())
2746 break;
2748 else
2750 if (!iter_cfg_sedge.false_value_p ())
2751 break;
2753 next_idx += 2;
2756 /* If we have more than one pair in the run, consolidate. */
2757 if (next_idx > start_idx + 2)
2759 const checker_event *old_end_ev
2760 = path->get_checker_event (next_idx - 1);
2761 log ("consolidating CFG edge events %i-%i into %i-%i",
2762 start_idx, next_idx - 1, start_idx, start_idx +1);
2763 start_consolidated_cfg_edges_event *new_start_ev
2764 = new start_consolidated_cfg_edges_event
2765 (old_start_ev->get_location (),
2766 old_start_ev->get_fndecl (),
2767 old_start_ev->get_stack_depth (),
2768 edge_sense);
2769 checker_event *new_end_ev
2770 = new end_consolidated_cfg_edges_event
2771 (old_end_ev->get_location (),
2772 old_end_ev->get_fndecl (),
2773 old_end_ev->get_stack_depth ());
2774 path->replace_event (start_idx, new_start_ev);
2775 path->replace_event (start_idx + 1, new_end_ev);
2776 path->delete_events (start_idx + 2, next_idx - (start_idx + 2));
2782 /* Final pass of diagnostic_manager::prune_path.
2784 If all we're left with is in one function, then filter function entry
2785 events. */
2787 void
2788 diagnostic_manager::finish_pruning (checker_path *path) const
2790 if (!path->interprocedural_p ())
2792 int idx = path->num_events () - 1;
2793 while (idx >= 0 && idx < (signed)path->num_events ())
2795 checker_event *base_event = path->get_checker_event (idx);
2796 if (base_event->m_kind == EK_FUNCTION_ENTRY)
2798 log ("filtering event %i:"
2799 " function entry for purely intraprocedural path", idx);
2800 path->delete_event (idx);
2802 idx--;
2807 } // namespace ana
2809 #endif /* #if ENABLE_ANALYZER */