xref: /netbsd-src/external/gpl3/gcc/dist/gcc/analyzer/exploded-graph.h (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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;
get_logger()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;
get_ext_state()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 
get_stmt()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:
point_and_state(const program_point & point,const program_state & state)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 
hash()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 
get_point()135   const program_point &get_point () const { return m_point; }
get_state()136   const program_state &get_state () const { return m_state; }
137 
set_state(const program_state & state)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   {
dump_args_teg_traits::dump_args_t161     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
dump_extra_infoeg_traits::dump_args_t166     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 
hash()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   {
on_stmt_flagson_stmt_flags223     on_stmt_flags () : m_terminate_path (false)
224     {}
225 
terminate_pathon_stmt_flags226     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:
on_stmt_flagson_stmt_flags236     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 
get_point()270   const program_point &get_point () const { return m_ps.get_point (); }
get_supernode()271   const supernode *get_supernode () const
272   {
273     return get_point ().get_supernode ();
274   }
get_function()275   function *get_function () const
276   {
277     return get_point ().get_function ();
278   }
get_stack_depth()279   int get_stack_depth () const
280   {
281     return get_point ().get_stack_depth ();
282   }
get_stmt()283   const gimple *get_stmt () const { return get_point ().get_stmt (); }
284   const gimple *get_processed_stmt (unsigned idx) const;
285 
get_state()286   const program_state &get_state () const { return m_ps.get_state (); }
287 
get_ps_key()288   const point_and_state *get_ps_key () const { return &m_ps; }
get_point_key()289   const program_point *get_point_key () const { return &m_ps.get_point (); }
290 
291   void dump_succs_and_preds (FILE *outf) const;
292 
get_status()293   enum status get_status () const { return m_status; }
set_status(enum status status)294   void set_status (enum status status)
295   {
296     gcc_assert (m_status == STATUS_WORKLIST);
297     m_status = status;
298   }
299 
add_diagnostic(const saved_diagnostic * sd)300   void add_diagnostic (const saved_diagnostic *sd)
301   {
302     m_saved_diagnostics.safe_push (sd);
303   }
get_num_diagnostics()304   unsigned get_num_diagnostics () const
305   {
306     return m_saved_diagnostics.length ();
307   }
get_saved_diagnostic(unsigned idx)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)
m_dynamic_call(dynamic_call)373   : m_dynamic_call (dynamic_call),
374     m_is_returning_call (is_returning_call)
375   {}
376 
print(pretty_printer * pp)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:
rewind_info_t(const setjmp_record & setjmp_record,const gcall * longjmp_call)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 
print(pretty_printer * pp)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 
get_setjmp_point()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 
get_setjmp_call()433   const gcall *get_setjmp_call () const
434   {
435     return m_setjmp_record.m_setjmp_call;
436   }
437 
get_longjmp_call()438   const gcall *get_longjmp_call () const
439   {
440     return m_longjmp_call;
441   }
442 
get_enode_origin()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 
hasheg_hash_map_traits478   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   }
equal_keyseg_hash_map_traits484   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>
removeeg_hash_map_traits497   static inline void remove (T &)
498   {
499     /* empty; the nodes are handled elsewhere.  */
500   }
501   template <typename T>
mark_deletedeg_hash_map_traits502   static inline void mark_deleted (T &entry)
503   {
504     entry.m_key = reinterpret_cast<key_type> (1);
505   }
506   template <typename T>
mark_emptyeg_hash_map_traits507   static inline void mark_empty (T &entry)
508   {
509     entry.m_key = NULL;
510   }
511   template <typename T>
is_deletedeg_hash_map_traits512   static inline bool is_deleted (const T &entry)
513   {
514     return entry.m_key == reinterpret_cast<key_type> (1);
515   }
516   template <typename T>
is_emptyeg_hash_map_traits517   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 {
per_program_point_dataper_program_point_data528   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 
hasheg_point_hash_map_traits548   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   }
equal_keyseg_point_hash_map_traits554   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>
removeeg_point_hash_map_traits567   static inline void remove (T &)
568   {
569     /* empty; the nodes are handled elsewhere.  */
570   }
571   template <typename T>
mark_deletedeg_point_hash_map_traits572   static inline void mark_deleted (T &entry)
573   {
574     entry.m_key = reinterpret_cast<key_type> (1);
575   }
576   template <typename T>
mark_emptyeg_point_hash_map_traits577   static inline void mark_empty (T &entry)
578   {
579     entry.m_key = NULL;
580   }
581   template <typename T>
is_deletedeg_point_hash_map_traits582   static inline bool is_deleted (const T &entry)
583   {
584     return entry.m_key == reinterpret_cast<key_type> (1);
585   }
586   template <typename T>
is_emptyeg_point_hash_map_traits587   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 {
per_call_string_dataper_call_string_data598   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 
hasheg_call_string_hash_map_traits615   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   }
equal_keyseg_call_string_hash_map_traits621   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>
removeeg_call_string_hash_map_traits634   static inline void remove (T &)
635   {
636     /* empty; the nodes are handled elsewhere.  */
637   }
638   template <typename T>
mark_deletedeg_call_string_hash_map_traits639   static inline void mark_deleted (T &entry)
640   {
641     entry.m_key = reinterpret_cast<key_type> (1);
642   }
643   template <typename T>
mark_emptyeg_call_string_hash_map_traits644   static inline void mark_empty (T &entry)
645   {
646     entry.m_key = NULL;
647   }
648   template <typename T>
is_deletedeg_call_string_hash_map_traits649   static inline bool is_deleted (const T &entry)
650   {
651     return entry.m_key == reinterpret_cast<key_type> (1);
652   }
653   template <typename T>
is_emptyeg_call_string_hash_map_traits654   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 {
per_function_dataper_function_data665   per_function_data () {}
666 
add_call_summaryper_function_data667   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 
get_scc_id(int node_index)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   {
per_node_dataper_node_data697     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);
get_scc_id(const supernode & snode)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:
key_t(const worklist & w,exploded_node * enode)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 
get_scc_id(const exploded_node * enode)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 
get_logger()804   logger *get_logger () const { return m_logger.get_logger (); }
805 
get_supergraph()806   const supergraph &get_supergraph () const { return m_sg; }
get_ext_state()807   const extrinsic_state &get_ext_state () const { return m_ext_state; }
get_engine()808   engine *get_engine () const { return m_ext_state.get_engine (); }
get_purge_map()809   const state_purge_map *get_purge_map () const { return m_purge_map; }
get_analysis_plan()810   const analysis_plan &get_analysis_plan () const { return m_plan; }
811 
get_origin()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 
get_diagnostic_manager()855   diagnostic_manager &get_diagnostic_manager ()
856   {
857     return m_diagnostic_manager;
858   }
get_diagnostic_manager()859   const diagnostic_manager &get_diagnostic_manager () const
860   {
861     return m_diagnostic_manager;
862   }
863 
get_global_stats()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 
get_per_call_string_data()875   const call_string_data_map_t *get_per_call_string_data () const
876   { return &m_per_call_string_data; }
877 
get_scc_id(const supernode & node)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:
exploded_path()942   exploded_path () : m_edges () {}
943   exploded_path (const exploded_path &other);
944 
length()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:
feasibility_problem(unsigned eedge_idx,const exploded_edge & eedge,const gimple * last_stmt,rejected_constraint * rc)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   {}
~feasibility_problem()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 
get_model()1001   const region_model &get_model () const { return m_model; }
get_snodes_visited()1002   const auto_sbitmap &get_snodes_visited () const { return m_snodes_visited; }
1003 
1004   void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
1005 
1006 private:
1007   region_model m_model;
1008   auto_sbitmap m_snodes_visited;
1009 };
1010 
1011 /* Finding the shortest exploded_path within an exploded_graph.  */
1012 
1013 typedef shortest_paths<eg_traits, exploded_path> shortest_exploded_paths;
1014 
1015 /* Abstract base class for use when passing NULL as the stmt for
1016    a possible warning, allowing the choice of stmt to be deferred
1017    until after we have an emission path (and know we're emitting a
1018    warning).  */
1019 
1020 class stmt_finder
1021 {
1022 public:
~stmt_finder()1023   virtual ~stmt_finder () {}
1024   virtual stmt_finder *clone () const = 0;
1025   virtual const gimple *find_stmt (const exploded_path &epath) = 0;
1026 };
1027 
1028 // TODO: split the above up?
1029 
1030 } // namespace ana
1031 
1032 #endif /* GCC_ANALYZER_EXPLODED_GRAPH_H */
1033