diagnostic-manager.cc revision 1.1.1.2 1 1.1 mrg /* Classes for saving, deduplicating, and emitting analyzer diagnostics.
2 1.1.1.2 mrg Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 1.1 mrg Contributed by David Malcolm <dmalcolm (at) redhat.com>.
4 1.1 mrg
5 1.1 mrg This file is part of GCC.
6 1.1 mrg
7 1.1 mrg GCC is free software; you can redistribute it and/or modify it
8 1.1 mrg under the terms of the GNU General Public License as published by
9 1.1 mrg the Free Software Foundation; either version 3, or (at your option)
10 1.1 mrg any later version.
11 1.1 mrg
12 1.1 mrg GCC is distributed in the hope that it will be useful, but
13 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of
14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 1.1 mrg General Public License for more details.
16 1.1 mrg
17 1.1 mrg You should have received a copy of the GNU General Public License
18 1.1 mrg along with GCC; see the file COPYING3. If not see
19 1.1 mrg <http://www.gnu.org/licenses/>. */
20 1.1 mrg
21 1.1 mrg #include "config.h"
22 1.1 mrg #include "system.h"
23 1.1 mrg #include "coretypes.h"
24 1.1 mrg #include "tree.h"
25 1.1 mrg #include "pretty-print.h"
26 1.1 mrg #include "gcc-rich-location.h"
27 1.1 mrg #include "gimple-pretty-print.h"
28 1.1 mrg #include "function.h"
29 1.1 mrg #include "diagnostic-core.h"
30 1.1 mrg #include "diagnostic-event-id.h"
31 1.1 mrg #include "diagnostic-path.h"
32 1.1 mrg #include "alloc-pool.h"
33 1.1 mrg #include "fibonacci_heap.h"
34 1.1 mrg #include "shortest-paths.h"
35 1.1 mrg #include "sbitmap.h"
36 1.1 mrg #include "bitmap.h"
37 1.1 mrg #include "tristate.h"
38 1.1 mrg #include "selftest.h"
39 1.1 mrg #include "ordered-hash-map.h"
40 1.1.1.2 mrg #include "json.h"
41 1.1 mrg #include "analyzer/analyzer.h"
42 1.1 mrg #include "analyzer/analyzer-logging.h"
43 1.1 mrg #include "analyzer/sm.h"
44 1.1 mrg #include "analyzer/pending-diagnostic.h"
45 1.1 mrg #include "analyzer/diagnostic-manager.h"
46 1.1.1.2 mrg #include "analyzer/call-string.h"
47 1.1.1.2 mrg #include "analyzer/program-point.h"
48 1.1.1.2 mrg #include "analyzer/store.h"
49 1.1 mrg #include "analyzer/region-model.h"
50 1.1 mrg #include "analyzer/constraint-manager.h"
51 1.1 mrg #include "cfg.h"
52 1.1 mrg #include "basic-block.h"
53 1.1 mrg #include "gimple.h"
54 1.1 mrg #include "gimple-iterator.h"
55 1.1 mrg #include "cgraph.h"
56 1.1 mrg #include "digraph.h"
57 1.1 mrg #include "analyzer/supergraph.h"
58 1.1 mrg #include "analyzer/program-state.h"
59 1.1 mrg #include "analyzer/exploded-graph.h"
60 1.1.1.2 mrg #include "analyzer/trimmed-graph.h"
61 1.1.1.2 mrg #include "analyzer/feasible-graph.h"
62 1.1 mrg #include "analyzer/checker-path.h"
63 1.1 mrg #include "analyzer/reachability.h"
64 1.1 mrg
65 1.1 mrg #if ENABLE_ANALYZER
66 1.1 mrg
67 1.1 mrg namespace ana {
68 1.1 mrg
69 1.1.1.2 mrg class feasible_worklist;
70 1.1.1.2 mrg
71 1.1.1.2 mrg /* State for finding the shortest feasible exploded_path for a
72 1.1.1.2 mrg saved_diagnostic.
73 1.1.1.2 mrg This is shared between all diagnostics, so that we avoid repeating work. */
74 1.1.1.2 mrg
75 1.1.1.2 mrg class epath_finder
76 1.1.1.2 mrg {
77 1.1.1.2 mrg public:
78 1.1.1.2 mrg epath_finder (const exploded_graph &eg)
79 1.1.1.2 mrg : m_eg (eg),
80 1.1.1.2 mrg m_sep (NULL)
81 1.1.1.2 mrg {
82 1.1.1.2 mrg /* This is shared by all diagnostics, but only needed if
83 1.1.1.2 mrg !flag_analyzer_feasibility. */
84 1.1.1.2 mrg if (!flag_analyzer_feasibility)
85 1.1.1.2 mrg m_sep = new shortest_exploded_paths (eg, eg.get_origin (),
86 1.1.1.2 mrg SPS_FROM_GIVEN_ORIGIN);
87 1.1.1.2 mrg }
88 1.1.1.2 mrg
89 1.1.1.2 mrg ~epath_finder () { delete m_sep; }
90 1.1.1.2 mrg
91 1.1.1.2 mrg logger *get_logger () const { return m_eg.get_logger (); }
92 1.1.1.2 mrg
93 1.1.1.2 mrg exploded_path *get_best_epath (const exploded_node *target_enode,
94 1.1.1.2 mrg const char *desc, unsigned diag_idx,
95 1.1.1.2 mrg feasibility_problem **out_problem);
96 1.1.1.2 mrg
97 1.1.1.2 mrg private:
98 1.1.1.2 mrg DISABLE_COPY_AND_ASSIGN(epath_finder);
99 1.1.1.2 mrg
100 1.1.1.2 mrg exploded_path *explore_feasible_paths (const exploded_node *target_enode,
101 1.1.1.2 mrg const char *desc, unsigned diag_idx);
102 1.1.1.2 mrg bool process_worklist_item (feasible_worklist *worklist,
103 1.1.1.2 mrg const trimmed_graph &tg,
104 1.1.1.2 mrg feasible_graph *fg,
105 1.1.1.2 mrg const exploded_node *target_enode,
106 1.1.1.2 mrg unsigned diag_idx,
107 1.1.1.2 mrg exploded_path **out_best_path) const;
108 1.1.1.2 mrg void dump_trimmed_graph (const exploded_node *target_enode,
109 1.1.1.2 mrg const char *desc, unsigned diag_idx,
110 1.1.1.2 mrg const trimmed_graph &tg,
111 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &sep);
112 1.1.1.2 mrg void dump_feasible_graph (const exploded_node *target_enode,
113 1.1.1.2 mrg const char *desc, unsigned diag_idx,
114 1.1.1.2 mrg const feasible_graph &fg);
115 1.1.1.2 mrg void dump_feasible_path (const exploded_node *target_enode,
116 1.1.1.2 mrg unsigned diag_idx,
117 1.1.1.2 mrg const feasible_graph &fg,
118 1.1.1.2 mrg const feasible_node &fnode) const;
119 1.1.1.2 mrg
120 1.1.1.2 mrg const exploded_graph &m_eg;
121 1.1.1.2 mrg shortest_exploded_paths *m_sep;
122 1.1.1.2 mrg };
123 1.1.1.2 mrg
124 1.1.1.2 mrg /* class epath_finder. */
125 1.1.1.2 mrg
126 1.1.1.2 mrg /* Get the "best" exploded_path for reaching ENODE from the origin,
127 1.1.1.2 mrg returning ownership of it to the caller.
128 1.1.1.2 mrg
129 1.1.1.2 mrg Ideally we want to report the shortest feasible path.
130 1.1.1.2 mrg Return NULL if we could not find a feasible path
131 1.1.1.2 mrg (when flag_analyzer_feasibility is true).
132 1.1.1.2 mrg
133 1.1.1.2 mrg If flag_analyzer_feasibility is false, then simply return the
134 1.1.1.2 mrg shortest path.
135 1.1.1.2 mrg
136 1.1.1.2 mrg Use DESC and DIAG_IDX when logging.
137 1.1.1.2 mrg
138 1.1.1.2 mrg Write any feasibility_problem to *OUT_PROBLEM. */
139 1.1.1.2 mrg
140 1.1.1.2 mrg exploded_path *
141 1.1.1.2 mrg epath_finder::get_best_epath (const exploded_node *enode,
142 1.1.1.2 mrg const char *desc, unsigned diag_idx,
143 1.1.1.2 mrg feasibility_problem **out_problem)
144 1.1.1.2 mrg {
145 1.1.1.2 mrg logger *logger = get_logger ();
146 1.1.1.2 mrg LOG_SCOPE (logger);
147 1.1.1.2 mrg
148 1.1.1.2 mrg unsigned snode_idx = enode->get_supernode ()->m_index;
149 1.1.1.2 mrg if (logger)
150 1.1.1.2 mrg logger->log ("considering %qs at EN: %i, SN: %i (sd: %i)",
151 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx);
152 1.1.1.2 mrg
153 1.1.1.2 mrg /* State-merging means that not every path in the egraph corresponds
154 1.1.1.2 mrg to a feasible one w.r.t. states.
155 1.1.1.2 mrg
156 1.1.1.2 mrg We want to find the shortest feasible path from the origin to ENODE
157 1.1.1.2 mrg in the egraph. */
158 1.1.1.2 mrg
159 1.1.1.2 mrg if (flag_analyzer_feasibility)
160 1.1.1.2 mrg {
161 1.1.1.2 mrg /* Attempt to find the shortest feasible path using feasible_graph. */
162 1.1.1.2 mrg if (logger)
163 1.1.1.2 mrg logger->log ("trying to find shortest feasible path");
164 1.1.1.2 mrg if (exploded_path *epath = explore_feasible_paths (enode, desc, diag_idx))
165 1.1.1.2 mrg {
166 1.1.1.2 mrg if (logger)
167 1.1.1.2 mrg logger->log ("accepting %qs at EN: %i, SN: %i (sd: %i)"
168 1.1.1.2 mrg " with feasible path (length: %i)",
169 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx,
170 1.1.1.2 mrg epath->length ());
171 1.1.1.2 mrg return epath;
172 1.1.1.2 mrg }
173 1.1.1.2 mrg else
174 1.1.1.2 mrg {
175 1.1.1.2 mrg if (logger)
176 1.1.1.2 mrg logger->log ("rejecting %qs at EN: %i, SN: %i (sd: %i)"
177 1.1.1.2 mrg " due to not finding feasible path",
178 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx);
179 1.1.1.2 mrg return NULL;
180 1.1.1.2 mrg }
181 1.1.1.2 mrg }
182 1.1.1.2 mrg else
183 1.1.1.2 mrg {
184 1.1.1.2 mrg /* As a crude approximation to shortest feasible path, simply find
185 1.1.1.2 mrg the shortest path, and note whether it is feasible.
186 1.1.1.2 mrg There could be longer feasible paths within the egraph, so this
187 1.1.1.2 mrg approach would lead to diagnostics being falsely rejected
188 1.1.1.2 mrg (PR analyzer/96374). */
189 1.1.1.2 mrg if (logger)
190 1.1.1.2 mrg logger->log ("trying to find shortest path ignoring feasibility");
191 1.1.1.2 mrg gcc_assert (m_sep);
192 1.1.1.2 mrg exploded_path *epath
193 1.1.1.2 mrg = new exploded_path (m_sep->get_shortest_path (enode));
194 1.1.1.2 mrg if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg))
195 1.1.1.2 mrg {
196 1.1.1.2 mrg if (logger)
197 1.1.1.2 mrg logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i)"
198 1.1.1.2 mrg " with feasible path (length: %i)",
199 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx,
200 1.1.1.2 mrg epath->length ());
201 1.1.1.2 mrg }
202 1.1.1.2 mrg else
203 1.1.1.2 mrg {
204 1.1.1.2 mrg if (logger)
205 1.1.1.2 mrg logger->log ("accepting %qs at EN: %i, SN: %i (sn: %i) (length: %i)"
206 1.1.1.2 mrg " despite infeasible path (due to %qs)",
207 1.1.1.2 mrg desc, enode->m_index, snode_idx, diag_idx,
208 1.1.1.2 mrg epath->length (),
209 1.1.1.2 mrg "-fno-analyzer-feasibility");
210 1.1.1.2 mrg }
211 1.1.1.2 mrg return epath;
212 1.1.1.2 mrg }
213 1.1.1.2 mrg }
214 1.1.1.2 mrg
215 1.1.1.2 mrg /* A class for managing the worklist of feasible_nodes in
216 1.1.1.2 mrg epath_finder::explore_feasible_paths, prioritizing them
217 1.1.1.2 mrg so that shorter paths appear earlier in the queue. */
218 1.1.1.2 mrg
219 1.1.1.2 mrg class feasible_worklist
220 1.1.1.2 mrg {
221 1.1.1.2 mrg public:
222 1.1.1.2 mrg feasible_worklist (const shortest_paths<eg_traits, exploded_path> &sep)
223 1.1.1.2 mrg : m_queue (key_t (*this, NULL)),
224 1.1.1.2 mrg m_sep (sep)
225 1.1.1.2 mrg {
226 1.1.1.2 mrg }
227 1.1.1.2 mrg
228 1.1.1.2 mrg feasible_node *take_next () { return m_queue.extract_min (); }
229 1.1.1.2 mrg
230 1.1.1.2 mrg void add_node (feasible_node *fnode)
231 1.1.1.2 mrg {
232 1.1.1.2 mrg m_queue.insert (key_t (*this, fnode), fnode);
233 1.1.1.2 mrg }
234 1.1.1.2 mrg
235 1.1.1.2 mrg private:
236 1.1.1.2 mrg struct key_t
237 1.1.1.2 mrg {
238 1.1.1.2 mrg key_t (const feasible_worklist &w, feasible_node *fnode)
239 1.1.1.2 mrg : m_worklist (w), m_fnode (fnode)
240 1.1.1.2 mrg {}
241 1.1.1.2 mrg
242 1.1.1.2 mrg bool operator< (const key_t &other) const
243 1.1.1.2 mrg {
244 1.1.1.2 mrg return cmp (*this, other) < 0;
245 1.1.1.2 mrg }
246 1.1.1.2 mrg
247 1.1.1.2 mrg bool operator== (const key_t &other) const
248 1.1.1.2 mrg {
249 1.1.1.2 mrg return cmp (*this, other) == 0;
250 1.1.1.2 mrg }
251 1.1.1.2 mrg
252 1.1.1.2 mrg bool operator> (const key_t &other) const
253 1.1.1.2 mrg {
254 1.1.1.2 mrg return !(*this == other || *this < other);
255 1.1.1.2 mrg }
256 1.1.1.2 mrg
257 1.1.1.2 mrg private:
258 1.1.1.2 mrg static int cmp (const key_t &ka, const key_t &kb)
259 1.1.1.2 mrg {
260 1.1.1.2 mrg /* Choose the node for which if the remaining path were feasible,
261 1.1.1.2 mrg it would be the shortest path (summing the length of the
262 1.1.1.2 mrg known-feasible path so far with that of the remaining
263 1.1.1.2 mrg possibly-feasible path). */
264 1.1.1.2 mrg int ca = ka.m_worklist.get_estimated_cost (ka.m_fnode);
265 1.1.1.2 mrg int cb = kb.m_worklist.get_estimated_cost (kb.m_fnode);
266 1.1.1.2 mrg return ca - cb;
267 1.1.1.2 mrg }
268 1.1.1.2 mrg
269 1.1.1.2 mrg const feasible_worklist &m_worklist;
270 1.1.1.2 mrg feasible_node *m_fnode;
271 1.1.1.2 mrg };
272 1.1.1.2 mrg
273 1.1.1.2 mrg /* Get the estimated length of a path involving FNODE from
274 1.1.1.2 mrg the origin to the target enode.
275 1.1.1.2 mrg Sum the length of the known-feasible path so far with
276 1.1.1.2 mrg that of the remaining possibly-feasible path. */
277 1.1.1.2 mrg
278 1.1.1.2 mrg int get_estimated_cost (const feasible_node *fnode) const
279 1.1.1.2 mrg {
280 1.1.1.2 mrg unsigned length_so_far = fnode->get_path_length ();
281 1.1.1.2 mrg int shortest_remaining_path
282 1.1.1.2 mrg = m_sep.get_shortest_distance (fnode->get_inner_node ());
283 1.1.1.2 mrg
284 1.1.1.2 mrg gcc_assert (shortest_remaining_path >= 0);
285 1.1.1.2 mrg /* This should be true since we're only exploring nodes within
286 1.1.1.2 mrg the trimmed graph (and we anticipate it being much smaller
287 1.1.1.2 mrg than this, and thus not overflowing the sum). */
288 1.1.1.2 mrg gcc_assert (shortest_remaining_path < INT_MAX);
289 1.1.1.2 mrg
290 1.1.1.2 mrg return length_so_far + shortest_remaining_path;
291 1.1.1.2 mrg }
292 1.1.1.2 mrg
293 1.1.1.2 mrg /* Priority queue, backed by a fibonacci_heap. */
294 1.1.1.2 mrg typedef fibonacci_heap<key_t, feasible_node> queue_t;
295 1.1.1.2 mrg queue_t m_queue;
296 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &m_sep;
297 1.1.1.2 mrg };
298 1.1.1.2 mrg
299 1.1.1.2 mrg /* When we're building the exploded graph we want to simplify
300 1.1.1.2 mrg overly-complicated symbolic values down to "UNKNOWN" to try to avoid
301 1.1.1.2 mrg state explosions and unbounded chains of exploration.
302 1.1.1.2 mrg
303 1.1.1.2 mrg However, when we're building the feasibility graph for a diagnostic
304 1.1.1.2 mrg (actually a tree), we don't want UNKNOWN values, as conditions on them
305 1.1.1.2 mrg are also unknown: we don't want to have a contradiction such as a path
306 1.1.1.2 mrg where (VAL != 0) and then (VAL == 0) along the same path.
307 1.1.1.2 mrg
308 1.1.1.2 mrg Hence this is an RAII class for temporarily disabling complexity-checking
309 1.1.1.2 mrg in the region_model_manager, for use within
310 1.1.1.2 mrg epath_finder::explore_feasible_paths.
311 1.1.1.2 mrg
312 1.1.1.2 mrg We also disable the creation of unknown_svalue instances during feasibility
313 1.1.1.2 mrg checking, instead creating unique svalues, to avoid paradoxes in paths. */
314 1.1.1.2 mrg
315 1.1.1.2 mrg class auto_checking_feasibility
316 1.1.1.2 mrg {
317 1.1.1.2 mrg public:
318 1.1.1.2 mrg auto_checking_feasibility (region_model_manager *mgr) : m_mgr (mgr)
319 1.1.1.2 mrg {
320 1.1.1.2 mrg m_mgr->begin_checking_feasibility ();
321 1.1.1.2 mrg }
322 1.1.1.2 mrg ~auto_checking_feasibility ()
323 1.1.1.2 mrg {
324 1.1.1.2 mrg m_mgr->end_checking_feasibility ();
325 1.1.1.2 mrg }
326 1.1.1.2 mrg private:
327 1.1.1.2 mrg region_model_manager *m_mgr;
328 1.1.1.2 mrg };
329 1.1.1.2 mrg
330 1.1.1.2 mrg /* Attempt to find the shortest feasible path from the origin to
331 1.1.1.2 mrg TARGET_ENODE by iteratively building a feasible_graph, in which
332 1.1.1.2 mrg every path to a feasible_node is feasible by construction.
333 1.1.1.2 mrg
334 1.1.1.2 mrg We effectively explore the tree of feasible paths in order of shortest
335 1.1.1.2 mrg path until we either find a feasible path to TARGET_ENODE, or hit
336 1.1.1.2 mrg a limit and give up.
337 1.1.1.2 mrg
338 1.1.1.2 mrg Preliminaries:
339 1.1.1.2 mrg - Find the shortest path from each node to the TARGET_ENODE (without
340 1.1.1.2 mrg checking feasibility), so that we can prioritize our worklist.
341 1.1.1.2 mrg - Construct a trimmed_graph: the subset of nodes/edges that
342 1.1.1.2 mrg are on a path that eventually reaches TARGET_ENODE. We will only need
343 1.1.1.2 mrg to consider these when considering the shortest feasible path.
344 1.1.1.2 mrg
345 1.1.1.2 mrg Build a feasible_graph, in which every path to a feasible_node
346 1.1.1.2 mrg is feasible by construction.
347 1.1.1.2 mrg We use a worklist to flatten the exploration into an iteration.
348 1.1.1.2 mrg Starting at the origin, find feasible out-edges within the trimmed graph.
349 1.1.1.2 mrg At each stage, choose the node for which if the remaining path were feasible,
350 1.1.1.2 mrg it would be the shortest path (summing the length of the known-feasible path
351 1.1.1.2 mrg so far with that of the remaining possibly-feasible path).
352 1.1.1.2 mrg This way, the first feasible path we find to TARGET_ENODE is the shortest.
353 1.1.1.2 mrg We start by trying the shortest possible path, but if that fails,
354 1.1.1.2 mrg we explore progressively longer paths, eventually trying iterations through
355 1.1.1.2 mrg loops. The exploration is captured in the feasible_graph, which can be
356 1.1.1.2 mrg dumped as a .dot file to visualize the exploration. The indices of the
357 1.1.1.2 mrg feasible_nodes show the order in which they were created.
358 1.1.1.2 mrg
359 1.1.1.2 mrg This is something of a brute-force approach, but the trimmed_graph
360 1.1.1.2 mrg hopefully keeps the complexity manageable.
361 1.1.1.2 mrg
362 1.1.1.2 mrg Terminate with failure when the number of infeasible edges exceeds
363 1.1.1.2 mrg a threshold (--param=analyzer-max-infeasible-edges=).
364 1.1.1.2 mrg This is guaranteed to eventually lead to terminatation, as
365 1.1.1.2 mrg we can't keep creating feasible nodes without eventually
366 1.1.1.2 mrg either reaching an infeasible edge, or reaching the
367 1.1.1.2 mrg TARGET_ENODE. Specifically, there can't be a cycle of
368 1.1.1.2 mrg feasible edges that doesn't reach the target_enode without
369 1.1.1.2 mrg an out-edge that either fails feasibility or gets closer
370 1.1.1.2 mrg to the TARGET_ENODE: on each iteration we are either:
371 1.1.1.2 mrg - effectively getting closer to the TARGET_ENODE (which can't
372 1.1.1.2 mrg continue forever without reaching the target), or
373 1.1.1.2 mrg - getting monotonically closer to the termination threshold. */
374 1.1.1.2 mrg
375 1.1.1.2 mrg exploded_path *
376 1.1.1.2 mrg epath_finder::explore_feasible_paths (const exploded_node *target_enode,
377 1.1.1.2 mrg const char *desc, unsigned diag_idx)
378 1.1.1.2 mrg {
379 1.1.1.2 mrg logger *logger = get_logger ();
380 1.1.1.2 mrg LOG_SCOPE (logger);
381 1.1.1.2 mrg
382 1.1.1.2 mrg region_model_manager *mgr = m_eg.get_engine ()->get_model_manager ();
383 1.1.1.2 mrg
384 1.1.1.2 mrg /* Determine the shortest path to TARGET_ENODE from each node in
385 1.1.1.2 mrg the exploded graph. */
386 1.1.1.2 mrg shortest_paths<eg_traits, exploded_path> sep
387 1.1.1.2 mrg (m_eg, target_enode, SPS_TO_GIVEN_TARGET);
388 1.1.1.2 mrg
389 1.1.1.2 mrg /* Construct a trimmed_graph: the subset of nodes/edges that
390 1.1.1.2 mrg are on a path that eventually reaches TARGET_ENODE.
391 1.1.1.2 mrg We only need to consider these when considering the shortest
392 1.1.1.2 mrg feasible path. */
393 1.1.1.2 mrg trimmed_graph tg (m_eg, target_enode);
394 1.1.1.2 mrg
395 1.1.1.2 mrg if (flag_dump_analyzer_feasibility)
396 1.1.1.2 mrg dump_trimmed_graph (target_enode, desc, diag_idx, tg, sep);
397 1.1.1.2 mrg
398 1.1.1.2 mrg feasible_graph fg;
399 1.1.1.2 mrg feasible_worklist worklist (sep);
400 1.1.1.2 mrg
401 1.1.1.2 mrg /* Populate the worklist with the origin node. */
402 1.1.1.2 mrg {
403 1.1.1.2 mrg feasibility_state init_state (mgr, m_eg.get_supergraph ());
404 1.1.1.2 mrg feasible_node *origin = fg.add_node (m_eg.get_origin (), init_state, 0);
405 1.1.1.2 mrg worklist.add_node (origin);
406 1.1.1.2 mrg }
407 1.1.1.2 mrg
408 1.1.1.2 mrg /* Iteratively explore the tree of feasible paths in order of shortest
409 1.1.1.2 mrg path until we either find a feasible path to TARGET_ENODE, or hit
410 1.1.1.2 mrg a limit. */
411 1.1.1.2 mrg
412 1.1.1.2 mrg /* Set this if we find a feasible path to TARGET_ENODE. */
413 1.1.1.2 mrg exploded_path *best_path = NULL;
414 1.1.1.2 mrg
415 1.1.1.2 mrg {
416 1.1.1.2 mrg auto_checking_feasibility sentinel (mgr);
417 1.1.1.2 mrg
418 1.1.1.2 mrg while (process_worklist_item (&worklist, tg, &fg, target_enode, diag_idx,
419 1.1.1.2 mrg &best_path))
420 1.1.1.2 mrg {
421 1.1.1.2 mrg /* Empty; the work is done within process_worklist_item. */
422 1.1.1.2 mrg }
423 1.1.1.2 mrg }
424 1.1.1.2 mrg
425 1.1.1.2 mrg if (logger)
426 1.1.1.2 mrg {
427 1.1.1.2 mrg logger->log ("tg for sd: %i:", diag_idx);
428 1.1.1.2 mrg logger->inc_indent ();
429 1.1.1.2 mrg tg.log_stats (logger);
430 1.1.1.2 mrg logger->dec_indent ();
431 1.1.1.2 mrg
432 1.1.1.2 mrg logger->log ("fg for sd: %i:", diag_idx);
433 1.1.1.2 mrg logger->inc_indent ();
434 1.1.1.2 mrg fg.log_stats (logger);
435 1.1.1.2 mrg logger->dec_indent ();
436 1.1.1.2 mrg }
437 1.1.1.2 mrg
438 1.1.1.2 mrg /* Dump the feasible_graph. */
439 1.1.1.2 mrg if (flag_dump_analyzer_feasibility)
440 1.1.1.2 mrg dump_feasible_graph (target_enode, desc, diag_idx, fg);
441 1.1.1.2 mrg
442 1.1.1.2 mrg return best_path;
443 1.1.1.2 mrg }
444 1.1.1.2 mrg
445 1.1.1.2 mrg /* Process the next item in WORKLIST, potentially adding new items
446 1.1.1.2 mrg based on feasible out-edges, and extending FG accordingly.
447 1.1.1.2 mrg Use TG to ignore out-edges that don't lead to TARGET_ENODE.
448 1.1.1.2 mrg Return true if the worklist processing should continue.
449 1.1.1.2 mrg Return false if the processing of the worklist should stop
450 1.1.1.2 mrg (either due to reaching TARGET_ENODE, or hitting a limit).
451 1.1.1.2 mrg Write to *OUT_BEST_PATH if stopping due to finding a feasible path
452 1.1.1.2 mrg to TARGET_ENODE. */
453 1.1.1.2 mrg
454 1.1.1.2 mrg bool
455 1.1.1.2 mrg epath_finder::process_worklist_item (feasible_worklist *worklist,
456 1.1.1.2 mrg const trimmed_graph &tg,
457 1.1.1.2 mrg feasible_graph *fg,
458 1.1.1.2 mrg const exploded_node *target_enode,
459 1.1.1.2 mrg unsigned diag_idx,
460 1.1.1.2 mrg exploded_path **out_best_path) const
461 1.1.1.2 mrg {
462 1.1.1.2 mrg logger *logger = get_logger ();
463 1.1.1.2 mrg
464 1.1.1.2 mrg feasible_node *fnode = worklist->take_next ();
465 1.1.1.2 mrg if (!fnode)
466 1.1.1.2 mrg {
467 1.1.1.2 mrg if (logger)
468 1.1.1.2 mrg logger->log ("drained worklist for sd: %i"
469 1.1.1.2 mrg " without finding feasible path",
470 1.1.1.2 mrg diag_idx);
471 1.1.1.2 mrg return false;
472 1.1.1.2 mrg }
473 1.1.1.2 mrg
474 1.1.1.2 mrg log_scope s (logger, "fg worklist item",
475 1.1.1.2 mrg "considering FN: %i (EN: %i) for sd: %i",
476 1.1.1.2 mrg fnode->get_index (), fnode->get_inner_node ()->m_index,
477 1.1.1.2 mrg diag_idx);
478 1.1.1.2 mrg
479 1.1.1.2 mrg /* Iterate through all out-edges from this item. */
480 1.1.1.2 mrg unsigned i;
481 1.1.1.2 mrg exploded_edge *succ_eedge;
482 1.1.1.2 mrg FOR_EACH_VEC_ELT (fnode->get_inner_node ()->m_succs, i, succ_eedge)
483 1.1.1.2 mrg {
484 1.1.1.2 mrg log_scope s (logger, "edge", "considering edge: EN:%i -> EN:%i",
485 1.1.1.2 mrg succ_eedge->m_src->m_index,
486 1.1.1.2 mrg succ_eedge->m_dest->m_index);
487 1.1.1.2 mrg /* Reject edges that aren't in the trimmed graph. */
488 1.1.1.2 mrg if (!tg.contains_p (succ_eedge))
489 1.1.1.2 mrg {
490 1.1.1.2 mrg if (logger)
491 1.1.1.2 mrg logger->log ("rejecting: not in trimmed graph");
492 1.1.1.2 mrg continue;
493 1.1.1.2 mrg }
494 1.1.1.2 mrg
495 1.1.1.2 mrg feasibility_state succ_state (fnode->get_state ());
496 1.1.1.2 mrg rejected_constraint *rc = NULL;
497 1.1.1.2 mrg if (succ_state.maybe_update_for_edge (logger, succ_eedge, &rc))
498 1.1.1.2 mrg {
499 1.1.1.2 mrg gcc_assert (rc == NULL);
500 1.1.1.2 mrg feasible_node *succ_fnode
501 1.1.1.2 mrg = fg->add_node (succ_eedge->m_dest,
502 1.1.1.2 mrg succ_state,
503 1.1.1.2 mrg fnode->get_path_length () + 1);
504 1.1.1.2 mrg if (logger)
505 1.1.1.2 mrg logger->log ("accepting as FN: %i", succ_fnode->get_index ());
506 1.1.1.2 mrg fg->add_edge (new feasible_edge (fnode, succ_fnode, succ_eedge));
507 1.1.1.2 mrg
508 1.1.1.2 mrg /* Have we reached TARGET_ENODE? */
509 1.1.1.2 mrg if (succ_fnode->get_inner_node () == target_enode)
510 1.1.1.2 mrg {
511 1.1.1.2 mrg if (logger)
512 1.1.1.2 mrg logger->log ("success: got feasible path to EN: %i (sd: %i)"
513 1.1.1.2 mrg " (length: %i)",
514 1.1.1.2 mrg target_enode->m_index, diag_idx,
515 1.1.1.2 mrg succ_fnode->get_path_length ());
516 1.1.1.2 mrg *out_best_path = fg->make_epath (succ_fnode);
517 1.1.1.2 mrg if (flag_dump_analyzer_feasibility)
518 1.1.1.2 mrg dump_feasible_path (target_enode, diag_idx, *fg, *succ_fnode);
519 1.1.1.2 mrg
520 1.1.1.2 mrg /* Success: stop the worklist iteration. */
521 1.1.1.2 mrg return false;
522 1.1.1.2 mrg }
523 1.1.1.2 mrg else
524 1.1.1.2 mrg worklist->add_node (succ_fnode);
525 1.1.1.2 mrg }
526 1.1.1.2 mrg else
527 1.1.1.2 mrg {
528 1.1.1.2 mrg if (logger)
529 1.1.1.2 mrg logger->log ("infeasible");
530 1.1.1.2 mrg gcc_assert (rc);
531 1.1.1.2 mrg fg->add_feasibility_problem (fnode,
532 1.1.1.2 mrg succ_eedge,
533 1.1.1.2 mrg rc);
534 1.1.1.2 mrg
535 1.1.1.2 mrg /* Give up if there have been too many infeasible edges. */
536 1.1.1.2 mrg if (fg->get_num_infeasible ()
537 1.1.1.2 mrg > (unsigned)param_analyzer_max_infeasible_edges)
538 1.1.1.2 mrg {
539 1.1.1.2 mrg if (logger)
540 1.1.1.2 mrg logger->log ("too many infeasible edges (%i); giving up",
541 1.1.1.2 mrg fg->get_num_infeasible ());
542 1.1.1.2 mrg return false;
543 1.1.1.2 mrg }
544 1.1.1.2 mrg }
545 1.1.1.2 mrg }
546 1.1.1.2 mrg
547 1.1.1.2 mrg /* Continue the worklist iteration. */
548 1.1.1.2 mrg return true;
549 1.1.1.2 mrg }
550 1.1.1.2 mrg
551 1.1.1.2 mrg /* Helper class for epath_finder::dump_trimmed_graph
552 1.1.1.2 mrg to dump extra per-node information.
553 1.1.1.2 mrg Use SEP to add the length of the shortest path from each
554 1.1.1.2 mrg node to the target node to each node's dump. */
555 1.1.1.2 mrg
556 1.1.1.2 mrg class dump_eg_with_shortest_path : public eg_traits::dump_args_t
557 1.1.1.2 mrg {
558 1.1.1.2 mrg public:
559 1.1.1.2 mrg dump_eg_with_shortest_path
560 1.1.1.2 mrg (const exploded_graph &eg,
561 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &sep)
562 1.1.1.2 mrg : dump_args_t (eg),
563 1.1.1.2 mrg m_sep (sep)
564 1.1.1.2 mrg {
565 1.1.1.2 mrg }
566 1.1.1.2 mrg
567 1.1.1.2 mrg void dump_extra_info (const exploded_node *enode,
568 1.1.1.2 mrg pretty_printer *pp) const FINAL OVERRIDE
569 1.1.1.2 mrg {
570 1.1.1.2 mrg pp_printf (pp, "sp: %i", m_sep.get_shortest_path (enode).length ());
571 1.1.1.2 mrg pp_newline (pp);
572 1.1.1.2 mrg }
573 1.1.1.2 mrg
574 1.1.1.2 mrg private:
575 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &m_sep;
576 1.1.1.2 mrg };
577 1.1.1.2 mrg
578 1.1.1.2 mrg /* Dump TG to "BASE_NAME.DESC.DIAG_IDX.to-enN.tg.dot",
579 1.1.1.2 mrg annotating each node with the length of the shortest path
580 1.1.1.2 mrg from that node to TARGET_ENODE (using SEP). */
581 1.1.1.2 mrg
582 1.1.1.2 mrg void
583 1.1.1.2 mrg epath_finder::
584 1.1.1.2 mrg dump_trimmed_graph (const exploded_node *target_enode,
585 1.1.1.2 mrg const char *desc, unsigned diag_idx,
586 1.1.1.2 mrg const trimmed_graph &tg,
587 1.1.1.2 mrg const shortest_paths<eg_traits, exploded_path> &sep)
588 1.1.1.2 mrg {
589 1.1.1.2 mrg auto_timevar tv (TV_ANALYZER_DUMP);
590 1.1.1.2 mrg dump_eg_with_shortest_path inner_args (m_eg, sep);
591 1.1.1.2 mrg trimmed_graph::dump_args_t args (inner_args);
592 1.1.1.2 mrg pretty_printer pp;
593 1.1.1.2 mrg pp_printf (&pp, "%s.%s.%i.to-en%i.tg.dot",
594 1.1.1.2 mrg dump_base_name, desc, diag_idx, target_enode->m_index);
595 1.1.1.2 mrg char *filename = xstrdup (pp_formatted_text (&pp));
596 1.1.1.2 mrg tg.dump_dot (filename, NULL, args);
597 1.1.1.2 mrg free (filename);
598 1.1.1.2 mrg }
599 1.1.1.2 mrg
600 1.1.1.2 mrg /* Dump FG to "BASE_NAME.DESC.DIAG_IDX.to-enN.fg.dot". */
601 1.1.1.2 mrg
602 1.1.1.2 mrg void
603 1.1.1.2 mrg epath_finder::dump_feasible_graph (const exploded_node *target_enode,
604 1.1.1.2 mrg const char *desc, unsigned diag_idx,
605 1.1.1.2 mrg const feasible_graph &fg)
606 1.1.1.2 mrg {
607 1.1.1.2 mrg auto_timevar tv (TV_ANALYZER_DUMP);
608 1.1.1.2 mrg exploded_graph::dump_args_t inner_args (m_eg);
609 1.1.1.2 mrg feasible_graph::dump_args_t args (inner_args);
610 1.1.1.2 mrg pretty_printer pp;
611 1.1.1.2 mrg pp_printf (&pp, "%s.%s.%i.to-en%i.fg.dot",
612 1.1.1.2 mrg dump_base_name, desc, diag_idx, target_enode->m_index);
613 1.1.1.2 mrg char *filename = xstrdup (pp_formatted_text (&pp));
614 1.1.1.2 mrg fg.dump_dot (filename, NULL, args);
615 1.1.1.2 mrg free (filename);
616 1.1.1.2 mrg }
617 1.1.1.2 mrg
618 1.1.1.2 mrg /* Dump the path to FNODE to "BASE_NAME.DIAG_IDX.to-enN.fpath.txt". */
619 1.1.1.2 mrg
620 1.1.1.2 mrg void
621 1.1.1.2 mrg epath_finder::dump_feasible_path (const exploded_node *target_enode,
622 1.1.1.2 mrg unsigned diag_idx,
623 1.1.1.2 mrg const feasible_graph &fg,
624 1.1.1.2 mrg const feasible_node &fnode) const
625 1.1.1.2 mrg {
626 1.1.1.2 mrg auto_timevar tv (TV_ANALYZER_DUMP);
627 1.1.1.2 mrg pretty_printer pp;
628 1.1.1.2 mrg pp_printf (&pp, "%s.%i.to-en%i.fpath.txt",
629 1.1.1.2 mrg dump_base_name, diag_idx, target_enode->m_index);
630 1.1.1.2 mrg char *filename = xstrdup (pp_formatted_text (&pp));
631 1.1.1.2 mrg fg.dump_feasible_path (fnode, filename);
632 1.1.1.2 mrg free (filename);
633 1.1.1.2 mrg }
634 1.1.1.2 mrg
635 1.1 mrg /* class saved_diagnostic. */
636 1.1 mrg
637 1.1 mrg /* saved_diagnostic's ctor.
638 1.1 mrg Take ownership of D and STMT_FINDER. */
639 1.1 mrg
640 1.1 mrg saved_diagnostic::saved_diagnostic (const state_machine *sm,
641 1.1 mrg const exploded_node *enode,
642 1.1 mrg const supernode *snode, const gimple *stmt,
643 1.1 mrg stmt_finder *stmt_finder,
644 1.1.1.2 mrg tree var,
645 1.1.1.2 mrg const svalue *sval,
646 1.1.1.2 mrg state_machine::state_t state,
647 1.1.1.2 mrg pending_diagnostic *d,
648 1.1.1.2 mrg unsigned idx)
649 1.1 mrg : m_sm (sm), m_enode (enode), m_snode (snode), m_stmt (stmt),
650 1.1 mrg /* stmt_finder could be on-stack; we want our own copy that can
651 1.1 mrg outlive that. */
652 1.1 mrg m_stmt_finder (stmt_finder ? stmt_finder->clone () : NULL),
653 1.1.1.2 mrg m_var (var), m_sval (sval), m_state (state),
654 1.1 mrg m_d (d), m_trailing_eedge (NULL),
655 1.1.1.2 mrg m_idx (idx),
656 1.1.1.2 mrg m_best_epath (NULL), m_problem (NULL),
657 1.1.1.2 mrg m_notes ()
658 1.1 mrg {
659 1.1 mrg gcc_assert (m_stmt || m_stmt_finder);
660 1.1 mrg
661 1.1 mrg /* We must have an enode in order to be able to look for paths
662 1.1 mrg through the exploded_graph to this diagnostic. */
663 1.1 mrg gcc_assert (m_enode);
664 1.1 mrg }
665 1.1 mrg
666 1.1 mrg /* saved_diagnostic's dtor. */
667 1.1 mrg
668 1.1 mrg saved_diagnostic::~saved_diagnostic ()
669 1.1 mrg {
670 1.1 mrg delete m_stmt_finder;
671 1.1 mrg delete m_d;
672 1.1.1.2 mrg delete m_best_epath;
673 1.1 mrg delete m_problem;
674 1.1 mrg }
675 1.1 mrg
676 1.1 mrg bool
677 1.1 mrg saved_diagnostic::operator== (const saved_diagnostic &other) const
678 1.1 mrg {
679 1.1.1.2 mrg if (m_notes.length () != other.m_notes.length ())
680 1.1.1.2 mrg return false;
681 1.1.1.2 mrg for (unsigned i = 0; i < m_notes.length (); i++)
682 1.1.1.2 mrg if (!m_notes[i]->equal_p (*other.m_notes[i]))
683 1.1.1.2 mrg return false;
684 1.1 mrg return (m_sm == other.m_sm
685 1.1 mrg /* We don't compare m_enode. */
686 1.1 mrg && m_snode == other.m_snode
687 1.1 mrg && m_stmt == other.m_stmt
688 1.1 mrg /* We don't compare m_stmt_finder. */
689 1.1 mrg && pending_diagnostic::same_tree_p (m_var, other.m_var)
690 1.1 mrg && m_state == other.m_state
691 1.1 mrg && m_d->equal_p (*other.m_d)
692 1.1 mrg && m_trailing_eedge == other.m_trailing_eedge);
693 1.1 mrg }
694 1.1 mrg
695 1.1.1.2 mrg /* Add PN to this diagnostic, taking ownership of it. */
696 1.1.1.2 mrg
697 1.1.1.2 mrg void
698 1.1.1.2 mrg saved_diagnostic::add_note (pending_note *pn)
699 1.1.1.2 mrg {
700 1.1.1.2 mrg gcc_assert (pn);
701 1.1.1.2 mrg m_notes.safe_push (pn);
702 1.1.1.2 mrg }
703 1.1.1.2 mrg
704 1.1.1.2 mrg /* Return a new json::object of the form
705 1.1.1.2 mrg {"sm": optional str,
706 1.1.1.2 mrg "enode": int,
707 1.1.1.2 mrg "snode": int,
708 1.1.1.2 mrg "sval": optional str,
709 1.1.1.2 mrg "state": optional str,
710 1.1.1.2 mrg "path_length": optional int,
711 1.1.1.2 mrg "pending_diagnostic": str,
712 1.1.1.2 mrg "idx": int}. */
713 1.1.1.2 mrg
714 1.1.1.2 mrg json::object *
715 1.1.1.2 mrg saved_diagnostic::to_json () const
716 1.1.1.2 mrg {
717 1.1.1.2 mrg json::object *sd_obj = new json::object ();
718 1.1.1.2 mrg
719 1.1.1.2 mrg if (m_sm)
720 1.1.1.2 mrg sd_obj->set ("sm", new json::string (m_sm->get_name ()));
721 1.1.1.2 mrg sd_obj->set ("enode", new json::integer_number (m_enode->m_index));
722 1.1.1.2 mrg sd_obj->set ("snode", new json::integer_number (m_snode->m_index));
723 1.1.1.2 mrg if (m_sval)
724 1.1.1.2 mrg sd_obj->set ("sval", m_sval->to_json ());
725 1.1.1.2 mrg if (m_state)
726 1.1.1.2 mrg sd_obj->set ("state", m_state->to_json ());
727 1.1.1.2 mrg if (m_best_epath)
728 1.1.1.2 mrg sd_obj->set ("path_length", new json::integer_number (get_epath_length ()));
729 1.1.1.2 mrg sd_obj->set ("pending_diagnostic", new json::string (m_d->get_kind ()));
730 1.1.1.2 mrg sd_obj->set ("idx", new json::integer_number (m_idx));
731 1.1.1.2 mrg
732 1.1.1.2 mrg /* We're not yet JSONifying the following fields:
733 1.1.1.2 mrg const gimple *m_stmt;
734 1.1.1.2 mrg stmt_finder *m_stmt_finder;
735 1.1.1.2 mrg tree m_var;
736 1.1.1.2 mrg exploded_edge *m_trailing_eedge;
737 1.1.1.2 mrg enum status m_status;
738 1.1.1.2 mrg feasibility_problem *m_problem;
739 1.1.1.2 mrg auto_delete_vec <pending_note> m_notes;
740 1.1.1.2 mrg */
741 1.1.1.2 mrg
742 1.1.1.2 mrg return sd_obj;
743 1.1.1.2 mrg }
744 1.1.1.2 mrg
745 1.1.1.2 mrg /* Dump this to PP in a form suitable for use as an id in .dot output. */
746 1.1.1.2 mrg
747 1.1.1.2 mrg void
748 1.1.1.2 mrg saved_diagnostic::dump_dot_id (pretty_printer *pp) const
749 1.1.1.2 mrg {
750 1.1.1.2 mrg pp_printf (pp, "sd_%i", m_idx);
751 1.1.1.2 mrg }
752 1.1.1.2 mrg
753 1.1.1.2 mrg /* Dump this to PP in a form suitable for use as a node in .dot output. */
754 1.1.1.2 mrg
755 1.1.1.2 mrg void
756 1.1.1.2 mrg saved_diagnostic::dump_as_dot_node (pretty_printer *pp) const
757 1.1.1.2 mrg {
758 1.1.1.2 mrg dump_dot_id (pp);
759 1.1.1.2 mrg pp_printf (pp,
760 1.1.1.2 mrg " [shape=none,margin=0,style=filled,fillcolor=\"red\",label=\"");
761 1.1.1.2 mrg pp_write_text_to_stream (pp);
762 1.1.1.2 mrg
763 1.1.1.2 mrg /* Node label. */
764 1.1.1.2 mrg pp_printf (pp, "DIAGNOSTIC: %s (sd: %i)\n",
765 1.1.1.2 mrg m_d->get_kind (), m_idx);
766 1.1.1.2 mrg if (m_sm)
767 1.1.1.2 mrg {
768 1.1.1.2 mrg pp_printf (pp, "sm: %s", m_sm->get_name ());
769 1.1.1.2 mrg if (m_state)
770 1.1.1.2 mrg {
771 1.1.1.2 mrg pp_printf (pp, "; state: ");
772 1.1.1.2 mrg m_state->dump_to_pp (pp);
773 1.1.1.2 mrg }
774 1.1.1.2 mrg pp_newline (pp);
775 1.1.1.2 mrg }
776 1.1.1.2 mrg if (m_stmt)
777 1.1.1.2 mrg {
778 1.1.1.2 mrg pp_string (pp, "stmt: ");
779 1.1.1.2 mrg pp_gimple_stmt_1 (pp, m_stmt, 0, (dump_flags_t)0);
780 1.1.1.2 mrg pp_newline (pp);
781 1.1.1.2 mrg }
782 1.1.1.2 mrg if (m_var)
783 1.1.1.2 mrg pp_printf (pp, "var: %qE\n", m_var);
784 1.1.1.2 mrg if (m_sval)
785 1.1.1.2 mrg {
786 1.1.1.2 mrg pp_string (pp, "sval: ");
787 1.1.1.2 mrg m_sval->dump_to_pp (pp, true);
788 1.1.1.2 mrg pp_newline (pp);
789 1.1.1.2 mrg }
790 1.1.1.2 mrg if (m_best_epath)
791 1.1.1.2 mrg pp_printf (pp, "path length: %i\n", get_epath_length ());
792 1.1.1.2 mrg
793 1.1.1.2 mrg pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/true);
794 1.1.1.2 mrg pp_string (pp, "\"];\n\n");
795 1.1.1.2 mrg
796 1.1.1.2 mrg /* Show links to duplicates. */
797 1.1.1.2 mrg for (auto iter : m_duplicates)
798 1.1.1.2 mrg {
799 1.1.1.2 mrg dump_dot_id (pp);
800 1.1.1.2 mrg pp_string (pp, " -> ");
801 1.1.1.2 mrg iter->dump_dot_id (pp);
802 1.1.1.2 mrg pp_string (pp, " [style=\"dotted\" arrowhead=\"none\"];");
803 1.1.1.2 mrg pp_newline (pp);
804 1.1.1.2 mrg }
805 1.1.1.2 mrg }
806 1.1.1.2 mrg
807 1.1.1.2 mrg /* Use PF to find the best exploded_path for this saved_diagnostic,
808 1.1.1.2 mrg and store it in m_best_epath.
809 1.1.1.2 mrg If m_stmt is still NULL, use m_stmt_finder on the epath to populate
810 1.1.1.2 mrg m_stmt.
811 1.1.1.2 mrg Return true if a best path was found. */
812 1.1.1.2 mrg
813 1.1.1.2 mrg bool
814 1.1.1.2 mrg saved_diagnostic::calc_best_epath (epath_finder *pf)
815 1.1.1.2 mrg {
816 1.1.1.2 mrg logger *logger = pf->get_logger ();
817 1.1.1.2 mrg LOG_SCOPE (logger);
818 1.1.1.2 mrg delete m_best_epath;
819 1.1.1.2 mrg delete m_problem;
820 1.1.1.2 mrg m_problem = NULL;
821 1.1.1.2 mrg
822 1.1.1.2 mrg m_best_epath = pf->get_best_epath (m_enode, m_d->get_kind (), m_idx,
823 1.1.1.2 mrg &m_problem);
824 1.1.1.2 mrg
825 1.1.1.2 mrg /* Handle failure to find a feasible path. */
826 1.1.1.2 mrg if (m_best_epath == NULL)
827 1.1.1.2 mrg return false;
828 1.1.1.2 mrg
829 1.1.1.2 mrg gcc_assert (m_best_epath);
830 1.1.1.2 mrg if (m_stmt == NULL)
831 1.1.1.2 mrg {
832 1.1.1.2 mrg gcc_assert (m_stmt_finder);
833 1.1.1.2 mrg m_stmt = m_stmt_finder->find_stmt (*m_best_epath);
834 1.1.1.2 mrg }
835 1.1.1.2 mrg gcc_assert (m_stmt);
836 1.1.1.2 mrg
837 1.1.1.2 mrg return true;
838 1.1.1.2 mrg }
839 1.1.1.2 mrg
840 1.1.1.2 mrg unsigned
841 1.1.1.2 mrg saved_diagnostic::get_epath_length () const
842 1.1.1.2 mrg {
843 1.1.1.2 mrg gcc_assert (m_best_epath);
844 1.1.1.2 mrg return m_best_epath->length ();
845 1.1.1.2 mrg }
846 1.1.1.2 mrg
847 1.1.1.2 mrg /* Record that OTHER (and its duplicates) are duplicates
848 1.1.1.2 mrg of this saved_diagnostic. */
849 1.1.1.2 mrg
850 1.1.1.2 mrg void
851 1.1.1.2 mrg saved_diagnostic::add_duplicate (saved_diagnostic *other)
852 1.1.1.2 mrg {
853 1.1.1.2 mrg gcc_assert (other);
854 1.1.1.2 mrg m_duplicates.reserve (m_duplicates.length ()
855 1.1.1.2 mrg + other->m_duplicates.length ()
856 1.1.1.2 mrg + 1);
857 1.1.1.2 mrg m_duplicates.splice (other->m_duplicates);
858 1.1.1.2 mrg other->m_duplicates.truncate (0);
859 1.1.1.2 mrg m_duplicates.safe_push (other);
860 1.1.1.2 mrg }
861 1.1.1.2 mrg
862 1.1.1.2 mrg /* Return true if this diagnostic supercedes OTHER, and that OTHER should
863 1.1.1.2 mrg therefore not be emitted. */
864 1.1.1.2 mrg
865 1.1.1.2 mrg bool
866 1.1.1.2 mrg saved_diagnostic::supercedes_p (const saved_diagnostic &other) const
867 1.1.1.2 mrg {
868 1.1.1.2 mrg /* They should be at the same stmt. */
869 1.1.1.2 mrg if (m_stmt != other.m_stmt)
870 1.1.1.2 mrg return false;
871 1.1.1.2 mrg return m_d->supercedes_p (*other.m_d);
872 1.1.1.2 mrg }
873 1.1.1.2 mrg
874 1.1.1.2 mrg /* Emit any pending notes owned by this diagnostic. */
875 1.1.1.2 mrg
876 1.1.1.2 mrg void
877 1.1.1.2 mrg saved_diagnostic::emit_any_notes () const
878 1.1.1.2 mrg {
879 1.1.1.2 mrg for (auto pn : m_notes)
880 1.1.1.2 mrg pn->emit ();
881 1.1.1.2 mrg }
882 1.1.1.2 mrg
883 1.1 mrg /* State for building a checker_path from a particular exploded_path.
884 1.1 mrg In particular, this precomputes reachability information: the set of
885 1.1 mrg source enodes for which a path be found to the diagnostic enode. */
886 1.1 mrg
887 1.1 mrg class path_builder
888 1.1 mrg {
889 1.1 mrg public:
890 1.1 mrg path_builder (const exploded_graph &eg,
891 1.1.1.2 mrg const exploded_path &epath,
892 1.1.1.2 mrg const feasibility_problem *problem,
893 1.1.1.2 mrg const saved_diagnostic &sd)
894 1.1 mrg : m_eg (eg),
895 1.1 mrg m_diag_enode (epath.get_final_enode ()),
896 1.1.1.2 mrg m_sd (sd),
897 1.1.1.2 mrg m_reachability (eg, m_diag_enode),
898 1.1.1.2 mrg m_feasibility_problem (problem)
899 1.1 mrg {}
900 1.1 mrg
901 1.1 mrg const exploded_node *get_diag_node () const { return m_diag_enode; }
902 1.1 mrg
903 1.1.1.2 mrg pending_diagnostic *get_pending_diagnostic () const
904 1.1.1.2 mrg {
905 1.1.1.2 mrg return m_sd.m_d;
906 1.1.1.2 mrg }
907 1.1.1.2 mrg
908 1.1 mrg bool reachable_from_p (const exploded_node *src_enode) const
909 1.1 mrg {
910 1.1 mrg return m_reachability.reachable_from_p (src_enode);
911 1.1 mrg }
912 1.1 mrg
913 1.1 mrg const extrinsic_state &get_ext_state () const { return m_eg.get_ext_state (); }
914 1.1 mrg
915 1.1.1.2 mrg const feasibility_problem *get_feasibility_problem () const
916 1.1.1.2 mrg {
917 1.1.1.2 mrg return m_feasibility_problem;
918 1.1.1.2 mrg }
919 1.1.1.2 mrg
920 1.1.1.2 mrg const state_machine *get_sm () const { return m_sd.m_sm; }
921 1.1.1.2 mrg
922 1.1 mrg private:
923 1.1 mrg typedef reachability<eg_traits> enode_reachability;
924 1.1 mrg
925 1.1 mrg const exploded_graph &m_eg;
926 1.1 mrg
927 1.1 mrg /* The enode where the diagnostic occurs. */
928 1.1 mrg const exploded_node *m_diag_enode;
929 1.1 mrg
930 1.1.1.2 mrg const saved_diagnostic &m_sd;
931 1.1.1.2 mrg
932 1.1 mrg /* Precompute all enodes from which the diagnostic is reachable. */
933 1.1 mrg enode_reachability m_reachability;
934 1.1.1.2 mrg
935 1.1.1.2 mrg const feasibility_problem *m_feasibility_problem;
936 1.1 mrg };
937 1.1 mrg
938 1.1.1.2 mrg /* Determine the emission location for PD at STMT in FUN. */
939 1.1.1.2 mrg
940 1.1.1.2 mrg static location_t
941 1.1.1.2 mrg get_emission_location (const gimple *stmt, function *fun,
942 1.1.1.2 mrg const pending_diagnostic &pd)
943 1.1.1.2 mrg {
944 1.1.1.2 mrg location_t loc = get_stmt_location (stmt, fun);
945 1.1.1.2 mrg
946 1.1.1.2 mrg /* Allow the pending_diagnostic to fix up the location. */
947 1.1.1.2 mrg loc = pd.fixup_location (loc);
948 1.1.1.2 mrg
949 1.1.1.2 mrg return loc;
950 1.1.1.2 mrg }
951 1.1.1.2 mrg
952 1.1 mrg /* class diagnostic_manager. */
953 1.1 mrg
954 1.1 mrg /* diagnostic_manager's ctor. */
955 1.1 mrg
956 1.1.1.2 mrg diagnostic_manager::diagnostic_manager (logger *logger, engine *eng,
957 1.1.1.2 mrg int verbosity)
958 1.1.1.2 mrg : log_user (logger), m_eng (eng), m_verbosity (verbosity),
959 1.1.1.2 mrg m_num_disabled_diagnostics (0)
960 1.1 mrg {
961 1.1 mrg }
962 1.1 mrg
963 1.1.1.2 mrg /* Queue pending_diagnostic D at ENODE for later emission.
964 1.1.1.2 mrg Return true/false signifying if the diagnostic was actually added.
965 1.1.1.2 mrg Take ownership of D (or delete it). */
966 1.1 mrg
967 1.1.1.2 mrg bool
968 1.1 mrg diagnostic_manager::add_diagnostic (const state_machine *sm,
969 1.1.1.2 mrg exploded_node *enode,
970 1.1 mrg const supernode *snode, const gimple *stmt,
971 1.1 mrg stmt_finder *finder,
972 1.1.1.2 mrg tree var,
973 1.1.1.2 mrg const svalue *sval,
974 1.1.1.2 mrg state_machine::state_t state,
975 1.1 mrg pending_diagnostic *d)
976 1.1 mrg {
977 1.1 mrg LOG_FUNC (get_logger ());
978 1.1 mrg
979 1.1 mrg /* We must have an enode in order to be able to look for paths
980 1.1 mrg through the exploded_graph to the diagnostic. */
981 1.1 mrg gcc_assert (enode);
982 1.1 mrg
983 1.1.1.2 mrg /* If this warning is ultimately going to be rejected by a -Wno-analyzer-*
984 1.1.1.2 mrg flag, reject it now.
985 1.1.1.2 mrg We can only do this for diagnostics where we already know the stmt,
986 1.1.1.2 mrg and thus can determine the emission location. */
987 1.1.1.2 mrg if (stmt)
988 1.1.1.2 mrg {
989 1.1.1.2 mrg location_t loc = get_emission_location (stmt, snode->m_fun, *d);
990 1.1.1.2 mrg int option = d->get_controlling_option ();
991 1.1.1.2 mrg if (!warning_enabled_at (loc, option))
992 1.1.1.2 mrg {
993 1.1.1.2 mrg if (get_logger ())
994 1.1.1.2 mrg get_logger ()->log ("rejecting disabled warning %qs",
995 1.1.1.2 mrg d->get_kind ());
996 1.1.1.2 mrg delete d;
997 1.1.1.2 mrg m_num_disabled_diagnostics++;
998 1.1.1.2 mrg return false;
999 1.1.1.2 mrg }
1000 1.1.1.2 mrg }
1001 1.1.1.2 mrg
1002 1.1 mrg saved_diagnostic *sd
1003 1.1.1.2 mrg = new saved_diagnostic (sm, enode, snode, stmt, finder, var, sval,
1004 1.1.1.2 mrg state, d, m_saved_diagnostics.length ());
1005 1.1 mrg m_saved_diagnostics.safe_push (sd);
1006 1.1.1.2 mrg enode->add_diagnostic (sd);
1007 1.1 mrg if (get_logger ())
1008 1.1.1.2 mrg log ("adding saved diagnostic %i at SN %i to EN %i: %qs",
1009 1.1.1.2 mrg sd->get_index (),
1010 1.1.1.2 mrg snode->m_index, enode->m_index, d->get_kind ());
1011 1.1.1.2 mrg return true;
1012 1.1 mrg }
1013 1.1 mrg
1014 1.1.1.2 mrg /* Queue pending_diagnostic D at ENODE for later emission.
1015 1.1.1.2 mrg Return true/false signifying if the diagnostic was actually added.
1016 1.1.1.2 mrg Take ownership of D (or delete it). */
1017 1.1 mrg
1018 1.1.1.2 mrg bool
1019 1.1.1.2 mrg diagnostic_manager::add_diagnostic (exploded_node *enode,
1020 1.1 mrg const supernode *snode, const gimple *stmt,
1021 1.1 mrg stmt_finder *finder,
1022 1.1 mrg pending_diagnostic *d)
1023 1.1 mrg {
1024 1.1 mrg gcc_assert (enode);
1025 1.1.1.2 mrg return add_diagnostic (NULL, enode, snode, stmt, finder, NULL_TREE,
1026 1.1.1.2 mrg NULL, 0, d);
1027 1.1.1.2 mrg }
1028 1.1.1.2 mrg
1029 1.1.1.2 mrg /* Add PN to the most recent saved_diagnostic. */
1030 1.1.1.2 mrg
1031 1.1.1.2 mrg void
1032 1.1.1.2 mrg diagnostic_manager::add_note (pending_note *pn)
1033 1.1.1.2 mrg {
1034 1.1.1.2 mrg LOG_FUNC (get_logger ());
1035 1.1.1.2 mrg gcc_assert (pn);
1036 1.1.1.2 mrg
1037 1.1.1.2 mrg /* Get most recent saved_diagnostic. */
1038 1.1.1.2 mrg gcc_assert (m_saved_diagnostics.length () > 0);
1039 1.1.1.2 mrg saved_diagnostic *sd = m_saved_diagnostics[m_saved_diagnostics.length () - 1];
1040 1.1.1.2 mrg sd->add_note (pn);
1041 1.1.1.2 mrg }
1042 1.1.1.2 mrg
1043 1.1.1.2 mrg /* Return a new json::object of the form
1044 1.1.1.2 mrg {"diagnostics" : [obj for saved_diagnostic]}. */
1045 1.1.1.2 mrg
1046 1.1.1.2 mrg json::object *
1047 1.1.1.2 mrg diagnostic_manager::to_json () const
1048 1.1.1.2 mrg {
1049 1.1.1.2 mrg json::object *dm_obj = new json::object ();
1050 1.1.1.2 mrg
1051 1.1.1.2 mrg {
1052 1.1.1.2 mrg json::array *sd_arr = new json::array ();
1053 1.1.1.2 mrg int i;
1054 1.1.1.2 mrg saved_diagnostic *sd;
1055 1.1.1.2 mrg FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1056 1.1.1.2 mrg sd_arr->append (sd->to_json ());
1057 1.1.1.2 mrg dm_obj->set ("diagnostics", sd_arr);
1058 1.1.1.2 mrg }
1059 1.1.1.2 mrg
1060 1.1.1.2 mrg return dm_obj;
1061 1.1 mrg }
1062 1.1 mrg
1063 1.1 mrg /* A class for identifying sets of duplicated pending_diagnostic.
1064 1.1 mrg
1065 1.1.1.2 mrg We want to find the simplest saved_diagnostic amongst those that share a
1066 1.1 mrg dedupe_key. */
1067 1.1 mrg
1068 1.1 mrg class dedupe_key
1069 1.1 mrg {
1070 1.1 mrg public:
1071 1.1.1.2 mrg dedupe_key (const saved_diagnostic &sd)
1072 1.1 mrg : m_sd (sd), m_stmt (sd.m_stmt)
1073 1.1 mrg {
1074 1.1 mrg gcc_assert (m_stmt);
1075 1.1 mrg }
1076 1.1 mrg
1077 1.1 mrg hashval_t hash () const
1078 1.1 mrg {
1079 1.1 mrg inchash::hash hstate;
1080 1.1 mrg hstate.add_ptr (m_stmt);
1081 1.1 mrg // TODO: m_sd
1082 1.1 mrg return hstate.end ();
1083 1.1 mrg }
1084 1.1 mrg bool operator== (const dedupe_key &other) const
1085 1.1 mrg {
1086 1.1 mrg return (m_sd == other.m_sd
1087 1.1 mrg && m_stmt == other.m_stmt);
1088 1.1 mrg }
1089 1.1 mrg
1090 1.1 mrg location_t get_location () const
1091 1.1 mrg {
1092 1.1 mrg return m_stmt->location;
1093 1.1 mrg }
1094 1.1 mrg
1095 1.1 mrg /* A qsort comparator for use by dedupe_winners::emit_best
1096 1.1 mrg to sort them into location_t order. */
1097 1.1 mrg
1098 1.1 mrg static int
1099 1.1 mrg comparator (const void *p1, const void *p2)
1100 1.1 mrg {
1101 1.1 mrg const dedupe_key *pk1 = *(const dedupe_key * const *)p1;
1102 1.1 mrg const dedupe_key *pk2 = *(const dedupe_key * const *)p2;
1103 1.1 mrg
1104 1.1 mrg location_t loc1 = pk1->get_location ();
1105 1.1 mrg location_t loc2 = pk2->get_location ();
1106 1.1 mrg
1107 1.1.1.2 mrg if (int cmp = linemap_compare_locations (line_table, loc2, loc1))
1108 1.1.1.2 mrg return cmp;
1109 1.1.1.2 mrg if (int cmp = ((int)pk1->m_sd.get_epath_length ()
1110 1.1.1.2 mrg - (int)pk2->m_sd.get_epath_length ()))
1111 1.1.1.2 mrg return cmp;
1112 1.1.1.2 mrg if (int cmp = strcmp (pk1->m_sd.m_d->get_kind (),
1113 1.1.1.2 mrg pk2->m_sd.m_d->get_kind ()))
1114 1.1.1.2 mrg return cmp;
1115 1.1.1.2 mrg return 0;
1116 1.1 mrg }
1117 1.1 mrg
1118 1.1 mrg const saved_diagnostic &m_sd;
1119 1.1 mrg const gimple *m_stmt;
1120 1.1 mrg };
1121 1.1 mrg
1122 1.1 mrg /* Traits for use by dedupe_winners. */
1123 1.1 mrg
1124 1.1 mrg class dedupe_hash_map_traits
1125 1.1 mrg {
1126 1.1 mrg public:
1127 1.1 mrg typedef const dedupe_key *key_type;
1128 1.1.1.2 mrg typedef saved_diagnostic *value_type;
1129 1.1.1.2 mrg typedef saved_diagnostic *compare_type;
1130 1.1 mrg
1131 1.1 mrg static inline hashval_t hash (const key_type &v)
1132 1.1 mrg {
1133 1.1 mrg return v->hash ();
1134 1.1 mrg }
1135 1.1 mrg static inline bool equal_keys (const key_type &k1, const key_type &k2)
1136 1.1 mrg {
1137 1.1 mrg return *k1 == *k2;
1138 1.1 mrg }
1139 1.1 mrg template <typename T>
1140 1.1 mrg static inline void remove (T &)
1141 1.1 mrg {
1142 1.1 mrg // TODO
1143 1.1 mrg }
1144 1.1 mrg template <typename T>
1145 1.1 mrg static inline void mark_deleted (T &entry)
1146 1.1 mrg {
1147 1.1 mrg entry.m_key = reinterpret_cast<key_type> (1);
1148 1.1 mrg }
1149 1.1 mrg template <typename T>
1150 1.1 mrg static inline void mark_empty (T &entry)
1151 1.1 mrg {
1152 1.1 mrg entry.m_key = NULL;
1153 1.1 mrg }
1154 1.1 mrg template <typename T>
1155 1.1 mrg static inline bool is_deleted (const T &entry)
1156 1.1 mrg {
1157 1.1 mrg return entry.m_key == reinterpret_cast<key_type> (1);
1158 1.1 mrg }
1159 1.1 mrg template <typename T>
1160 1.1 mrg static inline bool is_empty (const T &entry)
1161 1.1 mrg {
1162 1.1 mrg return entry.m_key == NULL;
1163 1.1 mrg }
1164 1.1 mrg static const bool empty_zero_p = true;
1165 1.1 mrg };
1166 1.1 mrg
1167 1.1 mrg /* A class for deduplicating diagnostics and finding (and emitting) the
1168 1.1.1.2 mrg best saved_diagnostic within each partition. */
1169 1.1 mrg
1170 1.1 mrg class dedupe_winners
1171 1.1 mrg {
1172 1.1 mrg public:
1173 1.1 mrg ~dedupe_winners ()
1174 1.1 mrg {
1175 1.1.1.2 mrg /* Delete all keys, but not the saved_diagnostics. */
1176 1.1 mrg for (map_t::iterator iter = m_map.begin ();
1177 1.1 mrg iter != m_map.end ();
1178 1.1 mrg ++iter)
1179 1.1.1.2 mrg delete (*iter).first;
1180 1.1 mrg }
1181 1.1 mrg
1182 1.1.1.2 mrg /* Determine an exploded_path for SD using PF and, if it's feasible,
1183 1.1.1.2 mrg determine if SD is the best seen so far for its dedupe_key.
1184 1.1.1.2 mrg Record the winning SD for each dedupe_key. */
1185 1.1 mrg
1186 1.1 mrg void add (logger *logger,
1187 1.1.1.2 mrg epath_finder *pf,
1188 1.1 mrg saved_diagnostic *sd)
1189 1.1 mrg {
1190 1.1.1.2 mrg /* Determine best epath for SD. */
1191 1.1.1.2 mrg if (!sd->calc_best_epath (pf))
1192 1.1.1.2 mrg return;
1193 1.1 mrg
1194 1.1.1.2 mrg dedupe_key *key = new dedupe_key (*sd);
1195 1.1.1.2 mrg if (saved_diagnostic **slot = m_map.get (key))
1196 1.1 mrg {
1197 1.1 mrg if (logger)
1198 1.1 mrg logger->log ("already have this dedupe_key");
1199 1.1 mrg
1200 1.1.1.2 mrg saved_diagnostic *cur_best_sd = *slot;
1201 1.1 mrg
1202 1.1.1.2 mrg if (sd->get_epath_length () < cur_best_sd->get_epath_length ())
1203 1.1 mrg {
1204 1.1 mrg /* We've got a shorter path for the key; replace
1205 1.1.1.2 mrg the current candidate, marking it as a duplicate of SD. */
1206 1.1 mrg if (logger)
1207 1.1 mrg logger->log ("length %i is better than existing length %i;"
1208 1.1 mrg " taking over this dedupe_key",
1209 1.1.1.2 mrg sd->get_epath_length (),
1210 1.1.1.2 mrg cur_best_sd->get_epath_length ());
1211 1.1.1.2 mrg sd->add_duplicate (cur_best_sd);
1212 1.1.1.2 mrg *slot = sd;
1213 1.1 mrg }
1214 1.1 mrg else
1215 1.1.1.2 mrg /* We haven't beaten the current best candidate; add SD
1216 1.1.1.2 mrg as a duplicate of it. */
1217 1.1 mrg {
1218 1.1 mrg if (logger)
1219 1.1 mrg logger->log ("length %i isn't better than existing length %i;"
1220 1.1 mrg " dropping this candidate",
1221 1.1.1.2 mrg sd->get_epath_length (),
1222 1.1.1.2 mrg cur_best_sd->get_epath_length ());
1223 1.1.1.2 mrg cur_best_sd->add_duplicate (sd);
1224 1.1 mrg }
1225 1.1 mrg delete key;
1226 1.1 mrg }
1227 1.1 mrg else
1228 1.1 mrg {
1229 1.1 mrg /* This is the first candidate for this key. */
1230 1.1.1.2 mrg m_map.put (key, sd);
1231 1.1 mrg if (logger)
1232 1.1 mrg logger->log ("first candidate for this dedupe_key");
1233 1.1 mrg }
1234 1.1 mrg }
1235 1.1 mrg
1236 1.1.1.2 mrg /* Handle interactions between the dedupe winners, so that some
1237 1.1.1.2 mrg diagnostics can supercede others (of different kinds).
1238 1.1.1.2 mrg
1239 1.1.1.2 mrg We want use-after-free to supercede use-of-unitialized-value,
1240 1.1.1.2 mrg so that if we have these at the same stmt, we don't emit
1241 1.1.1.2 mrg a use-of-uninitialized, just the use-after-free. */
1242 1.1.1.2 mrg
1243 1.1.1.2 mrg void handle_interactions (diagnostic_manager *dm)
1244 1.1.1.2 mrg {
1245 1.1.1.2 mrg LOG_SCOPE (dm->get_logger ());
1246 1.1.1.2 mrg auto_vec<const dedupe_key *> superceded;
1247 1.1.1.2 mrg for (auto outer : m_map)
1248 1.1.1.2 mrg {
1249 1.1.1.2 mrg const saved_diagnostic *outer_sd = outer.second;
1250 1.1.1.2 mrg for (auto inner : m_map)
1251 1.1.1.2 mrg {
1252 1.1.1.2 mrg const saved_diagnostic *inner_sd = inner.second;
1253 1.1.1.2 mrg if (inner_sd->supercedes_p (*outer_sd))
1254 1.1.1.2 mrg {
1255 1.1.1.2 mrg superceded.safe_push (outer.first);
1256 1.1.1.2 mrg if (dm->get_logger ())
1257 1.1.1.2 mrg dm->log ("sd[%i] \"%s\" superceded by sd[%i] \"%s\"",
1258 1.1.1.2 mrg outer_sd->get_index (), outer_sd->m_d->get_kind (),
1259 1.1.1.2 mrg inner_sd->get_index (), inner_sd->m_d->get_kind ());
1260 1.1.1.2 mrg break;
1261 1.1.1.2 mrg }
1262 1.1.1.2 mrg }
1263 1.1.1.2 mrg }
1264 1.1.1.2 mrg for (auto iter : superceded)
1265 1.1.1.2 mrg m_map.remove (iter);
1266 1.1.1.2 mrg }
1267 1.1.1.2 mrg
1268 1.1 mrg /* Emit the simplest diagnostic within each set. */
1269 1.1 mrg
1270 1.1 mrg void emit_best (diagnostic_manager *dm,
1271 1.1 mrg const exploded_graph &eg)
1272 1.1 mrg {
1273 1.1 mrg LOG_SCOPE (dm->get_logger ());
1274 1.1 mrg
1275 1.1 mrg /* Get keys into a vec for sorting. */
1276 1.1 mrg auto_vec<const dedupe_key *> keys (m_map.elements ());
1277 1.1 mrg for (map_t::iterator iter = m_map.begin ();
1278 1.1 mrg iter != m_map.end ();
1279 1.1 mrg ++iter)
1280 1.1 mrg keys.quick_push ((*iter).first);
1281 1.1 mrg
1282 1.1 mrg dm->log ("# keys after de-duplication: %i", keys.length ());
1283 1.1 mrg
1284 1.1 mrg /* Sort into a good emission order. */
1285 1.1 mrg keys.qsort (dedupe_key::comparator);
1286 1.1 mrg
1287 1.1.1.2 mrg /* Emit the best saved_diagnostics for each key. */
1288 1.1 mrg int i;
1289 1.1 mrg const dedupe_key *key;
1290 1.1 mrg FOR_EACH_VEC_ELT (keys, i, key)
1291 1.1 mrg {
1292 1.1.1.2 mrg saved_diagnostic **slot = m_map.get (key);
1293 1.1 mrg gcc_assert (*slot);
1294 1.1.1.2 mrg const saved_diagnostic *sd = *slot;
1295 1.1.1.2 mrg dm->emit_saved_diagnostic (eg, *sd);
1296 1.1 mrg }
1297 1.1 mrg }
1298 1.1 mrg
1299 1.1 mrg private:
1300 1.1.1.2 mrg /* This maps from each dedupe_key to a current best saved_diagnostic. */
1301 1.1 mrg
1302 1.1.1.2 mrg typedef hash_map<const dedupe_key *, saved_diagnostic *,
1303 1.1 mrg dedupe_hash_map_traits> map_t;
1304 1.1 mrg map_t m_map;
1305 1.1 mrg };
1306 1.1 mrg
1307 1.1 mrg /* Emit all saved diagnostics. */
1308 1.1 mrg
1309 1.1 mrg void
1310 1.1 mrg diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
1311 1.1 mrg {
1312 1.1 mrg LOG_SCOPE (get_logger ());
1313 1.1 mrg auto_timevar tv (TV_ANALYZER_DIAGNOSTICS);
1314 1.1 mrg log ("# saved diagnostics: %i", m_saved_diagnostics.length ());
1315 1.1.1.2 mrg log ("# disabled diagnostics: %i", m_num_disabled_diagnostics);
1316 1.1 mrg if (get_logger ())
1317 1.1 mrg {
1318 1.1 mrg unsigned i;
1319 1.1 mrg saved_diagnostic *sd;
1320 1.1 mrg FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1321 1.1 mrg log ("[%i] sd: %qs at EN: %i, SN: %i",
1322 1.1 mrg i, sd->m_d->get_kind (), sd->m_enode->m_index,
1323 1.1 mrg sd->m_snode->m_index);
1324 1.1 mrg }
1325 1.1 mrg
1326 1.1 mrg if (m_saved_diagnostics.length () == 0)
1327 1.1 mrg return;
1328 1.1 mrg
1329 1.1 mrg /* Compute the shortest_paths once, sharing it between all diagnostics. */
1330 1.1.1.2 mrg epath_finder pf (eg);
1331 1.1 mrg
1332 1.1 mrg /* Iterate through all saved diagnostics, adding them to a dedupe_winners
1333 1.1 mrg instance. This partitions the saved diagnostics by dedupe_key,
1334 1.1 mrg generating exploded_paths for them, and retaining the best one in each
1335 1.1 mrg partition. */
1336 1.1 mrg dedupe_winners best_candidates;
1337 1.1 mrg
1338 1.1 mrg int i;
1339 1.1 mrg saved_diagnostic *sd;
1340 1.1 mrg FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
1341 1.1.1.2 mrg best_candidates.add (get_logger (), &pf, sd);
1342 1.1.1.2 mrg
1343 1.1.1.2 mrg best_candidates.handle_interactions (this);
1344 1.1 mrg
1345 1.1 mrg /* For each dedupe-key, call emit_saved_diagnostic on the "best"
1346 1.1 mrg saved_diagnostic. */
1347 1.1 mrg best_candidates.emit_best (this, eg);
1348 1.1 mrg }
1349 1.1 mrg
1350 1.1.1.2 mrg /* Given a saved_diagnostic SD with m_best_epath through EG,
1351 1.1 mrg create an checker_path of suitable events and use it to call
1352 1.1 mrg SD's underlying pending_diagnostic "emit" vfunc to emit a diagnostic. */
1353 1.1 mrg
1354 1.1 mrg void
1355 1.1 mrg diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
1356 1.1.1.2 mrg const saved_diagnostic &sd)
1357 1.1 mrg {
1358 1.1 mrg LOG_SCOPE (get_logger ());
1359 1.1 mrg log ("sd: %qs at SN: %i", sd.m_d->get_kind (), sd.m_snode->m_index);
1360 1.1.1.2 mrg log ("num dupes: %i", sd.get_num_dupes ());
1361 1.1 mrg
1362 1.1 mrg pretty_printer *pp = global_dc->printer->clone ();
1363 1.1 mrg
1364 1.1.1.2 mrg const exploded_path *epath = sd.get_best_epath ();
1365 1.1.1.2 mrg gcc_assert (epath);
1366 1.1.1.2 mrg
1367 1.1 mrg /* Precompute all enodes from which the diagnostic is reachable. */
1368 1.1.1.2 mrg path_builder pb (eg, *epath, sd.get_feasibility_problem (), sd);
1369 1.1 mrg
1370 1.1 mrg /* This is the diagnostic_path subclass that will be built for
1371 1.1 mrg the diagnostic. */
1372 1.1 mrg checker_path emission_path;
1373 1.1 mrg
1374 1.1 mrg /* Populate emission_path with a full description of EPATH. */
1375 1.1.1.2 mrg build_emission_path (pb, *epath, &emission_path);
1376 1.1 mrg
1377 1.1 mrg /* Now prune it to just cover the most pertinent events. */
1378 1.1.1.2 mrg prune_path (&emission_path, sd.m_sm, sd.m_sval, sd.m_state);
1379 1.1 mrg
1380 1.1 mrg /* Add a final event to the path, covering the diagnostic itself.
1381 1.1 mrg We use the final enode from the epath, which might be different from
1382 1.1 mrg the sd.m_enode, as the dedupe code doesn't care about enodes, just
1383 1.1 mrg snodes. */
1384 1.1.1.2 mrg emission_path.add_final_event (sd.m_sm, epath->get_final_enode (), sd.m_stmt,
1385 1.1 mrg sd.m_var, sd.m_state);
1386 1.1 mrg
1387 1.1 mrg /* The "final" event might not be final; if the saved_diagnostic has a
1388 1.1 mrg trailing eedge stashed, add any events for it. This is for use
1389 1.1 mrg in handling longjmp, to show where a longjmp is rewinding to. */
1390 1.1 mrg if (sd.m_trailing_eedge)
1391 1.1.1.2 mrg add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path, NULL);
1392 1.1 mrg
1393 1.1 mrg emission_path.prepare_for_emission (sd.m_d);
1394 1.1 mrg
1395 1.1.1.2 mrg location_t loc
1396 1.1.1.2 mrg = get_emission_location (sd.m_stmt, sd.m_snode->m_fun, *sd.m_d);
1397 1.1.1.2 mrg
1398 1.1.1.2 mrg /* Allow the pending_diagnostic to fix up the locations of events. */
1399 1.1.1.2 mrg emission_path.fixup_locations (sd.m_d);
1400 1.1.1.2 mrg
1401 1.1.1.2 mrg gcc_rich_location rich_loc (loc);
1402 1.1 mrg rich_loc.set_path (&emission_path);
1403 1.1 mrg
1404 1.1 mrg auto_diagnostic_group d;
1405 1.1 mrg auto_cfun sentinel (sd.m_snode->m_fun);
1406 1.1 mrg if (sd.m_d->emit (&rich_loc))
1407 1.1 mrg {
1408 1.1.1.2 mrg sd.emit_any_notes ();
1409 1.1.1.2 mrg
1410 1.1.1.2 mrg unsigned num_dupes = sd.get_num_dupes ();
1411 1.1 mrg if (flag_analyzer_show_duplicate_count && num_dupes > 0)
1412 1.1.1.2 mrg inform_n (loc, num_dupes,
1413 1.1 mrg "%i duplicate", "%i duplicates",
1414 1.1 mrg num_dupes);
1415 1.1.1.2 mrg if (flag_dump_analyzer_exploded_paths)
1416 1.1.1.2 mrg {
1417 1.1.1.2 mrg auto_timevar tv (TV_ANALYZER_DUMP);
1418 1.1.1.2 mrg pretty_printer pp;
1419 1.1.1.2 mrg pp_printf (&pp, "%s.%i.%s.epath.txt",
1420 1.1.1.2 mrg dump_base_name, sd.get_index (), sd.m_d->get_kind ());
1421 1.1.1.2 mrg char *filename = xstrdup (pp_formatted_text (&pp));
1422 1.1.1.2 mrg epath->dump_to_file (filename, eg.get_ext_state ());
1423 1.1.1.2 mrg inform (loc, "exploded path written to %qs", filename);
1424 1.1.1.2 mrg free (filename);
1425 1.1 mrg }
1426 1.1 mrg }
1427 1.1.1.2 mrg delete pp;
1428 1.1 mrg }
1429 1.1 mrg
1430 1.1 mrg /* Emit a "path" of events to EMISSION_PATH describing the exploded path
1431 1.1 mrg EPATH within EG. */
1432 1.1 mrg
1433 1.1 mrg void
1434 1.1 mrg diagnostic_manager::build_emission_path (const path_builder &pb,
1435 1.1 mrg const exploded_path &epath,
1436 1.1 mrg checker_path *emission_path) const
1437 1.1 mrg {
1438 1.1 mrg LOG_SCOPE (get_logger ());
1439 1.1.1.2 mrg
1440 1.1.1.2 mrg interesting_t interest;
1441 1.1.1.2 mrg pb.get_pending_diagnostic ()->mark_interesting_stuff (&interest);
1442 1.1.1.2 mrg
1443 1.1.1.2 mrg /* Add region creation events for any globals of interest, at the
1444 1.1.1.2 mrg beginning of the path. */
1445 1.1.1.2 mrg {
1446 1.1.1.2 mrg for (auto reg : interest.m_region_creation)
1447 1.1.1.2 mrg switch (reg->get_memory_space ())
1448 1.1.1.2 mrg {
1449 1.1.1.2 mrg default:
1450 1.1.1.2 mrg continue;
1451 1.1.1.2 mrg case MEMSPACE_CODE:
1452 1.1.1.2 mrg case MEMSPACE_GLOBALS:
1453 1.1.1.2 mrg case MEMSPACE_READONLY_DATA:
1454 1.1.1.2 mrg {
1455 1.1.1.2 mrg const region *base_reg = reg->get_base_region ();
1456 1.1.1.2 mrg if (tree decl = base_reg->maybe_get_decl ())
1457 1.1.1.2 mrg if (DECL_P (decl)
1458 1.1.1.2 mrg && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
1459 1.1.1.2 mrg {
1460 1.1.1.2 mrg emission_path->add_region_creation_event
1461 1.1.1.2 mrg (reg,
1462 1.1.1.2 mrg DECL_SOURCE_LOCATION (decl),
1463 1.1.1.2 mrg NULL_TREE,
1464 1.1.1.2 mrg 0);
1465 1.1.1.2 mrg }
1466 1.1.1.2 mrg }
1467 1.1.1.2 mrg }
1468 1.1.1.2 mrg }
1469 1.1.1.2 mrg
1470 1.1.1.2 mrg /* Walk EPATH, adding events as appropriate. */
1471 1.1 mrg for (unsigned i = 0; i < epath.m_edges.length (); i++)
1472 1.1 mrg {
1473 1.1 mrg const exploded_edge *eedge = epath.m_edges[i];
1474 1.1.1.2 mrg add_events_for_eedge (pb, *eedge, emission_path, &interest);
1475 1.1 mrg }
1476 1.1 mrg }
1477 1.1 mrg
1478 1.1 mrg /* Subclass of state_change_visitor that creates state_change_event
1479 1.1 mrg instances. */
1480 1.1 mrg
1481 1.1 mrg class state_change_event_creator : public state_change_visitor
1482 1.1 mrg {
1483 1.1 mrg public:
1484 1.1.1.2 mrg state_change_event_creator (const path_builder &pb,
1485 1.1.1.2 mrg const exploded_edge &eedge,
1486 1.1 mrg checker_path *emission_path)
1487 1.1.1.2 mrg : m_pb (pb),
1488 1.1.1.2 mrg m_eedge (eedge),
1489 1.1 mrg m_emission_path (emission_path)
1490 1.1 mrg {}
1491 1.1 mrg
1492 1.1 mrg bool on_global_state_change (const state_machine &sm,
1493 1.1 mrg state_machine::state_t src_sm_val,
1494 1.1 mrg state_machine::state_t dst_sm_val)
1495 1.1 mrg FINAL OVERRIDE
1496 1.1 mrg {
1497 1.1.1.2 mrg if (&sm != m_pb.get_sm ())
1498 1.1.1.2 mrg return false;
1499 1.1 mrg const exploded_node *src_node = m_eedge.m_src;
1500 1.1 mrg const program_point &src_point = src_node->get_point ();
1501 1.1 mrg const int src_stack_depth = src_point.get_stack_depth ();
1502 1.1 mrg const exploded_node *dst_node = m_eedge.m_dest;
1503 1.1 mrg const gimple *stmt = src_point.get_stmt ();
1504 1.1 mrg const supernode *supernode = src_point.get_supernode ();
1505 1.1 mrg const program_state &dst_state = dst_node->get_state ();
1506 1.1 mrg
1507 1.1 mrg int stack_depth = src_stack_depth;
1508 1.1 mrg
1509 1.1 mrg m_emission_path->add_event (new state_change_event (supernode,
1510 1.1 mrg stmt,
1511 1.1 mrg stack_depth,
1512 1.1 mrg sm,
1513 1.1.1.2 mrg NULL,
1514 1.1 mrg src_sm_val,
1515 1.1 mrg dst_sm_val,
1516 1.1.1.2 mrg NULL,
1517 1.1 mrg dst_state));
1518 1.1 mrg return false;
1519 1.1 mrg }
1520 1.1 mrg
1521 1.1 mrg bool on_state_change (const state_machine &sm,
1522 1.1 mrg state_machine::state_t src_sm_val,
1523 1.1 mrg state_machine::state_t dst_sm_val,
1524 1.1.1.2 mrg const svalue *sval,
1525 1.1.1.2 mrg const svalue *dst_origin_sval) FINAL OVERRIDE
1526 1.1 mrg {
1527 1.1.1.2 mrg if (&sm != m_pb.get_sm ())
1528 1.1.1.2 mrg return false;
1529 1.1 mrg const exploded_node *src_node = m_eedge.m_src;
1530 1.1 mrg const program_point &src_point = src_node->get_point ();
1531 1.1 mrg const int src_stack_depth = src_point.get_stack_depth ();
1532 1.1 mrg const exploded_node *dst_node = m_eedge.m_dest;
1533 1.1 mrg const gimple *stmt = src_point.get_stmt ();
1534 1.1 mrg const supernode *supernode = src_point.get_supernode ();
1535 1.1 mrg const program_state &dst_state = dst_node->get_state ();
1536 1.1 mrg
1537 1.1 mrg int stack_depth = src_stack_depth;
1538 1.1 mrg
1539 1.1 mrg if (m_eedge.m_sedge
1540 1.1 mrg && m_eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE)
1541 1.1 mrg {
1542 1.1 mrg supernode = src_point.get_supernode ();
1543 1.1 mrg stmt = supernode->get_last_stmt ();
1544 1.1 mrg stack_depth = src_stack_depth;
1545 1.1 mrg }
1546 1.1 mrg
1547 1.1 mrg /* Bulletproofing for state changes at calls/returns;
1548 1.1 mrg TODO: is there a better way? */
1549 1.1 mrg if (!stmt)
1550 1.1 mrg return false;
1551 1.1 mrg
1552 1.1 mrg m_emission_path->add_event (new state_change_event (supernode,
1553 1.1 mrg stmt,
1554 1.1 mrg stack_depth,
1555 1.1 mrg sm,
1556 1.1.1.2 mrg sval,
1557 1.1 mrg src_sm_val,
1558 1.1 mrg dst_sm_val,
1559 1.1.1.2 mrg dst_origin_sval,
1560 1.1 mrg dst_state));
1561 1.1 mrg return false;
1562 1.1 mrg }
1563 1.1 mrg
1564 1.1.1.2 mrg const path_builder &m_pb;
1565 1.1 mrg const exploded_edge &m_eedge;
1566 1.1 mrg checker_path *m_emission_path;
1567 1.1 mrg };
1568 1.1 mrg
1569 1.1 mrg /* Compare SRC_STATE and DST_STATE (which use EXT_STATE), and call
1570 1.1 mrg VISITOR's on_state_change for every sm-state change that occurs
1571 1.1 mrg to a tree, and on_global_state_change for every global state change
1572 1.1 mrg that occurs.
1573 1.1 mrg
1574 1.1 mrg This determines the state changes that ought to be reported to
1575 1.1 mrg the user: a combination of the effects of changes to sm_state_map
1576 1.1 mrg (which maps svalues to sm-states), and of region_model changes
1577 1.1 mrg (which map trees to svalues).
1578 1.1 mrg
1579 1.1 mrg Bail out early and return true if any call to on_global_state_change
1580 1.1 mrg or on_state_change returns true, otherwise return false.
1581 1.1 mrg
1582 1.1 mrg This is split out to make it easier to experiment with changes to
1583 1.1 mrg exploded_node granularity (so that we can observe what state changes
1584 1.1 mrg lead to state_change_events being emitted). */
1585 1.1 mrg
1586 1.1 mrg bool
1587 1.1 mrg for_each_state_change (const program_state &src_state,
1588 1.1 mrg const program_state &dst_state,
1589 1.1 mrg const extrinsic_state &ext_state,
1590 1.1 mrg state_change_visitor *visitor)
1591 1.1 mrg {
1592 1.1 mrg gcc_assert (src_state.m_checker_states.length ()
1593 1.1 mrg == ext_state.get_num_checkers ());
1594 1.1 mrg gcc_assert (dst_state.m_checker_states.length ()
1595 1.1 mrg == ext_state.get_num_checkers ());
1596 1.1 mrg for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
1597 1.1 mrg {
1598 1.1 mrg const state_machine &sm = ext_state.get_sm (i);
1599 1.1 mrg const sm_state_map &src_smap = *src_state.m_checker_states[i];
1600 1.1 mrg const sm_state_map &dst_smap = *dst_state.m_checker_states[i];
1601 1.1 mrg
1602 1.1 mrg /* Add events for any global state changes. */
1603 1.1 mrg if (src_smap.get_global_state () != dst_smap.get_global_state ())
1604 1.1 mrg if (visitor->on_global_state_change (sm,
1605 1.1 mrg src_smap.get_global_state (),
1606 1.1 mrg dst_smap.get_global_state ()))
1607 1.1 mrg return true;
1608 1.1 mrg
1609 1.1 mrg /* Add events for per-svalue state changes. */
1610 1.1 mrg for (sm_state_map::iterator_t iter = dst_smap.begin ();
1611 1.1 mrg iter != dst_smap.end ();
1612 1.1 mrg ++iter)
1613 1.1 mrg {
1614 1.1.1.2 mrg const svalue *sval = (*iter).first;
1615 1.1 mrg state_machine::state_t dst_sm_val = (*iter).second.m_state;
1616 1.1.1.2 mrg state_machine::state_t src_sm_val
1617 1.1.1.2 mrg = src_smap.get_state (sval, ext_state);
1618 1.1.1.2 mrg if (dst_sm_val != src_sm_val)
1619 1.1 mrg {
1620 1.1.1.2 mrg const svalue *origin_sval = (*iter).second.m_origin;
1621 1.1.1.2 mrg if (visitor->on_state_change (sm, src_sm_val, dst_sm_val,
1622 1.1.1.2 mrg sval, origin_sval))
1623 1.1.1.2 mrg return true;
1624 1.1 mrg }
1625 1.1 mrg }
1626 1.1 mrg }
1627 1.1 mrg return false;
1628 1.1 mrg }
1629 1.1 mrg
1630 1.1.1.2 mrg /* An sm_context for adding state_change_event on assignments to NULL,
1631 1.1.1.2 mrg where the default state isn't m_start. Storing such state in the
1632 1.1.1.2 mrg sm_state_map would lead to bloat of the exploded_graph, so we want
1633 1.1.1.2 mrg to leave it as a default state, and inject state change events here
1634 1.1.1.2 mrg when we have a diagnostic.
1635 1.1.1.2 mrg Find transitions of constants, for handling on_zero_assignment. */
1636 1.1.1.2 mrg
1637 1.1.1.2 mrg struct null_assignment_sm_context : public sm_context
1638 1.1.1.2 mrg {
1639 1.1.1.2 mrg null_assignment_sm_context (int sm_idx,
1640 1.1.1.2 mrg const state_machine &sm,
1641 1.1.1.2 mrg const program_state *old_state,
1642 1.1.1.2 mrg const program_state *new_state,
1643 1.1.1.2 mrg const gimple *stmt,
1644 1.1.1.2 mrg const program_point *point,
1645 1.1.1.2 mrg checker_path *emission_path,
1646 1.1.1.2 mrg const extrinsic_state &ext_state)
1647 1.1.1.2 mrg : sm_context (sm_idx, sm), m_old_state (old_state), m_new_state (new_state),
1648 1.1.1.2 mrg m_stmt (stmt), m_point (point), m_emission_path (emission_path),
1649 1.1.1.2 mrg m_ext_state (ext_state)
1650 1.1.1.2 mrg {
1651 1.1.1.2 mrg }
1652 1.1.1.2 mrg
1653 1.1.1.2 mrg tree get_fndecl_for_call (const gcall */*call*/) FINAL OVERRIDE
1654 1.1.1.2 mrg {
1655 1.1.1.2 mrg return NULL_TREE;
1656 1.1.1.2 mrg }
1657 1.1.1.2 mrg
1658 1.1.1.2 mrg state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
1659 1.1.1.2 mrg tree var) FINAL OVERRIDE
1660 1.1.1.2 mrg {
1661 1.1.1.2 mrg const svalue *var_old_sval
1662 1.1.1.2 mrg = m_old_state->m_region_model->get_rvalue (var, NULL);
1663 1.1.1.2 mrg const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
1664 1.1.1.2 mrg
1665 1.1.1.2 mrg state_machine::state_t current
1666 1.1.1.2 mrg = old_smap->get_state (var_old_sval, m_ext_state);
1667 1.1.1.2 mrg
1668 1.1.1.2 mrg return current;
1669 1.1.1.2 mrg }
1670 1.1.1.2 mrg
1671 1.1.1.2 mrg state_machine::state_t get_state (const gimple *stmt ATTRIBUTE_UNUSED,
1672 1.1.1.2 mrg const svalue *sval) FINAL OVERRIDE
1673 1.1.1.2 mrg {
1674 1.1.1.2 mrg const sm_state_map *old_smap = m_old_state->m_checker_states[m_sm_idx];
1675 1.1.1.2 mrg state_machine::state_t current = old_smap->get_state (sval, m_ext_state);
1676 1.1.1.2 mrg return current;
1677 1.1.1.2 mrg }
1678 1.1.1.2 mrg
1679 1.1.1.2 mrg void set_next_state (const gimple *stmt,
1680 1.1.1.2 mrg tree var,
1681 1.1.1.2 mrg state_machine::state_t to,
1682 1.1.1.2 mrg tree origin ATTRIBUTE_UNUSED) FINAL OVERRIDE
1683 1.1.1.2 mrg {
1684 1.1.1.2 mrg state_machine::state_t from = get_state (stmt, var);
1685 1.1.1.2 mrg if (from != m_sm.get_start_state ())
1686 1.1.1.2 mrg return;
1687 1.1.1.2 mrg
1688 1.1.1.2 mrg const svalue *var_new_sval
1689 1.1.1.2 mrg = m_new_state->m_region_model->get_rvalue (var, NULL);
1690 1.1.1.2 mrg const supernode *supernode = m_point->get_supernode ();
1691 1.1.1.2 mrg int stack_depth = m_point->get_stack_depth ();
1692 1.1.1.2 mrg
1693 1.1.1.2 mrg m_emission_path->add_event (new state_change_event (supernode,
1694 1.1.1.2 mrg m_stmt,
1695 1.1.1.2 mrg stack_depth,
1696 1.1.1.2 mrg m_sm,
1697 1.1.1.2 mrg var_new_sval,
1698 1.1.1.2 mrg from, to,
1699 1.1.1.2 mrg NULL,
1700 1.1.1.2 mrg *m_new_state));
1701 1.1.1.2 mrg }
1702 1.1.1.2 mrg
1703 1.1.1.2 mrg void set_next_state (const gimple *stmt,
1704 1.1.1.2 mrg const svalue *sval,
1705 1.1.1.2 mrg state_machine::state_t to,
1706 1.1.1.2 mrg tree origin ATTRIBUTE_UNUSED) FINAL OVERRIDE
1707 1.1.1.2 mrg {
1708 1.1.1.2 mrg state_machine::state_t from = get_state (stmt, sval);
1709 1.1.1.2 mrg if (from != m_sm.get_start_state ())
1710 1.1.1.2 mrg return;
1711 1.1.1.2 mrg
1712 1.1.1.2 mrg const supernode *supernode = m_point->get_supernode ();
1713 1.1.1.2 mrg int stack_depth = m_point->get_stack_depth ();
1714 1.1.1.2 mrg
1715 1.1.1.2 mrg m_emission_path->add_event (new state_change_event (supernode,
1716 1.1.1.2 mrg m_stmt,
1717 1.1.1.2 mrg stack_depth,
1718 1.1.1.2 mrg m_sm,
1719 1.1.1.2 mrg sval,
1720 1.1.1.2 mrg from, to,
1721 1.1.1.2 mrg NULL,
1722 1.1.1.2 mrg *m_new_state));
1723 1.1.1.2 mrg }
1724 1.1.1.2 mrg
1725 1.1.1.2 mrg void warn (const supernode *, const gimple *,
1726 1.1.1.2 mrg tree, pending_diagnostic *d) FINAL OVERRIDE
1727 1.1.1.2 mrg {
1728 1.1.1.2 mrg delete d;
1729 1.1.1.2 mrg }
1730 1.1.1.2 mrg
1731 1.1.1.2 mrg tree get_diagnostic_tree (tree expr) FINAL OVERRIDE
1732 1.1.1.2 mrg {
1733 1.1.1.2 mrg return expr;
1734 1.1.1.2 mrg }
1735 1.1.1.2 mrg
1736 1.1.1.2 mrg tree get_diagnostic_tree (const svalue *sval) FINAL OVERRIDE
1737 1.1.1.2 mrg {
1738 1.1.1.2 mrg return m_new_state->m_region_model->get_representative_tree (sval);
1739 1.1.1.2 mrg }
1740 1.1.1.2 mrg
1741 1.1.1.2 mrg state_machine::state_t get_global_state () const FINAL OVERRIDE
1742 1.1.1.2 mrg {
1743 1.1.1.2 mrg return 0;
1744 1.1.1.2 mrg }
1745 1.1.1.2 mrg
1746 1.1.1.2 mrg void set_global_state (state_machine::state_t) FINAL OVERRIDE
1747 1.1.1.2 mrg {
1748 1.1.1.2 mrg /* No-op. */
1749 1.1.1.2 mrg }
1750 1.1.1.2 mrg
1751 1.1.1.2 mrg void on_custom_transition (custom_transition *) FINAL OVERRIDE
1752 1.1.1.2 mrg {
1753 1.1.1.2 mrg }
1754 1.1.1.2 mrg
1755 1.1.1.2 mrg tree is_zero_assignment (const gimple *stmt) FINAL OVERRIDE
1756 1.1.1.2 mrg {
1757 1.1.1.2 mrg const gassign *assign_stmt = dyn_cast <const gassign *> (stmt);
1758 1.1.1.2 mrg if (!assign_stmt)
1759 1.1.1.2 mrg return NULL_TREE;
1760 1.1.1.2 mrg if (const svalue *sval
1761 1.1.1.2 mrg = m_new_state->m_region_model->get_gassign_result (assign_stmt, NULL))
1762 1.1.1.2 mrg if (tree cst = sval->maybe_get_constant ())
1763 1.1.1.2 mrg if (::zerop(cst))
1764 1.1.1.2 mrg return gimple_assign_lhs (assign_stmt);
1765 1.1.1.2 mrg return NULL_TREE;
1766 1.1.1.2 mrg }
1767 1.1.1.2 mrg
1768 1.1.1.2 mrg const program_state *get_old_program_state () const FINAL OVERRIDE
1769 1.1.1.2 mrg {
1770 1.1.1.2 mrg return m_old_state;
1771 1.1.1.2 mrg }
1772 1.1.1.2 mrg
1773 1.1.1.2 mrg const program_state *m_old_state;
1774 1.1.1.2 mrg const program_state *m_new_state;
1775 1.1.1.2 mrg const gimple *m_stmt;
1776 1.1.1.2 mrg const program_point *m_point;
1777 1.1.1.2 mrg checker_path *m_emission_path;
1778 1.1.1.2 mrg const extrinsic_state &m_ext_state;
1779 1.1.1.2 mrg };
1780 1.1.1.2 mrg
1781 1.1 mrg /* Subroutine of diagnostic_manager::build_emission_path.
1782 1.1 mrg Add any events for EEDGE to EMISSION_PATH. */
1783 1.1 mrg
1784 1.1 mrg void
1785 1.1 mrg diagnostic_manager::add_events_for_eedge (const path_builder &pb,
1786 1.1 mrg const exploded_edge &eedge,
1787 1.1.1.2 mrg checker_path *emission_path,
1788 1.1.1.2 mrg interesting_t *interest) const
1789 1.1 mrg {
1790 1.1 mrg const exploded_node *src_node = eedge.m_src;
1791 1.1 mrg const program_point &src_point = src_node->get_point ();
1792 1.1.1.2 mrg const int src_stack_depth = src_point.get_stack_depth ();
1793 1.1 mrg const exploded_node *dst_node = eedge.m_dest;
1794 1.1 mrg const program_point &dst_point = dst_node->get_point ();
1795 1.1 mrg const int dst_stack_depth = dst_point.get_stack_depth ();
1796 1.1 mrg if (get_logger ())
1797 1.1 mrg {
1798 1.1 mrg get_logger ()->start_log_line ();
1799 1.1 mrg pretty_printer *pp = get_logger ()->get_printer ();
1800 1.1 mrg pp_printf (pp, "EN %i -> EN %i: ",
1801 1.1 mrg eedge.m_src->m_index,
1802 1.1 mrg eedge.m_dest->m_index);
1803 1.1 mrg src_point.print (pp, format (false));
1804 1.1 mrg pp_string (pp, "-> ");
1805 1.1 mrg dst_point.print (pp, format (false));
1806 1.1 mrg get_logger ()->end_log_line ();
1807 1.1 mrg }
1808 1.1 mrg const program_state &src_state = src_node->get_state ();
1809 1.1 mrg const program_state &dst_state = dst_node->get_state ();
1810 1.1 mrg
1811 1.1 mrg /* Add state change events for the states that have changed.
1812 1.1 mrg We add these before events for superedges, so that if we have a
1813 1.1 mrg state_change_event due to following an edge, we'll get this sequence
1814 1.1 mrg of events:
1815 1.1 mrg
1816 1.1 mrg | if (!ptr)
1817 1.1 mrg | ~
1818 1.1 mrg | |
1819 1.1 mrg | (1) assuming 'ptr' is non-NULL (state_change_event)
1820 1.1 mrg | (2) following 'false' branch... (start_cfg_edge_event)
1821 1.1 mrg ...
1822 1.1 mrg | do_something (ptr);
1823 1.1 mrg | ~~~~~~~~~~~~~^~~~~
1824 1.1 mrg | |
1825 1.1 mrg | (3) ...to here (end_cfg_edge_event). */
1826 1.1.1.2 mrg state_change_event_creator visitor (pb, eedge, emission_path);
1827 1.1 mrg for_each_state_change (src_state, dst_state, pb.get_ext_state (),
1828 1.1 mrg &visitor);
1829 1.1 mrg
1830 1.1 mrg /* Allow non-standard edges to add events, e.g. when rewinding from
1831 1.1 mrg longjmp to a setjmp. */
1832 1.1 mrg if (eedge.m_custom_info)
1833 1.1 mrg eedge.m_custom_info->add_events_to_path (emission_path, eedge);
1834 1.1 mrg
1835 1.1 mrg /* Add events for superedges, function entries, and for statements. */
1836 1.1 mrg switch (dst_point.get_kind ())
1837 1.1 mrg {
1838 1.1 mrg default:
1839 1.1 mrg break;
1840 1.1 mrg case PK_BEFORE_SUPERNODE:
1841 1.1 mrg if (src_point.get_kind () == PK_AFTER_SUPERNODE)
1842 1.1 mrg {
1843 1.1 mrg if (eedge.m_sedge)
1844 1.1 mrg add_events_for_superedge (pb, eedge, emission_path);
1845 1.1 mrg }
1846 1.1 mrg /* Add function entry events. */
1847 1.1 mrg if (dst_point.get_supernode ()->entry_p ())
1848 1.1 mrg {
1849 1.1 mrg emission_path->add_event
1850 1.1 mrg (new function_entry_event
1851 1.1 mrg (dst_point.get_supernode ()->get_start_location (),
1852 1.1 mrg dst_point.get_fndecl (),
1853 1.1 mrg dst_stack_depth));
1854 1.1.1.2 mrg /* Create region_creation_events for on-stack regions within
1855 1.1.1.2 mrg this frame. */
1856 1.1.1.2 mrg if (interest)
1857 1.1.1.2 mrg {
1858 1.1.1.2 mrg unsigned i;
1859 1.1.1.2 mrg const region *reg;
1860 1.1.1.2 mrg FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
1861 1.1.1.2 mrg if (const frame_region *frame = reg->maybe_get_frame_region ())
1862 1.1.1.2 mrg if (frame->get_fndecl () == dst_point.get_fndecl ())
1863 1.1.1.2 mrg {
1864 1.1.1.2 mrg const region *base_reg = reg->get_base_region ();
1865 1.1.1.2 mrg if (tree decl = base_reg->maybe_get_decl ())
1866 1.1.1.2 mrg if (DECL_P (decl)
1867 1.1.1.2 mrg && DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
1868 1.1.1.2 mrg {
1869 1.1.1.2 mrg emission_path->add_region_creation_event
1870 1.1.1.2 mrg (reg,
1871 1.1.1.2 mrg DECL_SOURCE_LOCATION (decl),
1872 1.1.1.2 mrg dst_point.get_fndecl (),
1873 1.1.1.2 mrg dst_stack_depth);
1874 1.1.1.2 mrg }
1875 1.1.1.2 mrg }
1876 1.1.1.2 mrg }
1877 1.1 mrg }
1878 1.1 mrg break;
1879 1.1 mrg case PK_BEFORE_STMT:
1880 1.1 mrg {
1881 1.1 mrg const gimple *stmt = dst_point.get_stmt ();
1882 1.1 mrg const gcall *call = dyn_cast <const gcall *> (stmt);
1883 1.1 mrg if (call && is_setjmp_call_p (call))
1884 1.1 mrg emission_path->add_event
1885 1.1 mrg (new setjmp_event (stmt->location,
1886 1.1 mrg dst_node,
1887 1.1 mrg dst_point.get_fndecl (),
1888 1.1 mrg dst_stack_depth,
1889 1.1 mrg call));
1890 1.1 mrg else
1891 1.1 mrg emission_path->add_event
1892 1.1 mrg (new statement_event (stmt,
1893 1.1 mrg dst_point.get_fndecl (),
1894 1.1 mrg dst_stack_depth, dst_state));
1895 1.1.1.2 mrg
1896 1.1.1.2 mrg /* Create state change events for assignment to NULL.
1897 1.1.1.2 mrg Iterate through the stmts in dst_enode, adding state change
1898 1.1.1.2 mrg events for them. */
1899 1.1.1.2 mrg if (dst_state.m_region_model)
1900 1.1.1.2 mrg {
1901 1.1.1.2 mrg program_state iter_state (dst_state);
1902 1.1.1.2 mrg program_point iter_point (dst_point);
1903 1.1.1.2 mrg while (1)
1904 1.1.1.2 mrg {
1905 1.1.1.2 mrg const gimple *stmt = iter_point.get_stmt ();
1906 1.1.1.2 mrg if (const gassign *assign = dyn_cast<const gassign *> (stmt))
1907 1.1.1.2 mrg {
1908 1.1.1.2 mrg const extrinsic_state &ext_state = pb.get_ext_state ();
1909 1.1.1.2 mrg program_state old_state (iter_state);
1910 1.1.1.2 mrg iter_state.m_region_model->on_assignment (assign, NULL);
1911 1.1.1.2 mrg for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
1912 1.1.1.2 mrg {
1913 1.1.1.2 mrg const state_machine &sm = ext_state.get_sm (i);
1914 1.1.1.2 mrg null_assignment_sm_context sm_ctxt (i, sm,
1915 1.1.1.2 mrg &old_state,
1916 1.1.1.2 mrg &iter_state,
1917 1.1.1.2 mrg stmt,
1918 1.1.1.2 mrg &iter_point,
1919 1.1.1.2 mrg emission_path,
1920 1.1.1.2 mrg pb.get_ext_state ());
1921 1.1.1.2 mrg sm.on_stmt (&sm_ctxt, dst_point.get_supernode (), stmt);
1922 1.1.1.2 mrg // TODO: what about phi nodes?
1923 1.1.1.2 mrg }
1924 1.1.1.2 mrg }
1925 1.1.1.2 mrg iter_point.next_stmt ();
1926 1.1.1.2 mrg if (iter_point.get_kind () == PK_AFTER_SUPERNODE
1927 1.1.1.2 mrg || (dst_node->m_succs.length () > 1
1928 1.1.1.2 mrg && (iter_point
1929 1.1.1.2 mrg == dst_node->m_succs[0]->m_dest->get_point ())))
1930 1.1.1.2 mrg break;
1931 1.1.1.2 mrg }
1932 1.1.1.2 mrg
1933 1.1.1.2 mrg }
1934 1.1 mrg }
1935 1.1 mrg break;
1936 1.1 mrg }
1937 1.1.1.2 mrg
1938 1.1.1.2 mrg /* Look for changes in dynamic extents, which will identify
1939 1.1.1.2 mrg the creation of heap-based regions and alloca regions. */
1940 1.1.1.2 mrg if (interest)
1941 1.1.1.2 mrg {
1942 1.1.1.2 mrg const region_model *src_model = src_state.m_region_model;
1943 1.1.1.2 mrg const region_model *dst_model = dst_state.m_region_model;
1944 1.1.1.2 mrg if (src_model->get_dynamic_extents ()
1945 1.1.1.2 mrg != dst_model->get_dynamic_extents ())
1946 1.1.1.2 mrg {
1947 1.1.1.2 mrg unsigned i;
1948 1.1.1.2 mrg const region *reg;
1949 1.1.1.2 mrg FOR_EACH_VEC_ELT (interest->m_region_creation, i, reg)
1950 1.1.1.2 mrg {
1951 1.1.1.2 mrg const region *base_reg = reg->get_base_region ();
1952 1.1.1.2 mrg const svalue *old_extents
1953 1.1.1.2 mrg = src_model->get_dynamic_extents (base_reg);
1954 1.1.1.2 mrg const svalue *new_extents
1955 1.1.1.2 mrg = dst_model->get_dynamic_extents (base_reg);
1956 1.1.1.2 mrg if (old_extents == NULL && new_extents != NULL)
1957 1.1.1.2 mrg switch (base_reg->get_kind ())
1958 1.1.1.2 mrg {
1959 1.1.1.2 mrg default:
1960 1.1.1.2 mrg break;
1961 1.1.1.2 mrg case RK_HEAP_ALLOCATED:
1962 1.1.1.2 mrg case RK_ALLOCA:
1963 1.1.1.2 mrg emission_path->add_region_creation_event
1964 1.1.1.2 mrg (reg,
1965 1.1.1.2 mrg src_point.get_location (),
1966 1.1.1.2 mrg src_point.get_fndecl (),
1967 1.1.1.2 mrg src_stack_depth);
1968 1.1.1.2 mrg break;
1969 1.1.1.2 mrg }
1970 1.1.1.2 mrg }
1971 1.1.1.2 mrg }
1972 1.1.1.2 mrg }
1973 1.1.1.2 mrg
1974 1.1.1.2 mrg if (pb.get_feasibility_problem ()
1975 1.1.1.2 mrg && &pb.get_feasibility_problem ()->m_eedge == &eedge)
1976 1.1.1.2 mrg {
1977 1.1.1.2 mrg pretty_printer pp;
1978 1.1.1.2 mrg pp_format_decoder (&pp) = default_tree_printer;
1979 1.1.1.2 mrg pp_string (&pp,
1980 1.1.1.2 mrg "this path would have been rejected as infeasible"
1981 1.1.1.2 mrg " at this edge: ");
1982 1.1.1.2 mrg pb.get_feasibility_problem ()->dump_to_pp (&pp);
1983 1.1.1.2 mrg emission_path->add_event (new precanned_custom_event
1984 1.1.1.2 mrg (dst_point.get_location (),
1985 1.1.1.2 mrg dst_point.get_fndecl (),
1986 1.1.1.2 mrg dst_stack_depth,
1987 1.1.1.2 mrg pp_formatted_text (&pp)));
1988 1.1.1.2 mrg }
1989 1.1 mrg }
1990 1.1 mrg
1991 1.1 mrg /* Return true if EEDGE is a significant edge in the path to the diagnostic
1992 1.1 mrg for PB.
1993 1.1 mrg
1994 1.1 mrg Consider all of the sibling out-eedges from the same source enode
1995 1.1 mrg as EEDGE.
1996 1.1 mrg If there's no path from the destinations of those eedges to the
1997 1.1 mrg diagnostic enode, then we have to take this eedge and thus it's
1998 1.1 mrg significant.
1999 1.1 mrg
2000 1.1 mrg Conversely if there is a path from the destination of any other sibling
2001 1.1 mrg eedge to the diagnostic enode, then this edge is insignificant.
2002 1.1 mrg
2003 1.1 mrg Example 1: redundant if-else:
2004 1.1 mrg
2005 1.1 mrg (A) if (...) A
2006 1.1 mrg (B) ... / \
2007 1.1 mrg else B C
2008 1.1 mrg (C) ... \ /
2009 1.1 mrg (D) [DIAGNOSTIC] D
2010 1.1 mrg
2011 1.1 mrg D is reachable by either B or C, so neither of these edges
2012 1.1 mrg are significant.
2013 1.1 mrg
2014 1.1 mrg Example 2: pertinent if-else:
2015 1.1 mrg
2016 1.1 mrg (A) if (...) A
2017 1.1 mrg (B) ... / \
2018 1.1 mrg else B C
2019 1.1 mrg (C) [NECESSARY CONDITION] | |
2020 1.1 mrg (D) [POSSIBLE DIAGNOSTIC] D1 D2
2021 1.1 mrg
2022 1.1 mrg D becomes D1 and D2 in the exploded graph, where the diagnostic occurs
2023 1.1 mrg at D2. D2 is only reachable via C, so the A -> C edge is significant.
2024 1.1 mrg
2025 1.1 mrg Example 3: redundant loop:
2026 1.1 mrg
2027 1.1 mrg (A) while (...) +-->A
2028 1.1 mrg (B) ... | / \
2029 1.1 mrg (C) ... +-B C
2030 1.1 mrg (D) [DIAGNOSTIC] |
2031 1.1 mrg D
2032 1.1 mrg
2033 1.1 mrg D is reachable from both B and C, so the A->C edge is not significant. */
2034 1.1 mrg
2035 1.1 mrg bool
2036 1.1 mrg diagnostic_manager::significant_edge_p (const path_builder &pb,
2037 1.1 mrg const exploded_edge &eedge) const
2038 1.1 mrg {
2039 1.1 mrg int i;
2040 1.1 mrg exploded_edge *sibling;
2041 1.1 mrg FOR_EACH_VEC_ELT (eedge.m_src->m_succs, i, sibling)
2042 1.1 mrg {
2043 1.1 mrg if (sibling == &eedge)
2044 1.1 mrg continue;
2045 1.1 mrg if (pb.reachable_from_p (sibling->m_dest))
2046 1.1 mrg {
2047 1.1 mrg if (get_logger ())
2048 1.1 mrg get_logger ()->log (" edge EN: %i -> EN: %i is insignificant as"
2049 1.1 mrg " EN: %i is also reachable via"
2050 1.1 mrg " EN: %i -> EN: %i",
2051 1.1 mrg eedge.m_src->m_index, eedge.m_dest->m_index,
2052 1.1 mrg pb.get_diag_node ()->m_index,
2053 1.1 mrg sibling->m_src->m_index,
2054 1.1 mrg sibling->m_dest->m_index);
2055 1.1 mrg return false;
2056 1.1 mrg }
2057 1.1 mrg }
2058 1.1 mrg
2059 1.1 mrg return true;
2060 1.1 mrg }
2061 1.1 mrg
2062 1.1 mrg /* Subroutine of diagnostic_manager::add_events_for_eedge
2063 1.1 mrg where EEDGE has an underlying superedge i.e. a CFG edge,
2064 1.1 mrg or an interprocedural call/return.
2065 1.1 mrg Add any events for the superedge to EMISSION_PATH. */
2066 1.1 mrg
2067 1.1 mrg void
2068 1.1 mrg diagnostic_manager::add_events_for_superedge (const path_builder &pb,
2069 1.1 mrg const exploded_edge &eedge,
2070 1.1 mrg checker_path *emission_path)
2071 1.1 mrg const
2072 1.1 mrg {
2073 1.1 mrg gcc_assert (eedge.m_sedge);
2074 1.1 mrg
2075 1.1.1.2 mrg /* Give diagnostics an opportunity to override this function. */
2076 1.1.1.2 mrg pending_diagnostic *pd = pb.get_pending_diagnostic ();
2077 1.1.1.2 mrg if (pd->maybe_add_custom_events_for_superedge (eedge, emission_path))
2078 1.1.1.2 mrg return;
2079 1.1.1.2 mrg
2080 1.1 mrg /* Don't add events for insignificant edges at verbosity levels below 3. */
2081 1.1 mrg if (m_verbosity < 3)
2082 1.1 mrg if (!significant_edge_p (pb, eedge))
2083 1.1 mrg return;
2084 1.1 mrg
2085 1.1 mrg const exploded_node *src_node = eedge.m_src;
2086 1.1 mrg const program_point &src_point = src_node->get_point ();
2087 1.1 mrg const exploded_node *dst_node = eedge.m_dest;
2088 1.1 mrg const program_point &dst_point = dst_node->get_point ();
2089 1.1 mrg const int src_stack_depth = src_point.get_stack_depth ();
2090 1.1 mrg const int dst_stack_depth = dst_point.get_stack_depth ();
2091 1.1 mrg const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
2092 1.1 mrg
2093 1.1 mrg switch (eedge.m_sedge->m_kind)
2094 1.1 mrg {
2095 1.1 mrg case SUPEREDGE_CFG_EDGE:
2096 1.1 mrg {
2097 1.1 mrg emission_path->add_event
2098 1.1 mrg (new start_cfg_edge_event (eedge,
2099 1.1 mrg (last_stmt
2100 1.1 mrg ? last_stmt->location
2101 1.1 mrg : UNKNOWN_LOCATION),
2102 1.1 mrg src_point.get_fndecl (),
2103 1.1 mrg src_stack_depth));
2104 1.1 mrg emission_path->add_event
2105 1.1 mrg (new end_cfg_edge_event (eedge,
2106 1.1 mrg dst_point.get_supernode ()->get_start_location (),
2107 1.1 mrg dst_point.get_fndecl (),
2108 1.1 mrg dst_stack_depth));
2109 1.1 mrg }
2110 1.1 mrg break;
2111 1.1 mrg
2112 1.1 mrg case SUPEREDGE_CALL:
2113 1.1 mrg {
2114 1.1 mrg emission_path->add_event
2115 1.1 mrg (new call_event (eedge,
2116 1.1 mrg (last_stmt
2117 1.1 mrg ? last_stmt->location
2118 1.1 mrg : UNKNOWN_LOCATION),
2119 1.1 mrg src_point.get_fndecl (),
2120 1.1 mrg src_stack_depth));
2121 1.1 mrg }
2122 1.1 mrg break;
2123 1.1 mrg
2124 1.1 mrg case SUPEREDGE_INTRAPROCEDURAL_CALL:
2125 1.1 mrg {
2126 1.1 mrg /* TODO: add a subclass for this, or generate events for the
2127 1.1 mrg summary. */
2128 1.1 mrg emission_path->add_event
2129 1.1 mrg (new debug_event ((last_stmt
2130 1.1 mrg ? last_stmt->location
2131 1.1 mrg : UNKNOWN_LOCATION),
2132 1.1 mrg src_point.get_fndecl (),
2133 1.1 mrg src_stack_depth,
2134 1.1 mrg "call summary"));
2135 1.1 mrg }
2136 1.1 mrg break;
2137 1.1 mrg
2138 1.1 mrg case SUPEREDGE_RETURN:
2139 1.1 mrg {
2140 1.1 mrg const return_superedge *return_edge
2141 1.1 mrg = as_a <const return_superedge *> (eedge.m_sedge);
2142 1.1 mrg
2143 1.1 mrg const gcall *call_stmt = return_edge->get_call_stmt ();
2144 1.1 mrg emission_path->add_event
2145 1.1 mrg (new return_event (eedge,
2146 1.1 mrg (call_stmt
2147 1.1 mrg ? call_stmt->location
2148 1.1 mrg : UNKNOWN_LOCATION),
2149 1.1 mrg dst_point.get_fndecl (),
2150 1.1 mrg dst_stack_depth));
2151 1.1 mrg }
2152 1.1 mrg break;
2153 1.1 mrg }
2154 1.1 mrg }
2155 1.1 mrg
2156 1.1 mrg /* Prune PATH, based on the verbosity level, to the most pertinent
2157 1.1 mrg events for a diagnostic that involves VAR ending in state STATE
2158 1.1 mrg (for state machine SM).
2159 1.1 mrg
2160 1.1 mrg PATH is updated in place, and the redundant checker_events are deleted.
2161 1.1 mrg
2162 1.1 mrg As well as deleting events, call record_critical_state on events in
2163 1.1 mrg which state critical to the pending_diagnostic is being handled; see
2164 1.1 mrg the comment for diagnostic_manager::prune_for_sm_diagnostic. */
2165 1.1 mrg
2166 1.1 mrg void
2167 1.1 mrg diagnostic_manager::prune_path (checker_path *path,
2168 1.1 mrg const state_machine *sm,
2169 1.1.1.2 mrg const svalue *sval,
2170 1.1 mrg state_machine::state_t state) const
2171 1.1 mrg {
2172 1.1 mrg LOG_FUNC (get_logger ());
2173 1.1 mrg path->maybe_log (get_logger (), "path");
2174 1.1.1.2 mrg prune_for_sm_diagnostic (path, sm, sval, state);
2175 1.1 mrg prune_interproc_events (path);
2176 1.1.1.2 mrg consolidate_conditions (path);
2177 1.1 mrg finish_pruning (path);
2178 1.1 mrg path->maybe_log (get_logger (), "pruned");
2179 1.1 mrg }
2180 1.1 mrg
2181 1.1 mrg /* A cheap test to determine if EXPR can be the expression of interest in
2182 1.1 mrg an sm-diagnostic, so that we can reject cases where we have a non-lvalue.
2183 1.1 mrg We don't have always have a model when calling this, so we can't use
2184 1.1 mrg tentative_region_model_context, so there can be false positives. */
2185 1.1 mrg
2186 1.1 mrg static bool
2187 1.1 mrg can_be_expr_of_interest_p (tree expr)
2188 1.1 mrg {
2189 1.1 mrg if (!expr)
2190 1.1 mrg return false;
2191 1.1 mrg
2192 1.1 mrg /* Reject constants. */
2193 1.1 mrg if (CONSTANT_CLASS_P (expr))
2194 1.1 mrg return false;
2195 1.1 mrg
2196 1.1 mrg /* Otherwise assume that it can be an lvalue. */
2197 1.1 mrg return true;
2198 1.1 mrg }
2199 1.1 mrg
2200 1.1 mrg /* First pass of diagnostic_manager::prune_path: apply verbosity level,
2201 1.1 mrg pruning unrelated state change events.
2202 1.1 mrg
2203 1.1 mrg Iterate backwards through PATH, skipping state change events that aren't
2204 1.1 mrg VAR but update the pertinent VAR when state-copying occurs.
2205 1.1 mrg
2206 1.1 mrg As well as deleting events, call record_critical_state on events in
2207 1.1 mrg which state critical to the pending_diagnostic is being handled, so
2208 1.1 mrg that the event's get_desc vfunc can potentially supply a more precise
2209 1.1 mrg description of the event to the user.
2210 1.1 mrg e.g. improving
2211 1.1 mrg "calling 'foo' from 'bar'"
2212 1.1 mrg to
2213 1.1 mrg "passing possibly-NULL pointer 'ptr' to 'foo' from 'bar' as param 1"
2214 1.1 mrg when the diagnostic relates to later dereferencing 'ptr'. */
2215 1.1 mrg
2216 1.1 mrg void
2217 1.1 mrg diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
2218 1.1 mrg const state_machine *sm,
2219 1.1.1.2 mrg const svalue *sval,
2220 1.1 mrg state_machine::state_t state) const
2221 1.1 mrg {
2222 1.1 mrg int idx = path->num_events () - 1;
2223 1.1 mrg while (idx >= 0 && idx < (signed)path->num_events ())
2224 1.1 mrg {
2225 1.1 mrg checker_event *base_event = path->get_checker_event (idx);
2226 1.1 mrg if (get_logger ())
2227 1.1 mrg {
2228 1.1 mrg if (sm)
2229 1.1 mrg {
2230 1.1.1.2 mrg if (sval)
2231 1.1.1.2 mrg {
2232 1.1.1.2 mrg label_text sval_desc = sval->get_desc ();
2233 1.1.1.2 mrg log ("considering event %i (%s), with sval: %qs, state: %qs",
2234 1.1.1.2 mrg idx, event_kind_to_string (base_event->m_kind),
2235 1.1.1.2 mrg sval_desc.m_buffer, state->get_name ());
2236 1.1.1.2 mrg sval_desc.maybe_free ();
2237 1.1.1.2 mrg }
2238 1.1 mrg else
2239 1.1.1.2 mrg log ("considering event %i (%s), with global state: %qs",
2240 1.1.1.2 mrg idx, event_kind_to_string (base_event->m_kind),
2241 1.1.1.2 mrg state->get_name ());
2242 1.1 mrg }
2243 1.1 mrg else
2244 1.1 mrg log ("considering event %i", idx);
2245 1.1 mrg }
2246 1.1.1.2 mrg
2247 1.1 mrg switch (base_event->m_kind)
2248 1.1 mrg {
2249 1.1 mrg default:
2250 1.1 mrg gcc_unreachable ();
2251 1.1 mrg
2252 1.1 mrg case EK_DEBUG:
2253 1.1 mrg if (m_verbosity < 4)
2254 1.1 mrg {
2255 1.1 mrg log ("filtering event %i: debug event", idx);
2256 1.1 mrg path->delete_event (idx);
2257 1.1 mrg }
2258 1.1 mrg break;
2259 1.1 mrg
2260 1.1 mrg case EK_CUSTOM:
2261 1.1 mrg /* Don't filter custom events. */
2262 1.1 mrg break;
2263 1.1 mrg
2264 1.1 mrg case EK_STMT:
2265 1.1 mrg {
2266 1.1 mrg if (m_verbosity < 4)
2267 1.1 mrg {
2268 1.1 mrg log ("filtering event %i: statement event", idx);
2269 1.1 mrg path->delete_event (idx);
2270 1.1 mrg }
2271 1.1 mrg }
2272 1.1 mrg break;
2273 1.1 mrg
2274 1.1.1.2 mrg case EK_REGION_CREATION:
2275 1.1.1.2 mrg /* Don't filter these. */
2276 1.1.1.2 mrg break;
2277 1.1.1.2 mrg
2278 1.1 mrg case EK_FUNCTION_ENTRY:
2279 1.1 mrg if (m_verbosity < 1)
2280 1.1 mrg {
2281 1.1 mrg log ("filtering event %i: function entry", idx);
2282 1.1 mrg path->delete_event (idx);
2283 1.1 mrg }
2284 1.1 mrg break;
2285 1.1 mrg
2286 1.1 mrg case EK_STATE_CHANGE:
2287 1.1 mrg {
2288 1.1 mrg state_change_event *state_change = (state_change_event *)base_event;
2289 1.1.1.2 mrg gcc_assert (state_change->m_dst_state.m_region_model);
2290 1.1.1.2 mrg
2291 1.1.1.2 mrg if (state_change->m_sval == sval)
2292 1.1 mrg {
2293 1.1 mrg if (state_change->m_origin)
2294 1.1 mrg {
2295 1.1.1.2 mrg if (get_logger ())
2296 1.1.1.2 mrg {
2297 1.1.1.2 mrg label_text sval_desc = sval->get_desc ();
2298 1.1.1.2 mrg label_text origin_sval_desc
2299 1.1.1.2 mrg = state_change->m_origin->get_desc ();
2300 1.1.1.2 mrg log ("event %i:"
2301 1.1.1.2 mrg " switching var of interest from %qs to %qs",
2302 1.1.1.2 mrg idx, sval_desc.m_buffer,
2303 1.1.1.2 mrg origin_sval_desc.m_buffer);
2304 1.1.1.2 mrg sval_desc.maybe_free ();
2305 1.1.1.2 mrg origin_sval_desc.maybe_free ();
2306 1.1.1.2 mrg }
2307 1.1.1.2 mrg sval = state_change->m_origin;
2308 1.1 mrg }
2309 1.1 mrg log ("event %i: switching state of interest from %qs to %qs",
2310 1.1.1.2 mrg idx, state_change->m_to->get_name (),
2311 1.1.1.2 mrg state_change->m_from->get_name ());
2312 1.1 mrg state = state_change->m_from;
2313 1.1 mrg }
2314 1.1 mrg else if (m_verbosity < 4)
2315 1.1 mrg {
2316 1.1.1.2 mrg if (get_logger ())
2317 1.1.1.2 mrg {
2318 1.1.1.2 mrg if (state_change->m_sval)
2319 1.1.1.2 mrg {
2320 1.1.1.2 mrg label_text change_sval_desc
2321 1.1.1.2 mrg = state_change->m_sval->get_desc ();
2322 1.1.1.2 mrg if (sval)
2323 1.1.1.2 mrg {
2324 1.1.1.2 mrg label_text sval_desc = sval->get_desc ();
2325 1.1.1.2 mrg log ("filtering event %i:"
2326 1.1.1.2 mrg " state change to %qs unrelated to %qs",
2327 1.1.1.2 mrg idx, change_sval_desc.m_buffer,
2328 1.1.1.2 mrg sval_desc.m_buffer);
2329 1.1.1.2 mrg }
2330 1.1.1.2 mrg else
2331 1.1.1.2 mrg log ("filtering event %i: state change to %qs",
2332 1.1.1.2 mrg idx, change_sval_desc.m_buffer);
2333 1.1.1.2 mrg change_sval_desc.maybe_free ();
2334 1.1.1.2 mrg }
2335 1.1.1.2 mrg else
2336 1.1.1.2 mrg log ("filtering event %i: global state change", idx);
2337 1.1.1.2 mrg }
2338 1.1 mrg path->delete_event (idx);
2339 1.1 mrg }
2340 1.1 mrg }
2341 1.1 mrg break;
2342 1.1 mrg
2343 1.1 mrg case EK_START_CFG_EDGE:
2344 1.1 mrg {
2345 1.1 mrg cfg_edge_event *event = (cfg_edge_event *)base_event;
2346 1.1 mrg
2347 1.1 mrg /* TODO: is this edge significant to var?
2348 1.1 mrg See if var can be in other states in the dest, but not
2349 1.1 mrg in other states in the src?
2350 1.1 mrg Must have multiple sibling edges. */
2351 1.1 mrg
2352 1.1 mrg if (event->should_filter_p (m_verbosity))
2353 1.1 mrg {
2354 1.1.1.2 mrg log ("filtering events %i and %i: CFG edge", idx, idx + 1);
2355 1.1 mrg path->delete_event (idx);
2356 1.1 mrg /* Also delete the corresponding EK_END_CFG_EDGE. */
2357 1.1 mrg gcc_assert (path->get_checker_event (idx)->m_kind
2358 1.1 mrg == EK_END_CFG_EDGE);
2359 1.1 mrg path->delete_event (idx);
2360 1.1 mrg }
2361 1.1 mrg }
2362 1.1 mrg break;
2363 1.1 mrg
2364 1.1 mrg case EK_END_CFG_EDGE:
2365 1.1 mrg /* These come in pairs with EK_START_CFG_EDGE events and are
2366 1.1 mrg filtered when their start event is filtered. */
2367 1.1 mrg break;
2368 1.1 mrg
2369 1.1 mrg case EK_CALL_EDGE:
2370 1.1 mrg {
2371 1.1 mrg call_event *event = (call_event *)base_event;
2372 1.1.1.2 mrg const region_model *callee_model
2373 1.1.1.2 mrg = event->m_eedge.m_dest->get_state ().m_region_model;
2374 1.1.1.2 mrg const region_model *caller_model
2375 1.1.1.2 mrg = event->m_eedge.m_src->get_state ().m_region_model;
2376 1.1.1.2 mrg tree callee_var = callee_model->get_representative_tree (sval);
2377 1.1 mrg callsite_expr expr;
2378 1.1.1.2 mrg
2379 1.1.1.2 mrg tree caller_var;
2380 1.1.1.2 mrg if(event->m_sedge)
2381 1.1.1.2 mrg {
2382 1.1.1.2 mrg const callgraph_superedge& cg_superedge
2383 1.1.1.2 mrg = event->get_callgraph_superedge ();
2384 1.1.1.2 mrg if (cg_superedge.m_cedge)
2385 1.1.1.2 mrg caller_var
2386 1.1.1.2 mrg = cg_superedge.map_expr_from_callee_to_caller (callee_var,
2387 1.1.1.2 mrg &expr);
2388 1.1.1.2 mrg else
2389 1.1.1.2 mrg caller_var = caller_model->get_representative_tree (sval);
2390 1.1.1.2 mrg }
2391 1.1.1.2 mrg else
2392 1.1.1.2 mrg caller_var = caller_model->get_representative_tree (sval);
2393 1.1.1.2 mrg
2394 1.1 mrg if (caller_var)
2395 1.1 mrg {
2396 1.1.1.2 mrg if (get_logger ())
2397 1.1.1.2 mrg {
2398 1.1.1.2 mrg label_text sval_desc = sval->get_desc ();
2399 1.1.1.2 mrg log ("event %i:"
2400 1.1.1.2 mrg " recording critical state for %qs at call"
2401 1.1.1.2 mrg " from %qE in callee to %qE in caller",
2402 1.1.1.2 mrg idx, sval_desc.m_buffer, callee_var, caller_var);
2403 1.1.1.2 mrg sval_desc.maybe_free ();
2404 1.1.1.2 mrg }
2405 1.1 mrg if (expr.param_p ())
2406 1.1.1.2 mrg event->record_critical_state (caller_var, state);
2407 1.1 mrg }
2408 1.1 mrg }
2409 1.1 mrg break;
2410 1.1 mrg
2411 1.1 mrg case EK_RETURN_EDGE:
2412 1.1 mrg {
2413 1.1.1.2 mrg if (sval)
2414 1.1 mrg {
2415 1.1 mrg return_event *event = (return_event *)base_event;
2416 1.1.1.2 mrg const region_model *caller_model
2417 1.1.1.2 mrg = event->m_eedge.m_dest->get_state ().m_region_model;
2418 1.1.1.2 mrg tree caller_var = caller_model->get_representative_tree (sval);
2419 1.1.1.2 mrg const region_model *callee_model
2420 1.1.1.2 mrg = event->m_eedge.m_src->get_state ().m_region_model;
2421 1.1 mrg callsite_expr expr;
2422 1.1.1.2 mrg
2423 1.1.1.2 mrg tree callee_var;
2424 1.1.1.2 mrg if (event->m_sedge)
2425 1.1.1.2 mrg {
2426 1.1.1.2 mrg const callgraph_superedge& cg_superedge
2427 1.1.1.2 mrg = event->get_callgraph_superedge ();
2428 1.1.1.2 mrg if (cg_superedge.m_cedge)
2429 1.1.1.2 mrg callee_var
2430 1.1.1.2 mrg = cg_superedge.map_expr_from_caller_to_callee (caller_var,
2431 1.1.1.2 mrg &expr);
2432 1.1.1.2 mrg else
2433 1.1.1.2 mrg callee_var = callee_model->get_representative_tree (sval);
2434 1.1.1.2 mrg }
2435 1.1.1.2 mrg else
2436 1.1.1.2 mrg callee_var = callee_model->get_representative_tree (sval);
2437 1.1.1.2 mrg
2438 1.1 mrg if (callee_var)
2439 1.1 mrg {
2440 1.1.1.2 mrg if (get_logger ())
2441 1.1.1.2 mrg {
2442 1.1.1.2 mrg label_text sval_desc = sval->get_desc ();
2443 1.1.1.2 mrg log ("event %i:"
2444 1.1.1.2 mrg " recording critical state for %qs at return"
2445 1.1.1.2 mrg " from %qE in caller to %qE in callee",
2446 1.1.1.2 mrg idx, sval_desc.m_buffer, callee_var, callee_var);
2447 1.1.1.2 mrg sval_desc.maybe_free ();
2448 1.1.1.2 mrg }
2449 1.1 mrg if (expr.return_value_p ())
2450 1.1.1.2 mrg event->record_critical_state (callee_var, state);
2451 1.1 mrg }
2452 1.1 mrg }
2453 1.1 mrg }
2454 1.1 mrg break;
2455 1.1 mrg
2456 1.1 mrg case EK_SETJMP:
2457 1.1 mrg /* TODO: only show setjmp_events that matter i.e. those for which
2458 1.1 mrg there is a later rewind event using them. */
2459 1.1 mrg case EK_REWIND_FROM_LONGJMP:
2460 1.1 mrg case EK_REWIND_TO_SETJMP:
2461 1.1 mrg break;
2462 1.1 mrg
2463 1.1 mrg case EK_WARNING:
2464 1.1 mrg /* Always show the final "warning" event in the path. */
2465 1.1 mrg break;
2466 1.1 mrg }
2467 1.1 mrg idx--;
2468 1.1 mrg }
2469 1.1 mrg }
2470 1.1 mrg
2471 1.1 mrg /* Subroutine of diagnostic_manager::prune_for_sm_diagnostic.
2472 1.1 mrg If *EXPR is not suitable to be the expression of interest in
2473 1.1 mrg an sm-diagnostic, set *EXPR to NULL and log. */
2474 1.1 mrg
2475 1.1 mrg void
2476 1.1 mrg diagnostic_manager::update_for_unsuitable_sm_exprs (tree *expr) const
2477 1.1 mrg {
2478 1.1 mrg gcc_assert (expr);
2479 1.1 mrg if (*expr && !can_be_expr_of_interest_p (*expr))
2480 1.1 mrg {
2481 1.1 mrg log ("new var %qE is unsuitable; setting var to NULL", *expr);
2482 1.1 mrg *expr = NULL_TREE;
2483 1.1 mrg }
2484 1.1 mrg }
2485 1.1 mrg
2486 1.1 mrg /* Second pass of diagnostic_manager::prune_path: remove redundant
2487 1.1 mrg interprocedural information.
2488 1.1 mrg
2489 1.1 mrg For example, given:
2490 1.1 mrg (1)- calling "f2" from "f1"
2491 1.1 mrg (2)--- entry to "f2"
2492 1.1 mrg (3)--- calling "f3" from "f2"
2493 1.1 mrg (4)----- entry to "f3"
2494 1.1 mrg (5)--- returning to "f2" to "f3"
2495 1.1 mrg (6)- returning to "f1" to "f2"
2496 1.1 mrg with no other intervening events, then none of these events are
2497 1.1 mrg likely to be interesting to the user.
2498 1.1 mrg
2499 1.1 mrg Prune [..., call, function-entry, return, ...] triples repeatedly
2500 1.1 mrg until nothing has changed. For the example above, this would
2501 1.1 mrg remove events (3, 4, 5), and then remove events (1, 2, 6). */
2502 1.1 mrg
2503 1.1 mrg void
2504 1.1 mrg diagnostic_manager::prune_interproc_events (checker_path *path) const
2505 1.1 mrg {
2506 1.1 mrg bool changed = false;
2507 1.1 mrg do
2508 1.1 mrg {
2509 1.1 mrg changed = false;
2510 1.1.1.2 mrg int idx = (signed)path->num_events () - 1;
2511 1.1 mrg while (idx >= 0)
2512 1.1 mrg {
2513 1.1 mrg /* Prune [..., call, function-entry, return, ...] triples. */
2514 1.1 mrg if (idx + 2 < (signed)path->num_events ()
2515 1.1 mrg && path->get_checker_event (idx)->is_call_p ()
2516 1.1 mrg && path->get_checker_event (idx + 1)->is_function_entry_p ()
2517 1.1 mrg && path->get_checker_event (idx + 2)->is_return_p ())
2518 1.1 mrg {
2519 1.1 mrg if (get_logger ())
2520 1.1 mrg {
2521 1.1 mrg label_text desc
2522 1.1 mrg (path->get_checker_event (idx)->get_desc (false));
2523 1.1 mrg log ("filtering events %i-%i:"
2524 1.1 mrg " irrelevant call/entry/return: %s",
2525 1.1 mrg idx, idx + 2, desc.m_buffer);
2526 1.1 mrg desc.maybe_free ();
2527 1.1 mrg }
2528 1.1 mrg path->delete_event (idx + 2);
2529 1.1 mrg path->delete_event (idx + 1);
2530 1.1 mrg path->delete_event (idx);
2531 1.1 mrg changed = true;
2532 1.1 mrg idx--;
2533 1.1 mrg continue;
2534 1.1 mrg }
2535 1.1 mrg
2536 1.1 mrg /* Prune [..., call, return, ...] pairs
2537 1.1 mrg (for -fanalyzer-verbosity=0). */
2538 1.1 mrg if (idx + 1 < (signed)path->num_events ()
2539 1.1 mrg && path->get_checker_event (idx)->is_call_p ()
2540 1.1 mrg && path->get_checker_event (idx + 1)->is_return_p ())
2541 1.1 mrg {
2542 1.1 mrg if (get_logger ())
2543 1.1 mrg {
2544 1.1 mrg label_text desc
2545 1.1 mrg (path->get_checker_event (idx)->get_desc (false));
2546 1.1 mrg log ("filtering events %i-%i:"
2547 1.1 mrg " irrelevant call/return: %s",
2548 1.1 mrg idx, idx + 1, desc.m_buffer);
2549 1.1 mrg desc.maybe_free ();
2550 1.1 mrg }
2551 1.1 mrg path->delete_event (idx + 1);
2552 1.1 mrg path->delete_event (idx);
2553 1.1 mrg changed = true;
2554 1.1 mrg idx--;
2555 1.1 mrg continue;
2556 1.1 mrg }
2557 1.1 mrg
2558 1.1 mrg idx--;
2559 1.1 mrg }
2560 1.1 mrg
2561 1.1 mrg }
2562 1.1 mrg while (changed);
2563 1.1 mrg }
2564 1.1 mrg
2565 1.1.1.2 mrg /* Return true iff event IDX within PATH is on the same line as REF_EXP_LOC. */
2566 1.1.1.2 mrg
2567 1.1.1.2 mrg static bool
2568 1.1.1.2 mrg same_line_as_p (const expanded_location &ref_exp_loc,
2569 1.1.1.2 mrg checker_path *path, unsigned idx)
2570 1.1.1.2 mrg {
2571 1.1.1.2 mrg const checker_event *ev = path->get_checker_event (idx);
2572 1.1.1.2 mrg expanded_location idx_exp_loc = expand_location (ev->get_location ());
2573 1.1.1.2 mrg gcc_assert (ref_exp_loc.file);
2574 1.1.1.2 mrg if (idx_exp_loc.file == NULL)
2575 1.1.1.2 mrg return false;
2576 1.1.1.2 mrg if (strcmp (ref_exp_loc.file, idx_exp_loc.file))
2577 1.1.1.2 mrg return false;
2578 1.1.1.2 mrg return ref_exp_loc.line == idx_exp_loc.line;
2579 1.1.1.2 mrg }
2580 1.1.1.2 mrg
2581 1.1.1.2 mrg /* This path-readability optimization reduces the verbosity of compound
2582 1.1.1.2 mrg conditional statements (without needing to reconstruct the AST, which
2583 1.1.1.2 mrg has already been lost).
2584 1.1.1.2 mrg
2585 1.1.1.2 mrg For example, it converts:
2586 1.1.1.2 mrg
2587 1.1.1.2 mrg | 61 | if (cp[0] != '\0' && cp[0] != '#')
2588 1.1.1.2 mrg | | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2589 1.1.1.2 mrg | | | | |
2590 1.1.1.2 mrg | | | | (6) ...to here
2591 1.1.1.2 mrg | | | (7) following true branch...
2592 1.1.1.2 mrg | | (5) following true branch...
2593 1.1.1.2 mrg | 62 | {
2594 1.1.1.2 mrg | 63 | alias = cp++;
2595 1.1.1.2 mrg | | ~~~~
2596 1.1.1.2 mrg | | |
2597 1.1.1.2 mrg | | (8) ...to here
2598 1.1.1.2 mrg
2599 1.1.1.2 mrg into:
2600 1.1.1.2 mrg
2601 1.1.1.2 mrg | 61 | if (cp[0] != '\0' && cp[0] != '#')
2602 1.1.1.2 mrg | | ~
2603 1.1.1.2 mrg | | |
2604 1.1.1.2 mrg | | (5) following true branch...
2605 1.1.1.2 mrg | 62 | {
2606 1.1.1.2 mrg | 63 | alias = cp++;
2607 1.1.1.2 mrg | | ~~~~
2608 1.1.1.2 mrg | | |
2609 1.1.1.2 mrg | | (6) ...to here
2610 1.1.1.2 mrg
2611 1.1.1.2 mrg by combining events 5-8 into new events 5-6.
2612 1.1.1.2 mrg
2613 1.1.1.2 mrg Find runs of consecutive (start_cfg_edge_event, end_cfg_edge_event) pairs
2614 1.1.1.2 mrg in which all events apart from the final end_cfg_edge_event are on the same
2615 1.1.1.2 mrg line, and for which either all the CFG edges are TRUE edges, or all are
2616 1.1.1.2 mrg FALSE edges.
2617 1.1.1.2 mrg
2618 1.1.1.2 mrg Consolidate each such run into a
2619 1.1.1.2 mrg (start_consolidated_cfg_edges_event, end_consolidated_cfg_edges_event)
2620 1.1.1.2 mrg pair. */
2621 1.1.1.2 mrg
2622 1.1.1.2 mrg void
2623 1.1.1.2 mrg diagnostic_manager::consolidate_conditions (checker_path *path) const
2624 1.1.1.2 mrg {
2625 1.1.1.2 mrg /* Don't simplify edges if we're debugging them. */
2626 1.1.1.2 mrg if (flag_analyzer_verbose_edges)
2627 1.1.1.2 mrg return;
2628 1.1.1.2 mrg
2629 1.1.1.2 mrg for (int start_idx = 0;
2630 1.1.1.2 mrg start_idx < (signed)path->num_events () - 1;
2631 1.1.1.2 mrg start_idx++)
2632 1.1.1.2 mrg {
2633 1.1.1.2 mrg if (path->cfg_edge_pair_at_p (start_idx))
2634 1.1.1.2 mrg {
2635 1.1.1.2 mrg const checker_event *old_start_ev
2636 1.1.1.2 mrg = path->get_checker_event (start_idx);
2637 1.1.1.2 mrg expanded_location start_exp_loc
2638 1.1.1.2 mrg = expand_location (old_start_ev->get_location ());
2639 1.1.1.2 mrg if (start_exp_loc.file == NULL)
2640 1.1.1.2 mrg continue;
2641 1.1.1.2 mrg if (!same_line_as_p (start_exp_loc, path, start_idx + 1))
2642 1.1.1.2 mrg continue;
2643 1.1.1.2 mrg
2644 1.1.1.2 mrg /* Are we looking for a run of all TRUE edges, or all FALSE edges? */
2645 1.1.1.2 mrg gcc_assert (old_start_ev->m_kind == EK_START_CFG_EDGE);
2646 1.1.1.2 mrg const start_cfg_edge_event *old_start_cfg_ev
2647 1.1.1.2 mrg = (const start_cfg_edge_event *)old_start_ev;
2648 1.1.1.2 mrg const cfg_superedge& first_cfg_sedge
2649 1.1.1.2 mrg = old_start_cfg_ev->get_cfg_superedge ();
2650 1.1.1.2 mrg bool edge_sense;
2651 1.1.1.2 mrg if (first_cfg_sedge.true_value_p ())
2652 1.1.1.2 mrg edge_sense = true;
2653 1.1.1.2 mrg else if (first_cfg_sedge.false_value_p ())
2654 1.1.1.2 mrg edge_sense = false;
2655 1.1.1.2 mrg else
2656 1.1.1.2 mrg continue;
2657 1.1.1.2 mrg
2658 1.1.1.2 mrg /* Find a run of CFG start/end event pairs from
2659 1.1.1.2 mrg [start_idx, next_idx)
2660 1.1.1.2 mrg where all apart from the final event are on the same line,
2661 1.1.1.2 mrg and all are either TRUE or FALSE edges, matching the initial. */
2662 1.1.1.2 mrg int next_idx = start_idx + 2;
2663 1.1.1.2 mrg while (path->cfg_edge_pair_at_p (next_idx)
2664 1.1.1.2 mrg && same_line_as_p (start_exp_loc, path, next_idx))
2665 1.1.1.2 mrg {
2666 1.1.1.2 mrg const checker_event *iter_ev
2667 1.1.1.2 mrg = path->get_checker_event (next_idx);
2668 1.1.1.2 mrg gcc_assert (iter_ev->m_kind == EK_START_CFG_EDGE);
2669 1.1.1.2 mrg const start_cfg_edge_event *iter_cfg_ev
2670 1.1.1.2 mrg = (const start_cfg_edge_event *)iter_ev;
2671 1.1.1.2 mrg const cfg_superedge& iter_cfg_sedge
2672 1.1.1.2 mrg = iter_cfg_ev->get_cfg_superedge ();
2673 1.1.1.2 mrg if (edge_sense)
2674 1.1.1.2 mrg {
2675 1.1.1.2 mrg if (!iter_cfg_sedge.true_value_p ())
2676 1.1.1.2 mrg break;
2677 1.1.1.2 mrg }
2678 1.1.1.2 mrg else
2679 1.1.1.2 mrg {
2680 1.1.1.2 mrg if (!iter_cfg_sedge.false_value_p ())
2681 1.1.1.2 mrg break;
2682 1.1.1.2 mrg }
2683 1.1.1.2 mrg next_idx += 2;
2684 1.1.1.2 mrg }
2685 1.1.1.2 mrg
2686 1.1.1.2 mrg /* If we have more than one pair in the run, consolidate. */
2687 1.1.1.2 mrg if (next_idx > start_idx + 2)
2688 1.1.1.2 mrg {
2689 1.1.1.2 mrg const checker_event *old_end_ev
2690 1.1.1.2 mrg = path->get_checker_event (next_idx - 1);
2691 1.1.1.2 mrg log ("consolidating CFG edge events %i-%i into %i-%i",
2692 1.1.1.2 mrg start_idx, next_idx - 1, start_idx, start_idx +1);
2693 1.1.1.2 mrg start_consolidated_cfg_edges_event *new_start_ev
2694 1.1.1.2 mrg = new start_consolidated_cfg_edges_event
2695 1.1.1.2 mrg (old_start_ev->get_location (),
2696 1.1.1.2 mrg old_start_ev->get_fndecl (),
2697 1.1.1.2 mrg old_start_ev->get_stack_depth (),
2698 1.1.1.2 mrg edge_sense);
2699 1.1.1.2 mrg checker_event *new_end_ev
2700 1.1.1.2 mrg = new end_consolidated_cfg_edges_event
2701 1.1.1.2 mrg (old_end_ev->get_location (),
2702 1.1.1.2 mrg old_end_ev->get_fndecl (),
2703 1.1.1.2 mrg old_end_ev->get_stack_depth ());
2704 1.1.1.2 mrg path->replace_event (start_idx, new_start_ev);
2705 1.1.1.2 mrg path->replace_event (start_idx + 1, new_end_ev);
2706 1.1.1.2 mrg path->delete_events (start_idx + 2, next_idx - (start_idx + 2));
2707 1.1.1.2 mrg }
2708 1.1.1.2 mrg }
2709 1.1.1.2 mrg }
2710 1.1.1.2 mrg }
2711 1.1.1.2 mrg
2712 1.1 mrg /* Final pass of diagnostic_manager::prune_path.
2713 1.1 mrg
2714 1.1 mrg If all we're left with is in one function, then filter function entry
2715 1.1 mrg events. */
2716 1.1 mrg
2717 1.1 mrg void
2718 1.1 mrg diagnostic_manager::finish_pruning (checker_path *path) const
2719 1.1 mrg {
2720 1.1 mrg if (!path->interprocedural_p ())
2721 1.1 mrg {
2722 1.1 mrg int idx = path->num_events () - 1;
2723 1.1 mrg while (idx >= 0 && idx < (signed)path->num_events ())
2724 1.1 mrg {
2725 1.1 mrg checker_event *base_event = path->get_checker_event (idx);
2726 1.1 mrg if (base_event->m_kind == EK_FUNCTION_ENTRY)
2727 1.1 mrg {
2728 1.1 mrg log ("filtering event %i:"
2729 1.1 mrg " function entry for purely intraprocedural path", idx);
2730 1.1 mrg path->delete_event (idx);
2731 1.1 mrg }
2732 1.1 mrg idx--;
2733 1.1 mrg }
2734 1.1 mrg }
2735 1.1 mrg }
2736 1.1 mrg
2737 1.1 mrg } // namespace ana
2738 1.1 mrg
2739 1.1 mrg #endif /* #if ENABLE_ANALYZER */
2740