void goto_symext::symex_dead(statet &state) { const goto_programt::instructiont &instruction=*state.source.pc; const codet &code=to_code(instruction.code); if(code.operands().size()!=1) throw "dead expects one operand"; if(code.op0().id()!=ID_symbol) throw "dead expects symbol as first operand"; // We increase the L2 renaming to make these non-deterministic. // We also prevent propagation of old values. ssa_exprt ssa(to_symbol_expr(code.op0())); state.rename(ssa, ns, goto_symex_statet::L1); // in case of pointers, put something into the value set if(ns.follow(code.op0().type()).id()==ID_pointer) { exprt failed= get_failed_symbol(to_symbol_expr(code.op0()), ns); exprt rhs; if(failed.is_not_nil()) { address_of_exprt address_of_expr; address_of_expr.object()=failed; address_of_expr.type()=code.op0().type(); rhs=address_of_expr; } else rhs=exprt(ID_invalid); state.rename(rhs, ns, goto_symex_statet::L1); state.value_set.assign(ssa, rhs, ns, true, false); } ssa_exprt ssa_lhs=to_ssa_expr(ssa); const irep_idt &l1_identifier=ssa_lhs.get_identifier(); // prevent propagation state.propagation.remove(l1_identifier); // L2 renaming if(state.level2.current_names.find(l1_identifier)!= state.level2.current_names.end()) state.level2.increase_counter(l1_identifier); }
void goto_symext::vcc( const exprt &vcc_expr, const std::string &msg, statet &state) { total_vccs++; exprt expr=vcc_expr; // we are willing to re-write some quantified expressions rewrite_quantifiers(expr, state); // now rename, enables propagation state.rename(expr, ns); // now try simplifier on it do_simplify(expr); if(expr.is_true()) return; state.guard.guard_expr(expr); remaining_vccs++; target.assertion(state.guard.as_expr(), expr, msg, state.source); }
void goto_symext::dereference( exprt &expr, statet &state, const bool write) { // The expression needs to be renamed to level 1 // in order to distinguish addresses of local variables // from different frames. Would be enough to rename // symbols whose address is taken. assert(!state.call_stack().empty()); state.rename(expr, ns, goto_symex_statet::L1); // start the recursion! guardt guard; dereference_rec(expr, state, guard, write); // dereferencing may introduce new symbol_exprt // (like __CPROVER_memory) state.rename(expr, ns, goto_symex_statet::L1); }
void goto_symext::symex_decl(statet &state) { const goto_programt::instructiont &instruction=*state.source.pc; const codet &code=to_code(instruction.code); if(code.operands().size()==2) throw "two-operand decl not supported here"; if(code.operands().size()!=1) throw "decl expects one operand"; if(code.op0().id()!=ID_symbol) throw "decl expects symbol as first operand"; // We increase the L2 renaming to make these non-deterministic. // We also prevent propagation of old values. const irep_idt &identifier= to_symbol_expr(code.op0()).get_identifier(); const irep_idt l1_identifier= state.rename(identifier, ns, goto_symex_statet::L1); // prevent propagation state.propagation.remove(l1_identifier); // L2 renaming unsigned new_count=state.level2.current_count(l1_identifier)+1; state.level2.rename(l1_identifier, new_count); // in case of pointers, put something into the value set if(ns.follow(code.op0().type()).id()==ID_pointer) { exprt failed= get_failed_symbol(to_symbol_expr(code.op0()), ns); exprt rhs; if(failed.is_not_nil()) { address_of_exprt address_of_expr; address_of_expr.object()=failed; address_of_expr.type()=code.op0().type(); rhs=address_of_expr; } else rhs=exprt(ID_invalid); symbol_exprt l1_lhs; l1_lhs.type()=code.op0().type(); l1_lhs.set_identifier(l1_identifier); state.rename(rhs, ns, goto_symex_statet::L1); state.value_set.assign(l1_lhs, rhs, ns); } // record the declaration symbol_exprt original_lhs=to_symbol_expr(code.op0()); symbol_exprt ssa_lhs=original_lhs; state.rename(ssa_lhs, ns); target.decl( state.guard, ssa_lhs, original_lhs, state.source); }
void goto_symext::symex_step( const goto_functionst &goto_functions, statet &state) { #if 0 std::cout << "\ninstruction type is " << state.source.pc->type << '\n'; std::cout << "Location: " << state.source.pc->source_location << '\n'; std::cout << "Guard: " << from_expr(ns, "", state.guard.as_expr()) << '\n'; std::cout << "Code: " << from_expr(ns, "", state.source.pc->code) << '\n'; #endif assert(!state.threads.empty()); assert(!state.call_stack().empty()); const goto_programt::instructiont &instruction=*state.source.pc; merge_gotos(state); // depth exceeded? { unsigned max_depth=options.get_unsigned_int_option("depth"); if(max_depth!=0 && state.depth>max_depth) state.guard.add(false_exprt()); state.depth++; } // actually do instruction switch(instruction.type) { case SKIP: if(!state.guard.is_false()) target.location(state.guard.as_expr(), state.source); state.source.pc++; break; case END_FUNCTION: // do even if state.guard.is_false() to clear out frame created // in symex_start_thread symex_end_of_function(state); state.source.pc++; break; case LOCATION: if(!state.guard.is_false()) target.location(state.guard.as_expr(), state.source); state.source.pc++; break; case GOTO: symex_goto(state); break; case ASSUME: if(!state.guard.is_false()) { exprt tmp=instruction.guard; clean_expr(tmp, state, false); state.rename(tmp, ns); symex_assume(state, tmp); } state.source.pc++; break; case ASSERT: if(!state.guard.is_false()) { std::string msg=id2string(state.source.pc->source_location.get_comment()); if(msg=="") msg="assertion"; exprt tmp(instruction.guard); clean_expr(tmp, state, false); vcc(tmp, msg, state); } state.source.pc++; break; case RETURN: if(!state.guard.is_false()) return_assignment(state); state.source.pc++; break; case ASSIGN: if(!state.guard.is_false()) symex_assign_rec(state, to_code_assign(instruction.code)); state.source.pc++; break; case FUNCTION_CALL: if(!state.guard.is_false()) { code_function_callt deref_code= to_code_function_call(instruction.code); if(deref_code.lhs().is_not_nil()) clean_expr(deref_code.lhs(), state, true); clean_expr(deref_code.function(), state, false); Forall_expr(it, deref_code.arguments()) clean_expr(*it, state, false); symex_function_call(goto_functions, state, deref_code); } else state.source.pc++; break; case OTHER: if(!state.guard.is_false()) symex_other(goto_functions, state); state.source.pc++; break; case DECL: if(!state.guard.is_false()) symex_decl(state); state.source.pc++; break; case DEAD: symex_dead(state); state.source.pc++; break; case START_THREAD: symex_start_thread(state); state.source.pc++; break; case END_THREAD: // behaves like assume(0); if(!state.guard.is_false()) state.guard.add(false_exprt()); state.source.pc++; break; case ATOMIC_BEGIN: symex_atomic_begin(state); state.source.pc++; break; case ATOMIC_END: symex_atomic_end(state); state.source.pc++; break; case CATCH: symex_catch(state); state.source.pc++; break; case THROW: symex_throw(state); state.source.pc++; break; case NO_INSTRUCTION_TYPE: throw "symex got NO_INSTRUCTION"; default: throw "symex got unexpected instruction"; } }
void goto_symext::symex_decl(statet &state, const symbol_exprt &expr) { // We increase the L2 renaming to make these non-deterministic. // We also prevent propagation of old values. ssa_exprt ssa(expr); state.rename(ssa, ns, goto_symex_statet::L1); const irep_idt &l1_identifier=ssa.get_identifier(); // rename type to L2 state.rename(ssa.type(), l1_identifier, ns); ssa.update_type(); // in case of pointers, put something into the value set if(ns.follow(expr.type()).id()==ID_pointer) { exprt failed= get_failed_symbol(expr, ns); exprt rhs; if(failed.is_not_nil()) { address_of_exprt address_of_expr; address_of_expr.object()=failed; address_of_expr.type()=expr.type(); rhs=address_of_expr; } else rhs=exprt(ID_invalid); state.rename(rhs, ns, goto_symex_statet::L1); state.value_set.assign(ssa, rhs, ns, true, false); } // prevent propagation state.propagation.remove(l1_identifier); // L2 renaming // inlining may yield multiple declarations of the same identifier // within the same L1 context if(state.level2.current_names.find(l1_identifier)== state.level2.current_names.end()) state.level2.current_names[l1_identifier]=std::make_pair(ssa, 0); state.level2.increase_counter(l1_identifier); const bool record_events=state.record_events; state.record_events=false; state.rename(ssa, ns); state.record_events=record_events; // we hide the declaration of auxiliary variables // and if the statement itself is hidden bool hidden= ns.lookup(expr.get_identifier()).is_auxiliary || state.top().hidden_function || state.source.pc->source_location.get_hide(); target.decl( state.guard.as_expr(), ssa, state.source, hidden?symex_targett::HIDDEN:symex_targett::STATE); assert(state.dirty); if((*state.dirty)(ssa.get_object_name()) && state.atomic_section_id==0) target.shared_write( state.guard.as_expr(), ssa, state.atomic_section_id, state.source); }