1 /* Classes for managing a directed graph of <point, state> pairs.
2 Copyright (C) 2019-2024 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef GCC_ANALYZER_EXPLODED_GRAPH_H
22 #define GCC_ANALYZER_EXPLODED_GRAPH_H
24 #include "alloc-pool.h"
25 #include "fibonacci_heap.h"
26 #include "supergraph.h"
28 #include "shortest-paths.h"
29 #include "analyzer/sm.h"
30 #include "analyzer/program-state.h"
31 #include "analyzer/diagnostic-manager.h"
35 /* Concrete implementation of region_model_context, wiring it up to the
36 rest of the analysis engine. */
38 class impl_region_model_context
: public region_model_context
41 impl_region_model_context (exploded_graph
&eg
,
42 exploded_node
*enode_for_diag
,
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
,
52 stmt_finder
*stmt_finder
= NULL
,
54 bool *out_could_have_done_work
= nullptr);
56 impl_region_model_context (program_state
*state
,
57 const extrinsic_state
&ext_state
,
58 uncertainty_t
*uncertainty
,
59 logger
*logger
= NULL
);
61 bool warn (std::unique_ptr
<pending_diagnostic
> d
,
62 const stmt_finder
*custom_finder
= NULL
) final override
;
63 void add_note (std::unique_ptr
<pending_note
> pn
) final override
;
64 void add_event (std::unique_ptr
<checker_event
> event
) final override
;
65 void on_svalue_leak (const svalue
*) override
;
66 void on_liveness_change (const svalue_set
&live_svalues
,
67 const region_model
*model
) final override
;
68 logger
*get_logger () final override
70 return m_logger
.get_logger ();
73 void on_state_leak (const state_machine
&sm
,
75 state_machine::state_t state
);
77 void on_condition (const svalue
*lhs
,
79 const svalue
*rhs
) final override
;
81 void on_bounded_ranges (const svalue
&sval
,
82 const bounded_ranges
&ranges
) final override
;
84 void on_pop_frame (const frame_region
*frame_reg
) final override
;
86 void on_unknown_change (const svalue
*sval
, bool is_mutable
) final override
;
88 void on_phi (const gphi
*phi
, tree rhs
) final override
;
90 void on_unexpected_tree_code (tree t
,
91 const dump_location_t
&loc
) final override
;
93 void on_escaped_function (tree fndecl
) final override
;
95 uncertainty_t
*get_uncertainty () final override
;
97 void purge_state_involving (const svalue
*sval
) final override
;
99 void bifurcate (std::unique_ptr
<custom_edge_info
> info
) final override
;
100 void terminate_path () final override
;
101 const extrinsic_state
*get_ext_state () const final override
106 get_state_map_by_name (const char *name
,
107 sm_state_map
**out_smap
,
108 const state_machine
**out_sm
,
109 unsigned *out_sm_idx
,
110 std::unique_ptr
<sm_context
> *out_sm_context
) override
;
112 const gimple
*get_stmt () const override
{ return m_stmt
; }
113 const exploded_graph
*get_eg () const override
{ return m_eg
; }
115 void maybe_did_work () override
;
116 bool checking_for_infinite_loop_p () const override
{ return false; }
117 void on_unusable_in_infinite_loop () override
{}
119 exploded_graph
*m_eg
;
121 exploded_node
*m_enode_for_diag
;
122 const program_state
*m_old_state
;
123 program_state
*m_new_state
;
124 const gimple
*m_stmt
;
125 stmt_finder
*m_stmt_finder
;
126 const extrinsic_state
&m_ext_state
;
127 uncertainty_t
*m_uncertainty
;
128 path_context
*m_path_ctxt
;
129 bool *m_out_could_have_done_work
;
132 /* A <program_point, program_state> pair, used internally by
133 exploded_node as its immutable data, and as a key for identifying
134 exploded_nodes we've already seen in the graph. */
136 class point_and_state
139 point_and_state (const program_point
&point
,
140 const program_state
&state
)
143 m_hash (m_point
.hash () ^ m_state
.hash ())
145 /* We shouldn't be building point_and_states and thus exploded_nodes
146 for states that aren't valid. */
147 gcc_assert (state
.m_valid
);
150 hashval_t
hash () const
154 bool operator== (const point_and_state
&other
) const
156 return m_point
== other
.m_point
&& m_state
== other
.m_state
;
159 const program_point
&get_point () const { return m_point
; }
160 const program_state
&get_state () const { return m_state
; }
162 void set_state (const program_state
&state
)
165 m_hash
= m_point
.hash () ^ m_state
.hash ();
168 void validate (const extrinsic_state
&ext_state
) const;
171 program_point m_point
;
172 program_state m_state
;
176 /* A traits class for exploded graphs and their nodes and edges. */
180 typedef exploded_node node_t
;
181 typedef exploded_edge edge_t
;
182 typedef exploded_graph graph_t
;
185 dump_args_t (const exploded_graph
&eg
) : m_eg (eg
) {}
187 bool show_enode_details_p (const exploded_node
&enode
) const;
190 dump_extra_info (const exploded_node
*, pretty_printer
*) const {}
192 const exploded_graph
&m_eg
;
194 typedef exploded_cluster cluster_t
;
197 /* An exploded_node is a unique, immutable <point, state> pair within the
199 Each exploded_node has a unique index within the graph
200 (for ease of debugging). */
202 class exploded_node
: public dnode
<eg_traits
>
205 /* Has this enode had exploded_graph::process_node called on it?
206 This allows us to distinguish enodes that were merged during
207 worklist-handling, and thus never had process_node called on them
208 (in favor of processing the merged node). */
211 /* Node is in the worklist. */
214 /* Node has had exploded_graph::process_node called on it. */
217 /* Node was left unprocessed due to merger; it won't have had
218 exploded_graph::process_node called on it. */
221 /* Node was processed by maybe_process_run_of_before_supernode_enodes. */
224 static const char * status_to_str (enum status s
);
226 exploded_node (const point_and_state
&ps
, int index
);
228 hashval_t
hash () const { return m_ps
.hash (); }
230 const char * get_dot_fillcolor () const;
231 void dump_dot (graphviz_out
*gv
, const dump_args_t
&args
)
232 const final override
;
233 void dump_dot_id (pretty_printer
*pp
) const;
235 void dump_to_pp (pretty_printer
*pp
, const extrinsic_state
&ext_state
) const;
236 void dump (FILE *fp
, const extrinsic_state
&ext_state
) const;
237 void dump (const extrinsic_state
&ext_state
) const;
239 void dump_processed_stmts (pretty_printer
*pp
) const;
240 void dump_saved_diagnostics (pretty_printer
*pp
) const;
242 json::object
*to_json (const extrinsic_state
&ext_state
) const;
244 /* The result of on_stmt. */
247 on_stmt_flags () : m_terminate_path (false)
250 static on_stmt_flags
terminate_path ()
252 return on_stmt_flags (true);
255 /* Should we stop analyzing this path (on_stmt may have already
256 added nodes/edges, e.g. when handling longjmp). */
257 bool m_terminate_path
: 1;
260 on_stmt_flags (bool terminate_path
)
261 : m_terminate_path (terminate_path
)
265 on_stmt_flags
on_stmt (exploded_graph
&eg
,
266 const supernode
*snode
,
268 program_state
*state
,
269 uncertainty_t
*uncertainty
,
270 bool *out_could_have_done_work
,
271 path_context
*path_ctxt
);
272 void on_stmt_pre (exploded_graph
&eg
,
274 program_state
*state
,
275 bool *out_terminate_path
,
276 bool *out_unknown_side_effects
,
277 region_model_context
*ctxt
);
278 void on_stmt_post (const gimple
*stmt
,
279 program_state
*state
,
280 bool unknown_side_effects
,
281 region_model_context
*ctxt
);
283 on_stmt_flags
replay_call_summaries (exploded_graph
&eg
,
284 const supernode
*snode
,
285 const gcall
*call_stmt
,
286 program_state
*state
,
287 path_context
*path_ctxt
,
289 per_function_data
*called_fn_data
,
290 region_model_context
*ctxt
);
291 void replay_call_summary (exploded_graph
&eg
,
292 const supernode
*snode
,
293 const gcall
*call_stmt
,
294 program_state
*state
,
295 path_context
*path_ctxt
,
297 call_summary
*summary
,
298 region_model_context
*ctxt
);
300 bool on_edge (exploded_graph
&eg
,
301 const superedge
*succ
,
302 program_point
*next_point
,
303 program_state
*next_state
,
304 uncertainty_t
*uncertainty
);
305 void on_longjmp (exploded_graph
&eg
,
307 program_state
*new_state
,
308 region_model_context
*ctxt
);
310 void detect_leaks (exploded_graph
&eg
);
312 const program_point
&get_point () const { return m_ps
.get_point (); }
313 const supernode
*get_supernode () const
315 return get_point ().get_supernode ();
317 function
*get_function () const
319 return get_point ().get_function ();
321 int get_stack_depth () const
323 return get_point ().get_stack_depth ();
325 const gimple
*get_stmt () const { return get_point ().get_stmt (); }
326 const gimple
*get_processed_stmt (unsigned idx
) const;
328 const program_state
&get_state () const { return m_ps
.get_state (); }
330 const point_and_state
*get_ps_key () const { return &m_ps
; }
331 const program_point
*get_point_key () const { return &m_ps
.get_point (); }
333 void dump_succs_and_preds (FILE *outf
) const;
335 enum status
get_status () const { return m_status
; }
336 void set_status (enum status status
)
338 gcc_assert (m_status
== STATUS_WORKLIST
);
342 void add_diagnostic (const saved_diagnostic
*sd
)
344 m_saved_diagnostics
.safe_push (sd
);
346 unsigned get_num_diagnostics () const
348 return m_saved_diagnostics
.length ();
350 const saved_diagnostic
*get_saved_diagnostic (unsigned idx
) const
352 return m_saved_diagnostics
[idx
];
356 DISABLE_COPY_AND_ASSIGN (exploded_node
);
358 /* The <program_point, program_state> pair. This is const, as it
359 is immutable once the exploded_node has been created. */
360 const point_and_state m_ps
;
362 enum status m_status
;
364 /* The saved_diagnostics at this enode, borrowed from the
365 diagnostic_manager. */
366 auto_vec
<const saved_diagnostic
*> m_saved_diagnostics
;
369 /* The index of this exploded_node. */
372 /* The number of stmts that were processed when process_node was
373 called on this enode. */
374 unsigned m_num_processed_stmts
;
377 /* An edge within the exploded graph.
378 Some exploded_edges have an underlying superedge; others don't. */
380 class exploded_edge
: public dedge
<eg_traits
>
383 exploded_edge (exploded_node
*src
, exploded_node
*dest
,
384 const superedge
*sedge
, bool could_do_work
,
385 std::unique_ptr
<custom_edge_info
> custom_info
);
386 void dump_dot (graphviz_out
*gv
, const dump_args_t
&args
)
387 const final override
;
388 void dump_dot_label (pretty_printer
*pp
) const;
390 json::object
*to_json () const;
393 const superedge
*const m_sedge
;
395 /* NULL for most edges; will be non-NULL for special cases
396 such as an unwind from a longjmp to a setjmp, or when
397 a signal is delivered to a signal-handler. */
398 std::unique_ptr
<custom_edge_info
> m_custom_info
;
400 bool could_do_work_p () const { return m_could_do_work_p
; }
403 DISABLE_COPY_AND_ASSIGN (exploded_edge
);
405 /* For -Wanalyzer-infinite-loop.
406 Set to true during processing if any of the activity along
407 this edge is "externally-visible work" (and thus ruling this
408 out as being part of an infinite loop.
415 although it is an infinite loop, presumably the point of the
416 program is the loop body, and thus reporting this as an infinite
417 loop is likely to be unhelpful to the user. */
418 bool m_could_do_work_p
;
421 /* Extra data for an exploded_edge that represents dynamic call info ( calls
422 that doesn't have an underlying superedge representing the call ). */
424 class dynamic_call_info_t
: public custom_edge_info
427 dynamic_call_info_t (const gcall
*dynamic_call
,
428 const bool is_returning_call
= false)
429 : m_dynamic_call (dynamic_call
),
430 m_is_returning_call (is_returning_call
)
433 void print (pretty_printer
*pp
) const final override
435 if (m_is_returning_call
)
436 pp_string (pp
, "dynamic_return");
438 pp_string (pp
, "dynamic_call");
441 bool update_model (region_model
*model
,
442 const exploded_edge
*eedge
,
443 region_model_context
*ctxt
) const final override
;
445 void add_events_to_path (checker_path
*emission_path
,
446 const exploded_edge
&eedge
) const final override
;
448 const gcall
*m_dynamic_call
;
449 const bool m_is_returning_call
;
453 /* Extra data for an exploded_edge that represents a rewind from a
454 longjmp to a setjmp (or from a siglongjmp to a sigsetjmp). */
456 class rewind_info_t
: public custom_edge_info
459 rewind_info_t (const setjmp_record
&setjmp_record
,
460 const gcall
*longjmp_call
)
461 : m_setjmp_record (setjmp_record
),
462 m_longjmp_call (longjmp_call
)
465 void print (pretty_printer
*pp
) const final override
467 pp_string (pp
, "rewind");
470 bool update_model (region_model
*model
,
471 const exploded_edge
*eedge
,
472 region_model_context
*ctxt
) const final override
;
474 void add_events_to_path (checker_path
*emission_path
,
475 const exploded_edge
&eedge
) const final override
;
477 const program_point
&get_setjmp_point () const
479 const program_point
&origin_point
= get_enode_origin ()->get_point ();
481 /* "origin_point" ought to be before the call to "setjmp". */
482 gcc_assert (origin_point
.get_kind () == PK_BEFORE_STMT
);
484 /* TODO: assert that it's the final stmt in its supernode. */
489 const gcall
*get_setjmp_call () const
491 return m_setjmp_record
.m_setjmp_call
;
494 const gcall
*get_longjmp_call () const
496 return m_longjmp_call
;
499 const exploded_node
*get_enode_origin () const
501 return m_setjmp_record
.m_enode
;
505 setjmp_record m_setjmp_record
;
506 const gcall
*m_longjmp_call
;
509 /* Statistics about aspects of an exploded_graph. */
513 stats (int num_supernodes
);
514 void log (logger
*logger
) const;
515 void dump (FILE *out
) const;
517 int get_total_enodes () const;
519 int m_num_nodes
[NUM_POINT_KINDS
];
520 int m_node_reuse_count
;
521 int m_node_reuse_after_merge_count
;
522 int m_num_supernodes
;
525 /* Traits class for ensuring uniqueness of point_and_state data within
526 an exploded_graph. */
528 struct eg_hash_map_traits
530 typedef const point_and_state
*key_type
;
531 typedef exploded_node
*value_type
;
532 typedef exploded_node
*compare_type
;
534 static inline hashval_t
hash (const key_type
&k
)
536 gcc_assert (k
!= NULL
);
537 gcc_assert (k
!= reinterpret_cast<key_type
> (1));
540 static inline bool equal_keys (const key_type
&k1
, const key_type
&k2
)
542 gcc_assert (k1
!= NULL
);
543 gcc_assert (k2
!= NULL
);
544 gcc_assert (k1
!= reinterpret_cast<key_type
> (1));
545 gcc_assert (k2
!= reinterpret_cast<key_type
> (1));
549 /* Otherwise they must both be non-NULL. */
552 template <typename T
>
553 static inline void remove (T
&)
555 /* empty; the nodes are handled elsewhere. */
557 template <typename T
>
558 static inline void mark_deleted (T
&entry
)
560 entry
.m_key
= reinterpret_cast<key_type
> (1);
562 template <typename T
>
563 static inline void mark_empty (T
&entry
)
567 template <typename T
>
568 static inline bool is_deleted (const T
&entry
)
570 return entry
.m_key
== reinterpret_cast<key_type
> (1);
572 template <typename T
>
573 static inline bool is_empty (const T
&entry
)
575 return entry
.m_key
== NULL
;
577 static const bool empty_zero_p
= false;
580 /* Per-program_point data for an exploded_graph. */
582 struct per_program_point_data
584 per_program_point_data (const program_point
&key
)
585 : m_key (key
), m_excess_enodes (0)
588 const program_point m_key
;
589 auto_vec
<exploded_node
*> m_enodes
;
590 /* The number of attempts to create an enode for this point
591 after exceeding --param=analyzer-max-enodes-per-program-point. */
595 /* Traits class for storing per-program_point data within
596 an exploded_graph. */
598 struct eg_point_hash_map_traits
600 typedef const program_point
*key_type
;
601 typedef per_program_point_data
*value_type
;
602 typedef per_program_point_data
*compare_type
;
604 static inline hashval_t
hash (const key_type
&k
)
606 gcc_assert (k
!= NULL
);
607 gcc_assert (k
!= reinterpret_cast<key_type
> (1));
610 static inline bool equal_keys (const key_type
&k1
, const key_type
&k2
)
612 gcc_assert (k1
!= NULL
);
613 gcc_assert (k2
!= NULL
);
614 gcc_assert (k1
!= reinterpret_cast<key_type
> (1));
615 gcc_assert (k2
!= reinterpret_cast<key_type
> (1));
619 /* Otherwise they must both be non-NULL. */
622 template <typename T
>
623 static inline void remove (T
&)
625 /* empty; the nodes are handled elsewhere. */
627 template <typename T
>
628 static inline void mark_deleted (T
&entry
)
630 entry
.m_key
= reinterpret_cast<key_type
> (1);
632 template <typename T
>
633 static inline void mark_empty (T
&entry
)
637 template <typename T
>
638 static inline bool is_deleted (const T
&entry
)
640 return entry
.m_key
== reinterpret_cast<key_type
> (1);
642 template <typename T
>
643 static inline bool is_empty (const T
&entry
)
645 return entry
.m_key
== NULL
;
647 static const bool empty_zero_p
= false;
650 /* Data about a particular call_string within an exploded_graph. */
652 struct per_call_string_data
654 per_call_string_data (const call_string
&key
, int num_supernodes
)
655 : m_key (key
), m_stats (num_supernodes
)
658 const call_string
&m_key
;
662 /* Data about a particular function within an exploded_graph. */
664 struct per_function_data
666 per_function_data () {}
667 ~per_function_data ();
669 void add_call_summary (exploded_node
*node
);
671 auto_vec
<call_summary
*> m_summaries
;
675 /* The strongly connected components of a supergraph.
676 In particular, this allows us to compute a partial ordering
679 class strongly_connected_components
682 strongly_connected_components (const supergraph
&sg
, logger
*logger
);
684 int get_scc_id (int node_index
) const
686 return m_per_node
[node_index
].m_lowlink
;
691 json::array
*to_json () const;
697 : m_index (-1), m_lowlink (-1), m_on_stack (false)
705 void strong_connect (unsigned index
);
707 const supergraph
&m_sg
;
708 auto_vec
<unsigned> m_stack
;
709 auto_vec
<per_node_data
> m_per_node
;
712 /* The worklist of exploded_node instances that have been added to
713 an exploded_graph, but that haven't yet been processed to find
714 their successors (or warnings).
716 The enodes are stored in a priority queue, ordered by a topological
717 sort of the SCCs in the supergraph, so that enodes for the same
718 program_point should appear at the front of the queue together.
719 This allows for state-merging at CFG join-points, so that
720 sufficiently-similar enodes can be merged into one. */
725 worklist (const exploded_graph
&eg
, const analysis_plan
&plan
);
726 unsigned length () const;
727 exploded_node
*take_next ();
728 exploded_node
*peek_next ();
729 void add_node (exploded_node
*enode
);
730 int get_scc_id (const supernode
&snode
) const
732 return m_scc
.get_scc_id (snode
.m_index
);
735 json::object
*to_json () const;
741 key_t (const worklist
&w
, exploded_node
*enode
)
742 : m_worklist (w
), m_enode (enode
)
745 bool operator< (const key_t
&other
) const
747 return cmp (*this, other
) < 0;
750 bool operator== (const key_t
&other
) const
752 return cmp (*this, other
) == 0;
755 bool operator> (const key_t
&other
) const
757 return !(*this == other
|| *this < other
);
761 static int cmp (const key_t
&ka
, const key_t
&kb
);
763 int get_scc_id (const exploded_node
*enode
) const
765 const supernode
*snode
= enode
->get_supernode ();
768 return m_worklist
.m_scc
.get_scc_id (snode
->m_index
);
771 const worklist
&m_worklist
;
772 exploded_node
*m_enode
;
775 /* The order is important here: m_scc needs to stick around
776 until after m_queue has finished being cleaned up (the dtor
777 calls the ordering fns). */
778 strongly_connected_components m_scc
;
779 const analysis_plan
&m_plan
;
781 /* Priority queue, backed by a fibonacci_heap. */
782 typedef fibonacci_heap
<key_t
, exploded_node
> queue_t
;
786 /* An exploded_graph is a directed graph of unique <point, state> pairs.
787 It also has a worklist of nodes that are waiting for their successors
788 to be added to the graph. */
790 class exploded_graph
: public digraph
<eg_traits
>
793 typedef hash_map
<const call_string
*,
794 per_call_string_data
*> call_string_data_map_t
;
796 exploded_graph (const supergraph
&sg
, logger
*logger
,
797 const extrinsic_state
&ext_state
,
798 const state_purge_map
*purge_map
,
799 const analysis_plan
&plan
,
803 logger
*get_logger () const { return m_logger
.get_logger (); }
805 const supergraph
&get_supergraph () const { return m_sg
; }
806 const extrinsic_state
&get_ext_state () const { return m_ext_state
; }
807 engine
*get_engine () const { return m_ext_state
.get_engine (); }
808 const state_purge_map
*get_purge_map () const { return m_purge_map
; }
809 const analysis_plan
&get_analysis_plan () const { return m_plan
; }
811 exploded_node
*get_origin () const { return m_origin
; }
813 exploded_node
*add_function_entry (function
*fun
);
815 void build_initial_worklist ();
816 void process_worklist ();
817 bool maybe_process_run_of_before_supernode_enodes (exploded_node
*node
);
818 void process_node (exploded_node
*node
);
820 bool maybe_create_dynamic_call (const gcall
*call
,
823 program_state next_state
,
824 program_point
&next_point
,
825 uncertainty_t
*uncertainty
,
828 exploded_node
*get_or_create_node (const program_point
&point
,
829 const program_state
&state
,
830 exploded_node
*enode_for_diag
);
831 exploded_edge
*add_edge (exploded_node
*src
, exploded_node
*dest
,
832 const superedge
*sedge
, bool could_do_work
,
833 std::unique_ptr
<custom_edge_info
> custom
= NULL
);
835 per_program_point_data
*
836 get_or_create_per_program_point_data (const program_point
&);
837 per_program_point_data
*
838 get_per_program_point_data (const program_point
&) const;
840 per_call_string_data
*
841 get_or_create_per_call_string_data (const call_string
&);
844 get_or_create_per_function_data (function
*);
845 per_function_data
*get_per_function_data (function
*) const;
847 void save_diagnostic (const state_machine
&sm
,
848 const exploded_node
*enode
,
849 const supernode
*node
, const gimple
*stmt
,
851 tree var
, state_machine::state_t state
,
852 pending_diagnostic
*d
);
854 diagnostic_manager
&get_diagnostic_manager ()
856 return m_diagnostic_manager
;
858 const diagnostic_manager
&get_diagnostic_manager () const
860 return m_diagnostic_manager
;
863 stats
*get_global_stats () { return &m_global_stats
; }
864 stats
*get_or_create_function_stats (function
*fn
);
865 void log_stats () const;
866 void dump_stats (FILE *) const;
867 void dump_states_for_supernode (FILE *, const supernode
*snode
) const;
868 void dump_exploded_nodes () const;
870 json::object
*to_json () const;
872 exploded_node
*get_node_by_index (int idx
) const;
874 const call_string_data_map_t
*get_per_call_string_data () const
875 { return &m_per_call_string_data
; }
877 int get_scc_id (const supernode
&node
) const
879 return m_worklist
.get_scc_id (node
);
882 void on_escaped_function (tree fndecl
);
884 /* In infinite-loop.cc */
885 void detect_infinite_loops ();
887 /* In infinite-recursion.cc */
888 void detect_infinite_recursion (exploded_node
*enode
);
889 exploded_node
*find_previous_entry_to (function
*top_of_stack_fun
,
890 exploded_node
*enode
) const;
893 void print_bar_charts (pretty_printer
*pp
) const;
895 DISABLE_COPY_AND_ASSIGN (exploded_graph
);
897 const supergraph
&m_sg
;
901 /* Map from point/state to exploded node.
902 To avoid duplication we store point_and_state
903 *pointers* as keys, rather than point_and_state, using the
904 instance from within the exploded_node, with a custom hasher. */
905 typedef hash_map
<const point_and_state
*, exploded_node
*,
906 eg_hash_map_traits
> map_t
;
907 map_t m_point_and_state_to_node
;
909 /* Map from program_point to per-program_point data. */
910 typedef hash_map
<const program_point
*, per_program_point_data
*,
911 eg_point_hash_map_traits
> point_map_t
;
912 point_map_t m_per_point_data
;
916 exploded_node
*m_origin
;
918 const extrinsic_state
&m_ext_state
;
920 const state_purge_map
*const m_purge_map
;
922 const analysis_plan
&m_plan
;
924 typedef hash_map
<function
*, per_function_data
*> per_function_data_t
;
925 per_function_data_t m_per_function_data
;
927 diagnostic_manager m_diagnostic_manager
;
930 stats m_global_stats
;
931 typedef ordered_hash_map
<function
*, stats
*> function_stat_map_t
;
932 function_stat_map_t m_per_function_stats
;
933 stats m_functionless_stats
;
935 call_string_data_map_t m_per_call_string_data
;
937 auto_vec
<int> m_PK_AFTER_SUPERNODE_per_snode
;
939 /* Functions with a top-level enode, to make add_function_entry
940 be idempotent, for use in handling callbacks. */
941 hash_set
<function
*> m_functions_with_enodes
;
944 /* A path within an exploded_graph: a sequence of edges. */
949 exploded_path () : m_edges () {}
950 exploded_path (const exploded_path
&other
);
952 unsigned length () const { return m_edges
.length (); }
954 bool find_stmt_backwards (const gimple
*search_stmt
,
957 exploded_node
*get_final_enode () const;
959 void dump_to_pp (pretty_printer
*pp
,
960 const extrinsic_state
*ext_state
) const;
961 void dump (FILE *fp
, const extrinsic_state
*ext_state
) const;
962 void dump (const extrinsic_state
*ext_state
= NULL
) const;
963 void dump_to_file (const char *filename
,
964 const extrinsic_state
&ext_state
) const;
966 bool feasible_p (logger
*logger
, std::unique_ptr
<feasibility_problem
> *out
,
967 engine
*eng
, const exploded_graph
*eg
) const;
969 auto_vec
<const exploded_edge
*> m_edges
;
972 /* A reason why a particular exploded_path is infeasible. */
974 class feasibility_problem
977 feasibility_problem (unsigned eedge_idx
,
978 const exploded_edge
&eedge
,
979 const gimple
*last_stmt
,
980 std::unique_ptr
<rejected_constraint
> rc
)
981 : m_eedge_idx (eedge_idx
), m_eedge (eedge
),
982 m_last_stmt (last_stmt
), m_rc (std::move (rc
))
985 void dump_to_pp (pretty_printer
*pp
) const;
987 unsigned m_eedge_idx
;
988 const exploded_edge
&m_eedge
;
989 const gimple
*m_last_stmt
;
990 std::unique_ptr
<rejected_constraint
> m_rc
;
993 /* A class for capturing the state of a node when checking a path
994 through the exploded_graph for feasibility. */
996 class feasibility_state
999 feasibility_state (region_model_manager
*manager
,
1000 const supergraph
&sg
);
1001 feasibility_state (const region_model
&model
,
1002 const supergraph
&sg
);
1003 feasibility_state (const feasibility_state
&other
);
1005 feasibility_state
&operator= (const feasibility_state
&other
);
1007 bool maybe_update_for_edge (logger
*logger
,
1008 const exploded_edge
*eedge
,
1009 region_model_context
*ctxt
,
1010 std::unique_ptr
<rejected_constraint
> *out_rc
);
1011 void update_for_stmt (const gimple
*stmt
);
1013 const region_model
&get_model () const { return m_model
; }
1014 const auto_sbitmap
&get_snodes_visited () const { return m_snodes_visited
; }
1016 void dump_to_pp (pretty_printer
*pp
, bool simple
, bool multiline
) const;
1019 region_model m_model
;
1020 auto_sbitmap m_snodes_visited
;
1023 /* Finding the shortest exploded_path within an exploded_graph. */
1025 typedef shortest_paths
<eg_traits
, exploded_path
> shortest_exploded_paths
;
1027 /* Abstract base class for use when passing NULL as the stmt for
1028 a possible warning, allowing the choice of stmt to be deferred
1029 until after we have an emission path (and know we're emitting a
1035 virtual ~stmt_finder () {}
1036 virtual std::unique_ptr
<stmt_finder
> clone () const = 0;
1037 virtual const gimple
*find_stmt (const exploded_path
&epath
) = 0;
1040 // TODO: split the above up?
1044 #endif /* GCC_ANALYZER_EXPLODED_GRAPH_H */