xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/analyzer/program-state.h (revision 4c3eb207d36f67d31994830c0a694161fc1ca39b)
1*4c3eb207Smrg /* Classes for representing the state of interest at a given path of analysis.
2*4c3eb207Smrg    Copyright (C) 2019-2020 Free Software Foundation, Inc.
3*4c3eb207Smrg    Contributed by David Malcolm <dmalcolm@redhat.com>.
4*4c3eb207Smrg 
5*4c3eb207Smrg This file is part of GCC.
6*4c3eb207Smrg 
7*4c3eb207Smrg GCC is free software; you can redistribute it and/or modify it
8*4c3eb207Smrg under the terms of the GNU General Public License as published by
9*4c3eb207Smrg the Free Software Foundation; either version 3, or (at your option)
10*4c3eb207Smrg any later version.
11*4c3eb207Smrg 
12*4c3eb207Smrg GCC is distributed in the hope that it will be useful, but
13*4c3eb207Smrg WITHOUT ANY WARRANTY; without even the implied warranty of
14*4c3eb207Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15*4c3eb207Smrg General Public License for more details.
16*4c3eb207Smrg 
17*4c3eb207Smrg You should have received a copy of the GNU General Public License
18*4c3eb207Smrg along with GCC; see the file COPYING3.  If not see
19*4c3eb207Smrg <http://www.gnu.org/licenses/>.  */
20*4c3eb207Smrg 
21*4c3eb207Smrg #ifndef GCC_ANALYZER_PROGRAM_STATE_H
22*4c3eb207Smrg #define GCC_ANALYZER_PROGRAM_STATE_H
23*4c3eb207Smrg 
24*4c3eb207Smrg namespace ana {
25*4c3eb207Smrg 
26*4c3eb207Smrg /* Data shared by all program_state instances.  */
27*4c3eb207Smrg 
28*4c3eb207Smrg class extrinsic_state
29*4c3eb207Smrg {
30*4c3eb207Smrg public:
extrinsic_state(auto_delete_vec<state_machine> & checkers)31*4c3eb207Smrg   extrinsic_state (auto_delete_vec <state_machine> &checkers)
32*4c3eb207Smrg   : m_checkers (checkers)
33*4c3eb207Smrg   {
34*4c3eb207Smrg   }
35*4c3eb207Smrg 
get_sm(int idx)36*4c3eb207Smrg   const state_machine &get_sm (int idx) const
37*4c3eb207Smrg   {
38*4c3eb207Smrg     return *m_checkers[idx];
39*4c3eb207Smrg   }
40*4c3eb207Smrg 
get_name(int idx)41*4c3eb207Smrg   const char *get_name (int idx) const
42*4c3eb207Smrg   {
43*4c3eb207Smrg     return m_checkers[idx]->get_name ();
44*4c3eb207Smrg   }
45*4c3eb207Smrg 
get_num_checkers()46*4c3eb207Smrg   unsigned get_num_checkers () const { return m_checkers.length (); }
47*4c3eb207Smrg 
48*4c3eb207Smrg   void dump_to_pp (pretty_printer *pp) const;
49*4c3eb207Smrg   void dump_to_file (FILE *outf) const;
50*4c3eb207Smrg   void dump () const;
51*4c3eb207Smrg 
52*4c3eb207Smrg private:
53*4c3eb207Smrg   /* The state machines.  */
54*4c3eb207Smrg   auto_delete_vec <state_machine> &m_checkers;
55*4c3eb207Smrg };
56*4c3eb207Smrg 
57*4c3eb207Smrg } // namespace ana
58*4c3eb207Smrg 
59*4c3eb207Smrg template <> struct default_hash_traits<svalue_id>
60*4c3eb207Smrg : public pod_hash_traits<svalue_id>
61*4c3eb207Smrg {
62*4c3eb207Smrg   static const bool empty_zero_p = false;
63*4c3eb207Smrg };
64*4c3eb207Smrg 
65*4c3eb207Smrg template <>
66*4c3eb207Smrg inline hashval_t
67*4c3eb207Smrg pod_hash_traits<svalue_id>::hash (value_type v)
68*4c3eb207Smrg {
69*4c3eb207Smrg   return v.as_int ();
70*4c3eb207Smrg }
71*4c3eb207Smrg 
72*4c3eb207Smrg template <>
73*4c3eb207Smrg inline bool
74*4c3eb207Smrg pod_hash_traits<svalue_id>::equal (const value_type &existing,
75*4c3eb207Smrg 				   const value_type &candidate)
76*4c3eb207Smrg {
77*4c3eb207Smrg   return existing == candidate;
78*4c3eb207Smrg }
79*4c3eb207Smrg template <>
80*4c3eb207Smrg inline void
81*4c3eb207Smrg pod_hash_traits<svalue_id>::mark_deleted (value_type &v)
82*4c3eb207Smrg {
83*4c3eb207Smrg   v = svalue_id::from_int (-2);
84*4c3eb207Smrg }
85*4c3eb207Smrg template <>
86*4c3eb207Smrg inline void
87*4c3eb207Smrg pod_hash_traits<svalue_id>::mark_empty (value_type &v)
88*4c3eb207Smrg {
89*4c3eb207Smrg   v = svalue_id::null ();
90*4c3eb207Smrg }
91*4c3eb207Smrg template <>
92*4c3eb207Smrg inline bool
93*4c3eb207Smrg pod_hash_traits<svalue_id>::is_deleted (value_type v)
94*4c3eb207Smrg {
95*4c3eb207Smrg   return v.as_int () == -2;
96*4c3eb207Smrg }
97*4c3eb207Smrg template <>
98*4c3eb207Smrg inline bool
99*4c3eb207Smrg pod_hash_traits<svalue_id>::is_empty (value_type v)
100*4c3eb207Smrg {
101*4c3eb207Smrg   return v.null_p ();
102*4c3eb207Smrg }
103*4c3eb207Smrg 
104*4c3eb207Smrg namespace ana {
105*4c3eb207Smrg 
106*4c3eb207Smrg /* Map from svalue_id to state machine state, also capturing the origin of
107*4c3eb207Smrg    each state.  */
108*4c3eb207Smrg 
109*4c3eb207Smrg class sm_state_map
110*4c3eb207Smrg {
111*4c3eb207Smrg public:
112*4c3eb207Smrg   /* An entry in the hash_map.  */
113*4c3eb207Smrg   struct entry_t
114*4c3eb207Smrg   {
115*4c3eb207Smrg     /* Default ctor needed by hash_map::empty.  */
116*4c3eb207Smrg     entry_t ()
117*4c3eb207Smrg     : m_state (0), m_origin (svalue_id::null ())
118*4c3eb207Smrg     {
119*4c3eb207Smrg     }
120*4c3eb207Smrg 
121*4c3eb207Smrg     entry_t (state_machine::state_t state,
122*4c3eb207Smrg 	     svalue_id origin)
123*4c3eb207Smrg     : m_state (state), m_origin (origin)
124*4c3eb207Smrg     {}
125*4c3eb207Smrg 
126*4c3eb207Smrg     bool operator== (const entry_t &other) const
127*4c3eb207Smrg     {
128*4c3eb207Smrg       return (m_state == other.m_state
129*4c3eb207Smrg 	      && m_origin == other.m_origin);
130*4c3eb207Smrg     }
131*4c3eb207Smrg     bool operator!= (const entry_t &other) const
132*4c3eb207Smrg     {
133*4c3eb207Smrg       return !(*this == other);
134*4c3eb207Smrg     }
135*4c3eb207Smrg 
136*4c3eb207Smrg     state_machine::state_t m_state;
137*4c3eb207Smrg     svalue_id m_origin;
138*4c3eb207Smrg   };
139*4c3eb207Smrg   typedef hash_map <svalue_id, entry_t> map_t;
140*4c3eb207Smrg   typedef map_t::iterator iterator_t;
141*4c3eb207Smrg 
142*4c3eb207Smrg   sm_state_map ();
143*4c3eb207Smrg 
144*4c3eb207Smrg   sm_state_map *clone () const;
145*4c3eb207Smrg 
146*4c3eb207Smrg   sm_state_map *
147*4c3eb207Smrg   clone_with_remapping (const one_way_svalue_id_map &id_map) const;
148*4c3eb207Smrg 
149*4c3eb207Smrg   void print (const state_machine &sm, const region_model *model,
150*4c3eb207Smrg 	      pretty_printer *pp) const;
151*4c3eb207Smrg   void dump (const state_machine &sm) const;
152*4c3eb207Smrg 
153*4c3eb207Smrg   bool is_empty_p () const;
154*4c3eb207Smrg 
155*4c3eb207Smrg   hashval_t hash () const;
156*4c3eb207Smrg 
157*4c3eb207Smrg   bool operator== (const sm_state_map &other) const;
158*4c3eb207Smrg   bool operator!= (const sm_state_map &other) const
159*4c3eb207Smrg   {
160*4c3eb207Smrg     return !(*this == other);
161*4c3eb207Smrg   }
162*4c3eb207Smrg 
163*4c3eb207Smrg   state_machine::state_t get_state (svalue_id sid) const;
164*4c3eb207Smrg   svalue_id get_origin (svalue_id sid) const;
165*4c3eb207Smrg 
166*4c3eb207Smrg   void set_state (region_model *model,
167*4c3eb207Smrg 		  svalue_id sid,
168*4c3eb207Smrg 		  state_machine::state_t state,
169*4c3eb207Smrg 		  svalue_id origin);
170*4c3eb207Smrg   bool set_state (const equiv_class &ec,
171*4c3eb207Smrg 		  state_machine::state_t state,
172*4c3eb207Smrg 		  svalue_id origin);
173*4c3eb207Smrg   bool impl_set_state (svalue_id sid,
174*4c3eb207Smrg 		       state_machine::state_t state,
175*4c3eb207Smrg 		       svalue_id origin);
176*4c3eb207Smrg 
177*4c3eb207Smrg   void set_global_state (state_machine::state_t state);
178*4c3eb207Smrg   state_machine::state_t get_global_state () const;
179*4c3eb207Smrg 
180*4c3eb207Smrg   void purge_for_unknown_fncall (const exploded_graph &eg,
181*4c3eb207Smrg 				 const state_machine &sm,
182*4c3eb207Smrg 				 const gcall *call, tree fndecl,
183*4c3eb207Smrg 				 region_model *new_model,
184*4c3eb207Smrg 				 region_model_context *ctxt);
185*4c3eb207Smrg 
186*4c3eb207Smrg   void remap_svalue_ids (const svalue_id_map &map);
187*4c3eb207Smrg 
188*4c3eb207Smrg   int on_svalue_purge (const state_machine &sm,
189*4c3eb207Smrg 		       int sm_idx,
190*4c3eb207Smrg 		       svalue_id first_unused_sid,
191*4c3eb207Smrg 		       const svalue_id_map &map,
192*4c3eb207Smrg 		       impl_region_model_context *ctxt);
193*4c3eb207Smrg 
194*4c3eb207Smrg   void on_inherited_svalue (svalue_id parent_sid,
195*4c3eb207Smrg 			    svalue_id child_sid);
196*4c3eb207Smrg 
197*4c3eb207Smrg   void on_cast (svalue_id src_sid,
198*4c3eb207Smrg 		svalue_id dst_sid);
199*4c3eb207Smrg 
200*4c3eb207Smrg   void on_unknown_change (svalue_id sid);
201*4c3eb207Smrg 
202*4c3eb207Smrg   void validate (const state_machine &sm, int num_svalues) const;
203*4c3eb207Smrg 
204*4c3eb207Smrg   iterator_t begin () const { return m_map.begin (); }
205*4c3eb207Smrg   iterator_t end () const { return m_map.end (); }
206*4c3eb207Smrg 
207*4c3eb207Smrg private:
208*4c3eb207Smrg   map_t m_map;
209*4c3eb207Smrg   state_machine::state_t m_global_state;
210*4c3eb207Smrg };
211*4c3eb207Smrg 
212*4c3eb207Smrg /* A class for representing the state of interest at a given path of
213*4c3eb207Smrg    analysis.
214*4c3eb207Smrg 
215*4c3eb207Smrg    Currently this is a combination of:
216*4c3eb207Smrg    (a) a region_model, giving:
217*4c3eb207Smrg       (a.1) a hierarchy of memory regions
218*4c3eb207Smrg       (a.2) values for the regions
219*4c3eb207Smrg       (a.3) inequalities between values
220*4c3eb207Smrg    (b) sm_state_maps per state machine, giving a sparse mapping of
221*4c3eb207Smrg        values to states.  */
222*4c3eb207Smrg 
223*4c3eb207Smrg class program_state
224*4c3eb207Smrg {
225*4c3eb207Smrg public:
226*4c3eb207Smrg   program_state (const extrinsic_state &ext_state);
227*4c3eb207Smrg   program_state (const program_state &other);
228*4c3eb207Smrg   program_state& operator= (const program_state &other);
229*4c3eb207Smrg 
230*4c3eb207Smrg #if __cplusplus >= 201103
231*4c3eb207Smrg   program_state (program_state &&other);
232*4c3eb207Smrg   program_state& operator= (program_state &&other); // doesn't seem to be used
233*4c3eb207Smrg #endif
234*4c3eb207Smrg 
235*4c3eb207Smrg   ~program_state ();
236*4c3eb207Smrg 
237*4c3eb207Smrg   hashval_t hash () const;
238*4c3eb207Smrg   bool operator== (const program_state &other) const;
239*4c3eb207Smrg   bool operator!= (const program_state &other) const
240*4c3eb207Smrg   {
241*4c3eb207Smrg     return !(*this == other);
242*4c3eb207Smrg   }
243*4c3eb207Smrg 
244*4c3eb207Smrg   void print (const extrinsic_state &ext_state,
245*4c3eb207Smrg 	      pretty_printer *pp) const;
246*4c3eb207Smrg 
247*4c3eb207Smrg   void dump_to_pp (const extrinsic_state &ext_state, bool summarize,
248*4c3eb207Smrg 		   pretty_printer *pp) const;
249*4c3eb207Smrg   void dump_to_file (const extrinsic_state &ext_state, bool summarize,
250*4c3eb207Smrg 		     FILE *outf) const;
251*4c3eb207Smrg   void dump (const extrinsic_state &ext_state, bool summarize) const;
252*4c3eb207Smrg 
253*4c3eb207Smrg   bool on_edge (exploded_graph &eg,
254*4c3eb207Smrg 		const exploded_node &enode,
255*4c3eb207Smrg 		const superedge *succ,
256*4c3eb207Smrg 		state_change *change);
257*4c3eb207Smrg 
258*4c3eb207Smrg   program_state prune_for_point (exploded_graph &eg,
259*4c3eb207Smrg 				 const program_point &point,
260*4c3eb207Smrg 				 state_change *change) const;
261*4c3eb207Smrg 
262*4c3eb207Smrg   void remap_svalue_ids (const svalue_id_map &map);
263*4c3eb207Smrg 
264*4c3eb207Smrg   tree get_representative_tree (svalue_id sid) const;
265*4c3eb207Smrg 
266*4c3eb207Smrg   bool can_purge_p (const extrinsic_state &ext_state,
267*4c3eb207Smrg 		    svalue_id sid)
268*4c3eb207Smrg   {
269*4c3eb207Smrg     /* Don't purge vars that have non-purgeable sm state, to avoid
270*4c3eb207Smrg        generating false "leak" complaints.  */
271*4c3eb207Smrg     int i;
272*4c3eb207Smrg     sm_state_map *smap;
273*4c3eb207Smrg     FOR_EACH_VEC_ELT (m_checker_states, i, smap)
274*4c3eb207Smrg       {
275*4c3eb207Smrg 	const state_machine &sm = ext_state.get_sm (i);
276*4c3eb207Smrg 	if (!sm.can_purge_p (smap->get_state (sid)))
277*4c3eb207Smrg 	  return false;
278*4c3eb207Smrg       }
279*4c3eb207Smrg     return true;
280*4c3eb207Smrg   }
281*4c3eb207Smrg 
282*4c3eb207Smrg   bool can_merge_with_p (const program_state &other,
283*4c3eb207Smrg 			 const extrinsic_state &ext_state,
284*4c3eb207Smrg 			 program_state *out) const;
285*4c3eb207Smrg 
286*4c3eb207Smrg   void validate (const extrinsic_state &ext_state) const;
287*4c3eb207Smrg 
288*4c3eb207Smrg   /* TODO: lose the pointer here (const-correctness issues?).  */
289*4c3eb207Smrg   region_model *m_region_model;
290*4c3eb207Smrg   auto_delete_vec<sm_state_map> m_checker_states;
291*4c3eb207Smrg 
292*4c3eb207Smrg   /* If false, then don't attempt to explore further states along this path.
293*4c3eb207Smrg      For use in "handling" lvalues for tree codes we haven't yet
294*4c3eb207Smrg      implemented.  */
295*4c3eb207Smrg   bool m_valid;
296*4c3eb207Smrg };
297*4c3eb207Smrg 
298*4c3eb207Smrg /* An abstract base class for use with for_each_state_change.  */
299*4c3eb207Smrg 
300*4c3eb207Smrg class state_change_visitor
301*4c3eb207Smrg {
302*4c3eb207Smrg public:
303*4c3eb207Smrg   virtual ~state_change_visitor () {}
304*4c3eb207Smrg 
305*4c3eb207Smrg   /* Return true for early exit, false to keep iterating.  */
306*4c3eb207Smrg   virtual bool on_global_state_change (const state_machine &sm,
307*4c3eb207Smrg 				       state_machine::state_t src_sm_val,
308*4c3eb207Smrg 				       state_machine::state_t dst_sm_val) = 0;
309*4c3eb207Smrg 
310*4c3eb207Smrg   /* Return true for early exit, false to keep iterating.  */
311*4c3eb207Smrg   virtual bool on_state_change (const state_machine &sm,
312*4c3eb207Smrg 				state_machine::state_t src_sm_val,
313*4c3eb207Smrg 				state_machine::state_t dst_sm_val,
314*4c3eb207Smrg 				tree dst_rep,
315*4c3eb207Smrg 				svalue_id dst_origin_sid) = 0;
316*4c3eb207Smrg };
317*4c3eb207Smrg 
318*4c3eb207Smrg extern bool for_each_state_change (const program_state &src_state,
319*4c3eb207Smrg 				   const program_state &dst_state,
320*4c3eb207Smrg 				   const extrinsic_state &ext_state,
321*4c3eb207Smrg 				   state_change_visitor *visitor);
322*4c3eb207Smrg 
323*4c3eb207Smrg /* A class for recording "interesting" state changes.
324*4c3eb207Smrg    This is used for annotating edges in the GraphViz output of the
325*4c3eb207Smrg    exploded_graph, and for recording sm-state-changes, so that
326*4c3eb207Smrg    values that change aren't purged (to make it easier to generate
327*4c3eb207Smrg    state_change_event instances in the diagnostic_path).  */
328*4c3eb207Smrg 
329*4c3eb207Smrg class state_change
330*4c3eb207Smrg {
331*4c3eb207Smrg  public:
332*4c3eb207Smrg   struct sm_change
333*4c3eb207Smrg   {
334*4c3eb207Smrg     sm_change (int sm_idx,
335*4c3eb207Smrg 	       svalue_id new_sid,
336*4c3eb207Smrg 	       state_machine::state_t old_state,
337*4c3eb207Smrg 	       state_machine::state_t new_state)
338*4c3eb207Smrg     : m_sm_idx (sm_idx),
339*4c3eb207Smrg       m_new_sid (new_sid),
340*4c3eb207Smrg       m_old_state (old_state), m_new_state (new_state)
341*4c3eb207Smrg     {}
342*4c3eb207Smrg 
343*4c3eb207Smrg     const state_machine &get_sm (const extrinsic_state &ext_state) const
344*4c3eb207Smrg     {
345*4c3eb207Smrg       return ext_state.get_sm (m_sm_idx);
346*4c3eb207Smrg     }
347*4c3eb207Smrg 
348*4c3eb207Smrg     void dump (pretty_printer *pp, const extrinsic_state &ext_state) const;
349*4c3eb207Smrg 
350*4c3eb207Smrg     void remap_svalue_ids (const svalue_id_map &map);
351*4c3eb207Smrg     int on_svalue_purge (svalue_id first_unused_sid);
352*4c3eb207Smrg 
353*4c3eb207Smrg     void validate (const program_state &new_state,
354*4c3eb207Smrg 		   const extrinsic_state &ext_state) const;
355*4c3eb207Smrg 
356*4c3eb207Smrg     int m_sm_idx;
357*4c3eb207Smrg     svalue_id m_new_sid;
358*4c3eb207Smrg     state_machine::state_t m_old_state;
359*4c3eb207Smrg     state_machine::state_t m_new_state;
360*4c3eb207Smrg   };
361*4c3eb207Smrg 
362*4c3eb207Smrg   state_change ();
363*4c3eb207Smrg   state_change (const state_change &other);
364*4c3eb207Smrg 
365*4c3eb207Smrg   void add_sm_change (int sm_idx,
366*4c3eb207Smrg 		      svalue_id new_sid,
367*4c3eb207Smrg 		      state_machine::state_t old_state,
368*4c3eb207Smrg 		      state_machine::state_t new_state);
369*4c3eb207Smrg 
370*4c3eb207Smrg   bool affects_p (svalue_id sid) const;
371*4c3eb207Smrg 
372*4c3eb207Smrg   void dump (pretty_printer *pp, const extrinsic_state &ext_state) const;
373*4c3eb207Smrg   void dump (const extrinsic_state &ext_state) const;
374*4c3eb207Smrg 
375*4c3eb207Smrg   void remap_svalue_ids (const svalue_id_map &map);
376*4c3eb207Smrg   int on_svalue_purge (svalue_id first_unused_sid);
377*4c3eb207Smrg 
378*4c3eb207Smrg   void validate (const program_state &new_state,
379*4c3eb207Smrg 		 const extrinsic_state &ext_state) const;
380*4c3eb207Smrg 
381*4c3eb207Smrg  private:
382*4c3eb207Smrg   auto_vec<sm_change> m_sm_changes;
383*4c3eb207Smrg };
384*4c3eb207Smrg 
385*4c3eb207Smrg } // namespace ana
386*4c3eb207Smrg 
387*4c3eb207Smrg #endif /* GCC_ANALYZER_PROGRAM_STATE_H */
388