Bug Summary

File:build/gcc/analyzer/diagnostic-manager.cc
Warning:line 2058, column 7
Called C++ object pointer is null

Annotated Source Code

Press '?' to see keyboard shortcuts

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