]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/analyzer/exploded-graph.h
analyzer: add notes to write-to-const/string from access attr [PR104793]
[thirdparty/gcc.git] / gcc / analyzer / exploded-graph.h
1 /* Classes for managing a directed graph of <point, state> pairs.
2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #ifndef GCC_ANALYZER_EXPLODED_GRAPH_H
22 #define GCC_ANALYZER_EXPLODED_GRAPH_H
23
24 namespace ana {
25
26 /* Concrete implementation of region_model_context, wiring it up to the
27 rest of the analysis engine. */
28
29 class impl_region_model_context : public region_model_context
30 {
31 public:
32 impl_region_model_context (exploded_graph &eg,
33 exploded_node *enode_for_diag,
34
35 /* TODO: should we be getting the ECs from the
36 old state, rather than the new? */
37 const program_state *old_state,
38 program_state *new_state,
39 uncertainty_t *uncertainty,
40 path_context *path_ctxt,
41
42 const gimple *stmt,
43 stmt_finder *stmt_finder = NULL);
44
45 impl_region_model_context (program_state *state,
46 const extrinsic_state &ext_state,
47 uncertainty_t *uncertainty,
48 logger *logger = NULL);
49
50 bool warn (pending_diagnostic *d) FINAL OVERRIDE;
51 void add_note (pending_note *pn) FINAL OVERRIDE;
52 void on_svalue_leak (const svalue *) OVERRIDE;
53 void on_liveness_change (const svalue_set &live_svalues,
54 const region_model *model) FINAL OVERRIDE;
55 logger *get_logger () FINAL OVERRIDE
56 {
57 return m_logger.get_logger ();
58 }
59
60 void on_state_leak (const state_machine &sm,
61 const svalue *sval,
62 state_machine::state_t state);
63
64 void on_condition (const svalue *lhs,
65 enum tree_code op,
66 const svalue *rhs) FINAL OVERRIDE;
67
68 void on_unknown_change (const svalue *sval, bool is_mutable) FINAL OVERRIDE;
69
70 void on_phi (const gphi *phi, tree rhs) FINAL OVERRIDE;
71
72 void on_unexpected_tree_code (tree t,
73 const dump_location_t &loc) FINAL OVERRIDE;
74
75 void on_escaped_function (tree fndecl) FINAL OVERRIDE;
76
77 uncertainty_t *get_uncertainty () FINAL OVERRIDE;
78
79 void purge_state_involving (const svalue *sval) FINAL OVERRIDE;
80
81 void bifurcate (custom_edge_info *info) FINAL OVERRIDE;
82 void terminate_path () FINAL OVERRIDE;
83 const extrinsic_state *get_ext_state () const FINAL OVERRIDE
84 {
85 return &m_ext_state;
86 }
87 bool get_malloc_map (sm_state_map **out_smap,
88 const state_machine **out_sm,
89 unsigned *out_sm_idx) FINAL OVERRIDE;
90 bool get_taint_map (sm_state_map **out_smap,
91 const state_machine **out_sm,
92 unsigned *out_sm_idx) FINAL OVERRIDE;
93
94 const gimple *get_stmt () const OVERRIDE { return m_stmt; }
95
96 exploded_graph *m_eg;
97 log_user m_logger;
98 exploded_node *m_enode_for_diag;
99 const program_state *m_old_state;
100 program_state *m_new_state;
101 const gimple *m_stmt;
102 stmt_finder *m_stmt_finder;
103 const extrinsic_state &m_ext_state;
104 uncertainty_t *m_uncertainty;
105 path_context *m_path_ctxt;
106 };
107
108 /* A <program_point, program_state> pair, used internally by
109 exploded_node as its immutable data, and as a key for identifying
110 exploded_nodes we've already seen in the graph. */
111
112 class point_and_state
113 {
114 public:
115 point_and_state (const program_point &point,
116 const program_state &state)
117 : m_point (point),
118 m_state (state),
119 m_hash (m_point.hash () ^ m_state.hash ())
120 {
121 /* We shouldn't be building point_and_states and thus exploded_nodes
122 for states that aren't valid. */
123 gcc_assert (state.m_valid);
124 }
125
126 hashval_t hash () const
127 {
128 return m_hash;
129 }
130 bool operator== (const point_and_state &other) const
131 {
132 return m_point == other.m_point && m_state == other.m_state;
133 }
134
135 const program_point &get_point () const { return m_point; }
136 const program_state &get_state () const { return m_state; }
137
138 void set_state (const program_state &state)
139 {
140 m_state = state;
141 m_hash = m_point.hash () ^ m_state.hash ();
142 }
143
144 void validate (const extrinsic_state &ext_state) const;
145
146 private:
147 program_point m_point;
148 program_state m_state;
149 hashval_t m_hash;
150 };
151
152 /* A traits class for exploded graphs and their nodes and edges. */
153
154 struct eg_traits
155 {
156 typedef exploded_node node_t;
157 typedef exploded_edge edge_t;
158 typedef exploded_graph graph_t;
159 struct dump_args_t
160 {
161 dump_args_t (const exploded_graph &eg) : m_eg (eg) {}
162
163 bool show_enode_details_p (const exploded_node &enode) const;
164
165 virtual void
166 dump_extra_info (const exploded_node *, pretty_printer *) const {}
167
168 const exploded_graph &m_eg;
169 };
170 typedef exploded_cluster cluster_t;
171 };
172
173 /* An exploded_node is a unique, immutable <point, state> pair within the
174 exploded_graph.
175 Each exploded_node has a unique index within the graph
176 (for ease of debugging). */
177
178 class exploded_node : public dnode<eg_traits>
179 {
180 public:
181 /* Has this enode had exploded_graph::process_node called on it?
182 This allows us to distinguish enodes that were merged during
183 worklist-handling, and thus never had process_node called on them
184 (in favor of processing the merged node). */
185 enum status
186 {
187 /* Node is in the worklist. */
188 STATUS_WORKLIST,
189
190 /* Node has had exploded_graph::process_node called on it. */
191 STATUS_PROCESSED,
192
193 /* Node was left unprocessed due to merger; it won't have had
194 exploded_graph::process_node called on it. */
195 STATUS_MERGER,
196
197 /* Node was processed by maybe_process_run_of_before_supernode_enodes. */
198 STATUS_BULK_MERGED
199 };
200 static const char * status_to_str (enum status s);
201
202 exploded_node (const point_and_state &ps, int index);
203
204 hashval_t hash () const { return m_ps.hash (); }
205
206 const char * get_dot_fillcolor () const;
207 void dump_dot (graphviz_out *gv, const dump_args_t &args)
208 const FINAL OVERRIDE;
209 void dump_dot_id (pretty_printer *pp) const;
210
211 void dump_to_pp (pretty_printer *pp, const extrinsic_state &ext_state) const;
212 void dump (FILE *fp, const extrinsic_state &ext_state) const;
213 void dump (const extrinsic_state &ext_state) const;
214
215 void dump_processed_stmts (pretty_printer *pp) const;
216 void dump_saved_diagnostics (pretty_printer *pp) const;
217
218 json::object *to_json (const extrinsic_state &ext_state) const;
219
220 /* The result of on_stmt. */
221 struct on_stmt_flags
222 {
223 on_stmt_flags () : m_terminate_path (false)
224 {}
225
226 static on_stmt_flags terminate_path ()
227 {
228 return on_stmt_flags (true);
229 }
230
231 /* Should we stop analyzing this path (on_stmt may have already
232 added nodes/edges, e.g. when handling longjmp). */
233 bool m_terminate_path : 1;
234
235 private:
236 on_stmt_flags (bool terminate_path)
237 : m_terminate_path (terminate_path)
238 {}
239 };
240
241 on_stmt_flags on_stmt (exploded_graph &eg,
242 const supernode *snode,
243 const gimple *stmt,
244 program_state *state,
245 uncertainty_t *uncertainty,
246 path_context *path_ctxt);
247 void on_stmt_pre (exploded_graph &eg,
248 const gimple *stmt,
249 program_state *state,
250 bool *out_terminate_path,
251 bool *out_unknown_side_effects,
252 region_model_context *ctxt);
253 void on_stmt_post (const gimple *stmt,
254 program_state *state,
255 bool unknown_side_effects,
256 region_model_context *ctxt);
257
258 bool on_edge (exploded_graph &eg,
259 const superedge *succ,
260 program_point *next_point,
261 program_state *next_state,
262 uncertainty_t *uncertainty);
263 void on_longjmp (exploded_graph &eg,
264 const gcall *call,
265 program_state *new_state,
266 region_model_context *ctxt);
267
268 void detect_leaks (exploded_graph &eg);
269
270 const program_point &get_point () const { return m_ps.get_point (); }
271 const supernode *get_supernode () const
272 {
273 return get_point ().get_supernode ();
274 }
275 function *get_function () const
276 {
277 return get_point ().get_function ();
278 }
279 int get_stack_depth () const
280 {
281 return get_point ().get_stack_depth ();
282 }
283 const gimple *get_stmt () const { return get_point ().get_stmt (); }
284 const gimple *get_processed_stmt (unsigned idx) const;
285
286 const program_state &get_state () const { return m_ps.get_state (); }
287
288 const point_and_state *get_ps_key () const { return &m_ps; }
289 const program_point *get_point_key () const { return &m_ps.get_point (); }
290
291 void dump_succs_and_preds (FILE *outf) const;
292
293 enum status get_status () const { return m_status; }
294 void set_status (enum status status)
295 {
296 gcc_assert (m_status == STATUS_WORKLIST);
297 m_status = status;
298 }
299
300 void add_diagnostic (const saved_diagnostic *sd)
301 {
302 m_saved_diagnostics.safe_push (sd);
303 }
304 unsigned get_num_diagnostics () const
305 {
306 return m_saved_diagnostics.length ();
307 }
308 const saved_diagnostic *get_saved_diagnostic (unsigned idx) const
309 {
310 return m_saved_diagnostics[idx];
311 }
312
313 private:
314 DISABLE_COPY_AND_ASSIGN (exploded_node);
315
316 /* The <program_point, program_state> pair. This is const, as it
317 is immutable once the exploded_node has been created. */
318 const point_and_state m_ps;
319
320 enum status m_status;
321
322 /* The saved_diagnostics at this enode, borrowed from the
323 diagnostic_manager. */
324 auto_vec <const saved_diagnostic *> m_saved_diagnostics;
325
326 public:
327 /* The index of this exploded_node. */
328 const int m_index;
329
330 /* The number of stmts that were processed when process_node was
331 called on this enode. */
332 unsigned m_num_processed_stmts;
333 };
334
335 /* An edge within the exploded graph.
336 Some exploded_edges have an underlying superedge; others don't. */
337
338 class exploded_edge : public dedge<eg_traits>
339 {
340 public:
341 exploded_edge (exploded_node *src, exploded_node *dest,
342 const superedge *sedge,
343 custom_edge_info *custom_info);
344 ~exploded_edge ();
345 void dump_dot (graphviz_out *gv, const dump_args_t &args)
346 const FINAL OVERRIDE;
347 void dump_dot_label (pretty_printer *pp) const;
348
349 json::object *to_json () const;
350
351 //private:
352 const superedge *const m_sedge;
353
354 /* NULL for most edges; will be non-NULL for special cases
355 such as an unwind from a longjmp to a setjmp, or when
356 a signal is delivered to a signal-handler.
357
358 Owned by this class. */
359 custom_edge_info *m_custom_info;
360
361 private:
362 DISABLE_COPY_AND_ASSIGN (exploded_edge);
363 };
364
365 /* Extra data for an exploded_edge that represents dynamic call info ( calls
366 that doesn't have an underlying superedge representing the call ). */
367
368 class dynamic_call_info_t : public custom_edge_info
369 {
370 public:
371 dynamic_call_info_t (const gcall *dynamic_call,
372 const bool is_returning_call = false)
373 : m_dynamic_call (dynamic_call),
374 m_is_returning_call (is_returning_call)
375 {}
376
377 void print (pretty_printer *pp) const FINAL OVERRIDE
378 {
379 if (m_is_returning_call)
380 pp_string (pp, "dynamic_return");
381 else
382 pp_string (pp, "dynamic_call");
383 }
384
385 bool update_model (region_model *model,
386 const exploded_edge *eedge,
387 region_model_context *ctxt) const FINAL OVERRIDE;
388
389 void add_events_to_path (checker_path *emission_path,
390 const exploded_edge &eedge) const FINAL OVERRIDE;
391 private:
392 const gcall *m_dynamic_call;
393 const bool m_is_returning_call;
394 };
395
396
397 /* Extra data for an exploded_edge that represents a rewind from a
398 longjmp to a setjmp (or from a siglongjmp to a sigsetjmp). */
399
400 class rewind_info_t : public custom_edge_info
401 {
402 public:
403 rewind_info_t (const setjmp_record &setjmp_record,
404 const gcall *longjmp_call)
405 : m_setjmp_record (setjmp_record),
406 m_longjmp_call (longjmp_call)
407 {}
408
409 void print (pretty_printer *pp) const FINAL OVERRIDE
410 {
411 pp_string (pp, "rewind");
412 }
413
414 bool update_model (region_model *model,
415 const exploded_edge *eedge,
416 region_model_context *ctxt) const FINAL OVERRIDE;
417
418 void add_events_to_path (checker_path *emission_path,
419 const exploded_edge &eedge) const FINAL OVERRIDE;
420
421 const program_point &get_setjmp_point () const
422 {
423 const program_point &origin_point = get_enode_origin ()->get_point ();
424
425 /* "origin_point" ought to be before the call to "setjmp". */
426 gcc_assert (origin_point.get_kind () == PK_BEFORE_STMT);
427
428 /* TODO: assert that it's the final stmt in its supernode. */
429
430 return origin_point;
431 }
432
433 const gcall *get_setjmp_call () const
434 {
435 return m_setjmp_record.m_setjmp_call;
436 }
437
438 const gcall *get_longjmp_call () const
439 {
440 return m_longjmp_call;
441 }
442
443 const exploded_node *get_enode_origin () const
444 {
445 return m_setjmp_record.m_enode;
446 }
447
448 private:
449 setjmp_record m_setjmp_record;
450 const gcall *m_longjmp_call;
451 };
452
453 /* Statistics about aspects of an exploded_graph. */
454
455 struct stats
456 {
457 stats (int num_supernodes);
458 void log (logger *logger) const;
459 void dump (FILE *out) const;
460
461 int get_total_enodes () const;
462
463 int m_num_nodes[NUM_POINT_KINDS];
464 int m_node_reuse_count;
465 int m_node_reuse_after_merge_count;
466 int m_num_supernodes;
467 };
468
469 /* Traits class for ensuring uniqueness of point_and_state data within
470 an exploded_graph. */
471
472 struct eg_hash_map_traits
473 {
474 typedef const point_and_state *key_type;
475 typedef exploded_node *value_type;
476 typedef exploded_node *compare_type;
477
478 static inline hashval_t hash (const key_type &k)
479 {
480 gcc_assert (k != NULL);
481 gcc_assert (k != reinterpret_cast<key_type> (1));
482 return k->hash ();
483 }
484 static inline bool equal_keys (const key_type &k1, const key_type &k2)
485 {
486 gcc_assert (k1 != NULL);
487 gcc_assert (k2 != NULL);
488 gcc_assert (k1 != reinterpret_cast<key_type> (1));
489 gcc_assert (k2 != reinterpret_cast<key_type> (1));
490 if (k1 && k2)
491 return *k1 == *k2;
492 else
493 /* Otherwise they must both be non-NULL. */
494 return k1 == k2;
495 }
496 template <typename T>
497 static inline void remove (T &)
498 {
499 /* empty; the nodes are handled elsewhere. */
500 }
501 template <typename T>
502 static inline void mark_deleted (T &entry)
503 {
504 entry.m_key = reinterpret_cast<key_type> (1);
505 }
506 template <typename T>
507 static inline void mark_empty (T &entry)
508 {
509 entry.m_key = NULL;
510 }
511 template <typename T>
512 static inline bool is_deleted (const T &entry)
513 {
514 return entry.m_key == reinterpret_cast<key_type> (1);
515 }
516 template <typename T>
517 static inline bool is_empty (const T &entry)
518 {
519 return entry.m_key == NULL;
520 }
521 static const bool empty_zero_p = false;
522 };
523
524 /* Per-program_point data for an exploded_graph. */
525
526 struct per_program_point_data
527 {
528 per_program_point_data (const program_point &key)
529 : m_key (key), m_excess_enodes (0)
530 {}
531
532 const program_point m_key;
533 auto_vec<exploded_node *> m_enodes;
534 /* The number of attempts to create an enode for this point
535 after exceeding --param=analyzer-max-enodes-per-program-point. */
536 int m_excess_enodes;
537 };
538
539 /* Traits class for storing per-program_point data within
540 an exploded_graph. */
541
542 struct eg_point_hash_map_traits
543 {
544 typedef const program_point *key_type;
545 typedef per_program_point_data *value_type;
546 typedef per_program_point_data *compare_type;
547
548 static inline hashval_t hash (const key_type &k)
549 {
550 gcc_assert (k != NULL);
551 gcc_assert (k != reinterpret_cast<key_type> (1));
552 return k->hash ();
553 }
554 static inline bool equal_keys (const key_type &k1, const key_type &k2)
555 {
556 gcc_assert (k1 != NULL);
557 gcc_assert (k2 != NULL);
558 gcc_assert (k1 != reinterpret_cast<key_type> (1));
559 gcc_assert (k2 != reinterpret_cast<key_type> (1));
560 if (k1 && k2)
561 return *k1 == *k2;
562 else
563 /* Otherwise they must both be non-NULL. */
564 return k1 == k2;
565 }
566 template <typename T>
567 static inline void remove (T &)
568 {
569 /* empty; the nodes are handled elsewhere. */
570 }
571 template <typename T>
572 static inline void mark_deleted (T &entry)
573 {
574 entry.m_key = reinterpret_cast<key_type> (1);
575 }
576 template <typename T>
577 static inline void mark_empty (T &entry)
578 {
579 entry.m_key = NULL;
580 }
581 template <typename T>
582 static inline bool is_deleted (const T &entry)
583 {
584 return entry.m_key == reinterpret_cast<key_type> (1);
585 }
586 template <typename T>
587 static inline bool is_empty (const T &entry)
588 {
589 return entry.m_key == NULL;
590 }
591 static const bool empty_zero_p = false;
592 };
593
594 /* Data about a particular call_string within an exploded_graph. */
595
596 struct per_call_string_data
597 {
598 per_call_string_data (const call_string &key, int num_supernodes)
599 : m_key (key), m_stats (num_supernodes)
600 {}
601
602 const call_string m_key;
603 stats m_stats;
604 };
605
606 /* Traits class for storing per-call_string data within
607 an exploded_graph. */
608
609 struct eg_call_string_hash_map_traits
610 {
611 typedef const call_string *key_type;
612 typedef per_call_string_data *value_type;
613 typedef per_call_string_data *compare_type;
614
615 static inline hashval_t hash (const key_type &k)
616 {
617 gcc_assert (k != NULL);
618 gcc_assert (k != reinterpret_cast<key_type> (1));
619 return k->hash ();
620 }
621 static inline bool equal_keys (const key_type &k1, const key_type &k2)
622 {
623 gcc_assert (k1 != NULL);
624 gcc_assert (k2 != NULL);
625 gcc_assert (k1 != reinterpret_cast<key_type> (1));
626 gcc_assert (k2 != reinterpret_cast<key_type> (1));
627 if (k1 && k2)
628 return *k1 == *k2;
629 else
630 /* Otherwise they must both be non-NULL. */
631 return k1 == k2;
632 }
633 template <typename T>
634 static inline void remove (T &)
635 {
636 /* empty; the nodes are handled elsewhere. */
637 }
638 template <typename T>
639 static inline void mark_deleted (T &entry)
640 {
641 entry.m_key = reinterpret_cast<key_type> (1);
642 }
643 template <typename T>
644 static inline void mark_empty (T &entry)
645 {
646 entry.m_key = NULL;
647 }
648 template <typename T>
649 static inline bool is_deleted (const T &entry)
650 {
651 return entry.m_key == reinterpret_cast<key_type> (1);
652 }
653 template <typename T>
654 static inline bool is_empty (const T &entry)
655 {
656 return entry.m_key == NULL;
657 }
658 static const bool empty_zero_p = false;
659 };
660
661 /* Data about a particular function within an exploded_graph. */
662
663 struct per_function_data
664 {
665 per_function_data () {}
666
667 void add_call_summary (exploded_node *node)
668 {
669 m_summaries.safe_push (node);
670 }
671
672 auto_vec<exploded_node *> m_summaries;
673 };
674
675
676 /* The strongly connected components of a supergraph.
677 In particular, this allows us to compute a partial ordering
678 of supernodes. */
679
680 class strongly_connected_components
681 {
682 public:
683 strongly_connected_components (const supergraph &sg, logger *logger);
684
685 int get_scc_id (int node_index) const
686 {
687 return m_per_node[node_index].m_lowlink;
688 }
689
690 void dump () const;
691
692 json::array *to_json () const;
693
694 private:
695 struct per_node_data
696 {
697 per_node_data ()
698 : m_index (-1), m_lowlink (-1), m_on_stack (false)
699 {}
700
701 int m_index;
702 int m_lowlink;
703 bool m_on_stack;
704 };
705
706 void strong_connect (unsigned index);
707
708 const supergraph &m_sg;
709 auto_vec<unsigned> m_stack;
710 auto_vec<per_node_data> m_per_node;
711 };
712
713 /* The worklist of exploded_node instances that have been added to
714 an exploded_graph, but that haven't yet been processed to find
715 their successors (or warnings).
716
717 The enodes are stored in a priority queue, ordered by a topological
718 sort of the SCCs in the supergraph, so that enodes for the same
719 program_point should appear at the front of the queue together.
720 This allows for state-merging at CFG join-points, so that
721 sufficiently-similar enodes can be merged into one. */
722
723 class worklist
724 {
725 public:
726 worklist (const exploded_graph &eg, const analysis_plan &plan);
727 unsigned length () const;
728 exploded_node *take_next ();
729 exploded_node *peek_next ();
730 void add_node (exploded_node *enode);
731 int get_scc_id (const supernode &snode) const
732 {
733 return m_scc.get_scc_id (snode.m_index);
734 }
735
736 json::object *to_json () const;
737
738 private:
739 class key_t
740 {
741 public:
742 key_t (const worklist &w, exploded_node *enode)
743 : m_worklist (w), m_enode (enode)
744 {}
745
746 bool operator< (const key_t &other) const
747 {
748 return cmp (*this, other) < 0;
749 }
750
751 bool operator== (const key_t &other) const
752 {
753 return cmp (*this, other) == 0;
754 }
755
756 bool operator> (const key_t &other) const
757 {
758 return !(*this == other || *this < other);
759 }
760
761 private:
762 static int cmp (const key_t &ka, const key_t &kb);
763
764 int get_scc_id (const exploded_node *enode) const
765 {
766 const supernode *snode = enode->get_supernode ();
767 if (snode == NULL)
768 return 0;
769 return m_worklist.m_scc.get_scc_id (snode->m_index);
770 }
771
772 const worklist &m_worklist;
773 exploded_node *m_enode;
774 };
775
776 /* The order is important here: m_scc needs to stick around
777 until after m_queue has finished being cleaned up (the dtor
778 calls the ordering fns). */
779 strongly_connected_components m_scc;
780 const analysis_plan &m_plan;
781
782 /* Priority queue, backed by a fibonacci_heap. */
783 typedef fibonacci_heap<key_t, exploded_node> queue_t;
784 queue_t m_queue;
785 };
786
787 /* An exploded_graph is a directed graph of unique <point, state> pairs.
788 It also has a worklist of nodes that are waiting for their successors
789 to be added to the graph. */
790
791 class exploded_graph : public digraph<eg_traits>
792 {
793 public:
794 typedef hash_map <const call_string *, per_call_string_data *,
795 eg_call_string_hash_map_traits> call_string_data_map_t;
796
797 exploded_graph (const supergraph &sg, logger *logger,
798 const extrinsic_state &ext_state,
799 const state_purge_map *purge_map,
800 const analysis_plan &plan,
801 int verbosity);
802 ~exploded_graph ();
803
804 logger *get_logger () const { return m_logger.get_logger (); }
805
806 const supergraph &get_supergraph () const { return m_sg; }
807 const extrinsic_state &get_ext_state () const { return m_ext_state; }
808 engine *get_engine () const { return m_ext_state.get_engine (); }
809 const state_purge_map *get_purge_map () const { return m_purge_map; }
810 const analysis_plan &get_analysis_plan () const { return m_plan; }
811
812 exploded_node *get_origin () const { return m_origin; }
813
814 exploded_node *add_function_entry (function *fun);
815
816 void build_initial_worklist ();
817 void process_worklist ();
818 bool maybe_process_run_of_before_supernode_enodes (exploded_node *node);
819 void process_node (exploded_node *node);
820
821 bool maybe_create_dynamic_call (const gcall *call,
822 tree fn_decl,
823 exploded_node *node,
824 program_state next_state,
825 program_point &next_point,
826 uncertainty_t *uncertainty,
827 logger *logger);
828
829 exploded_node *get_or_create_node (const program_point &point,
830 const program_state &state,
831 exploded_node *enode_for_diag);
832 exploded_edge *add_edge (exploded_node *src, exploded_node *dest,
833 const superedge *sedge,
834 custom_edge_info *custom = NULL);
835
836 per_program_point_data *
837 get_or_create_per_program_point_data (const program_point &);
838 per_program_point_data *
839 get_per_program_point_data (const program_point &) const;
840
841 per_call_string_data *
842 get_or_create_per_call_string_data (const call_string &);
843
844 per_function_data *
845 get_or_create_per_function_data (function *);
846 per_function_data *get_per_function_data (function *) const;
847
848 void save_diagnostic (const state_machine &sm,
849 const exploded_node *enode,
850 const supernode *node, const gimple *stmt,
851 stmt_finder *finder,
852 tree var, state_machine::state_t state,
853 pending_diagnostic *d);
854
855 diagnostic_manager &get_diagnostic_manager ()
856 {
857 return m_diagnostic_manager;
858 }
859 const diagnostic_manager &get_diagnostic_manager () const
860 {
861 return m_diagnostic_manager;
862 }
863
864 stats *get_global_stats () { return &m_global_stats; }
865 stats *get_or_create_function_stats (function *fn);
866 void log_stats () const;
867 void dump_stats (FILE *) const;
868 void dump_states_for_supernode (FILE *, const supernode *snode) const;
869 void dump_exploded_nodes () const;
870
871 json::object *to_json () const;
872
873 exploded_node *get_node_by_index (int idx) const;
874
875 const call_string_data_map_t *get_per_call_string_data () const
876 { return &m_per_call_string_data; }
877
878 int get_scc_id (const supernode &node) const
879 {
880 return m_worklist.get_scc_id (node);
881 }
882
883 void on_escaped_function (tree fndecl);
884
885 private:
886 void print_bar_charts (pretty_printer *pp) const;
887
888 DISABLE_COPY_AND_ASSIGN (exploded_graph);
889
890 const supergraph &m_sg;
891
892 log_user m_logger;
893
894 /* Map from point/state to exploded node.
895 To avoid duplication we store point_and_state
896 *pointers* as keys, rather than point_and_state, using the
897 instance from within the exploded_node, with a custom hasher. */
898 typedef hash_map <const point_and_state *, exploded_node *,
899 eg_hash_map_traits> map_t;
900 map_t m_point_and_state_to_node;
901
902 /* Map from program_point to per-program_point data. */
903 typedef hash_map <const program_point *, per_program_point_data *,
904 eg_point_hash_map_traits> point_map_t;
905 point_map_t m_per_point_data;
906
907 worklist m_worklist;
908
909 exploded_node *m_origin;
910
911 const extrinsic_state &m_ext_state;
912
913 const state_purge_map *const m_purge_map;
914
915 const analysis_plan &m_plan;
916
917 typedef hash_map<function *, per_function_data *> per_function_data_t;
918 per_function_data_t m_per_function_data;
919
920 diagnostic_manager m_diagnostic_manager;
921
922 /* Stats. */
923 stats m_global_stats;
924 typedef ordered_hash_map<function *, stats *> function_stat_map_t;
925 function_stat_map_t m_per_function_stats;
926 stats m_functionless_stats;
927
928 call_string_data_map_t m_per_call_string_data;
929
930 auto_vec<int> m_PK_AFTER_SUPERNODE_per_snode;
931
932 /* Functions with a top-level enode, to make add_function_entry
933 be idempotent, for use in handling callbacks. */
934 hash_set<function *> m_functions_with_enodes;
935 };
936
937 /* A path within an exploded_graph: a sequence of edges. */
938
939 class exploded_path
940 {
941 public:
942 exploded_path () : m_edges () {}
943 exploded_path (const exploded_path &other);
944
945 unsigned length () const { return m_edges.length (); }
946
947 bool find_stmt_backwards (const gimple *search_stmt,
948 int *out_idx) const;
949
950 exploded_node *get_final_enode () const;
951
952 void dump_to_pp (pretty_printer *pp,
953 const extrinsic_state *ext_state) const;
954 void dump (FILE *fp, const extrinsic_state *ext_state) const;
955 void dump (const extrinsic_state *ext_state = NULL) const;
956 void dump_to_file (const char *filename,
957 const extrinsic_state &ext_state) const;
958
959 bool feasible_p (logger *logger, feasibility_problem **out,
960 engine *eng, const exploded_graph *eg) const;
961
962 auto_vec<const exploded_edge *> m_edges;
963 };
964
965 /* A reason why a particular exploded_path is infeasible. */
966
967 class feasibility_problem
968 {
969 public:
970 feasibility_problem (unsigned eedge_idx,
971 const exploded_edge &eedge,
972 const gimple *last_stmt,
973 rejected_constraint *rc)
974 : m_eedge_idx (eedge_idx), m_eedge (eedge),
975 m_last_stmt (last_stmt), m_rc (rc)
976 {}
977 ~feasibility_problem () { delete m_rc; }
978
979 void dump_to_pp (pretty_printer *pp) const;
980
981 unsigned m_eedge_idx;
982 const exploded_edge &m_eedge;
983 const gimple *m_last_stmt;
984 rejected_constraint *m_rc;
985 };
986
987 /* A class for capturing the state of a node when checking a path
988 through the exploded_graph for feasibility. */
989
990 class feasibility_state
991 {
992 public:
993 feasibility_state (region_model_manager *manager,
994 const supergraph &sg);
995 feasibility_state (const feasibility_state &other);
996
997 bool maybe_update_for_edge (logger *logger,
998 const exploded_edge *eedge,
999 rejected_constraint **out_rc);
1000
1001 const region_model &get_model () const { return m_model; }
1002 const auto_sbitmap &get_snodes_visited () const { return m_snodes_visited; }
1003
1004 private:
1005 region_model m_model;
1006 auto_sbitmap m_snodes_visited;
1007 };
1008
1009 /* Finding the shortest exploded_path within an exploded_graph. */
1010
1011 typedef shortest_paths<eg_traits, exploded_path> shortest_exploded_paths;
1012
1013 /* Abstract base class for use when passing NULL as the stmt for
1014 a possible warning, allowing the choice of stmt to be deferred
1015 until after we have an emission path (and know we're emitting a
1016 warning). */
1017
1018 class stmt_finder
1019 {
1020 public:
1021 virtual ~stmt_finder () {}
1022 virtual stmt_finder *clone () const = 0;
1023 virtual const gimple *find_stmt (const exploded_path &epath) = 0;
1024 };
1025
1026 // TODO: split the above up?
1027
1028 } // namespace ana
1029
1030 #endif /* GCC_ANALYZER_EXPLODED_GRAPH_H */