1 1.1 mrg /* Classes for representing the state of interest at a given path of analysis. 2 1.1.1.2 mrg Copyright (C) 2019-2022 Free Software Foundation, Inc. 3 1.1 mrg Contributed by David Malcolm <dmalcolm (at) redhat.com>. 4 1.1 mrg 5 1.1 mrg This file is part of GCC. 6 1.1 mrg 7 1.1 mrg GCC is free software; you can redistribute it and/or modify it 8 1.1 mrg under the terms of the GNU General Public License as published by 9 1.1 mrg the Free Software Foundation; either version 3, or (at your option) 10 1.1 mrg any later version. 11 1.1 mrg 12 1.1 mrg GCC is distributed in the hope that it will be useful, but 13 1.1 mrg WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 mrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 1.1 mrg General Public License for more details. 16 1.1 mrg 17 1.1 mrg You should have received a copy of the GNU General Public License 18 1.1 mrg along with GCC; see the file COPYING3. If not see 19 1.1 mrg <http://www.gnu.org/licenses/>. */ 20 1.1 mrg 21 1.1 mrg #include "config.h" 22 1.1 mrg #include "system.h" 23 1.1 mrg #include "coretypes.h" 24 1.1 mrg #include "tree.h" 25 1.1 mrg #include "diagnostic-core.h" 26 1.1 mrg #include "diagnostic.h" 27 1.1 mrg #include "function.h" 28 1.1.1.2 mrg #include "json.h" 29 1.1 mrg #include "analyzer/analyzer.h" 30 1.1 mrg #include "analyzer/analyzer-logging.h" 31 1.1 mrg #include "analyzer/sm.h" 32 1.1 mrg #include "sbitmap.h" 33 1.1 mrg #include "bitmap.h" 34 1.1 mrg #include "tristate.h" 35 1.1 mrg #include "ordered-hash-map.h" 36 1.1 mrg #include "selftest.h" 37 1.1.1.2 mrg #include "analyzer/call-string.h" 38 1.1.1.2 mrg #include "analyzer/program-point.h" 39 1.1.1.2 mrg #include "analyzer/store.h" 40 1.1 mrg #include "analyzer/region-model.h" 41 1.1 mrg #include "analyzer/program-state.h" 42 1.1 mrg #include "analyzer/constraint-manager.h" 43 1.1 mrg #include "alloc-pool.h" 44 1.1 mrg #include "fibonacci_heap.h" 45 1.1 mrg #include "shortest-paths.h" 46 1.1 mrg #include "diagnostic-event-id.h" 47 1.1 mrg #include "analyzer/pending-diagnostic.h" 48 1.1 mrg #include "analyzer/diagnostic-manager.h" 49 1.1 mrg #include "cfg.h" 50 1.1 mrg #include "basic-block.h" 51 1.1 mrg #include "gimple.h" 52 1.1 mrg #include "gimple-iterator.h" 53 1.1 mrg #include "cgraph.h" 54 1.1 mrg #include "digraph.h" 55 1.1 mrg #include "analyzer/supergraph.h" 56 1.1 mrg #include "analyzer/program-state.h" 57 1.1 mrg #include "analyzer/exploded-graph.h" 58 1.1 mrg #include "analyzer/state-purge.h" 59 1.1 mrg #include "analyzer/analyzer-selftests.h" 60 1.1 mrg 61 1.1 mrg #if ENABLE_ANALYZER 62 1.1 mrg 63 1.1 mrg namespace ana { 64 1.1 mrg 65 1.1 mrg /* class extrinsic_state. */ 66 1.1 mrg 67 1.1 mrg /* Dump a multiline representation of this state to PP. */ 68 1.1 mrg 69 1.1 mrg void 70 1.1 mrg extrinsic_state::dump_to_pp (pretty_printer *pp) const 71 1.1 mrg { 72 1.1 mrg pp_printf (pp, "extrinsic_state: %i checker(s)\n", get_num_checkers ()); 73 1.1 mrg unsigned i; 74 1.1 mrg state_machine *checker; 75 1.1 mrg FOR_EACH_VEC_ELT (m_checkers, i, checker) 76 1.1 mrg { 77 1.1 mrg pp_printf (pp, "m_checkers[%i]: %qs\n", i, checker->get_name ()); 78 1.1 mrg checker->dump_to_pp (pp); 79 1.1 mrg } 80 1.1 mrg } 81 1.1 mrg 82 1.1 mrg /* Dump a multiline representation of this state to OUTF. */ 83 1.1 mrg 84 1.1 mrg void 85 1.1 mrg extrinsic_state::dump_to_file (FILE *outf) const 86 1.1 mrg { 87 1.1 mrg pretty_printer pp; 88 1.1 mrg if (outf == stderr) 89 1.1 mrg pp_show_color (&pp) = pp_show_color (global_dc->printer); 90 1.1 mrg pp.buffer->stream = outf; 91 1.1 mrg dump_to_pp (&pp); 92 1.1 mrg pp_flush (&pp); 93 1.1 mrg } 94 1.1 mrg 95 1.1 mrg /* Dump a multiline representation of this state to stderr. */ 96 1.1 mrg 97 1.1 mrg DEBUG_FUNCTION void 98 1.1 mrg extrinsic_state::dump () const 99 1.1 mrg { 100 1.1 mrg dump_to_file (stderr); 101 1.1 mrg } 102 1.1 mrg 103 1.1.1.2 mrg /* Return a new json::object of the form 104 1.1.1.2 mrg {"checkers" : array of objects, one for each state_machine}. */ 105 1.1 mrg 106 1.1.1.2 mrg json::object * 107 1.1.1.2 mrg extrinsic_state::to_json () const 108 1.1.1.2 mrg { 109 1.1.1.2 mrg json::object *ext_state_obj = new json::object (); 110 1.1.1.2 mrg 111 1.1.1.2 mrg { 112 1.1.1.2 mrg json::array *checkers_arr = new json::array (); 113 1.1.1.2 mrg unsigned i; 114 1.1.1.2 mrg state_machine *sm; 115 1.1.1.2 mrg FOR_EACH_VEC_ELT (m_checkers, i, sm) 116 1.1.1.2 mrg checkers_arr->append (sm->to_json ()); 117 1.1.1.2 mrg ext_state_obj->set ("checkers", checkers_arr); 118 1.1.1.2 mrg } 119 1.1 mrg 120 1.1.1.2 mrg return ext_state_obj; 121 1.1.1.2 mrg } 122 1.1.1.2 mrg 123 1.1.1.2 mrg /* Get the region_model_manager for this extrinsic_state. */ 124 1.1.1.2 mrg 125 1.1.1.2 mrg region_model_manager * 126 1.1.1.2 mrg extrinsic_state::get_model_manager () const 127 1.1 mrg { 128 1.1.1.2 mrg if (m_engine) 129 1.1.1.2 mrg return m_engine->get_model_manager (); 130 1.1.1.2 mrg else 131 1.1.1.2 mrg return NULL; /* for selftests. */ 132 1.1 mrg } 133 1.1 mrg 134 1.1.1.2 mrg /* Try to find a state machine named NAME. 135 1.1.1.2 mrg If found, return true and write its index to *OUT. 136 1.1.1.2 mrg Otherwise return false. */ 137 1.1 mrg 138 1.1.1.2 mrg bool 139 1.1.1.2 mrg extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const 140 1.1 mrg { 141 1.1.1.2 mrg unsigned i; 142 1.1.1.2 mrg state_machine *sm; 143 1.1.1.2 mrg FOR_EACH_VEC_ELT (m_checkers, i, sm) 144 1.1.1.2 mrg if (0 == strcmp (name, sm->get_name ())) 145 1.1.1.2 mrg { 146 1.1.1.2 mrg /* Found NAME. */ 147 1.1.1.2 mrg *out = i; 148 1.1.1.2 mrg return true; 149 1.1.1.2 mrg } 150 1.1.1.2 mrg 151 1.1.1.2 mrg /* NAME not found. */ 152 1.1.1.2 mrg return false; 153 1.1 mrg } 154 1.1 mrg 155 1.1.1.2 mrg /* struct sm_state_map::entry_t. */ 156 1.1 mrg 157 1.1.1.2 mrg int 158 1.1.1.2 mrg sm_state_map::entry_t::cmp (const entry_t &entry_a, const entry_t &entry_b) 159 1.1.1.2 mrg { 160 1.1.1.2 mrg gcc_assert (entry_a.m_state); 161 1.1.1.2 mrg gcc_assert (entry_b.m_state); 162 1.1.1.2 mrg if (int cmp_state = ((int)entry_a.m_state->get_id () 163 1.1.1.2 mrg - (int)entry_b.m_state->get_id ())) 164 1.1.1.2 mrg return cmp_state; 165 1.1.1.2 mrg if (entry_a.m_origin && entry_b.m_origin) 166 1.1.1.2 mrg return svalue::cmp_ptr (entry_a.m_origin, entry_b.m_origin); 167 1.1.1.2 mrg if (entry_a.m_origin) 168 1.1.1.2 mrg return 1; 169 1.1.1.2 mrg if (entry_b.m_origin) 170 1.1.1.2 mrg return -1; 171 1.1.1.2 mrg return 0; 172 1.1.1.2 mrg } 173 1.1 mrg 174 1.1.1.2 mrg /* class sm_state_map. */ 175 1.1.1.2 mrg 176 1.1.1.2 mrg /* sm_state_map's ctor. */ 177 1.1.1.2 mrg 178 1.1.1.2 mrg sm_state_map::sm_state_map (const state_machine &sm) 179 1.1.1.2 mrg : m_sm (sm), m_map (), m_global_state (sm.get_start_state ()) 180 1.1 mrg { 181 1.1.1.2 mrg } 182 1.1 mrg 183 1.1.1.2 mrg /* Clone the sm_state_map. */ 184 1.1.1.2 mrg 185 1.1.1.2 mrg sm_state_map * 186 1.1.1.2 mrg sm_state_map::clone () const 187 1.1.1.2 mrg { 188 1.1.1.2 mrg return new sm_state_map (*this); 189 1.1 mrg } 190 1.1 mrg 191 1.1.1.2 mrg /* Print this sm_state_map to PP. 192 1.1 mrg If MODEL is non-NULL, print representative tree values where 193 1.1 mrg available. */ 194 1.1 mrg 195 1.1 mrg void 196 1.1.1.2 mrg sm_state_map::print (const region_model *model, 197 1.1.1.2 mrg bool simple, bool multiline, 198 1.1.1.2 mrg pretty_printer *pp) const 199 1.1 mrg { 200 1.1 mrg bool first = true; 201 1.1.1.2 mrg if (!multiline) 202 1.1.1.2 mrg pp_string (pp, "{"); 203 1.1.1.2 mrg if (m_global_state != m_sm.get_start_state ()) 204 1.1.1.2 mrg { 205 1.1.1.2 mrg if (multiline) 206 1.1.1.2 mrg pp_string (pp, " "); 207 1.1.1.2 mrg pp_string (pp, "global: "); 208 1.1.1.2 mrg m_global_state->dump_to_pp (pp); 209 1.1.1.2 mrg if (multiline) 210 1.1.1.2 mrg pp_newline (pp); 211 1.1 mrg first = false; 212 1.1 mrg } 213 1.1.1.2 mrg auto_vec <const svalue *> keys (m_map.elements ()); 214 1.1 mrg for (map_t::iterator iter = m_map.begin (); 215 1.1 mrg iter != m_map.end (); 216 1.1 mrg ++iter) 217 1.1.1.2 mrg keys.quick_push ((*iter).first); 218 1.1.1.2 mrg keys.qsort (svalue::cmp_ptr_ptr); 219 1.1.1.2 mrg unsigned i; 220 1.1.1.2 mrg const svalue *sval; 221 1.1.1.2 mrg FOR_EACH_VEC_ELT (keys, i, sval) 222 1.1 mrg { 223 1.1.1.2 mrg if (multiline) 224 1.1.1.2 mrg pp_string (pp, " "); 225 1.1.1.2 mrg else if (!first) 226 1.1 mrg pp_string (pp, ", "); 227 1.1 mrg first = false; 228 1.1.1.2 mrg if (!flag_dump_noaddr) 229 1.1.1.2 mrg { 230 1.1.1.2 mrg pp_pointer (pp, sval); 231 1.1.1.2 mrg pp_string (pp, ": "); 232 1.1.1.2 mrg } 233 1.1.1.2 mrg sval->dump_to_pp (pp, simple); 234 1.1 mrg 235 1.1.1.2 mrg entry_t e = *const_cast <map_t &> (m_map).get (sval); 236 1.1.1.2 mrg pp_string (pp, ": "); 237 1.1.1.2 mrg e.m_state->dump_to_pp (pp); 238 1.1 mrg if (model) 239 1.1.1.2 mrg if (tree rep = model->get_representative_tree (sval)) 240 1.1 mrg { 241 1.1 mrg pp_string (pp, " ("); 242 1.1 mrg dump_quoted_tree (pp, rep); 243 1.1 mrg pp_character (pp, ')'); 244 1.1 mrg } 245 1.1.1.2 mrg if (e.m_origin) 246 1.1 mrg { 247 1.1 mrg pp_string (pp, " (origin: "); 248 1.1.1.2 mrg if (!flag_dump_noaddr) 249 1.1.1.2 mrg { 250 1.1.1.2 mrg pp_pointer (pp, e.m_origin); 251 1.1.1.2 mrg pp_string (pp, ": "); 252 1.1.1.2 mrg } 253 1.1.1.2 mrg e.m_origin->dump_to_pp (pp, simple); 254 1.1 mrg if (model) 255 1.1 mrg if (tree rep = model->get_representative_tree (e.m_origin)) 256 1.1 mrg { 257 1.1 mrg pp_string (pp, " ("); 258 1.1 mrg dump_quoted_tree (pp, rep); 259 1.1 mrg pp_character (pp, ')'); 260 1.1 mrg } 261 1.1 mrg pp_string (pp, ")"); 262 1.1 mrg } 263 1.1.1.2 mrg if (multiline) 264 1.1.1.2 mrg pp_newline (pp); 265 1.1 mrg } 266 1.1.1.2 mrg if (!multiline) 267 1.1.1.2 mrg pp_string (pp, "}"); 268 1.1 mrg } 269 1.1 mrg 270 1.1.1.2 mrg /* Dump this object to stderr. */ 271 1.1 mrg 272 1.1 mrg DEBUG_FUNCTION void 273 1.1.1.2 mrg sm_state_map::dump (bool simple) const 274 1.1 mrg { 275 1.1 mrg pretty_printer pp; 276 1.1.1.2 mrg pp_format_decoder (&pp) = default_tree_printer; 277 1.1 mrg pp_show_color (&pp) = pp_show_color (global_dc->printer); 278 1.1 mrg pp.buffer->stream = stderr; 279 1.1.1.2 mrg print (NULL, simple, true, &pp); 280 1.1 mrg pp_newline (&pp); 281 1.1 mrg pp_flush (&pp); 282 1.1 mrg } 283 1.1 mrg 284 1.1.1.2 mrg /* Return a new json::object of the form 285 1.1.1.2 mrg {"global" : (optional) value for global state, 286 1.1.1.2 mrg SVAL_DESC : value for state}. */ 287 1.1.1.2 mrg 288 1.1.1.2 mrg json::object * 289 1.1.1.2 mrg sm_state_map::to_json () const 290 1.1.1.2 mrg { 291 1.1.1.2 mrg json::object *map_obj = new json::object (); 292 1.1.1.2 mrg 293 1.1.1.2 mrg if (m_global_state != m_sm.get_start_state ()) 294 1.1.1.2 mrg map_obj->set ("global", m_global_state->to_json ()); 295 1.1.1.2 mrg for (map_t::iterator iter = m_map.begin (); 296 1.1.1.2 mrg iter != m_map.end (); 297 1.1.1.2 mrg ++iter) 298 1.1.1.2 mrg { 299 1.1.1.2 mrg const svalue *sval = (*iter).first; 300 1.1.1.2 mrg entry_t e = (*iter).second; 301 1.1.1.2 mrg 302 1.1.1.2 mrg label_text sval_desc = sval->get_desc (); 303 1.1.1.2 mrg map_obj->set (sval_desc.m_buffer, e.m_state->to_json ()); 304 1.1.1.2 mrg sval_desc.maybe_free (); 305 1.1.1.2 mrg 306 1.1.1.2 mrg /* This doesn't yet JSONify e.m_origin. */ 307 1.1.1.2 mrg } 308 1.1.1.2 mrg return map_obj; 309 1.1.1.2 mrg } 310 1.1.1.2 mrg 311 1.1 mrg /* Return true if no states have been set within this map 312 1.1 mrg (all expressions are for the start state). */ 313 1.1 mrg 314 1.1 mrg bool 315 1.1 mrg sm_state_map::is_empty_p () const 316 1.1 mrg { 317 1.1.1.2 mrg return m_map.elements () == 0 && m_global_state == m_sm.get_start_state (); 318 1.1 mrg } 319 1.1 mrg 320 1.1 mrg /* Generate a hash value for this sm_state_map. */ 321 1.1 mrg 322 1.1 mrg hashval_t 323 1.1 mrg sm_state_map::hash () const 324 1.1 mrg { 325 1.1 mrg hashval_t result = 0; 326 1.1 mrg 327 1.1 mrg /* Accumulate the result by xoring a hash for each slot, so that the 328 1.1 mrg result doesn't depend on the ordering of the slots in the map. */ 329 1.1 mrg 330 1.1 mrg for (map_t::iterator iter = m_map.begin (); 331 1.1 mrg iter != m_map.end (); 332 1.1 mrg ++iter) 333 1.1 mrg { 334 1.1 mrg inchash::hash hstate; 335 1.1.1.2 mrg hstate.add_ptr ((*iter).first); 336 1.1 mrg entry_t e = (*iter).second; 337 1.1.1.2 mrg hstate.add_int (e.m_state->get_id ()); 338 1.1.1.2 mrg hstate.add_ptr (e.m_origin); 339 1.1 mrg result ^= hstate.end (); 340 1.1 mrg } 341 1.1.1.2 mrg result ^= m_global_state->get_id (); 342 1.1 mrg 343 1.1 mrg return result; 344 1.1 mrg } 345 1.1 mrg 346 1.1 mrg /* Equality operator for sm_state_map. */ 347 1.1 mrg 348 1.1 mrg bool 349 1.1 mrg sm_state_map::operator== (const sm_state_map &other) const 350 1.1 mrg { 351 1.1 mrg if (m_global_state != other.m_global_state) 352 1.1 mrg return false; 353 1.1 mrg 354 1.1 mrg if (m_map.elements () != other.m_map.elements ()) 355 1.1 mrg return false; 356 1.1 mrg 357 1.1 mrg for (map_t::iterator iter = m_map.begin (); 358 1.1 mrg iter != m_map.end (); 359 1.1 mrg ++iter) 360 1.1 mrg { 361 1.1.1.2 mrg const svalue *sval = (*iter).first; 362 1.1 mrg entry_t e = (*iter).second; 363 1.1.1.2 mrg entry_t *other_slot = const_cast <map_t &> (other.m_map).get (sval); 364 1.1 mrg if (other_slot == NULL) 365 1.1 mrg return false; 366 1.1 mrg if (e != *other_slot) 367 1.1 mrg return false; 368 1.1 mrg } 369 1.1 mrg 370 1.1 mrg gcc_checking_assert (hash () == other.hash ()); 371 1.1 mrg 372 1.1 mrg return true; 373 1.1 mrg } 374 1.1 mrg 375 1.1.1.2 mrg /* Get the state of SVAL within this object. 376 1.1 mrg States default to the start state. */ 377 1.1 mrg 378 1.1 mrg state_machine::state_t 379 1.1.1.2 mrg sm_state_map::get_state (const svalue *sval, 380 1.1.1.2 mrg const extrinsic_state &ext_state) const 381 1.1 mrg { 382 1.1.1.2 mrg gcc_assert (sval); 383 1.1.1.2 mrg 384 1.1.1.2 mrg sval = canonicalize_svalue (sval, ext_state); 385 1.1 mrg 386 1.1 mrg if (entry_t *slot 387 1.1.1.2 mrg = const_cast <map_t &> (m_map).get (sval)) 388 1.1 mrg return slot->m_state; 389 1.1.1.2 mrg 390 1.1.1.2 mrg /* SVAL has no explicit sm-state. 391 1.1.1.2 mrg If this sm allows for state inheritance, then SVAL might have implicit 392 1.1.1.2 mrg sm-state inherited via a parent. 393 1.1.1.2 mrg For example INIT_VAL(foo.field) might inherit taintedness state from 394 1.1.1.2 mrg INIT_VAL(foo). */ 395 1.1.1.2 mrg if (m_sm.inherited_state_p ()) 396 1.1.1.2 mrg if (region_model_manager *mgr = ext_state.get_model_manager ()) 397 1.1.1.2 mrg { 398 1.1.1.2 mrg if (const initial_svalue *init_sval = sval->dyn_cast_initial_svalue ()) 399 1.1.1.2 mrg { 400 1.1.1.2 mrg const region *reg = init_sval->get_region (); 401 1.1.1.2 mrg /* Try recursing upwards (up to the base region for the 402 1.1.1.2 mrg cluster). */ 403 1.1.1.2 mrg if (!reg->base_region_p ()) 404 1.1.1.2 mrg if (const region *parent_reg = reg->get_parent_region ()) 405 1.1.1.2 mrg { 406 1.1.1.2 mrg const svalue *parent_init_sval 407 1.1.1.2 mrg = mgr->get_or_create_initial_value (parent_reg); 408 1.1.1.2 mrg state_machine::state_t parent_state 409 1.1.1.2 mrg = get_state (parent_init_sval, ext_state); 410 1.1.1.2 mrg if (parent_state) 411 1.1.1.2 mrg return parent_state; 412 1.1.1.2 mrg } 413 1.1.1.2 mrg } 414 1.1.1.2 mrg else if (const sub_svalue *sub_sval = sval->dyn_cast_sub_svalue ()) 415 1.1.1.2 mrg { 416 1.1.1.2 mrg const svalue *parent_sval = sub_sval->get_parent (); 417 1.1.1.2 mrg if (state_machine::state_t parent_state 418 1.1.1.2 mrg = get_state (parent_sval, ext_state)) 419 1.1.1.2 mrg return parent_state; 420 1.1.1.2 mrg } 421 1.1.1.2 mrg } 422 1.1.1.2 mrg 423 1.1.1.2 mrg if (state_machine::state_t state 424 1.1.1.2 mrg = m_sm.alt_get_inherited_state (*this, sval, ext_state)) 425 1.1.1.2 mrg return state; 426 1.1.1.2 mrg 427 1.1.1.2 mrg return m_sm.get_default_state (sval); 428 1.1 mrg } 429 1.1 mrg 430 1.1.1.2 mrg /* Get the "origin" svalue for any state of SVAL. */ 431 1.1 mrg 432 1.1.1.2 mrg const svalue * 433 1.1.1.2 mrg sm_state_map::get_origin (const svalue *sval, 434 1.1.1.2 mrg const extrinsic_state &ext_state) const 435 1.1 mrg { 436 1.1.1.2 mrg gcc_assert (sval); 437 1.1.1.2 mrg 438 1.1.1.2 mrg sval = canonicalize_svalue (sval, ext_state); 439 1.1 mrg 440 1.1 mrg entry_t *slot 441 1.1.1.2 mrg = const_cast <map_t &> (m_map).get (sval); 442 1.1 mrg if (slot) 443 1.1 mrg return slot->m_origin; 444 1.1 mrg else 445 1.1.1.2 mrg return NULL; 446 1.1 mrg } 447 1.1 mrg 448 1.1 mrg /* Set the state of SID within MODEL to STATE, recording that 449 1.1 mrg the state came from ORIGIN. */ 450 1.1 mrg 451 1.1 mrg void 452 1.1 mrg sm_state_map::set_state (region_model *model, 453 1.1.1.2 mrg const svalue *sval, 454 1.1 mrg state_machine::state_t state, 455 1.1.1.2 mrg const svalue *origin, 456 1.1.1.2 mrg const extrinsic_state &ext_state) 457 1.1 mrg { 458 1.1 mrg if (model == NULL) 459 1.1 mrg return; 460 1.1 mrg 461 1.1.1.2 mrg /* Reject attempts to set state on UNKNOWN/POISONED. */ 462 1.1.1.2 mrg if (!sval->can_have_associated_state_p ()) 463 1.1.1.2 mrg return; 464 1.1 mrg 465 1.1.1.2 mrg equiv_class &ec = model->get_constraints ()->get_equiv_class (sval); 466 1.1.1.2 mrg if (!set_state (ec, state, origin, ext_state)) 467 1.1.1.2 mrg return; 468 1.1 mrg } 469 1.1 mrg 470 1.1 mrg /* Set the state of EC to STATE, recording that the state came from 471 1.1 mrg ORIGIN. 472 1.1 mrg Return true if any states of svalue_ids within EC changed. */ 473 1.1 mrg 474 1.1 mrg bool 475 1.1 mrg sm_state_map::set_state (const equiv_class &ec, 476 1.1 mrg state_machine::state_t state, 477 1.1.1.2 mrg const svalue *origin, 478 1.1.1.2 mrg const extrinsic_state &ext_state) 479 1.1 mrg { 480 1.1 mrg bool any_changed = false; 481 1.1.1.2 mrg for (const svalue *sval : ec.m_vars) 482 1.1.1.2 mrg any_changed |= impl_set_state (sval, state, origin, ext_state); 483 1.1 mrg return any_changed; 484 1.1 mrg } 485 1.1 mrg 486 1.1.1.2 mrg /* Set state of SVAL to STATE, bypassing equivalence classes. 487 1.1 mrg Return true if the state changed. */ 488 1.1 mrg 489 1.1 mrg bool 490 1.1.1.2 mrg sm_state_map::impl_set_state (const svalue *sval, 491 1.1.1.2 mrg state_machine::state_t state, 492 1.1.1.2 mrg const svalue *origin, 493 1.1.1.2 mrg const extrinsic_state &ext_state) 494 1.1 mrg { 495 1.1.1.2 mrg sval = canonicalize_svalue (sval, ext_state); 496 1.1.1.2 mrg 497 1.1.1.2 mrg if (get_state (sval, ext_state) == state) 498 1.1 mrg return false; 499 1.1 mrg 500 1.1.1.2 mrg gcc_assert (sval->can_have_associated_state_p ()); 501 1.1.1.2 mrg 502 1.1.1.2 mrg if (m_sm.inherited_state_p ()) 503 1.1.1.2 mrg { 504 1.1.1.2 mrg if (const compound_svalue *compound_sval 505 1.1.1.2 mrg = sval->dyn_cast_compound_svalue ()) 506 1.1.1.2 mrg for (auto iter : *compound_sval) 507 1.1.1.2 mrg { 508 1.1.1.2 mrg const svalue *inner_sval = iter.second; 509 1.1.1.2 mrg if (inner_sval->can_have_associated_state_p ()) 510 1.1.1.2 mrg impl_set_state (inner_sval, state, origin, ext_state); 511 1.1.1.2 mrg } 512 1.1.1.2 mrg } 513 1.1.1.2 mrg 514 1.1 mrg /* Special-case state 0 as the default value. */ 515 1.1 mrg if (state == 0) 516 1.1 mrg { 517 1.1.1.2 mrg if (m_map.get (sval)) 518 1.1.1.2 mrg m_map.remove (sval); 519 1.1 mrg return true; 520 1.1 mrg } 521 1.1.1.2 mrg gcc_assert (sval); 522 1.1.1.2 mrg m_map.put (sval, entry_t (state, origin)); 523 1.1 mrg return true; 524 1.1 mrg } 525 1.1 mrg 526 1.1 mrg /* Set the "global" state within this state map to STATE. */ 527 1.1 mrg 528 1.1 mrg void 529 1.1 mrg sm_state_map::set_global_state (state_machine::state_t state) 530 1.1 mrg { 531 1.1 mrg m_global_state = state; 532 1.1 mrg } 533 1.1 mrg 534 1.1 mrg /* Get the "global" state within this state map. */ 535 1.1 mrg 536 1.1 mrg state_machine::state_t 537 1.1 mrg sm_state_map::get_global_state () const 538 1.1 mrg { 539 1.1 mrg return m_global_state; 540 1.1 mrg } 541 1.1 mrg 542 1.1.1.2 mrg /* Purge any state for SVAL. 543 1.1.1.2 mrg If !SM::can_purge_p, then report the state as leaking, 544 1.1.1.2 mrg using CTXT. */ 545 1.1 mrg 546 1.1 mrg void 547 1.1.1.2 mrg sm_state_map::on_svalue_leak (const svalue *sval, 548 1.1.1.2 mrg impl_region_model_context *ctxt) 549 1.1 mrg { 550 1.1.1.2 mrg if (state_machine::state_t state = get_state (sval, ctxt->m_ext_state)) 551 1.1 mrg { 552 1.1.1.2 mrg if (!m_sm.can_purge_p (state)) 553 1.1.1.2 mrg ctxt->on_state_leak (m_sm, sval, state); 554 1.1.1.2 mrg m_map.remove (sval); 555 1.1 mrg } 556 1.1 mrg } 557 1.1 mrg 558 1.1.1.2 mrg /* Purge any state for svalues that aren't live with respect to LIVE_SVALUES 559 1.1.1.2 mrg and MODEL. */ 560 1.1 mrg 561 1.1 mrg void 562 1.1.1.2 mrg sm_state_map::on_liveness_change (const svalue_set &live_svalues, 563 1.1.1.2 mrg const region_model *model, 564 1.1.1.2 mrg impl_region_model_context *ctxt) 565 1.1 mrg { 566 1.1.1.2 mrg svalue_set svals_to_unset; 567 1.1.1.2 mrg uncertainty_t *uncertainty = ctxt->get_uncertainty (); 568 1.1 mrg 569 1.1.1.2 mrg auto_vec<const svalue *> leaked_svals (m_map.elements ()); 570 1.1 mrg for (map_t::iterator iter = m_map.begin (); 571 1.1 mrg iter != m_map.end (); 572 1.1 mrg ++iter) 573 1.1 mrg { 574 1.1.1.2 mrg const svalue *iter_sval = (*iter).first; 575 1.1.1.2 mrg if (!iter_sval->live_p (&live_svalues, model)) 576 1.1.1.2 mrg { 577 1.1.1.2 mrg svals_to_unset.add (iter_sval); 578 1.1.1.2 mrg entry_t e = (*iter).second; 579 1.1.1.2 mrg if (!m_sm.can_purge_p (e.m_state)) 580 1.1.1.2 mrg leaked_svals.quick_push (iter_sval); 581 1.1.1.2 mrg } 582 1.1.1.2 mrg if (uncertainty) 583 1.1.1.2 mrg if (uncertainty->unknown_sm_state_p (iter_sval)) 584 1.1.1.2 mrg svals_to_unset.add (iter_sval); 585 1.1 mrg } 586 1.1 mrg 587 1.1.1.2 mrg leaked_svals.qsort (svalue::cmp_ptr_ptr); 588 1.1 mrg 589 1.1.1.2 mrg unsigned i; 590 1.1.1.2 mrg const svalue *sval; 591 1.1.1.2 mrg FOR_EACH_VEC_ELT (leaked_svals, i, sval) 592 1.1 mrg { 593 1.1.1.2 mrg entry_t e = *m_map.get (sval); 594 1.1.1.2 mrg ctxt->on_state_leak (m_sm, sval, e.m_state); 595 1.1 mrg } 596 1.1.1.2 mrg 597 1.1.1.2 mrg for (svalue_set::iterator iter = svals_to_unset.begin (); 598 1.1.1.2 mrg iter != svals_to_unset.end (); ++iter) 599 1.1.1.2 mrg m_map.remove (*iter); 600 1.1 mrg } 601 1.1 mrg 602 1.1.1.2 mrg /* Purge state from SVAL (in response to a call to an unknown function). */ 603 1.1.1.2 mrg 604 1.1.1.2 mrg void 605 1.1.1.2 mrg sm_state_map::on_unknown_change (const svalue *sval, 606 1.1.1.2 mrg bool is_mutable, 607 1.1.1.2 mrg const extrinsic_state &ext_state) 608 1.1.1.2 mrg { 609 1.1.1.2 mrg svalue_set svals_to_unset; 610 1.1 mrg 611 1.1 mrg for (map_t::iterator iter = m_map.begin (); 612 1.1 mrg iter != m_map.end (); 613 1.1 mrg ++iter) 614 1.1 mrg { 615 1.1.1.2 mrg const svalue *key = (*iter).first; 616 1.1.1.2 mrg entry_t e = (*iter).second; 617 1.1.1.2 mrg /* We only want to purge state for some states when things 618 1.1.1.2 mrg are mutable. For example, in sm-malloc.cc, an on-stack ptr 619 1.1.1.2 mrg doesn't stop being stack-allocated when passed to an unknown fn. */ 620 1.1.1.2 mrg if (!m_sm.reset_when_passed_to_unknown_fn_p (e.m_state, is_mutable)) 621 1.1.1.2 mrg continue; 622 1.1.1.2 mrg if (key == sval) 623 1.1.1.2 mrg svals_to_unset.add (key); 624 1.1.1.2 mrg /* If we have INIT_VAL(BASE_REG), then unset any INIT_VAL(REG) 625 1.1.1.2 mrg for REG within BASE_REG. */ 626 1.1.1.2 mrg if (const initial_svalue *init_sval = sval->dyn_cast_initial_svalue ()) 627 1.1.1.2 mrg if (const initial_svalue *init_key = key->dyn_cast_initial_svalue ()) 628 1.1.1.2 mrg { 629 1.1.1.2 mrg const region *changed_reg = init_sval->get_region (); 630 1.1.1.2 mrg const region *changed_key = init_key->get_region (); 631 1.1.1.2 mrg if (changed_key->get_base_region () == changed_reg) 632 1.1.1.2 mrg svals_to_unset.add (key); 633 1.1.1.2 mrg } 634 1.1 mrg } 635 1.1 mrg 636 1.1.1.2 mrg for (svalue_set::iterator iter = svals_to_unset.begin (); 637 1.1.1.2 mrg iter != svals_to_unset.end (); ++iter) 638 1.1.1.2 mrg impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state); 639 1.1 mrg } 640 1.1 mrg 641 1.1.1.2 mrg /* Purge state for things involving SVAL. 642 1.1.1.2 mrg For use when SVAL changes meaning, at the def_stmt on an SSA_NAME. */ 643 1.1 mrg 644 1.1 mrg void 645 1.1.1.2 mrg sm_state_map::purge_state_involving (const svalue *sval, 646 1.1.1.2 mrg const extrinsic_state &ext_state) 647 1.1 mrg { 648 1.1.1.2 mrg /* Currently svalue::involves_p requires this. */ 649 1.1.1.2 mrg if (!(sval->get_kind () == SK_INITIAL 650 1.1.1.2 mrg || sval->get_kind () == SK_CONJURED)) 651 1.1.1.2 mrg return; 652 1.1 mrg 653 1.1.1.2 mrg svalue_set svals_to_unset; 654 1.1 mrg 655 1.1.1.2 mrg for (map_t::iterator iter = m_map.begin (); 656 1.1.1.2 mrg iter != m_map.end (); 657 1.1.1.2 mrg ++iter) 658 1.1.1.2 mrg { 659 1.1.1.2 mrg const svalue *key = (*iter).first; 660 1.1.1.2 mrg entry_t e = (*iter).second; 661 1.1.1.2 mrg if (!m_sm.can_purge_p (e.m_state)) 662 1.1.1.2 mrg continue; 663 1.1.1.2 mrg if (key->involves_p (sval)) 664 1.1.1.2 mrg svals_to_unset.add (key); 665 1.1.1.2 mrg } 666 1.1 mrg 667 1.1.1.2 mrg for (svalue_set::iterator iter = svals_to_unset.begin (); 668 1.1.1.2 mrg iter != svals_to_unset.end (); ++iter) 669 1.1.1.2 mrg impl_set_state (*iter, (state_machine::state_t)0, NULL, ext_state); 670 1.1 mrg } 671 1.1 mrg 672 1.1.1.2 mrg /* Comparator for imposing an order on sm_state_map instances. */ 673 1.1 mrg 674 1.1.1.2 mrg int 675 1.1.1.2 mrg sm_state_map::cmp (const sm_state_map &smap_a, const sm_state_map &smap_b) 676 1.1 mrg { 677 1.1.1.2 mrg if (int cmp_count = smap_a.elements () - smap_b.elements ()) 678 1.1.1.2 mrg return cmp_count; 679 1.1 mrg 680 1.1.1.2 mrg auto_vec <const svalue *> keys_a (smap_a.elements ()); 681 1.1.1.2 mrg for (map_t::iterator iter = smap_a.begin (); 682 1.1.1.2 mrg iter != smap_a.end (); 683 1.1 mrg ++iter) 684 1.1.1.2 mrg keys_a.quick_push ((*iter).first); 685 1.1.1.2 mrg keys_a.qsort (svalue::cmp_ptr_ptr); 686 1.1 mrg 687 1.1.1.2 mrg auto_vec <const svalue *> keys_b (smap_b.elements ()); 688 1.1.1.2 mrg for (map_t::iterator iter = smap_b.begin (); 689 1.1.1.2 mrg iter != smap_b.end (); 690 1.1.1.2 mrg ++iter) 691 1.1.1.2 mrg keys_b.quick_push ((*iter).first); 692 1.1.1.2 mrg keys_b.qsort (svalue::cmp_ptr_ptr); 693 1.1.1.2 mrg 694 1.1.1.2 mrg unsigned i; 695 1.1.1.2 mrg const svalue *sval_a; 696 1.1.1.2 mrg FOR_EACH_VEC_ELT (keys_a, i, sval_a) 697 1.1.1.2 mrg { 698 1.1.1.2 mrg const svalue *sval_b = keys_b[i]; 699 1.1.1.2 mrg if (int cmp_sval = svalue::cmp_ptr (sval_a, sval_b)) 700 1.1.1.2 mrg return cmp_sval; 701 1.1.1.2 mrg const entry_t *e_a = const_cast <map_t &> (smap_a.m_map).get (sval_a); 702 1.1.1.2 mrg const entry_t *e_b = const_cast <map_t &> (smap_b.m_map).get (sval_b); 703 1.1.1.2 mrg if (int cmp_entry = entry_t::cmp (*e_a, *e_b)) 704 1.1.1.2 mrg return cmp_entry; 705 1.1 mrg } 706 1.1.1.2 mrg 707 1.1.1.2 mrg return 0; 708 1.1.1.2 mrg } 709 1.1.1.2 mrg 710 1.1.1.2 mrg /* Canonicalize SVAL before getting/setting it within the map. 711 1.1.1.2 mrg Convert all NULL pointers to (void *) to avoid state explosions 712 1.1.1.2 mrg involving all of the various (foo *)NULL vs (bar *)NULL. */ 713 1.1.1.2 mrg 714 1.1.1.2 mrg const svalue * 715 1.1.1.2 mrg sm_state_map::canonicalize_svalue (const svalue *sval, 716 1.1.1.2 mrg const extrinsic_state &ext_state) 717 1.1.1.2 mrg { 718 1.1.1.2 mrg region_model_manager *mgr = ext_state.get_model_manager (); 719 1.1.1.2 mrg if (mgr && sval->get_type () && POINTER_TYPE_P (sval->get_type ())) 720 1.1.1.2 mrg if (tree cst = sval->maybe_get_constant ()) 721 1.1.1.2 mrg if (zerop (cst)) 722 1.1.1.2 mrg return mgr->get_or_create_constant_svalue (null_pointer_node); 723 1.1.1.2 mrg 724 1.1.1.2 mrg return sval; 725 1.1 mrg } 726 1.1 mrg 727 1.1 mrg /* class program_state. */ 728 1.1 mrg 729 1.1 mrg /* program_state's ctor. */ 730 1.1 mrg 731 1.1 mrg program_state::program_state (const extrinsic_state &ext_state) 732 1.1.1.2 mrg : m_region_model (NULL), 733 1.1 mrg m_checker_states (ext_state.get_num_checkers ()), 734 1.1 mrg m_valid (true) 735 1.1 mrg { 736 1.1.1.2 mrg engine *eng = ext_state.get_engine (); 737 1.1.1.2 mrg region_model_manager *mgr = eng->get_model_manager (); 738 1.1.1.2 mrg m_region_model = new region_model (mgr); 739 1.1.1.2 mrg const int num_states = ext_state.get_num_checkers (); 740 1.1 mrg for (int i = 0; i < num_states; i++) 741 1.1.1.2 mrg { 742 1.1.1.2 mrg sm_state_map *sm = new sm_state_map (ext_state.get_sm (i)); 743 1.1.1.2 mrg m_checker_states.quick_push (sm); 744 1.1.1.2 mrg } 745 1.1 mrg } 746 1.1 mrg 747 1.1 mrg /* program_state's copy ctor. */ 748 1.1 mrg 749 1.1 mrg program_state::program_state (const program_state &other) 750 1.1 mrg : m_region_model (new region_model (*other.m_region_model)), 751 1.1 mrg m_checker_states (other.m_checker_states.length ()), 752 1.1 mrg m_valid (true) 753 1.1 mrg { 754 1.1 mrg int i; 755 1.1 mrg sm_state_map *smap; 756 1.1 mrg FOR_EACH_VEC_ELT (other.m_checker_states, i, smap) 757 1.1 mrg m_checker_states.quick_push (smap->clone ()); 758 1.1 mrg } 759 1.1 mrg 760 1.1 mrg /* program_state's assignment operator. */ 761 1.1 mrg 762 1.1 mrg program_state& 763 1.1 mrg program_state::operator= (const program_state &other) 764 1.1 mrg { 765 1.1 mrg delete m_region_model; 766 1.1 mrg m_region_model = new region_model (*other.m_region_model); 767 1.1 mrg 768 1.1 mrg int i; 769 1.1 mrg sm_state_map *smap; 770 1.1 mrg FOR_EACH_VEC_ELT (m_checker_states, i, smap) 771 1.1 mrg delete smap; 772 1.1 mrg m_checker_states.truncate (0); 773 1.1 mrg gcc_assert (m_checker_states.space (other.m_checker_states.length ())); 774 1.1 mrg 775 1.1 mrg FOR_EACH_VEC_ELT (other.m_checker_states, i, smap) 776 1.1 mrg m_checker_states.quick_push (smap->clone ()); 777 1.1 mrg 778 1.1 mrg m_valid = other.m_valid; 779 1.1 mrg 780 1.1 mrg return *this; 781 1.1 mrg } 782 1.1 mrg 783 1.1 mrg /* Move constructor for program_state (when building with C++11). */ 784 1.1 mrg program_state::program_state (program_state &&other) 785 1.1 mrg : m_region_model (other.m_region_model), 786 1.1 mrg m_checker_states (other.m_checker_states.length ()) 787 1.1 mrg { 788 1.1 mrg other.m_region_model = NULL; 789 1.1 mrg 790 1.1 mrg int i; 791 1.1 mrg sm_state_map *smap; 792 1.1 mrg FOR_EACH_VEC_ELT (other.m_checker_states, i, smap) 793 1.1 mrg m_checker_states.quick_push (smap); 794 1.1 mrg other.m_checker_states.truncate (0); 795 1.1 mrg 796 1.1 mrg m_valid = other.m_valid; 797 1.1 mrg } 798 1.1 mrg 799 1.1 mrg /* program_state's dtor. */ 800 1.1 mrg 801 1.1 mrg program_state::~program_state () 802 1.1 mrg { 803 1.1 mrg delete m_region_model; 804 1.1 mrg } 805 1.1 mrg 806 1.1 mrg /* Generate a hash value for this program_state. */ 807 1.1 mrg 808 1.1 mrg hashval_t 809 1.1 mrg program_state::hash () const 810 1.1 mrg { 811 1.1 mrg hashval_t result = m_region_model->hash (); 812 1.1 mrg 813 1.1 mrg int i; 814 1.1 mrg sm_state_map *smap; 815 1.1 mrg FOR_EACH_VEC_ELT (m_checker_states, i, smap) 816 1.1 mrg result ^= smap->hash (); 817 1.1 mrg return result; 818 1.1 mrg } 819 1.1 mrg 820 1.1 mrg /* Equality operator for program_state. 821 1.1 mrg All parts of the program_state (region model, checker states) must 822 1.1 mrg equal their counterparts in OTHER for the two program_states to be 823 1.1 mrg considered equal. */ 824 1.1 mrg 825 1.1 mrg bool 826 1.1 mrg program_state::operator== (const program_state &other) const 827 1.1 mrg { 828 1.1 mrg if (!(*m_region_model == *other.m_region_model)) 829 1.1 mrg return false; 830 1.1 mrg 831 1.1 mrg int i; 832 1.1 mrg sm_state_map *smap; 833 1.1 mrg FOR_EACH_VEC_ELT (m_checker_states, i, smap) 834 1.1 mrg if (!(*smap == *other.m_checker_states[i])) 835 1.1 mrg return false; 836 1.1 mrg 837 1.1 mrg gcc_checking_assert (hash () == other.hash ()); 838 1.1 mrg 839 1.1 mrg return true; 840 1.1 mrg } 841 1.1 mrg 842 1.1 mrg /* Print a compact representation of this state to PP. */ 843 1.1 mrg 844 1.1 mrg void 845 1.1 mrg program_state::print (const extrinsic_state &ext_state, 846 1.1 mrg pretty_printer *pp) const 847 1.1 mrg { 848 1.1 mrg pp_printf (pp, "rmodel: "); 849 1.1.1.2 mrg m_region_model->dump_to_pp (pp, true, false); 850 1.1 mrg pp_newline (pp); 851 1.1 mrg 852 1.1 mrg int i; 853 1.1 mrg sm_state_map *smap; 854 1.1 mrg FOR_EACH_VEC_ELT (m_checker_states, i, smap) 855 1.1 mrg { 856 1.1 mrg if (!smap->is_empty_p ()) 857 1.1 mrg { 858 1.1 mrg pp_printf (pp, "%s: ", ext_state.get_name (i)); 859 1.1.1.2 mrg smap->print (m_region_model, true, false, pp); 860 1.1 mrg pp_newline (pp); 861 1.1 mrg } 862 1.1 mrg } 863 1.1 mrg if (!m_valid) 864 1.1 mrg { 865 1.1 mrg pp_printf (pp, "invalid state"); 866 1.1 mrg pp_newline (pp); 867 1.1 mrg } 868 1.1 mrg } 869 1.1 mrg 870 1.1.1.2 mrg /* Dump a representation of this state to PP. */ 871 1.1 mrg 872 1.1 mrg void 873 1.1 mrg program_state::dump_to_pp (const extrinsic_state &ext_state, 874 1.1.1.2 mrg bool /*summarize*/, bool multiline, 875 1.1 mrg pretty_printer *pp) const 876 1.1 mrg { 877 1.1.1.2 mrg if (!multiline) 878 1.1.1.2 mrg pp_string (pp, "{"); 879 1.1.1.2 mrg { 880 1.1.1.2 mrg pp_printf (pp, "rmodel:"); 881 1.1.1.2 mrg if (multiline) 882 1.1.1.2 mrg pp_newline (pp); 883 1.1.1.2 mrg else 884 1.1.1.2 mrg pp_string (pp, " {"); 885 1.1.1.2 mrg m_region_model->dump_to_pp (pp, true, multiline); 886 1.1.1.2 mrg if (!multiline) 887 1.1.1.2 mrg pp_string (pp, "}"); 888 1.1.1.2 mrg } 889 1.1 mrg 890 1.1 mrg int i; 891 1.1 mrg sm_state_map *smap; 892 1.1 mrg FOR_EACH_VEC_ELT (m_checker_states, i, smap) 893 1.1 mrg { 894 1.1 mrg if (!smap->is_empty_p ()) 895 1.1 mrg { 896 1.1.1.2 mrg if (!multiline) 897 1.1.1.2 mrg pp_string (pp, " {"); 898 1.1 mrg pp_printf (pp, "%s: ", ext_state.get_name (i)); 899 1.1.1.2 mrg if (multiline) 900 1.1 mrg pp_newline (pp); 901 1.1.1.2 mrg smap->print (m_region_model, true, multiline, pp); 902 1.1.1.2 mrg if (!multiline) 903 1.1.1.2 mrg pp_string (pp, "}"); 904 1.1 mrg } 905 1.1 mrg } 906 1.1 mrg 907 1.1 mrg if (!m_valid) 908 1.1 mrg { 909 1.1.1.2 mrg if (!multiline) 910 1.1 mrg pp_space (pp); 911 1.1 mrg pp_printf (pp, "invalid state"); 912 1.1.1.2 mrg if (multiline) 913 1.1 mrg pp_newline (pp); 914 1.1 mrg } 915 1.1.1.2 mrg if (!multiline) 916 1.1.1.2 mrg pp_string (pp, "}"); 917 1.1 mrg } 918 1.1 mrg 919 1.1.1.2 mrg /* Dump a representation of this state to OUTF. */ 920 1.1 mrg 921 1.1 mrg void 922 1.1 mrg program_state::dump_to_file (const extrinsic_state &ext_state, 923 1.1.1.2 mrg bool summarize, bool multiline, 924 1.1 mrg FILE *outf) const 925 1.1 mrg { 926 1.1 mrg pretty_printer pp; 927 1.1 mrg pp_format_decoder (&pp) = default_tree_printer; 928 1.1 mrg if (outf == stderr) 929 1.1 mrg pp_show_color (&pp) = pp_show_color (global_dc->printer); 930 1.1 mrg pp.buffer->stream = outf; 931 1.1.1.2 mrg dump_to_pp (ext_state, summarize, multiline, &pp); 932 1.1 mrg pp_flush (&pp); 933 1.1 mrg } 934 1.1 mrg 935 1.1 mrg /* Dump a multiline representation of this state to stderr. */ 936 1.1 mrg 937 1.1 mrg DEBUG_FUNCTION void 938 1.1 mrg program_state::dump (const extrinsic_state &ext_state, 939 1.1 mrg bool summarize) const 940 1.1 mrg { 941 1.1.1.2 mrg dump_to_file (ext_state, summarize, true, stderr); 942 1.1.1.2 mrg } 943 1.1.1.2 mrg 944 1.1.1.2 mrg /* Return a new json::object of the form 945 1.1.1.2 mrg {"store" : object for store, 946 1.1.1.2 mrg "constraints" : object for constraint_manager, 947 1.1.1.2 mrg "curr_frame" : (optional) str for current frame, 948 1.1.1.2 mrg "checkers" : { STATE_NAME : object per sm_state_map }, 949 1.1.1.2 mrg "valid" : true/false}. */ 950 1.1.1.2 mrg 951 1.1.1.2 mrg json::object * 952 1.1.1.2 mrg program_state::to_json (const extrinsic_state &ext_state) const 953 1.1.1.2 mrg { 954 1.1.1.2 mrg json::object *state_obj = new json::object (); 955 1.1.1.2 mrg 956 1.1.1.2 mrg state_obj->set ("store", m_region_model->get_store ()->to_json ()); 957 1.1.1.2 mrg state_obj->set ("constraints", 958 1.1.1.2 mrg m_region_model->get_constraints ()->to_json ()); 959 1.1.1.2 mrg if (m_region_model->get_current_frame ()) 960 1.1.1.2 mrg state_obj->set ("curr_frame", 961 1.1.1.2 mrg m_region_model->get_current_frame ()->to_json ()); 962 1.1.1.2 mrg 963 1.1.1.2 mrg /* Provide m_checker_states as an object, using names as keys. */ 964 1.1.1.2 mrg { 965 1.1.1.2 mrg json::object *checkers_obj = new json::object (); 966 1.1.1.2 mrg 967 1.1.1.2 mrg int i; 968 1.1.1.2 mrg sm_state_map *smap; 969 1.1.1.2 mrg FOR_EACH_VEC_ELT (m_checker_states, i, smap) 970 1.1.1.2 mrg if (!smap->is_empty_p ()) 971 1.1.1.2 mrg checkers_obj->set (ext_state.get_name (i), smap->to_json ()); 972 1.1.1.2 mrg 973 1.1.1.2 mrg state_obj->set ("checkers", checkers_obj); 974 1.1.1.2 mrg } 975 1.1.1.2 mrg 976 1.1.1.2 mrg state_obj->set ("valid", new json::literal (m_valid)); 977 1.1.1.2 mrg 978 1.1.1.2 mrg return state_obj; 979 1.1.1.2 mrg } 980 1.1.1.2 mrg 981 1.1.1.2 mrg /* Update this program_state to reflect a top-level call to FUN. 982 1.1.1.2 mrg The params will have initial_svalues. */ 983 1.1.1.2 mrg 984 1.1.1.2 mrg void 985 1.1.1.2 mrg program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED, 986 1.1.1.2 mrg function *fun) 987 1.1.1.2 mrg { 988 1.1.1.2 mrg m_region_model->push_frame (fun, NULL, NULL); 989 1.1.1.2 mrg } 990 1.1.1.2 mrg 991 1.1.1.2 mrg /* Get the current function of this state. */ 992 1.1.1.2 mrg 993 1.1.1.2 mrg function * 994 1.1.1.2 mrg program_state::get_current_function () const 995 1.1.1.2 mrg { 996 1.1.1.2 mrg return m_region_model->get_current_function (); 997 1.1 mrg } 998 1.1 mrg 999 1.1 mrg /* Determine if following edge SUCC from ENODE is valid within the graph EG 1000 1.1 mrg and update this state accordingly in-place. 1001 1.1 mrg 1002 1.1 mrg Return true if the edge can be followed, or false otherwise. 1003 1.1 mrg 1004 1.1 mrg Check for relevant conditionals and switch-values for conditionals 1005 1.1 mrg and switch statements, adding the relevant conditions to this state. 1006 1.1 mrg Push/pop frames for interprocedural edges and update params/returned 1007 1.1 mrg values. 1008 1.1 mrg 1009 1.1 mrg This is the "state" half of exploded_node::on_edge. */ 1010 1.1 mrg 1011 1.1 mrg bool 1012 1.1 mrg program_state::on_edge (exploded_graph &eg, 1013 1.1.1.2 mrg exploded_node *enode, 1014 1.1 mrg const superedge *succ, 1015 1.1.1.2 mrg uncertainty_t *uncertainty) 1016 1.1 mrg { 1017 1.1 mrg /* Update state. */ 1018 1.1.1.2 mrg const program_point &point = enode->get_point (); 1019 1.1 mrg const gimple *last_stmt = point.get_supernode ()->get_last_stmt (); 1020 1.1 mrg 1021 1.1 mrg /* For conditionals and switch statements, add the 1022 1.1 mrg relevant conditions (for the specific edge) to new_state; 1023 1.1 mrg skip edges for which the resulting constraints 1024 1.1 mrg are impossible. 1025 1.1 mrg This also updates frame information for call/return superedges. 1026 1.1 mrg Adding the relevant conditions for the edge could also trigger 1027 1.1 mrg sm-state transitions (e.g. transitions due to ptrs becoming known 1028 1.1 mrg to be NULL or non-NULL) */ 1029 1.1 mrg 1030 1.1.1.2 mrg impl_region_model_context ctxt (eg, enode, 1031 1.1.1.2 mrg &enode->get_state (), 1032 1.1.1.2 mrg this, 1033 1.1.1.2 mrg uncertainty, NULL, 1034 1.1 mrg last_stmt); 1035 1.1 mrg if (!m_region_model->maybe_update_for_edge (*succ, 1036 1.1 mrg last_stmt, 1037 1.1.1.2 mrg &ctxt, NULL)) 1038 1.1 mrg { 1039 1.1 mrg logger * const logger = eg.get_logger (); 1040 1.1 mrg if (logger) 1041 1.1 mrg logger->log ("edge to SN: %i is impossible" 1042 1.1 mrg " due to region_model constraints", 1043 1.1 mrg succ->m_dest->m_index); 1044 1.1 mrg return false; 1045 1.1 mrg } 1046 1.1 mrg 1047 1.1.1.2 mrg program_state::detect_leaks (enode->get_state (), *this, 1048 1.1.1.2 mrg NULL, eg.get_ext_state (), 1049 1.1.1.2 mrg &ctxt); 1050 1.1.1.2 mrg 1051 1.1 mrg return true; 1052 1.1 mrg } 1053 1.1 mrg 1054 1.1.1.2 mrg /* Update this program_state to reflect a call to function 1055 1.1.1.2 mrg represented by CALL_STMT. 1056 1.1.1.2 mrg currently used only when the call doesn't have a superedge representing 1057 1.1.1.2 mrg the call ( like call via a function pointer ) */ 1058 1.1.1.2 mrg void 1059 1.1.1.2 mrg program_state::push_call (exploded_graph &eg, 1060 1.1.1.2 mrg exploded_node *enode, 1061 1.1.1.2 mrg const gcall *call_stmt, 1062 1.1.1.2 mrg uncertainty_t *uncertainty) 1063 1.1.1.2 mrg { 1064 1.1.1.2 mrg /* Update state. */ 1065 1.1.1.2 mrg const program_point &point = enode->get_point (); 1066 1.1.1.2 mrg const gimple *last_stmt = point.get_supernode ()->get_last_stmt (); 1067 1.1.1.2 mrg 1068 1.1.1.2 mrg impl_region_model_context ctxt (eg, enode, 1069 1.1.1.2 mrg &enode->get_state (), 1070 1.1.1.2 mrg this, 1071 1.1.1.2 mrg uncertainty, 1072 1.1.1.2 mrg NULL, 1073 1.1.1.2 mrg last_stmt); 1074 1.1.1.2 mrg m_region_model->update_for_gcall (call_stmt, &ctxt); 1075 1.1.1.2 mrg } 1076 1.1.1.2 mrg 1077 1.1.1.2 mrg /* Update this program_state to reflect a return from function 1078 1.1.1.2 mrg call to which is represented by CALL_STMT. 1079 1.1.1.2 mrg currently used only when the call doesn't have a superedge representing 1080 1.1.1.2 mrg the return */ 1081 1.1.1.2 mrg void 1082 1.1.1.2 mrg program_state::returning_call (exploded_graph &eg, 1083 1.1.1.2 mrg exploded_node *enode, 1084 1.1.1.2 mrg const gcall *call_stmt, 1085 1.1.1.2 mrg uncertainty_t *uncertainty) 1086 1.1.1.2 mrg { 1087 1.1.1.2 mrg /* Update state. */ 1088 1.1.1.2 mrg const program_point &point = enode->get_point (); 1089 1.1.1.2 mrg const gimple *last_stmt = point.get_supernode ()->get_last_stmt (); 1090 1.1.1.2 mrg 1091 1.1.1.2 mrg impl_region_model_context ctxt (eg, enode, 1092 1.1.1.2 mrg &enode->get_state (), 1093 1.1.1.2 mrg this, 1094 1.1.1.2 mrg uncertainty, 1095 1.1.1.2 mrg NULL, 1096 1.1.1.2 mrg last_stmt); 1097 1.1.1.2 mrg m_region_model->update_for_return_gcall (call_stmt, &ctxt); 1098 1.1.1.2 mrg } 1099 1.1.1.2 mrg 1100 1.1 mrg /* Generate a simpler version of THIS, discarding state that's no longer 1101 1.1 mrg relevant at POINT. 1102 1.1 mrg The idea is that we're more likely to be able to consolidate 1103 1.1 mrg multiple (point, state) into single exploded_nodes if we discard 1104 1.1.1.2 mrg irrelevant state (e.g. at the end of functions). */ 1105 1.1 mrg 1106 1.1 mrg program_state 1107 1.1 mrg program_state::prune_for_point (exploded_graph &eg, 1108 1.1 mrg const program_point &point, 1109 1.1.1.2 mrg exploded_node *enode_for_diag, 1110 1.1.1.2 mrg uncertainty_t *uncertainty) const 1111 1.1 mrg { 1112 1.1 mrg logger * const logger = eg.get_logger (); 1113 1.1 mrg LOG_SCOPE (logger); 1114 1.1 mrg 1115 1.1 mrg function *fun = point.get_function (); 1116 1.1 mrg if (!fun) 1117 1.1 mrg return *this; 1118 1.1 mrg 1119 1.1 mrg program_state new_state (*this); 1120 1.1 mrg 1121 1.1 mrg const state_purge_map *pm = eg.get_purge_map (); 1122 1.1 mrg if (pm) 1123 1.1 mrg { 1124 1.1.1.2 mrg unsigned num_ssas_purged = 0; 1125 1.1.1.2 mrg unsigned num_decls_purged = 0; 1126 1.1.1.2 mrg auto_vec<const decl_region *> regs; 1127 1.1.1.2 mrg new_state.m_region_model->get_regions_for_current_frame (®s); 1128 1.1.1.2 mrg regs.qsort (region::cmp_ptr_ptr); 1129 1.1.1.2 mrg unsigned i; 1130 1.1.1.2 mrg const decl_region *reg; 1131 1.1.1.2 mrg FOR_EACH_VEC_ELT (regs, i, reg) 1132 1.1 mrg { 1133 1.1.1.2 mrg const tree node = reg->get_decl (); 1134 1.1.1.2 mrg if (TREE_CODE (node) == SSA_NAME) 1135 1.1 mrg { 1136 1.1.1.2 mrg const tree ssa_name = node; 1137 1.1 mrg const state_purge_per_ssa_name &per_ssa 1138 1.1.1.2 mrg = pm->get_data_for_ssa_name (node); 1139 1.1 mrg if (!per_ssa.needed_at_point_p (point.get_function_point ())) 1140 1.1 mrg { 1141 1.1.1.2 mrg /* Don't purge bindings of SSA names to svalues 1142 1.1.1.2 mrg that have unpurgable sm-state, so that leaks are 1143 1.1.1.2 mrg reported at the end of the function, rather than 1144 1.1.1.2 mrg at the last place that such an SSA name is referred to. 1145 1.1.1.2 mrg 1146 1.1.1.2 mrg But do purge them for temporaries (when SSA_NAME_VAR is 1147 1.1.1.2 mrg NULL), so that we report for cases where a leak happens when 1148 1.1.1.2 mrg a variable is overwritten with another value, so that the leak 1149 1.1.1.2 mrg is reported at the point of overwrite, rather than having 1150 1.1.1.2 mrg temporaries keep the value reachable until the frame is 1151 1.1.1.2 mrg popped. */ 1152 1.1.1.2 mrg const svalue *sval 1153 1.1.1.2 mrg = new_state.m_region_model->get_store_value (reg, NULL); 1154 1.1.1.2 mrg if (!new_state.can_purge_p (eg.get_ext_state (), sval) 1155 1.1.1.2 mrg && SSA_NAME_VAR (ssa_name)) 1156 1.1 mrg { 1157 1.1.1.2 mrg /* (currently only state maps can keep things 1158 1.1.1.2 mrg alive). */ 1159 1.1.1.2 mrg if (logger) 1160 1.1.1.2 mrg logger->log ("not purging binding for %qE" 1161 1.1.1.2 mrg " (used by state map)", ssa_name); 1162 1.1.1.2 mrg continue; 1163 1.1 mrg } 1164 1.1.1.2 mrg 1165 1.1.1.2 mrg new_state.m_region_model->purge_region (reg); 1166 1.1.1.2 mrg num_ssas_purged++; 1167 1.1 mrg } 1168 1.1 mrg } 1169 1.1.1.2 mrg else 1170 1.1.1.2 mrg { 1171 1.1.1.2 mrg const tree decl = node; 1172 1.1.1.2 mrg gcc_assert (TREE_CODE (node) == VAR_DECL 1173 1.1.1.2 mrg || TREE_CODE (node) == PARM_DECL 1174 1.1.1.2 mrg || TREE_CODE (node) == RESULT_DECL); 1175 1.1.1.2 mrg if (const state_purge_per_decl *per_decl 1176 1.1.1.2 mrg = pm->get_any_data_for_decl (decl)) 1177 1.1.1.2 mrg if (!per_decl->needed_at_point_p (point.get_function_point ())) 1178 1.1.1.2 mrg { 1179 1.1.1.2 mrg /* Don't purge bindings of decls if there are svalues 1180 1.1.1.2 mrg that have unpurgable sm-state within the decl's cluster, 1181 1.1.1.2 mrg so that leaks are reported at the end of the function, 1182 1.1.1.2 mrg rather than at the last place that such a decl is 1183 1.1.1.2 mrg referred to. */ 1184 1.1.1.2 mrg if (!new_state.can_purge_base_region_p (eg.get_ext_state (), 1185 1.1.1.2 mrg reg)) 1186 1.1.1.2 mrg { 1187 1.1.1.2 mrg /* (currently only state maps can keep things 1188 1.1.1.2 mrg alive). */ 1189 1.1.1.2 mrg if (logger) 1190 1.1.1.2 mrg logger->log ("not purging binding for %qE" 1191 1.1.1.2 mrg " (value in binding used by state map)", 1192 1.1.1.2 mrg decl); 1193 1.1.1.2 mrg continue; 1194 1.1.1.2 mrg } 1195 1.1.1.2 mrg 1196 1.1.1.2 mrg new_state.m_region_model->purge_region (reg); 1197 1.1.1.2 mrg num_decls_purged++; 1198 1.1.1.2 mrg } 1199 1.1.1.2 mrg } 1200 1.1 mrg } 1201 1.1 mrg 1202 1.1.1.2 mrg if (num_ssas_purged > 0 || num_decls_purged > 0) 1203 1.1.1.2 mrg { 1204 1.1.1.2 mrg if (logger) 1205 1.1.1.2 mrg { 1206 1.1.1.2 mrg logger->log ("num_ssas_purged: %i", num_ssas_purged); 1207 1.1.1.2 mrg logger->log ("num_decl_purged: %i", num_decls_purged); 1208 1.1.1.2 mrg } 1209 1.1.1.2 mrg impl_region_model_context ctxt (eg, enode_for_diag, 1210 1.1.1.2 mrg this, 1211 1.1.1.2 mrg &new_state, 1212 1.1.1.2 mrg uncertainty, NULL, 1213 1.1.1.2 mrg point.get_stmt ()); 1214 1.1.1.2 mrg detect_leaks (*this, new_state, NULL, eg.get_ext_state (), &ctxt); 1215 1.1.1.2 mrg } 1216 1.1 mrg } 1217 1.1 mrg 1218 1.1.1.2 mrg new_state.m_region_model->canonicalize (); 1219 1.1 mrg 1220 1.1 mrg return new_state; 1221 1.1 mrg } 1222 1.1 mrg 1223 1.1.1.2 mrg /* Return true if there are no unpurgeable bindings within BASE_REG. */ 1224 1.1 mrg 1225 1.1.1.2 mrg bool 1226 1.1.1.2 mrg program_state::can_purge_base_region_p (const extrinsic_state &ext_state, 1227 1.1.1.2 mrg const region *base_reg) const 1228 1.1 mrg { 1229 1.1.1.2 mrg binding_cluster *cluster 1230 1.1.1.2 mrg = m_region_model->get_store ()->get_cluster (base_reg); 1231 1.1.1.2 mrg if (!cluster) 1232 1.1.1.2 mrg return true; 1233 1.1.1.2 mrg 1234 1.1.1.2 mrg for (auto iter : *cluster) 1235 1.1.1.2 mrg { 1236 1.1.1.2 mrg const svalue *sval = iter.second; 1237 1.1.1.2 mrg if (!can_purge_p (ext_state, sval)) 1238 1.1.1.2 mrg return false; 1239 1.1.1.2 mrg } 1240 1.1.1.2 mrg 1241 1.1.1.2 mrg return true; 1242 1.1 mrg } 1243 1.1 mrg 1244 1.1.1.2 mrg /* Get a representative tree to use for describing SVAL. */ 1245 1.1 mrg 1246 1.1 mrg tree 1247 1.1.1.2 mrg program_state::get_representative_tree (const svalue *sval) const 1248 1.1 mrg { 1249 1.1.1.2 mrg gcc_assert (m_region_model); 1250 1.1.1.2 mrg return m_region_model->get_representative_tree (sval); 1251 1.1 mrg } 1252 1.1 mrg 1253 1.1.1.2 mrg /* Attempt to merge this state with OTHER, both at POINT. 1254 1.1 mrg Write the result to *OUT. 1255 1.1 mrg If the states were merged successfully, return true. */ 1256 1.1 mrg 1257 1.1 mrg bool 1258 1.1 mrg program_state::can_merge_with_p (const program_state &other, 1259 1.1 mrg const extrinsic_state &ext_state, 1260 1.1.1.2 mrg const program_point &point, 1261 1.1 mrg program_state *out) const 1262 1.1 mrg { 1263 1.1 mrg gcc_assert (out); 1264 1.1.1.2 mrg gcc_assert (m_region_model); 1265 1.1 mrg 1266 1.1.1.2 mrg /* Early reject if there are sm-differences between the states. */ 1267 1.1.1.2 mrg int i; 1268 1.1.1.2 mrg sm_state_map *smap; 1269 1.1.1.2 mrg FOR_EACH_VEC_ELT (out->m_checker_states, i, smap) 1270 1.1.1.2 mrg if (*m_checker_states[i] != *other.m_checker_states[i]) 1271 1.1.1.2 mrg return false; 1272 1.1 mrg 1273 1.1 mrg /* Attempt to merge the region_models. */ 1274 1.1 mrg if (!m_region_model->can_merge_with_p (*other.m_region_model, 1275 1.1.1.2 mrg point, 1276 1.1 mrg out->m_region_model, 1277 1.1.1.2 mrg &ext_state, 1278 1.1.1.2 mrg this, &other)) 1279 1.1 mrg return false; 1280 1.1 mrg 1281 1.1.1.2 mrg /* Copy m_checker_states to OUT. */ 1282 1.1 mrg FOR_EACH_VEC_ELT (out->m_checker_states, i, smap) 1283 1.1 mrg { 1284 1.1.1.2 mrg delete smap; 1285 1.1.1.2 mrg out->m_checker_states[i] = m_checker_states[i]->clone (); 1286 1.1 mrg } 1287 1.1 mrg 1288 1.1.1.2 mrg out->m_region_model->canonicalize (); 1289 1.1 mrg 1290 1.1 mrg return true; 1291 1.1 mrg } 1292 1.1 mrg 1293 1.1 mrg /* Assert that this object is valid. */ 1294 1.1 mrg 1295 1.1 mrg void 1296 1.1 mrg program_state::validate (const extrinsic_state &ext_state) const 1297 1.1 mrg { 1298 1.1 mrg /* Skip this in a release build. */ 1299 1.1 mrg #if !CHECKING_P 1300 1.1 mrg return; 1301 1.1 mrg #endif 1302 1.1 mrg 1303 1.1 mrg gcc_assert (m_checker_states.length () == ext_state.get_num_checkers ()); 1304 1.1.1.2 mrg m_region_model->validate (); 1305 1.1 mrg } 1306 1.1 mrg 1307 1.1.1.2 mrg static void 1308 1.1.1.2 mrg log_set_of_svalues (logger *logger, const char *name, 1309 1.1.1.2 mrg const svalue_set &set) 1310 1.1 mrg { 1311 1.1.1.2 mrg logger->log (name); 1312 1.1.1.2 mrg logger->inc_indent (); 1313 1.1.1.2 mrg auto_vec<const svalue *> sval_vecs (set.elements ()); 1314 1.1.1.2 mrg for (svalue_set::iterator iter = set.begin (); 1315 1.1.1.2 mrg iter != set.end (); ++iter) 1316 1.1.1.2 mrg sval_vecs.quick_push (*iter); 1317 1.1.1.2 mrg sval_vecs.qsort (svalue::cmp_ptr_ptr); 1318 1.1.1.2 mrg unsigned i; 1319 1.1.1.2 mrg const svalue *sval; 1320 1.1.1.2 mrg FOR_EACH_VEC_ELT (sval_vecs, i, sval) 1321 1.1.1.2 mrg { 1322 1.1.1.2 mrg logger->start_log_line (); 1323 1.1.1.2 mrg pretty_printer *pp = logger->get_printer (); 1324 1.1.1.2 mrg if (!flag_dump_noaddr) 1325 1.1.1.2 mrg { 1326 1.1.1.2 mrg pp_pointer (pp, sval); 1327 1.1.1.2 mrg pp_string (pp, ": "); 1328 1.1.1.2 mrg } 1329 1.1.1.2 mrg sval->dump_to_pp (pp, false); 1330 1.1.1.2 mrg logger->end_log_line (); 1331 1.1.1.2 mrg } 1332 1.1.1.2 mrg logger->dec_indent (); 1333 1.1 mrg } 1334 1.1 mrg 1335 1.1.1.2 mrg /* Compare the sets of svalues reachable from each of SRC_STATE and DEST_STATE. 1336 1.1.1.2 mrg For all svalues that are reachable in SRC_STATE and are not live in 1337 1.1.1.2 mrg DEST_STATE (whether explicitly reachable in DEST_STATE, or implicitly live 1338 1.1.1.2 mrg based on the former set), call CTXT->on_svalue_leak for them. 1339 1.1 mrg 1340 1.1.1.2 mrg Call on_liveness_change on both the CTXT and on the DEST_STATE's 1341 1.1.1.2 mrg constraint_manager, purging dead svalues from sm-state and from 1342 1.1.1.2 mrg constraints, respectively. 1343 1.1 mrg 1344 1.1.1.2 mrg This function should be called at each fine-grained state change, not 1345 1.1.1.2 mrg just at exploded edges. */ 1346 1.1 mrg 1347 1.1.1.2 mrg void 1348 1.1.1.2 mrg program_state::detect_leaks (const program_state &src_state, 1349 1.1.1.2 mrg const program_state &dest_state, 1350 1.1.1.2 mrg const svalue *extra_sval, 1351 1.1.1.2 mrg const extrinsic_state &ext_state, 1352 1.1.1.2 mrg region_model_context *ctxt) 1353 1.1 mrg { 1354 1.1.1.2 mrg logger *logger = ext_state.get_logger (); 1355 1.1.1.2 mrg LOG_SCOPE (logger); 1356 1.1.1.2 mrg const uncertainty_t *uncertainty = ctxt->get_uncertainty (); 1357 1.1.1.2 mrg if (logger) 1358 1.1 mrg { 1359 1.1.1.2 mrg pretty_printer *pp = logger->get_printer (); 1360 1.1.1.2 mrg logger->start_log_line (); 1361 1.1.1.2 mrg pp_string (pp, "src_state: "); 1362 1.1.1.2 mrg src_state.dump_to_pp (ext_state, true, false, pp); 1363 1.1.1.2 mrg logger->end_log_line (); 1364 1.1.1.2 mrg logger->start_log_line (); 1365 1.1.1.2 mrg pp_string (pp, "dest_state: "); 1366 1.1.1.2 mrg dest_state.dump_to_pp (ext_state, true, false, pp); 1367 1.1.1.2 mrg logger->end_log_line (); 1368 1.1.1.2 mrg if (extra_sval) 1369 1.1.1.2 mrg { 1370 1.1.1.2 mrg logger->start_log_line (); 1371 1.1.1.2 mrg pp_string (pp, "extra_sval: "); 1372 1.1.1.2 mrg extra_sval->dump_to_pp (pp, true); 1373 1.1.1.2 mrg logger->end_log_line (); 1374 1.1.1.2 mrg } 1375 1.1.1.2 mrg if (uncertainty) 1376 1.1.1.2 mrg { 1377 1.1.1.2 mrg logger->start_log_line (); 1378 1.1.1.2 mrg pp_string (pp, "uncertainty: "); 1379 1.1.1.2 mrg uncertainty->dump_to_pp (pp, true); 1380 1.1.1.2 mrg logger->end_log_line (); 1381 1.1.1.2 mrg } 1382 1.1 mrg } 1383 1.1 mrg 1384 1.1.1.2 mrg /* Get svalues reachable from each of src_state and dest_state. 1385 1.1.1.2 mrg Get svalues *known* to be reachable in src_state. 1386 1.1.1.2 mrg Pass in uncertainty for dest_state so that we additionally get svalues that 1387 1.1.1.2 mrg *might* still be reachable in dst_state. */ 1388 1.1.1.2 mrg svalue_set known_src_svalues; 1389 1.1.1.2 mrg src_state.m_region_model->get_reachable_svalues (&known_src_svalues, 1390 1.1.1.2 mrg NULL, NULL); 1391 1.1.1.2 mrg svalue_set maybe_dest_svalues; 1392 1.1.1.2 mrg dest_state.m_region_model->get_reachable_svalues (&maybe_dest_svalues, 1393 1.1.1.2 mrg extra_sval, uncertainty); 1394 1.1 mrg 1395 1.1.1.2 mrg if (logger) 1396 1.1.1.2 mrg { 1397 1.1.1.2 mrg log_set_of_svalues (logger, "src_state known reachable svalues:", 1398 1.1.1.2 mrg known_src_svalues); 1399 1.1.1.2 mrg log_set_of_svalues (logger, "dest_state maybe reachable svalues:", 1400 1.1.1.2 mrg maybe_dest_svalues); 1401 1.1.1.2 mrg } 1402 1.1.1.2 mrg 1403 1.1.1.2 mrg auto_vec <const svalue *> dead_svals (known_src_svalues.elements ()); 1404 1.1.1.2 mrg for (svalue_set::iterator iter = known_src_svalues.begin (); 1405 1.1.1.2 mrg iter != known_src_svalues.end (); ++iter) 1406 1.1.1.2 mrg { 1407 1.1.1.2 mrg const svalue *sval = (*iter); 1408 1.1.1.2 mrg /* For each sval reachable from SRC_STATE, determine if it is 1409 1.1.1.2 mrg live in DEST_STATE: either explicitly reachable, implicitly 1410 1.1.1.2 mrg live based on the set of explicitly reachable svalues, 1411 1.1.1.2 mrg or possibly reachable as recorded in uncertainty. 1412 1.1.1.2 mrg Record those that have ceased to be live i.e. were known 1413 1.1.1.2 mrg to be live, and are now not known to be even possibly-live. */ 1414 1.1.1.2 mrg if (!sval->live_p (&maybe_dest_svalues, dest_state.m_region_model)) 1415 1.1.1.2 mrg dead_svals.quick_push (sval); 1416 1.1.1.2 mrg } 1417 1.1.1.2 mrg 1418 1.1.1.2 mrg /* Call CTXT->on_svalue_leak on all svals in SRC_STATE that have ceased 1419 1.1.1.2 mrg to be live, sorting them first to ensure deterministic behavior. */ 1420 1.1.1.2 mrg dead_svals.qsort (svalue::cmp_ptr_ptr); 1421 1.1.1.2 mrg unsigned i; 1422 1.1.1.2 mrg const svalue *sval; 1423 1.1.1.2 mrg FOR_EACH_VEC_ELT (dead_svals, i, sval) 1424 1.1.1.2 mrg ctxt->on_svalue_leak (sval); 1425 1.1 mrg 1426 1.1.1.2 mrg /* Purge dead svals from sm-state. */ 1427 1.1.1.2 mrg ctxt->on_liveness_change (maybe_dest_svalues, 1428 1.1.1.2 mrg dest_state.m_region_model); 1429 1.1 mrg 1430 1.1.1.2 mrg /* Purge dead svals from constraints. */ 1431 1.1.1.2 mrg dest_state.m_region_model->get_constraints ()->on_liveness_change 1432 1.1.1.2 mrg (maybe_dest_svalues, dest_state.m_region_model); 1433 1.1 mrg 1434 1.1.1.2 mrg /* Purge dead heap-allocated regions from dynamic extents. */ 1435 1.1.1.2 mrg for (const svalue *sval : dead_svals) 1436 1.1.1.2 mrg if (const region *reg = sval->maybe_get_region ()) 1437 1.1.1.2 mrg if (reg->get_kind () == RK_HEAP_ALLOCATED) 1438 1.1.1.2 mrg dest_state.m_region_model->unset_dynamic_extents (reg); 1439 1.1 mrg } 1440 1.1 mrg 1441 1.1.1.2 mrg /* Handle calls to "__analyzer_dump_state". */ 1442 1.1 mrg 1443 1.1 mrg void 1444 1.1.1.2 mrg program_state::impl_call_analyzer_dump_state (const gcall *call, 1445 1.1.1.2 mrg const extrinsic_state &ext_state, 1446 1.1.1.2 mrg region_model_context *ctxt) 1447 1.1 mrg { 1448 1.1.1.2 mrg call_details cd (call, m_region_model, ctxt); 1449 1.1.1.2 mrg const char *sm_name = cd.get_arg_string_literal (0); 1450 1.1.1.2 mrg if (!sm_name) 1451 1.1 mrg { 1452 1.1.1.2 mrg error_at (call->location, "cannot determine state machine"); 1453 1.1.1.2 mrg return; 1454 1.1 mrg } 1455 1.1.1.2 mrg unsigned sm_idx; 1456 1.1.1.2 mrg if (!ext_state.get_sm_idx_by_name (sm_name, &sm_idx)) 1457 1.1 mrg { 1458 1.1.1.2 mrg error_at (call->location, "unrecognized state machine %qs", sm_name); 1459 1.1.1.2 mrg return; 1460 1.1 mrg } 1461 1.1.1.2 mrg const sm_state_map *smap = m_checker_states[sm_idx]; 1462 1.1 mrg 1463 1.1.1.2 mrg const svalue *sval = cd.get_arg_svalue (1); 1464 1.1 mrg 1465 1.1.1.2 mrg /* Strip off cast to int (due to variadic args). */ 1466 1.1.1.2 mrg if (const svalue *cast = sval->maybe_undo_cast ()) 1467 1.1.1.2 mrg sval = cast; 1468 1.1 mrg 1469 1.1.1.2 mrg state_machine::state_t state = smap->get_state (sval, ext_state); 1470 1.1.1.2 mrg warning_at (call->location, 0, "state: %qs", state->get_name ()); 1471 1.1 mrg } 1472 1.1 mrg 1473 1.1 mrg #if CHECKING_P 1474 1.1 mrg 1475 1.1 mrg namespace selftest { 1476 1.1 mrg 1477 1.1 mrg /* Tests for sm_state_map. */ 1478 1.1 mrg 1479 1.1 mrg static void 1480 1.1 mrg test_sm_state_map () 1481 1.1 mrg { 1482 1.1 mrg tree x = build_global_decl ("x", integer_type_node); 1483 1.1 mrg tree y = build_global_decl ("y", integer_type_node); 1484 1.1 mrg tree z = build_global_decl ("z", integer_type_node); 1485 1.1 mrg 1486 1.1.1.2 mrg state_machine *sm = make_malloc_state_machine (NULL); 1487 1.1.1.2 mrg auto_delete_vec <state_machine> checkers; 1488 1.1.1.2 mrg checkers.safe_push (sm); 1489 1.1.1.2 mrg engine eng; 1490 1.1.1.2 mrg extrinsic_state ext_state (checkers, &eng); 1491 1.1.1.2 mrg state_machine::state_t start = sm->get_start_state (); 1492 1.1.1.2 mrg 1493 1.1 mrg /* Test setting states on svalue_id instances directly. */ 1494 1.1 mrg { 1495 1.1.1.2 mrg const state_machine::state test_state_42 ("test state 42", 42); 1496 1.1.1.2 mrg const state_machine::state_t TEST_STATE_42 = &test_state_42; 1497 1.1.1.2 mrg region_model_manager mgr; 1498 1.1.1.2 mrg region_model model (&mgr); 1499 1.1.1.2 mrg const svalue *x_sval = model.get_rvalue (x, NULL); 1500 1.1.1.2 mrg const svalue *y_sval = model.get_rvalue (y, NULL); 1501 1.1.1.2 mrg const svalue *z_sval = model.get_rvalue (z, NULL); 1502 1.1 mrg 1503 1.1.1.2 mrg sm_state_map map (*sm); 1504 1.1 mrg ASSERT_TRUE (map.is_empty_p ()); 1505 1.1.1.2 mrg ASSERT_EQ (map.get_state (x_sval, ext_state), start); 1506 1.1 mrg 1507 1.1.1.2 mrg map.impl_set_state (x_sval, TEST_STATE_42, z_sval, ext_state); 1508 1.1.1.2 mrg ASSERT_EQ (map.get_state (x_sval, ext_state), TEST_STATE_42); 1509 1.1.1.2 mrg ASSERT_EQ (map.get_origin (x_sval, ext_state), z_sval); 1510 1.1.1.2 mrg ASSERT_EQ (map.get_state (y_sval, ext_state), start); 1511 1.1 mrg ASSERT_FALSE (map.is_empty_p ()); 1512 1.1 mrg 1513 1.1.1.2 mrg map.impl_set_state (y_sval, 0, z_sval, ext_state); 1514 1.1.1.2 mrg ASSERT_EQ (map.get_state (y_sval, ext_state), start); 1515 1.1 mrg 1516 1.1.1.2 mrg map.impl_set_state (x_sval, 0, z_sval, ext_state); 1517 1.1.1.2 mrg ASSERT_EQ (map.get_state (x_sval, ext_state), start); 1518 1.1 mrg ASSERT_TRUE (map.is_empty_p ()); 1519 1.1 mrg } 1520 1.1 mrg 1521 1.1.1.2 mrg const state_machine::state test_state_5 ("test state 5", 5); 1522 1.1.1.2 mrg const state_machine::state_t TEST_STATE_5 = &test_state_5; 1523 1.1.1.2 mrg 1524 1.1 mrg /* Test setting states via equivalence classes. */ 1525 1.1 mrg { 1526 1.1.1.2 mrg region_model_manager mgr; 1527 1.1.1.2 mrg region_model model (&mgr); 1528 1.1.1.2 mrg const svalue *x_sval = model.get_rvalue (x, NULL); 1529 1.1.1.2 mrg const svalue *y_sval = model.get_rvalue (y, NULL); 1530 1.1.1.2 mrg const svalue *z_sval = model.get_rvalue (z, NULL); 1531 1.1 mrg 1532 1.1.1.2 mrg sm_state_map map (*sm); 1533 1.1 mrg ASSERT_TRUE (map.is_empty_p ()); 1534 1.1.1.2 mrg ASSERT_EQ (map.get_state (x_sval, ext_state), start); 1535 1.1.1.2 mrg ASSERT_EQ (map.get_state (y_sval, ext_state), start); 1536 1.1 mrg 1537 1.1 mrg model.add_constraint (x, EQ_EXPR, y, NULL); 1538 1.1 mrg 1539 1.1 mrg /* Setting x to a state should also update y, as they 1540 1.1 mrg are in the same equivalence class. */ 1541 1.1.1.2 mrg map.set_state (&model, x_sval, TEST_STATE_5, z_sval, ext_state); 1542 1.1.1.2 mrg ASSERT_EQ (map.get_state (x_sval, ext_state), TEST_STATE_5); 1543 1.1.1.2 mrg ASSERT_EQ (map.get_state (y_sval, ext_state), TEST_STATE_5); 1544 1.1.1.2 mrg ASSERT_EQ (map.get_origin (x_sval, ext_state), z_sval); 1545 1.1.1.2 mrg ASSERT_EQ (map.get_origin (y_sval, ext_state), z_sval); 1546 1.1 mrg } 1547 1.1 mrg 1548 1.1 mrg /* Test equality and hashing. */ 1549 1.1 mrg { 1550 1.1.1.2 mrg region_model_manager mgr; 1551 1.1.1.2 mrg region_model model (&mgr); 1552 1.1.1.2 mrg const svalue *y_sval = model.get_rvalue (y, NULL); 1553 1.1.1.2 mrg const svalue *z_sval = model.get_rvalue (z, NULL); 1554 1.1.1.2 mrg 1555 1.1.1.2 mrg sm_state_map map0 (*sm); 1556 1.1.1.2 mrg sm_state_map map1 (*sm); 1557 1.1.1.2 mrg sm_state_map map2 (*sm); 1558 1.1 mrg 1559 1.1 mrg ASSERT_EQ (map0.hash (), map1.hash ()); 1560 1.1 mrg ASSERT_EQ (map0, map1); 1561 1.1 mrg 1562 1.1.1.2 mrg map1.impl_set_state (y_sval, TEST_STATE_5, z_sval, ext_state); 1563 1.1 mrg ASSERT_NE (map0.hash (), map1.hash ()); 1564 1.1 mrg ASSERT_NE (map0, map1); 1565 1.1 mrg 1566 1.1 mrg /* Make the same change to map2. */ 1567 1.1.1.2 mrg map2.impl_set_state (y_sval, TEST_STATE_5, z_sval, ext_state); 1568 1.1 mrg ASSERT_EQ (map1.hash (), map2.hash ()); 1569 1.1 mrg ASSERT_EQ (map1, map2); 1570 1.1 mrg } 1571 1.1 mrg 1572 1.1 mrg /* Equality and hashing shouldn't depend on ordering. */ 1573 1.1 mrg { 1574 1.1.1.2 mrg const state_machine::state test_state_2 ("test state 2", 2); 1575 1.1.1.2 mrg const state_machine::state_t TEST_STATE_2 = &test_state_2; 1576 1.1.1.2 mrg const state_machine::state test_state_3 ("test state 3", 3); 1577 1.1.1.2 mrg const state_machine::state_t TEST_STATE_3 = &test_state_3; 1578 1.1.1.2 mrg sm_state_map map0 (*sm); 1579 1.1.1.2 mrg sm_state_map map1 (*sm); 1580 1.1.1.2 mrg sm_state_map map2 (*sm); 1581 1.1 mrg 1582 1.1 mrg ASSERT_EQ (map0.hash (), map1.hash ()); 1583 1.1 mrg ASSERT_EQ (map0, map1); 1584 1.1 mrg 1585 1.1.1.2 mrg region_model_manager mgr; 1586 1.1.1.2 mrg region_model model (&mgr); 1587 1.1.1.2 mrg const svalue *x_sval = model.get_rvalue (x, NULL); 1588 1.1.1.2 mrg const svalue *y_sval = model.get_rvalue (y, NULL); 1589 1.1.1.2 mrg const svalue *z_sval = model.get_rvalue (z, NULL); 1590 1.1.1.2 mrg 1591 1.1.1.2 mrg map1.impl_set_state (x_sval, TEST_STATE_2, NULL, ext_state); 1592 1.1.1.2 mrg map1.impl_set_state (y_sval, TEST_STATE_3, NULL, ext_state); 1593 1.1.1.2 mrg map1.impl_set_state (z_sval, TEST_STATE_2, NULL, ext_state); 1594 1.1.1.2 mrg 1595 1.1.1.2 mrg map2.impl_set_state (z_sval, TEST_STATE_2, NULL, ext_state); 1596 1.1.1.2 mrg map2.impl_set_state (y_sval, TEST_STATE_3, NULL, ext_state); 1597 1.1.1.2 mrg map2.impl_set_state (x_sval, TEST_STATE_2, NULL, ext_state); 1598 1.1 mrg 1599 1.1 mrg ASSERT_EQ (map1.hash (), map2.hash ()); 1600 1.1 mrg ASSERT_EQ (map1, map2); 1601 1.1 mrg } 1602 1.1 mrg 1603 1.1 mrg // TODO: coverage for purging 1604 1.1 mrg } 1605 1.1 mrg 1606 1.1.1.2 mrg /* Check program_state works as expected. */ 1607 1.1 mrg 1608 1.1 mrg static void 1609 1.1.1.2 mrg test_program_state_1 () 1610 1.1 mrg { 1611 1.1 mrg /* Create a program_state for a global ptr "p" that has 1612 1.1 mrg malloc sm-state, pointing to a region on the heap. */ 1613 1.1 mrg tree p = build_global_decl ("p", ptr_type_node); 1614 1.1 mrg 1615 1.1 mrg state_machine *sm = make_malloc_state_machine (NULL); 1616 1.1 mrg const state_machine::state_t UNCHECKED_STATE 1617 1.1 mrg = sm->get_state_by_name ("unchecked"); 1618 1.1 mrg auto_delete_vec <state_machine> checkers; 1619 1.1 mrg checkers.safe_push (sm); 1620 1.1 mrg 1621 1.1.1.2 mrg engine eng; 1622 1.1.1.2 mrg extrinsic_state ext_state (checkers, &eng); 1623 1.1.1.2 mrg region_model_manager *mgr = eng.get_model_manager (); 1624 1.1 mrg program_state s (ext_state); 1625 1.1 mrg region_model *model = s.m_region_model; 1626 1.1.1.2 mrg const svalue *size_in_bytes 1627 1.1.1.2 mrg = mgr->get_or_create_unknown_svalue (size_type_node); 1628 1.1.1.2 mrg const region *new_reg 1629 1.1.1.2 mrg = model->create_region_for_heap_alloc (size_in_bytes, NULL); 1630 1.1.1.2 mrg const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg); 1631 1.1 mrg model->set_value (model->get_lvalue (p, NULL), 1632 1.1.1.2 mrg ptr_sval, NULL); 1633 1.1 mrg sm_state_map *smap = s.m_checker_states[0]; 1634 1.1 mrg 1635 1.1.1.2 mrg smap->impl_set_state (ptr_sval, UNCHECKED_STATE, NULL, ext_state); 1636 1.1.1.2 mrg ASSERT_EQ (smap->get_state (ptr_sval, ext_state), UNCHECKED_STATE); 1637 1.1 mrg } 1638 1.1 mrg 1639 1.1.1.2 mrg /* Check that program_state works for string literals. */ 1640 1.1 mrg 1641 1.1 mrg static void 1642 1.1.1.2 mrg test_program_state_2 () 1643 1.1 mrg { 1644 1.1.1.2 mrg /* Create a program_state for a global ptr "p" that points to 1645 1.1.1.2 mrg a string constant. */ 1646 1.1 mrg tree p = build_global_decl ("p", ptr_type_node); 1647 1.1 mrg 1648 1.1 mrg tree string_cst_ptr = build_string_literal (4, "foo"); 1649 1.1 mrg 1650 1.1 mrg auto_delete_vec <state_machine> checkers; 1651 1.1.1.2 mrg engine eng; 1652 1.1.1.2 mrg extrinsic_state ext_state (checkers, &eng); 1653 1.1 mrg 1654 1.1 mrg program_state s (ext_state); 1655 1.1 mrg region_model *model = s.m_region_model; 1656 1.1.1.2 mrg const region *p_reg = model->get_lvalue (p, NULL); 1657 1.1.1.2 mrg const svalue *str_sval = model->get_rvalue (string_cst_ptr, NULL); 1658 1.1.1.2 mrg model->set_value (p_reg, str_sval, NULL); 1659 1.1 mrg } 1660 1.1 mrg 1661 1.1 mrg /* Verify that program_states with identical sm-state can be merged, 1662 1.1 mrg and that the merged program_state preserves the sm-state. */ 1663 1.1 mrg 1664 1.1 mrg static void 1665 1.1 mrg test_program_state_merging () 1666 1.1 mrg { 1667 1.1 mrg /* Create a program_state for a global ptr "p" that has 1668 1.1 mrg malloc sm-state, pointing to a region on the heap. */ 1669 1.1 mrg tree p = build_global_decl ("p", ptr_type_node); 1670 1.1 mrg 1671 1.1.1.2 mrg program_point point (program_point::origin ()); 1672 1.1 mrg auto_delete_vec <state_machine> checkers; 1673 1.1 mrg checkers.safe_push (make_malloc_state_machine (NULL)); 1674 1.1.1.2 mrg engine eng; 1675 1.1.1.2 mrg extrinsic_state ext_state (checkers, &eng); 1676 1.1.1.2 mrg region_model_manager *mgr = eng.get_model_manager (); 1677 1.1 mrg 1678 1.1 mrg program_state s0 (ext_state); 1679 1.1.1.2 mrg uncertainty_t uncertainty; 1680 1.1.1.2 mrg impl_region_model_context ctxt (&s0, ext_state, &uncertainty); 1681 1.1 mrg 1682 1.1 mrg region_model *model0 = s0.m_region_model; 1683 1.1.1.2 mrg const svalue *size_in_bytes 1684 1.1.1.2 mrg = mgr->get_or_create_unknown_svalue (size_type_node); 1685 1.1.1.2 mrg const region *new_reg 1686 1.1.1.2 mrg = model0->create_region_for_heap_alloc (size_in_bytes, NULL); 1687 1.1.1.2 mrg const svalue *ptr_sval = mgr->get_ptr_svalue (ptr_type_node, new_reg); 1688 1.1 mrg model0->set_value (model0->get_lvalue (p, &ctxt), 1689 1.1.1.2 mrg ptr_sval, &ctxt); 1690 1.1 mrg sm_state_map *smap = s0.m_checker_states[0]; 1691 1.1.1.2 mrg const state_machine::state test_state ("test state", 0); 1692 1.1.1.2 mrg const state_machine::state_t TEST_STATE = &test_state; 1693 1.1.1.2 mrg smap->impl_set_state (ptr_sval, TEST_STATE, NULL, ext_state); 1694 1.1.1.2 mrg ASSERT_EQ (smap->get_state (ptr_sval, ext_state), TEST_STATE); 1695 1.1 mrg 1696 1.1.1.2 mrg model0->canonicalize (); 1697 1.1 mrg 1698 1.1 mrg /* Verify that canonicalization preserves sm-state. */ 1699 1.1.1.2 mrg ASSERT_EQ (smap->get_state (model0->get_rvalue (p, NULL), ext_state), 1700 1.1.1.2 mrg TEST_STATE); 1701 1.1 mrg 1702 1.1 mrg /* Make a copy of the program_state. */ 1703 1.1 mrg program_state s1 (s0); 1704 1.1 mrg ASSERT_EQ (s0, s1); 1705 1.1 mrg 1706 1.1 mrg /* We have two identical states with "p" pointing to a heap region 1707 1.1 mrg with the given sm-state. 1708 1.1 mrg They ought to be mergeable, preserving the sm-state. */ 1709 1.1 mrg program_state merged (ext_state); 1710 1.1.1.2 mrg ASSERT_TRUE (s0.can_merge_with_p (s1, ext_state, point, &merged)); 1711 1.1 mrg merged.validate (ext_state); 1712 1.1 mrg 1713 1.1 mrg /* Verify that the merged state has the sm-state for "p". */ 1714 1.1 mrg region_model *merged_model = merged.m_region_model; 1715 1.1 mrg sm_state_map *merged_smap = merged.m_checker_states[0]; 1716 1.1.1.2 mrg ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, NULL), 1717 1.1.1.2 mrg ext_state), 1718 1.1 mrg TEST_STATE); 1719 1.1 mrg 1720 1.1 mrg /* Try canonicalizing. */ 1721 1.1.1.2 mrg merged.m_region_model->canonicalize (); 1722 1.1 mrg merged.validate (ext_state); 1723 1.1 mrg 1724 1.1 mrg /* Verify that the merged state still has the sm-state for "p". */ 1725 1.1.1.2 mrg ASSERT_EQ (merged_smap->get_state (merged_model->get_rvalue (p, NULL), 1726 1.1.1.2 mrg ext_state), 1727 1.1 mrg TEST_STATE); 1728 1.1 mrg 1729 1.1 mrg /* After canonicalization, we ought to have equality with the inputs. */ 1730 1.1 mrg ASSERT_EQ (s0, merged); 1731 1.1 mrg } 1732 1.1 mrg 1733 1.1 mrg /* Verify that program_states with different global-state in an sm-state 1734 1.1 mrg can't be merged. */ 1735 1.1 mrg 1736 1.1 mrg static void 1737 1.1 mrg test_program_state_merging_2 () 1738 1.1 mrg { 1739 1.1.1.2 mrg program_point point (program_point::origin ()); 1740 1.1 mrg auto_delete_vec <state_machine> checkers; 1741 1.1 mrg checkers.safe_push (make_signal_state_machine (NULL)); 1742 1.1.1.2 mrg engine eng; 1743 1.1.1.2 mrg extrinsic_state ext_state (checkers, &eng); 1744 1.1.1.2 mrg 1745 1.1.1.2 mrg const state_machine::state test_state_0 ("test state 0", 0); 1746 1.1.1.2 mrg const state_machine::state test_state_1 ("test state 1", 1); 1747 1.1.1.2 mrg const state_machine::state_t TEST_STATE_0 = &test_state_0; 1748 1.1.1.2 mrg const state_machine::state_t TEST_STATE_1 = &test_state_1; 1749 1.1 mrg 1750 1.1 mrg program_state s0 (ext_state); 1751 1.1 mrg { 1752 1.1 mrg sm_state_map *smap0 = s0.m_checker_states[0]; 1753 1.1 mrg smap0->set_global_state (TEST_STATE_0); 1754 1.1 mrg ASSERT_EQ (smap0->get_global_state (), TEST_STATE_0); 1755 1.1 mrg } 1756 1.1 mrg 1757 1.1 mrg program_state s1 (ext_state); 1758 1.1 mrg { 1759 1.1 mrg sm_state_map *smap1 = s1.m_checker_states[0]; 1760 1.1 mrg smap1->set_global_state (TEST_STATE_1); 1761 1.1 mrg ASSERT_EQ (smap1->get_global_state (), TEST_STATE_1); 1762 1.1 mrg } 1763 1.1 mrg 1764 1.1 mrg ASSERT_NE (s0, s1); 1765 1.1 mrg 1766 1.1 mrg /* They ought to not be mergeable. */ 1767 1.1 mrg program_state merged (ext_state); 1768 1.1.1.2 mrg ASSERT_FALSE (s0.can_merge_with_p (s1, ext_state, point, &merged)); 1769 1.1 mrg } 1770 1.1 mrg 1771 1.1 mrg /* Run all of the selftests within this file. */ 1772 1.1 mrg 1773 1.1 mrg void 1774 1.1 mrg analyzer_program_state_cc_tests () 1775 1.1 mrg { 1776 1.1 mrg test_sm_state_map (); 1777 1.1.1.2 mrg test_program_state_1 (); 1778 1.1.1.2 mrg test_program_state_2 (); 1779 1.1 mrg test_program_state_merging (); 1780 1.1 mrg test_program_state_merging_2 (); 1781 1.1 mrg } 1782 1.1 mrg 1783 1.1 mrg } // namespace selftest 1784 1.1 mrg 1785 1.1 mrg #endif /* CHECKING_P */ 1786 1.1 mrg 1787 1.1 mrg } // namespace ana 1788 1.1 mrg 1789 1.1 mrg #endif /* #if ENABLE_ANALYZER */ 1790