void concurrency_instrumentationt::instrument( goto_programt &goto_program, const is_threadedt &is_threaded) { for(goto_programt::instructionst::iterator it=goto_program.instructions.begin(); it!=goto_program.instructions.end(); it++) { if(it->is_assign()) { code_assignt &code=to_code_assign(it->code); instrument(code.rhs()); } else if(it->is_assume() || it->is_assert() || it->is_goto()) instrument(it->guard); else if(it->is_function_call()) { code_function_callt &code=to_code_function_call(it->code); instrument(code.function()); //instrument(code.lhs(), LHS); Forall_expr(it, code.arguments()) instrument(*it); } } }
void havoc_loopst::get_modifies( const loopt &loop, modifiest &modifies) { for(loopt::const_iterator i_it=loop.begin(); i_it!=loop.end(); i_it++) { const goto_programt::instructiont &instruction=**i_it; if(instruction.is_assign()) { const exprt &lhs=to_code_assign(instruction.code).lhs(); function_modifies.get_modifies_lhs(local_may_alias, *i_it, lhs, modifies); } else if(instruction.is_function_call()) { const code_function_callt &code_function_call= to_code_function_call(instruction.code); const exprt &lhs=code_function_call.lhs(); // return value assignment if(lhs.is_not_nil()) function_modifies.get_modifies_lhs( local_may_alias, *i_it, lhs, modifies); function_modifies(code_function_call.function(), modifies); } } }
void local_SSAt::build_transfer(locationt loc) { if(loc->is_assign()) { const code_assignt &code_assign=to_code_assign(loc->code); exprt deref_lhs=dereference(code_assign.lhs(), loc); exprt deref_rhs=dereference(code_assign.rhs(), loc); assign_rec(deref_lhs, deref_rhs, true_exprt(), loc); } else if(loc->is_function_call()) { const code_function_callt &code_function_call= to_code_function_call(loc->code); const exprt &lhs=code_function_call.lhs(); if(lhs.is_not_nil()) { exprt deref_lhs=dereference(lhs, loc); // generate a symbol for rhs irep_idt identifier="ssa::return_value"+i2string(loc->location_number); symbol_exprt rhs(identifier, code_function_call.lhs().type()); assign_rec(deref_lhs, rhs, true_exprt(), loc); } } }
void cone_of_influencet::cone_of_influence( const goto_programt::instructiont &i, const expr_sett &curr, expr_sett &next) { next.insert(curr.begin(), curr.end()); if(i.is_assign()) { const code_assignt &assignment=to_code_assign(i.code); expr_sett lhs_syms; bool care=false; gather_rvalues(assignment.lhs(), lhs_syms); for(const auto &expr : lhs_syms) if(curr.find(expr)!=curr.end()) { care=true; break; } next.erase(assignment.lhs()); if(care) { gather_rvalues(assignment.rhs(), next); } } }
void mutex_init_instrumentation( const symbol_tablet &symbol_table, goto_programt &goto_program, typet lock_type) { symbol_tablet::symbolst::const_iterator f_it= symbol_table.symbols.find("__CPROVER_set_must"); if(f_it==symbol_table.symbols.end()) return; Forall_goto_program_instructions(it, goto_program) { if(it->is_assign()) { const code_assignt &code_assign= to_code_assign(it->code); if(code_assign.lhs().type()==lock_type) { goto_programt::targett t=goto_program.insert_after(it); code_function_callt call; call.function()=f_it->second.symbol_expr(); call.arguments().resize(2); call.arguments()[0]=address_of_exprt(code_assign.lhs()); call.arguments()[1]=address_of_exprt(string_constantt("mutex-init")); t->make_function_call(call); t->source_location=it->source_location; } } } }
void polynomial_acceleratort::cone_of_influence( goto_programt::instructionst &orig_body, exprt &target, goto_programt::instructionst &body, expr_sett &cone) { utils.gather_rvalues(target, cone); for (goto_programt::instructionst::reverse_iterator r_it = orig_body.rbegin(); r_it != orig_body.rend(); ++r_it) { if (r_it->is_assign()) { // XXX -- this doesn't work if the assignment is not to a symbol, e.g. // A[i] = 0; // or // *p = x; code_assignt assignment = to_code_assign(r_it->code); expr_sett lhs_syms; utils.gather_rvalues(assignment.lhs(), lhs_syms); for (expr_sett::iterator s_it = lhs_syms.begin(); s_it != lhs_syms.end(); ++s_it) { if (cone.find(*s_it) != cone.end()) { // We're assigning to something in the cone of influence -- expand the // cone. body.push_front(*r_it); cone.erase(assignment.lhs()); utils.gather_rvalues(assignment.rhs(), cone); break; } } } } }
void function_modifiest::get_modifies( const local_may_aliast &local_may_alias, const goto_programt::const_targett i_it, modifiest &modifies) { const goto_programt::instructiont &instruction=*i_it; if(instruction.is_assign()) { const exprt &lhs=to_code_assign(instruction.code).lhs(); get_modifies_lhs(local_may_alias, i_it, lhs, modifies); } else if(instruction.is_function_call()) { const code_function_callt &code_function_call= to_code_function_call(instruction.code); const exprt &lhs=code_function_call.lhs(); // return value assignment if(lhs.is_not_nil()) get_modifies_lhs(local_may_alias, i_it, lhs, modifies); get_modifies_function( code_function_call.function(), modifies); } }
void java_bytecode_typecheckt::typecheck_code(codet &code) { const irep_idt &statement=code.get_statement(); if(statement==ID_assign) { code_assignt &code_assign=to_code_assign(code); typecheck_expr(code_assign.lhs()); typecheck_expr(code_assign.rhs()); if(code_assign.lhs().type()!=code_assign.rhs().type()) code_assign.rhs().make_typecast(code_assign.lhs().type()); } else if(statement==ID_block) { Forall_operands(it, code) typecheck_code(to_code(*it)); } else if(statement==ID_label) { code_labelt &code_label=to_code_label(code); typecheck_code(code_label.code()); } else if(statement==ID_goto) { } else if(statement==ID_ifthenelse) { code_ifthenelset &code_ifthenelse=to_code_ifthenelse(code); typecheck_expr(code_ifthenelse.cond()); typecheck_code(code_ifthenelse.then_case()); if(code_ifthenelse.else_case().is_not_nil()) typecheck_code(code_ifthenelse.else_case()); } else if(statement==ID_switch) { code_switcht &code_switch = to_code_switch(code); typecheck_expr(code_switch.value()); } else if(statement==ID_return) { if(code.operands().size()==1) typecheck_expr(code.op0()); } else if(statement==ID_function_call) { code_function_callt &code_function_call=to_code_function_call(code); typecheck_expr(code_function_call.lhs()); typecheck_expr(code_function_call.function()); for(code_function_callt::argumentst::iterator a_it=code_function_call.arguments().begin(); a_it!=code_function_call.arguments().end(); a_it++) typecheck_expr(*a_it); } }
void insert_solution(control_programt &program, const control_solutiont &solution) { goto_functionst &gf=program.gf; goto_programt &init=get_body(gf, CPROVER_INIT); const goto_programt::targett pos=get_solution_assignment(init); const symbol_tablet &st=program.st; const source_locationt &loc=pos->source_location; to_code_assign(pos->code).rhs()=to_struct_expr(st, solution, loc); }
void interval_domaint::transform( locationt from, locationt to, ai_baset &ai, const namespacet &ns) { const goto_programt::instructiont &instruction=*from; switch(instruction.type) { case DECL: havoc_rec(to_code_decl(instruction.code).symbol()); break; case DEAD: havoc_rec(to_code_dead(instruction.code).symbol()); break; case ASSIGN: assign(to_code_assign(instruction.code)); break; case GOTO: { locationt next=from; next++; if(next==to) assume(not_exprt(instruction.guard), ns); else assume(instruction.guard, ns); } break; case ASSUME: assume(instruction.guard, ns); break; case FUNCTION_CALL: { const code_function_callt &code_function_call= to_code_function_call(instruction.code); if(code_function_call.lhs().is_not_nil()) havoc_rec(code_function_call.lhs()); } break; default: { } } }
const typet &get_affected_type(const goto_programt::instructiont &instr) { switch (instr.type) { case goto_program_instruction_typet::DECL: return to_code_decl(instr.code).symbol().type(); case goto_program_instruction_typet::ASSIGN: return to_code_assign(instr.code).lhs().type(); case goto_program_instruction_typet::DEAD: return to_code_dead(instr.code).symbol().type(); default: assert(!"Only DECL, ASSIGN, DEAD allowed."); } }
const irep_idt &get_affected_variable(const goto_programt::instructiont &instr) { switch (instr.type) { case goto_program_instruction_typet::DECL: return to_code_decl(instr.code).get_identifier(); case goto_program_instruction_typet::ASSIGN: return to_symbol_expr(to_code_assign(instr.code).lhs()).get_identifier(); case goto_program_instruction_typet::DEAD: return to_code_dead(instr.code).get_identifier(); default: assert(!"Only DECL, ASSIGN, DEAD allowed."); } }
bool is_nondet(goto_programt::const_targett target, goto_programt::const_targett end) { const goto_programt::instructiont &instr=*target; switch (instr.type) { case goto_program_instruction_typet::DECL: { goto_programt::const_targett next=std::next(target); if (next == end) return true; if (goto_program_instruction_typet::FUNCTION_CALL == next->type) { if (to_code_function_call(next->code).lhs().is_not_nil()) return false; else ++next; } const goto_programt::instructiont next_instr=*next; if (goto_program_instruction_typet::ASSIGN != next_instr.type) return true; const irep_idt id(get_affected_variable(instr)); if (id != get_affected_variable(next_instr)) return true; return contains(to_code_assign(next_instr.code).rhs(), id); } case goto_program_instruction_typet::ASSIGN: { const exprt &rhs=to_code_assign(instr.code).rhs(); if (ID_side_effect != rhs.id()) return false; return ID_nondet == to_side_effect_expr(rhs).get_statement(); } case goto_program_instruction_typet::FUNCTION_CALL: { const code_function_callt &call=to_code_function_call(instr.code); if (call.lhs().is_not_nil()) return false; } default: return false; } }
void nondet_static( const namespacet &ns, goto_functionst &goto_functions, const irep_idt &fct_name) { goto_functionst::function_mapt::iterator i_it=goto_functions.function_map.find(fct_name); assert(i_it!=goto_functions.function_map.end()); goto_programt &init=i_it->second.body; Forall_goto_program_instructions(i_it, init) { const goto_programt::instructiont &instruction=*i_it; if(instruction.is_assign()) { const symbol_exprt &sym=to_symbol_expr( to_code_assign(instruction.code).lhs()); // is it a __CPROVER_* variable? if(has_prefix(id2string(sym.get_identifier()), CPROVER_PREFIX)) continue; // static lifetime? if(!ns.lookup(sym.get_identifier()).is_static_lifetime) continue; // constant? if(sym.type().get_bool(ID_C_constant)) continue; i_it=init.insert_before(++i_it); i_it->make_assignment(); i_it->code=code_assignt(sym, side_effect_expr_nondett(sym.type())); i_it->location=instruction.location; i_it->function=instruction.function; } else if(instruction.is_function_call()) { const code_function_callt &fct=to_code_function_call(instruction.code); const symbol_exprt &fsym=to_symbol_expr(fct.function()); if(has_prefix(id2string(fsym.get_identifier()), "c::#ini#")) nondet_static(ns, goto_functions, fsym.get_identifier()); } } }
void jsil_typecheckt::typecheck_code(codet &code) { const irep_idt &statement=code.get_statement(); if(statement==ID_function_call) typecheck_function_call(to_code_function_call(code)); else if(statement==ID_return) typecheck_return(to_code_return(code)); else if(statement==ID_expression) { if(code.operands().size()!=1) throw "expression statement expected to have one operand"; typecheck_expr(code.op0()); } else if(statement==ID_label) { typecheck_code(to_code_label(code).code()); // TODO: produce defined label set } else if(statement==ID_block) typecheck_block(code); else if(statement==ID_ifthenelse) typecheck_ifthenelse(to_code_ifthenelse(code)); else if(statement==ID_goto) { // TODO: produce used label set } else if(statement==ID_assign) typecheck_assign(to_code_assign(code)); else if(statement==ID_try_catch) typecheck_try_catch(to_code_try_catch(code)); else if(statement==ID_skip) { } else { err_location(code); error() << "unexpected statement: " << statement << eom; throw 0; } }
void k_inductiont::get_modifies( const loopt &loop, modifiest &modifies) { for(loopt::const_iterator i_it=loop.begin(); i_it!=loop.end(); i_it++) { const goto_programt::instructiont &instruction=**i_it; if(instruction.is_assign()) { const exprt &lhs=to_code_assign(instruction.code).lhs(); get_modifies_lhs(*i_it, lhs, modifies); } else if(instruction.is_function_call()) { const exprt &lhs=to_code_function_call(instruction.code).lhs(); get_modifies_lhs(*i_it, lhs, modifies); } } }
void interpretert::execute_assign() { const code_assignt &code_assign= to_code_assign(PC->code); std::vector<mp_integer> rhs; evaluate(code_assign.rhs(), rhs); if(!rhs.empty()) { mp_integer address=evaluate_address(code_assign.lhs()); unsigned size=get_size(code_assign.lhs().type()); if(size!=rhs.size()) std::cout << "!! failed to obtain rhs (" << rhs.size() << " vs. " << size << ")" << std::endl; else assign(address, rhs); } }
goto_tracet::stepst::const_iterator termination_baset::get_loop( goto_tracet &trace) { if(trace.steps.size()<3) throw "counterexample is too short"; const goto_trace_stept &assertion=trace.steps.back(); assert(assertion.is_assert()); goto_tracet::stepst::const_iterator step=--trace.steps.end(); // skip over assertion step--; // we need to see the copy-instruction at least once. assert(assertion.pc->guard.operands().size()==2); const irep_idt my_id=assertion.pc->guard.op0().get("identifier"); bool seen_copy=false; while(step->pc!=assertion.pc || !seen_copy) { if(step==trace.steps.begin()) // failed throw "failed to find beginning of loop"; if(step->pc->type==ASSIGN) { const code_assignt &code=to_code_assign(step->pc->code); if(code.lhs().id()=="symbol" && code.lhs().get("identifier")==my_id) seen_copy=true; } step--; } // found it! return step; }
exprt polynomial_acceleratort::precondition(patht &path) { exprt ret = false_exprt(); for (patht::reverse_iterator r_it = path.rbegin(); r_it != path.rend(); ++r_it) { goto_programt::const_targett t = r_it->loc; if (t->is_assign()) { // XXX Need to check for aliasing... const code_assignt &assignment = to_code_assign(t->code); const exprt &lhs = assignment.lhs(); const exprt &rhs = assignment.rhs(); if (lhs.id() == ID_symbol) { replace_expr(lhs, rhs, ret); } else if (lhs.id() == ID_index || lhs.id() == ID_dereference) { continue; } else { throw "Couldn't take WP of " + expr2c(lhs, ns) + " = " + expr2c(rhs, ns); } } else if (t->is_assume() || t->is_assert()) { ret = implies_exprt(t->guard, ret); } else { // Ignore. } if (!r_it->guard.is_true() && !r_it->guard.is_nil()) { // The guard isn't constant true, so we need to accumulate that too. ret = implies_exprt(r_it->guard, ret); } } simplify(ret, ns); return ret; }
void rd_range_domaint::transform( const namespacet &ns, locationt from, locationt to) { if(from->is_dead()) { const symbol_exprt &symbol= to_symbol_expr(to_code_dead(from->code).symbol()); values.erase(symbol.get_identifier()); return; } else if(!from->is_assign()) return; const exprt &lhs=to_code_assign(from->code).lhs(); if(lhs.id()==ID_complex_real || lhs.id()==ID_complex_imag) { assert(lhs.type().id()==ID_complex); mp_integer offset=compute_pointer_offset(ns, lhs.op0()); mp_integer sub_size=pointer_offset_size(ns, lhs.type().subtype()); assign( ns, from, lhs.op0(), offset+((offset==-1 || lhs.id()==ID_complex_real) ? 0 : sub_size), sub_size); } else { mp_integer size=pointer_offset_size(ns, lhs.type()); assign(ns, from, lhs, size); } }
void termination_baset::find_required_steps( const goto_tracet &goto_trace, goto_tracet::stepst::const_iterator &loop_begin, required_stepst &required_steps, const std::string &prefix) const { find_symbols_sett required_symbols; unsigned before=0, after=1; // initialize: find all (potential) loop exits and // remember the symbols in them for(goto_tracet::stepst::const_iterator it1=loop_begin; it1!=goto_trace.steps.end(); it1++) { if(it1->pc->is_goto() && it1->pc->function==loop_begin->pc->function) { bool found_next=false, found_target=false; goto_programt::const_targett next=it1->pc; next++; goto_programt::const_targett target=it1->pc->targets.front(); for(goto_tracet::stepst::const_iterator it2=loop_begin; it2!=goto_trace.steps.end(); it2++) { if(it1!=it2) { if(it2->pc==next) found_next=true; else if(it2->pc==target) found_target=true; } } if(!found_target || !found_next) { exprt temp=it1->cond_expr; remove_ssa_ids(temp); find_symbols(temp, required_symbols); } } } #if 0 std::cout << "INITIAL SYMBOLS: "; for(find_symbols_sett::const_iterator it=required_symbols.begin(); it!=required_symbols.end(); it++) std::cout << *it << ", "; std::cout << std::endl; #endif // get the fixpoint while(before!=after) { before=required_symbols.size(); for(goto_tracet::stepst::const_iterator step=loop_begin; step!=goto_trace.steps.end(); step++) { find_symbols_sett intersection; if(step->is_assignment()) { exprt lhs, rhs; const codet &code=to_code(step->pc->code); if(code.get_statement()==ID_assign) { const code_assignt &acode=to_code_assign(step->pc->code); lhs=acode.lhs(); rhs=acode.rhs(); } else if(code.get_statement()==ID_function_call) { const code_function_callt fcode=to_code_function_call(step->pc->code); lhs=fcode.lhs(); rhs=fcode.op2(); } else throw "Unexpected assign statement"; if(lhs.id()==ID_symbol && has_prefix(lhs.get_string(ID_identifier), prefix)) { // if we depend on the RHS syms, we also need the pre-symbol find_symbols_sett rhs_sym; find_symbols(rhs, rhs_sym); if(intersects(rhs_sym, required_symbols)) { find_symbols(lhs, required_symbols); required_steps.insert(&(*step)); } } else { find_symbols_sett lhs_sym; if(lhs.id()==ID_index) find_symbols(lhs.op0(), lhs_sym); // we're not modifying the index else find_symbols(lhs, lhs_sym); if(intersects(lhs_sym, required_symbols)) { find_symbols(rhs, required_symbols); required_steps.insert(&(*step)); } } } else if(step->is_assume()) { find_symbols_sett syms; find_symbols(step->pc->guard, syms); if(intersects(syms, required_symbols)) { required_symbols.insert(syms.begin(), syms.end()); required_steps.insert(&(*step)); } } } after=required_symbols.size(); #if 0 std::cout << "REQUIRED SYMBOLS: "; for(find_symbols_sett::const_iterator it=required_symbols.begin(); it!=required_symbols.end(); it++) std::cout << *it << ", "; std::cout << std::endl; #endif } }
bodyt termination_baset::get_body( goto_tracet::stepst::const_iterator &loop_begin, const goto_tracet &trace) { bodyt result_body; exprt::operandst op; const goto_trace_stept &assertion=trace.steps.back(); // let's get a loop number as well: assert(assertion.pc->guard.id()=="=>"); std::string c_str = assertion.pc->guard.op0().get_string("identifier"); std::string prefix = termination_prefix+ c_str.substr(c_str.rfind("_")+1) + "::"; // find out what we actually need required_stepst required_steps; find_required_steps(trace, loop_begin, required_steps, prefix); /* We perform a new SSA-conversion. However, since we can only get a single path through the program, there are no joins and thus no phi-functions. We just increment counters. */ std::map<irep_idt, unsigned> ssa_counters; replace_idt replace_id; // get the required body constraints for(goto_tracet::stepst::const_iterator step=loop_begin; step!=--trace.steps.end(); step++) { last_path.push_back(step->pc); // required_stepst::const_iterator fit=required_steps.find(&(*step)); // if(fit==required_steps.end()) continue; switch(step->pc->type) { case ASSIGN: { const code_assignt &code=to_code_assign(step->pc->code); find_symbols_sett w; find_symbols_w(code.lhs(), w); equal_exprt equality(code.lhs(), code.rhs()); replace_id.replace(equality.rhs()); // All the written ones get their SSA-ID updated for(find_symbols_sett::const_iterator it=w.begin(); it!=w.end(); it++) { // Are we writing a pre-variable? if(has_prefix(id2string(*it), prefix)) { assert(code.rhs().id()==ID_symbol); const irep_idt &post_id=code.rhs().get(ID_identifier); const irep_idt &pre_id=code.lhs().get(ID_identifier); result_body.variable_map[post_id]=pre_id; // the RHS gets a #0 id irep_idt new_id=id2string(post_id)+"!0"; replace_id.insert(post_id, new_id); equality.rhs().set(ID_identifier, new_id); } else { const irep_idt &old_id=*it; unsigned cur=++ssa_counters[old_id]; // 0 is never used // gets a new ID irep_idt new_id=id2string(old_id)+"!"+i2string(cur); replace_id.insert(old_id, new_id); } } replace_id.replace(equality.lhs()); op.push_back(equality); break; } case ASSUME: case ASSERT: { if(!step->cond_expr.is_true() && !step->cond_expr.is_nil()) { exprt guard=step->cond_expr; // That's SSA! remove_ssa_ids(guard); // exprt guard=step->pc->guard; find_symbols_sett syms; find_symbols(guard, syms); for(find_symbols_sett::const_iterator it=syms.begin(); it!=syms.end(); it++) { if(ssa_counters.find(*it)==ssa_counters.end()) { irep_idt new_id=id2string(*it)+"!"+i2string(++ssa_counters[*it]); replace_id.insert(*it, new_id); } } replace_id.replace(guard); if(!step->cond_value) guard.negate(); op.push_back(guard); } break; } case GOTO: { if(!step->cond_expr.is_nil()) { // exprt guard=step->pc->guard; exprt guard=step->cond_expr; remove_ssa_ids(guard); find_symbols_sett syms; find_symbols(guard, syms); for(find_symbols_sett::const_iterator it=syms.begin(); it!=syms.end(); it++) { if(ssa_counters.find(*it)==ssa_counters.end()) { ssa_counters[*it]=0; irep_idt new_id=id2string(*it)+"!"+i2string(0); replace_id.insert(*it, new_id); } } replace_id.replace(guard); if(!step->cond_value) guard.negate(); op.push_back(guard); } break; } case DECL: /* nothing */ break; case LOCATION: /* These can show up here? */ break; default: throw std::string("unexpected instruction type."); } } // the final result, which (again) contains SSA variables exprt &body_expr = result_body.body_relation; body_expr = and_exprt(op); if(result_body.variable_map.empty()) { // used to be: // throw "BUG: No variables found; path missing."; // Though: No variable is ever saved, i.e., this loop // must be completely nondeterministic. warning("No pre-variables found; this " "loop is completely non-deterministic."); body_expr=false_exprt(); } // The last SSA-occurrence of a variable is the // output variable and it gets its non-SSA name. replace_idt last_map; for(std::map<irep_idt, unsigned>::const_iterator it=ssa_counters.begin(); it!=ssa_counters.end(); it++) { const irep_idt &id=it->first; unsigned last=it->second; irep_idt last_name=id2string(id)+"!"+i2string(last); last_map.insert(last_name, id); } last_map.replace(body_expr); replace_nondet_sideeffects(body_expr); return result_body; }
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_inlinet::expand_function_call( goto_programt &dest, goto_programt::targett &target, const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, const exprt &constrain, bool full) { // look it up const irep_idt identifier=function.get_identifier(); // we ignore certain calls if(identifier=="__CPROVER_cleanup" || identifier=="__CPROVER_set_must" || identifier=="__CPROVER_set_may" || identifier=="__CPROVER_clear_must" || identifier=="__CPROVER_clear_may" || identifier=="__CPROVER_cover") { target++; return; // ignore } // see if we are already expanding it if(recursion_set.find(identifier)!=recursion_set.end()) { if(!full) { target++; return; // simply ignore, we don't do full inlining, it's ok } // it's really recursive, and we need full inlining. // Uh. Buh. Give up. warning().source_location=function.find_source_location(); warning() << "recursion is ignored" << eom; target->make_skip(); target++; return; } goto_functionst::function_mapt::iterator m_it= goto_functions.function_map.find(identifier); if(m_it==goto_functions.function_map.end()) { if(!full) { target++; return; // simply ignore, we don't do full inlining, it's ok } error().source_location=function.find_source_location(); error() << "failed to find function `" << identifier << "'" << eom; throw 0; } const goto_functionst::goto_functiont &f=m_it->second; // see if we need to inline this if(!full) { if(!f.body_available() || (!f.is_inlined() && f.body.instructions.size() > smallfunc_limit)) { target++; return; } } if(f.body_available()) { recursion_set.insert(identifier); // first make sure that this one is already inlined goto_inline_rec(m_it, full); goto_programt tmp2; tmp2.copy_from(f.body); assert(tmp2.instructions.back().is_end_function()); tmp2.instructions.back().type=LOCATION; replace_return(tmp2, lhs, constrain); goto_programt tmp; parameter_assignments(target->source_location, identifier, f.type, arguments, tmp); tmp.destructive_append(tmp2); parameter_destruction(target->source_location, identifier, f.type, tmp); if(f.is_hidden()) { source_locationt new_source_location= function.find_source_location(); if(new_source_location.is_not_nil()) { new_source_location.set_hide(); Forall_goto_program_instructions(it, tmp) { if(it->function==identifier) { // don't hide assignment to lhs if(it->is_assign() && to_code_assign(it->code).lhs()==lhs) { } else { replace_location(it->source_location, new_source_location); replace_location(it->guard, new_source_location); replace_location(it->code, new_source_location); } it->function=target->function; } } }
void goto_checkt::goto_check(goto_functiont &goto_function) { { const symbolt *init_symbol; if(!ns.lookup(CPROVER_PREFIX "initialize", init_symbol)) mode=init_symbol->mode; } assertions.clear(); local_bitvector_analysist local_bitvector_analysis_obj(goto_function); local_bitvector_analysis=&local_bitvector_analysis_obj; goto_programt &goto_program=goto_function.body; Forall_goto_program_instructions(it, goto_program) { t=it; goto_programt::instructiont &i=*it; new_code.clear(); // we clear all recorded assertions if // 1) we want to generate all assertions or // 2) the instruction is a branch target if(retain_trivial || i.is_target()) assertions.clear(); check(i.guard); // magic ERROR label? for(optionst::value_listt::const_iterator l_it=error_labels.begin(); l_it!=error_labels.end(); l_it++) { if(std::find(i.labels.begin(), i.labels.end(), *l_it)!=i.labels.end()) { goto_program_instruction_typet type= enable_assert_to_assume?ASSUME:ASSERT; goto_programt::targett t=new_code.add_instruction(type); t->guard=false_exprt(); t->source_location=i.source_location; t->source_location.set_property_class("error label"); t->source_location.set_comment("error label "+*l_it); t->source_location.set("user-provided", true); } } if(i.is_other()) { const irep_idt &statement=i.code.get(ID_statement); if(statement==ID_expression) { check(i.code); } else if(statement==ID_printf) { forall_operands(it, i.code) check(*it); } } else if(i.is_assign()) { const code_assignt &code_assign=to_code_assign(i.code); check(code_assign.lhs()); check(code_assign.rhs()); // the LHS might invalidate any assertion invalidate(code_assign.lhs()); } else if(i.is_function_call()) { const code_function_callt &code_function_call= to_code_function_call(i.code); // for Java, need to check whether 'this' is null // on non-static method invocations if(mode==ID_java && enable_pointer_check && !code_function_call.arguments().empty() && code_function_call.function().type().id()==ID_code && to_code_type(code_function_call.function().type()).has_this()) { exprt pointer=code_function_call.arguments()[0]; local_bitvector_analysist::flagst flags= local_bitvector_analysis->get(t, pointer); if(flags.is_unknown() || flags.is_null()) { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "this is null on method invokation", "pointer dereference", i.source_location, pointer, guardt()); } } forall_operands(it, code_function_call) check(*it); // the call might invalidate any assertion assertions.clear(); } else if(i.is_return()) { if(i.code.operands().size()==1) { check(i.code.op0()); // the return value invalidate any assertion invalidate(i.code.op0()); } } else if(i.is_throw()) { if(i.code.get_statement()==ID_expression && i.code.operands().size()==1 && i.code.op0().operands().size()==1) { // must not throw NULL exprt pointer=i.code.op0().op0(); if(pointer.type().subtype().get(ID_identifier)!="java::java.lang.AssertionError") { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "throwing null", "pointer dereference", i.source_location, pointer, guardt()); } } // this has no successor assertions.clear(); } else if(i.is_assert()) { if(i.source_location.get_bool("user-provided") && i.source_location.get_property_class()!="error label" && !enable_assertions) i.type=SKIP; } else if(i.is_assume()) { if(!enable_assumptions) i.type=SKIP; } else if(i.is_dead()) { if(enable_pointer_check) { assert(i.code.operands().size()==1); const symbol_exprt &variable=to_symbol_expr(i.code.op0()); // is it dirty? if(local_bitvector_analysis->dirty(variable)) { // need to mark the dead variable as dead goto_programt::targett t=new_code.add_instruction(ASSIGN); exprt address_of_expr=address_of_exprt(variable); exprt lhs=ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr(); if(!base_type_eq(lhs.type(), address_of_expr.type(), ns)) address_of_expr.make_typecast(lhs.type()); exprt rhs=if_exprt( side_effect_expr_nondett(bool_typet()), address_of_expr, lhs, lhs.type()); t->source_location=i.source_location; t->code=code_assignt(lhs, rhs); t->code.add_source_location()=i.source_location; } } } else if(i.is_end_function()) { if(i.function==goto_functionst::entry_point() && enable_memory_leak_check) { const symbolt &leak=ns.lookup(CPROVER_PREFIX "memory_leak"); const symbol_exprt leak_expr=leak.symbol_expr(); // add self-assignment to get helpful counterexample output goto_programt::targett t=new_code.add_instruction(); t->make_assignment(); t->code=code_assignt(leak_expr, leak_expr); source_locationt source_location; source_location.set_function(i.function); equal_exprt eq(leak_expr, gen_zero(ns.follow(leak.type))); add_guarded_claim( eq, "dynamically allocated memory never freed", "memory-leak", source_location, eq, guardt()); } } for(goto_programt::instructionst::iterator i_it=new_code.instructions.begin(); i_it!=new_code.instructions.end(); i_it++) { if(i_it->source_location.is_nil()) { i_it->source_location.id(irep_idt()); if(it->source_location.get_file()!=irep_idt()) i_it->source_location.set_file(it->source_location.get_file()); if(it->source_location.get_line()!=irep_idt()) i_it->source_location.set_line(it->source_location.get_line()); if(it->source_location.get_function()!=irep_idt()) i_it->source_location.set_function(it->source_location.get_function()); if(it->source_location.get_column()!=irep_idt()) i_it->source_location.set_column(it->source_location.get_column()); } if(i_it->function==irep_idt()) i_it->function=it->function; } // insert new instructions -- make sure targets are not moved while(!new_code.instructions.empty()) { goto_program.insert_before_swap(it, new_code.instructions.front()); new_code.instructions.pop_front(); it++; } }
bool refiner_wpt::refine_prefix( predicatest &predicates, abstract_modelt &abstract_model, const fail_infot &fail_info) { status("Refining set of predicates according to counterexample (WP)"); reset_num_predicates_added(); bool found_new=false; // keep track of the loops that we're in (may be nested) std::list<fail_infot::induction_infot> loops; exprt invariant; if(fail_info.use_invariants) status("Using recurrence predicates detected by loop detection."); print(10, "refiner_wpt::refine_prefix_async 1"); print(10, "Inconsistent prefix:"); for(abstract_counterexamplet::stepst::const_reverse_iterator r_it=fail_info.steps.rbegin(); r_it!=fail_info.steps.rend(); r_it++) { std::stringstream str; abstract_programt::targett abstract_pc=r_it->pc; goto_programt::const_targett concrete_pc= abstract_pc->code.concrete_pc; if(concrete_pc->is_goto()) str << "GUARD: " << (r_it->branch_taken?"(":"!(") << from_expr(concrete_model.ns, "", concrete_pc->guard) << ")"; else if(concrete_pc->is_assert()) str << "ASSERT: " << from_expr(concrete_model.ns, "", concrete_pc->guard); else if(concrete_pc->is_location()) str << "LOC" << std::endl; else if(concrete_pc->is_other() || concrete_pc->is_assign() || concrete_pc->is_decl()) str << from_expr(concrete_model.ns, "", concrete_pc->code); else { str << concrete_pc->type; } str << " // " << (concrete_pc->location); str << std::endl << "**********"; print(10, str.str()); } { // get the constraint causing the failure exprt predicate=fail_info.guard; #ifdef DEBUG std::cout << "P start0: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif simplify(predicate, concrete_model.ns); abstract_counterexamplet::stepst::const_iterator it=--fail_info.steps.end(); // there must be at least two steps, or it's odd assert(it!=fail_info.steps.begin()); { abstract_programt::targett abstract_pc=it->pc; #ifdef DEBUG std::cout << "P start1: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif add_predicates( abstract_pc, predicates, predicate, found_new, FROM); } // now do the WPs goto_symex_statet renaming_state; renaming_state.source.thread_nr=it->thread_nr; renaming_state.rename(predicate, concrete_model.ns, goto_symex_statet::L0); for(it--; // skip last instruction it!=fail_info.steps.begin(); it--) { #ifdef DEBUG std::cout << "refiner_wpt::refine_prefix_async 2\n"; #endif // handle loops if(fail_info.use_invariants) { if(it->is_loop_begin()) { loops.pop_back(); // pop induction_info if we leave loop #ifdef DEBUG std::cout << "INV: " << from_expr(concrete_model.ns, "", invariant) << std::endl; #endif exprt wp(ID_and, typet(ID_bool)); wp.operands().resize(2); wp.op0().swap(invariant); wp.op1().swap(predicate); predicate.swap(wp); } else if (it->is_loop_end()) { push_induction_info(fail_info, it, loops); invariant.make_true(); } } if(!it->is_state()) continue; if(predicate.is_true() && found_new) { // ok, refuted it, done break; } // add the predicate goto_programt::const_targett concrete_pc= it->pc->code.concrete_pc; abstract_programt::targett abstract_pc=it->pc; #ifdef DEBUG std::cout << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif exprt no_tid_predicate=predicate; renaming_state.get_original_name(no_tid_predicate); add_predicates(abstract_pc, predicates, no_tid_predicate, found_new, TO); // skip irrelevant instructions if(!it->relevant) continue; exprt pred_bak=predicate; #ifdef DEBUG goto_programt tmp; tmp.output_instruction(concrete_model.ns, "", std::cerr, concrete_pc); #endif // compute weakest precondition switch(it->pc->type) { case ASSUME: // we only do this for assumptions // if we haven't found a new predicate so far if(1/*!found_new*/) { exprt tid_guard=concrete_pc->guard; renaming_state.source.thread_nr=it->thread_nr; renaming_state.rename(tid_guard, concrete_model.ns, goto_symex_statet::L0); predicate=implies_exprt(tid_guard, predicate); simplify(predicate, concrete_model.ns); } break; case GOTO: { exprt tid_guard=concrete_pc->guard; if(!it->branch_taken) tid_guard.make_not(); renaming_state.source.thread_nr=it->thread_nr; renaming_state.rename(tid_guard, concrete_model.ns, goto_symex_statet::L0); predicate=implies_exprt(tid_guard, predicate); simplify(predicate, concrete_model.ns); } break; case OTHER: /* Ignore if user-specified predicate, otherwise treat like assign */ if(it->pc->code.concrete_pc->code.get_statement()==ID_user_specified_predicate || it->pc->code.concrete_pc->code.get_statement()==ID_user_specified_parameter_predicates || it->pc->code.concrete_pc->code.get_statement()==ID_user_specified_return_predicates) break; case DECL: case ASSIGN: #ifdef DEBUG std::cout << "OTHER/ASSIGN/DECL\n"; #endif { codet tid_tmp_code; if(!fail_info.use_invariants || !get_instruction(concrete_pc, loops, tid_tmp_code, invariant)) tid_tmp_code=to_code(concrete_pc->code); #ifdef DEBUG std::cout << "A P before: " << from_expr(concrete_model.ns, "", predicate) << std::endl; std::cout << "Code: " << from_expr(concrete_model.ns, "", tid_tmp_code) << std::endl; #endif // compute weakest precondition if(tid_tmp_code.get_statement()==ID_assign) approximate_nondet(to_code_assign(tid_tmp_code).rhs()); renaming_state.source.thread_nr=it->thread_nr; renaming_state.rename(tid_tmp_code, concrete_model.ns, goto_symex_statet::L0); exprt predicate_wp=wp(tid_tmp_code, predicate, concrete_model.ns); simplify(predicate_wp, concrete_model.ns); predicate=predicate_wp; #ifdef DEBUG std::cout << "A P after: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif } break; default: // ignore break; } #ifdef DEBUG std::cout << "B P to-check: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif if(pred_bak != predicate) { satcheckt satcheck; bv_pointerst solver(concrete_model.ns, satcheck); solver.unbounded_array=boolbvt::U_NONE; literalt li=make_pos(concrete_model.ns, solver, predicate); satcheck.set_assumptions(bvt(1, li)); propt::resultt result=satcheck.prop_solve(); assert(propt::P_SATISFIABLE==result || propt::P_UNSATISFIABLE==result); if(propt::P_UNSATISFIABLE==result) predicate.make_false(); else { satcheck.set_assumptions(bvt(1, li.negation())); propt::resultt result=satcheck.prop_solve(); assert(propt::P_SATISFIABLE==result || propt::P_UNSATISFIABLE==result); if(propt::P_UNSATISFIABLE==result) { predicate.make_true(); if(it->pc->type==ASSIGN) { const codet &code=concrete_pc->code; if(code.get_statement()==ID_assign) { equal_exprt pred_new(to_code_assign(code).lhs(), to_code_assign(code).rhs()); simplify(pred_new, concrete_model.ns); #ifdef DEBUG std::cout << "Adding new predicate as we arrived at TRUE: " << from_expr(concrete_model.ns, "", pred_new) << std::endl; #endif no_tid_predicate=pred_new; renaming_state.get_original_name(no_tid_predicate); add_predicates(abstract_pc, predicates, no_tid_predicate, found_new, FROM); } } else if(it->pc->type==ASSUME || it->pc->type==GOTO) { exprt pred_new=concrete_pc->guard; simplify(pred_new, concrete_model.ns); #ifdef DEBUG std::cout << "Adding new predicate as we arrived at TRUE: " << from_expr(concrete_model.ns, "", pred_new) << std::endl; #endif no_tid_predicate=pred_new; renaming_state.get_original_name(no_tid_predicate); add_predicates(abstract_pc, predicates, no_tid_predicate, found_new, FROM); } } } } #ifdef DEBUG std::cout << "B P after: " << from_expr(concrete_model.ns, "", predicate) << std::endl; #endif no_tid_predicate=predicate; renaming_state.get_original_name(no_tid_predicate); add_predicates(abstract_pc, predicates, no_tid_predicate, found_new, FROM); } if(!predicate.is_true() && fail_info.warn_on_failure) { warning("Failed to refute spurious trace with WPs (got "+ from_expr(concrete_model.ns, "", predicate)+")"); } } if(found_new && fail_info.use_invariants) { add_induction_predicates( fail_info, abstract_model, predicates); } // make sure we have progress return !found_new; }
void invariant_set_domaint::transform( locationt from_l, locationt to_l, ai_baset &ai, const namespacet &ns) { switch(from_l->type) { case GOTO: { exprt tmp(from_l->guard); goto_programt::const_targett next=from_l; next++; if(next==to_l) tmp.make_not(); simplify(tmp, ns); invariant_set.strengthen(tmp); } break; case ASSERT: case ASSUME: { exprt tmp(from_l->guard); simplify(tmp, ns); invariant_set.strengthen(tmp); } break; case RETURN: // ignore break; case ASSIGN: { const code_assignt &assignment=to_code_assign(from_l->code); invariant_set.assignment(assignment.lhs(), assignment.rhs()); } break; case OTHER: if(from_l->code.is_not_nil()) invariant_set.apply_code(from_l->code); break; case DECL: invariant_set.apply_code(from_l->code); break; case FUNCTION_CALL: invariant_set.apply_code(from_l->code); break; case START_THREAD: invariant_set.make_threaded(); break; default: { // do nothing } } }