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