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