void invariant_propagationt::add_objects( const goto_programt &goto_program) { // get the globals object_listt globals; get_globals(globals); // get the locals goto_programt::decl_identifierst locals; goto_program.get_decl_identifiers(locals); // cache the list for the locals to speed things up typedef hash_map_cont<irep_idt, object_listt, irep_id_hash> object_cachet; object_cachet object_cache; for(goto_programt::instructionst::const_iterator i_it=goto_program.instructions.begin(); i_it!=goto_program.instructions.end(); i_it++) { #if 0 invariant_sett &is=(*this)[i_it].invariant_set; is.add_objects(globals); #endif for(goto_programt::decl_identifierst::const_iterator l_it=locals.begin(); l_it!=locals.end(); l_it++) { // cache hit? object_cachet::const_iterator e_it=object_cache.find(*l_it); if(e_it==object_cache.end()) { const symbolt &symbol=ns.lookup(*l_it); object_listt &objects=object_cache[*l_it]; get_objects(symbol, objects); #if 0 is.add_objects(objects); #endif } #if 0 else is.add_objects(e_it->second); #endif } } }
void string_instrumentationt::do_function_call( goto_programt &dest, goto_programt::targett target) { code_function_callt &call= to_code_function_call(target->code); exprt &function=call.function(); //const exprt &lhs=call.lhs(); if(function.id()==ID_symbol) { const irep_idt &identifier= to_symbol_expr(function).get_identifier(); if(identifier=="strcoll") { } else if(identifier=="strncmp") do_strncmp(dest, target, call); else if(identifier=="strxfrm") { } else if(identifier=="strchr") do_strchr(dest, target, call); else if(identifier=="strcspn") { } else if(identifier=="strpbrk") { } else if(identifier=="strrchr") do_strrchr(dest, target, call); else if(identifier=="strspn") { } else if(identifier=="strerror") do_strerror(dest, target, call); else if(identifier=="strstr") do_strstr(dest, target, call); else if(identifier=="strtok") do_strtok(dest, target, call); else if(identifier=="sprintf") do_sprintf(dest, target, call); else if(identifier=="snprintf") do_snprintf(dest, target, call); else if(identifier=="fscanf") do_fscanf(dest, target, call); dest.update(); } }
void stack_depth( goto_programt &goto_program, const symbol_exprt &symbol, const int i_depth, const exprt &max_depth) { assert(!goto_program.instructions.empty()); goto_programt::targett first=goto_program.instructions.begin(); binary_relation_exprt guard(symbol, ID_le, max_depth); goto_programt::targett assert_ins=goto_program.insert_before(first); assert_ins->make_assertion(guard); assert_ins->location=first->location; assert_ins->function=first->function; assert_ins->location.set_comment("Stack depth exceeds "+i2string(i_depth)); assert_ins->location.set_property("stack-depth"); goto_programt::targett plus_ins=goto_program.insert_before(first); plus_ins->make_assignment(); plus_ins->code=code_assignt(symbol, plus_exprt(symbol, from_integer(1, symbol.type()))); plus_ins->location=first->location; plus_ins->function=first->function; goto_programt::targett last=--goto_program.instructions.end(); assert(last->is_end_function()); goto_programt::instructiont minus_ins; minus_ins.make_assignment(); minus_ins.code=code_assignt(symbol, minus_exprt(symbol, from_integer(1, symbol.type()))); minus_ins.location=last->location; minus_ins.function=last->function; goto_program.insert_before_swap(last, minus_ins); }
void remove_return(goto_programt &body, const goto_programt::targett pos) { code_function_callt &call=to_code_function_call(pos->code); const irep_idt &id=to_symbol_expr(call.function()).get_identifier(); const typet &type=call.lhs().type(); const source_locationt &loc=pos->source_location; const irep_idt &func=pos->function; const goto_programt::targett assign=body.insert_after(pos); assign->make_assignment(); assign->source_location=loc; assign->code=code_assignt(call.lhs(), get_ret_val_var(id, type)); assign->function=func; call.lhs().make_nil(); }
void goto_convertt::convert_CPROVER_throw( const codet &code, goto_programt &dest) { // set the 'exception' flag { goto_programt::targett t_set_exception= dest.add_instruction(ASSIGN); t_set_exception->source_location=code.source_location(); t_set_exception->code=code_assignt(exception_flag(), true_exprt()); } // do we catch locally? if(targets.throw_set) { // need to process destructor stack unwind_destructor_stack( code.source_location(), targets.throw_stack_size, dest); // add goto goto_programt::targett t=dest.add_instruction(); t->make_goto(targets.throw_target); t->source_location=code.source_location(); } else // otherwise, we do a return { // need to process destructor stack unwind_destructor_stack(code.source_location(), 0, dest); // add goto goto_programt::targett t=dest.add_instruction(); t->make_goto(targets.return_target); t->source_location=code.source_location(); } }
void goto_checkt::add_guarded_claim( const exprt &_expr, const std::string &comment, const std::string &property_class, const source_locationt &source_location, const exprt &src_expr, const guardt &guard) { exprt expr(_expr); // first try simplifier on it if(enable_simplify) simplify(expr, ns); // throw away trivial properties? if(!retain_trivial && expr.is_true()) return; // add the guard exprt guard_expr=guard.as_expr(); exprt new_expr; if(guard_expr.is_true()) new_expr.swap(expr); else { new_expr=exprt(ID_implies, bool_typet()); new_expr.move_to_operands(guard_expr, expr); } if(assertions.insert(new_expr).second) { goto_program_instruction_typet type= enable_assert_to_assume?ASSUME:ASSERT; goto_programt::targett t=new_code.add_instruction(type); std::string source_expr_string=from_expr(ns, "", src_expr); t->guard.swap(new_expr); t->source_location=source_location; t->source_location.set_comment(comment+" in "+source_expr_string); t->source_location.set_property_class(property_class); } }
void goto_convertt::do_function_call_other( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { // don't know what to do with it goto_programt::targett t=dest.add_instruction(FUNCTION_CALL); code_function_callt function_call; function_call.add_source_location()=function.source_location(); function_call.lhs()=lhs; function_call.function()=function; function_call.arguments()=arguments; t->source_location=function.source_location(); t->code.swap(function_call); }
void goto_convertt::convert_try_catch( const codet &code, goto_programt &dest) { assert(code.operands().size()>=2); // add the CATCH-push instruction to 'dest' goto_programt::targett catch_push_instruction=dest.add_instruction(); catch_push_instruction->make_catch(); catch_push_instruction->code.set_statement(ID_catch); catch_push_instruction->source_location=code.source_location(); // the CATCH-push instruction is annotated with a list of IDs, // one per target irept::subt &exception_list= catch_push_instruction->code.add(ID_exception_list).get_sub(); // add a SKIP target for the end of everything goto_programt end; goto_programt::targett end_target=end.add_instruction(); end_target->make_skip(); // the first operand is the 'try' block convert(to_code(code.op0()), dest); // add the CATCH-pop to the end of the 'try' block goto_programt::targett catch_pop_instruction=dest.add_instruction(); catch_pop_instruction->make_catch(); catch_pop_instruction->code.set_statement(ID_catch); // add a goto to the end of the 'try' block dest.add_instruction()->make_goto(end_target); for(unsigned i=1; i<code.operands().size(); i++) { const codet &block=to_code(code.operands()[i]); // grab the ID and add to CATCH instruction exception_list.push_back(irept(block.get(ID_exception_id))); goto_programt tmp; convert(block, tmp); catch_push_instruction->targets.push_back(tmp.instructions.begin()); dest.destructive_append(tmp); // add a goto to the end of the 'catch' block dest.add_instruction()->make_goto(end_target); } // add the end-target dest.destructive_append(end); }
void goto_checkt::add_guarded_claim(const exprt &_expr, const std::string &comment, const std::string &property, const locationt &location, const guardt &guard) { bool all_claims = options.get_bool_option("all-claims"); exprt expr(_expr); // first try simplifier on it if (!options.get_bool_option("no-simplify")) { expr2tc tmpexpr; migrate_expr(expr, tmpexpr); base_type(tmpexpr, ns); expr = migrate_expr_back(tmpexpr); simplify(expr); } if (!all_claims && expr.is_true()) return; // add the guard exprt guard_expr = migrate_expr_back(guard.as_expr()); exprt new_expr; if (guard_expr.is_true()) new_expr.swap(expr); else { new_expr = exprt("=>", bool_typet()); new_expr.move_to_operands(guard_expr, expr); } if (assertions.insert(new_expr).second) { goto_programt::targett t = new_code.add_instruction(ASSERT); migrate_expr(new_expr, t->guard); t->location = location; t->location.comment(comment); t->location.property(property); } }
void cfg_dominatorst::construct_cfg( const goto_programt &program, goto_programt::const_targett PC) { nodet &node=node_map[PC]; node.PC=PC; program.get_successors(PC, node.successors); // now do backward edges for(goto_programt::const_targetst::const_iterator s_it=node.successors.begin(); s_it!=node.successors.end(); s_it++) { node_map[*s_it].predecessors.push_back(node.PC); } }
void string_instrumentationt::do_snprintf( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()<3) { error().source_location=target->source_location; error() << "snprintf expected to have three or more arguments" << eom; throw 0; } goto_programt tmp; goto_programt::targett assertion=tmp.add_instruction(); assertion->source_location=target->source_location; assertion->source_location.set_property_class("string"); assertion->source_location.set_comment("snprintf buffer overflow"); exprt bufsize=buffer_size(arguments[0]); assertion->make_assertion( binary_relation_exprt(bufsize, ID_ge, arguments[1])); do_format_string_read(tmp, target, arguments, 2, 3, "snprintf"); if(call.lhs().is_not_nil()) { goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN); return_assignment->source_location=target->source_location; exprt rhs=side_effect_expr_nondett(call.lhs().type()); rhs.add_source_location()=target->source_location; return_assignment->code=code_assignt(call.lhs(), rhs); } target->make_skip(); dest.insert_before_swap(target, tmp); }
void havoc_loopst::build_havoc_code( const goto_programt::targett loop_head, const modifiest &modifies, goto_programt &dest) { for(modifiest::const_iterator m_it=modifies.begin(); m_it!=modifies.end(); m_it++) { exprt lhs=*m_it; exprt rhs=side_effect_expr_nondett(lhs.type()); goto_programt::targett t=dest.add_instruction(ASSIGN); t->function=loop_head->function; t->source_location=loop_head->source_location; t->code=code_assignt(lhs, rhs); t->code.add_source_location()=loop_head->source_location; } }
void string_instrumentationt::do_sprintf( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()<2) { error().source_location=target->source_location; error() << "sprintf expected to have two or more arguments" << eom; throw 0; } goto_programt tmp; goto_programt::targett assertion=tmp.add_instruction(); assertion->source_location=target->source_location; assertion->source_location.set_property_class("string"); assertion->source_location.set_comment("sprintf buffer overflow"); // in the abstract model, we have to report a // (possibly false) positive here assertion->make_assertion(false_exprt()); do_format_string_read(tmp, target, arguments, 1, 2, "sprintf"); if(call.lhs().is_not_nil()) { goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN); return_assignment->source_location=target->source_location; exprt rhs=side_effect_expr_nondett(call.lhs().type()); rhs.add_source_location()=target->source_location; return_assignment->code=code_assignt(call.lhs(), rhs); } target->make_skip(); dest.insert_before_swap(target, tmp); }
void goto_convertt::do_atomic_end( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { if(lhs.is_not_nil()) { err_location(lhs); throw "atomic_end does not expect an LHS"; } if(!arguments.empty()) { err_location(function); throw "atomic_end takes no arguments"; } goto_programt::targett t=dest.add_instruction(ATOMIC_END); t->source_location=function.source_location(); }
static bool skip_loops( goto_programt &goto_program, const loop_idst &loop_ids, messaget &message) { loop_idst::const_iterator l_it=loop_ids.begin(); Forall_goto_program_instructions(it, goto_program) { if(l_it==loop_ids.end()) break; if(!it->is_backwards_goto()) continue; const unsigned loop_id=it->loop_number; if(*l_it<loop_id) break; // error handled below if(*l_it>loop_id) continue; goto_programt::targett loop_head=it->get_target(); goto_programt::targett next=it; ++next; assert(next!=goto_program.instructions.end()); goto_programt::targett g=goto_program.insert_before(loop_head); g->make_goto(next, true_exprt()); g->source_location=loop_head->source_location; g->function=loop_head->function; ++l_it; } if(l_it!=loop_ids.end()) { message.error() << "Loop " << *l_it << " not found" << messaget::eom; return true; } return false; }
void goto_inlinet::parameter_destruction( const source_locationt &source_location, const irep_idt &function_name, const code_typet &code_type, goto_programt &dest) { const code_typet::parameterst ¶meter_types= code_type.parameters(); // iterates over the types of the parameters for(code_typet::parameterst::const_iterator it=parameter_types.begin(); it!=parameter_types.end(); it++) { const code_typet::parametert ¶meter=*it; const irep_idt &identifier=parameter.get_identifier(); if(identifier==irep_idt()) { error().source_location=source_location; error() << "no identifier for function parameter" << eom; throw 0; } { const symbolt &symbol=ns.lookup(identifier); goto_programt::targett dead=dest.add_instruction(); dead->make_dead(); dead->code=code_deadt(symbol.symbol_expr()); dead->code.add_source_location()=source_location; dead->source_location=source_location; dead->function=function_name; } } }
void remove_function_pointerst::fix_return_type( code_function_callt &function_call, goto_programt &dest) { // are we returning anything at all? if(function_call.lhs().is_nil()) return; const code_typet &code_type= to_code_type(ns.follow(function_call.function().type())); // type already ok? if(type_eq( function_call.lhs().type(), code_type.return_type(), ns)) return; symbolt &tmp_symbol= get_fresh_aux_symbol( code_type.return_type(), "remove_function_pointers", "tmp_return_val", function_call.source_location(), irep_idt(), symbol_table); symbol_exprt tmp_symbol_expr; tmp_symbol_expr.type()=tmp_symbol.type; tmp_symbol_expr.set_identifier(tmp_symbol.name); exprt old_lhs=function_call.lhs(); function_call.lhs()=tmp_symbol_expr; goto_programt::targett t_assign=dest.add_instruction(); t_assign->make_assignment(); t_assign->code=code_assignt( old_lhs, typecast_exprt(tmp_symbol_expr, old_lhs.type())); }
void goto_program_dereferencet::dereference_program( goto_programt &goto_program, bool checks_only) { for(goto_programt::instructionst::iterator it=goto_program.instructions.begin(); it!=goto_program.instructions.end(); it++) { new_code.clear(); assertions.clear(); dereference_instruction(it, checks_only); // insert new instructions while(!new_code.instructions.empty()) { goto_program.insert_before_swap(it, new_code.instructions.front()); new_code.instructions.pop_front(); it++; } } }
void value_set_analysis_fivrt::add_vars( const goto_programt &goto_program) { typedef std::list<value_set_fivrt::entryt> entry_listt; // get the globals entry_listt globals; get_globals(globals); // get the locals goto_programt::decl_identifierst locals; goto_program.get_decl_identifiers(locals); // cache the list for the locals to speed things up typedef std::unordered_map<irep_idt, entry_listt, irep_id_hash> entry_cachet; entry_cachet entry_cache; value_set_fivrt &v=state.value_set; v.add_vars(globals); for(auto l : locals) { // cache hit? entry_cachet::const_iterator e_it=entry_cache.find(l); if(e_it==entry_cache.end()) { const symbolt &symbol=ns.lookup(l); std::list<value_set_fivrt::entryt> &entries=entry_cache[l]; get_entries(symbol, entries); v.add_vars(entries); } else v.add_vars(e_it->second); } }
void goto_convertt::convert_msc_try_finally( const codet &code, goto_programt &dest) { if(code.operands().size()!=2) { error().source_location=code.find_source_location(); error() << "msc_try_finally expects two arguments" << eom; throw 0; } goto_programt tmp; tmp.add_instruction(SKIP)->source_location=code.source_location(); { // save 'leave' target leave_targett leave_target(targets); targets.set_leave(tmp.instructions.begin()); // first put 'finally' code onto destructor stack targets.destructor_stack.push_back(to_code(code.op1())); // do 'try' code convert(to_code(code.op0()), dest); // pop 'finally' from destructor stack targets.destructor_stack.pop_back(); // 'leave' target gets restored here } // now add 'finally' code convert(to_code(code.op1()), dest); // this is the target for 'leave' dest.destructive_append(tmp); }
void remove_unreachable(goto_programt &goto_program) { std::set<goto_programt::targett> reachable; std::stack<goto_programt::targett> working; working.push(goto_program.instructions.begin()); while(!working.empty()) { goto_programt::targett t=working.top(); working.pop(); if(reachable.find(t)==reachable.end() && t!=goto_program.instructions.end()) { reachable.insert(t); goto_programt::targetst successors; goto_program.get_successors(t, successors); for(goto_programt::targetst::const_iterator s_it=successors.begin(); s_it!=successors.end(); s_it++) working.push(*s_it); } } // make all unreachable code a skip // unless it's an 'end_function' Forall_goto_program_instructions(it, goto_program) { if(reachable.find(it)==reachable.end() && !it->is_end_function()) it->make_skip(); } }
void goto_convertt::convert_CPROVER_try_catch( const codet &code, goto_programt &dest) { if(code.operands().size()!=2) { error().source_location=code.find_source_location(); error() << "CPROVER_try_catch expects two arguments" << eom; throw 0; } // this is where we go after 'throw' goto_programt tmp; tmp.add_instruction(SKIP)->source_location=code.source_location(); // set 'throw' target throw_targett throw_target(targets); targets.set_throw(tmp.instructions.begin()); // now put 'catch' code onto destructor stack code_ifthenelset catch_code; catch_code.cond()=exception_flag(); catch_code.add_source_location()=code.source_location(); catch_code.then_case()=to_code(code.op1()); targets.destructor_stack.push_back(catch_code); // now convert 'try' code convert(to_code(code.op0()), dest); // pop 'catch' code off stack targets.destructor_stack.pop_back(); // add 'throw' target dest.destructive_append(tmp); }
void string_instrumentationt::do_strrchr( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()!=2) { err_location(target->location); throw "strrchr expected to have two arguments"; } goto_programt tmp; goto_programt::targett assertion=tmp.add_instruction(); assertion->make_assertion(is_zero_string(arguments[0])); assertion->location=target->location; assertion->location.set("property", "string"); assertion->location.set("comment", "zero-termination of string argument of strrchr"); target->make_skip(); dest.insert_before_swap(target, tmp); }
void goto_convertt::convert_msc_leave( const codet &code, goto_programt &dest) { if(!targets.leave_set) { err_location(code); throw "leave without target"; } // need to process destructor stack for(unsigned d=targets.destructor_stack.size(); d!=targets.leave_stack_size; d--) { codet d_code=targets.destructor_stack[d-1]; d_code.add_source_location()=code.source_location(); convert(d_code, dest); } goto_programt::targett t=dest.add_instruction(); t->make_goto(targets.leave_target); t->source_location=code.source_location(); }
void remove_skip(goto_programt &goto_program) { typedef std::map<goto_programt::targett, goto_programt::targett> new_targetst; new_targetst new_targets; // remove skip statements for(goto_programt::instructionst::iterator it=goto_program.instructions.begin(); it!=goto_program.instructions.end();) { goto_programt::targett old_target=it; // for collecting labels std::list<irep_idt> labels; while(is_skip(it)) { // don't remove the last skip statement, // it could be a target if(it==--goto_program.instructions.end()) break; // save labels labels.splice(labels.end(), it->labels); it++; } goto_programt::targett new_target=it; // save labels it->labels.splice(it->labels.begin(), labels); if(new_target!=old_target) { while(new_target!=old_target) { // remember the old targets new_targets[old_target]=new_target; old_target=goto_program.instructions.erase(old_target); } } else it++; } // adjust gotos Forall_goto_program_instructions(i_it, goto_program) if(i_it->is_goto()) { for(goto_programt::instructiont::targetst::iterator t_it=i_it->targets.begin(); t_it!=i_it->targets.end(); t_it++) { new_targetst::const_iterator result=new_targets.find(*t_it); if(result!=new_targets.end()) *t_it=result->second; } } // remove the last skip statement unless it's a target goto_program.compute_incoming_edges(); if(!goto_program.instructions.empty() && is_skip(--goto_program.instructions.end()) && !goto_program.instructions.back().is_target()) goto_program.instructions.pop_back(); }
void goto_inlinet::parameter_assignments( const locationt &location, const code_typet &code_type, const exprt::operandst &arguments, goto_programt &dest) { // iterates over the operands exprt::operandst::const_iterator it1=arguments.begin(); goto_programt::local_variablest local_variables; const code_typet::argumentst &argument_types= code_type.arguments(); // iterates over the types of the arguments for(code_typet::argumentst::const_iterator it2=argument_types.begin(); it2!=argument_types.end(); it2++) { // if you run out of actual arguments there was a mismatch if(it1==arguments.end()) { err_location(location); throw "function call: not enough arguments"; } const exprt &argument=static_cast<const exprt &>(*it2); // this is the type the n-th argument should be const typet &arg_type=ns.follow(argument.type()); const irep_idt &identifier=argument.cmt_identifier(); if(identifier=="") { err_location(location); throw "no identifier for function argument"; } { const symbolt &symbol=ns.lookup(identifier); goto_programt::targett decl=dest.add_instruction(); decl->make_other(); exprt tmp = code_declt(symbol_expr(symbol)); migrate_expr(tmp, decl->code); decl->location=location; decl->function=location.get_function(); decl->local_variables=local_variables; } local_variables.insert(identifier); // nil means "don't assign" if(it1->is_nil()) { } else { // this is the actual parameter exprt actual(*it1); // it should be the same exact type type2tc arg_type_2, actual_type_2; migrate_type(arg_type, arg_type_2); migrate_type(actual.type(), actual_type_2); if (!base_type_eq(arg_type_2, actual_type_2, ns)) { const typet &f_argtype = ns.follow(arg_type); const typet &f_acttype = ns.follow(actual.type()); // we are willing to do some conversion if((f_argtype.id()=="pointer" && f_acttype.id()=="pointer") || (f_argtype.is_array() && f_acttype.id()=="pointer" && f_argtype.subtype()==f_acttype.subtype())) { actual.make_typecast(arg_type); } else if((f_argtype.id()=="signedbv" || f_argtype.id()=="unsignedbv" || f_argtype.is_bool()) && (f_acttype.id()=="signedbv" || f_acttype.id()=="unsignedbv" || f_acttype.is_bool())) { actual.make_typecast(arg_type); } else { err_location(location); str << "function call: argument `" << identifier << "' type mismatch: got " << from_type(ns, identifier, it1->type()) << ", expected " << from_type(ns, identifier, arg_type); throw 0; } } // adds an assignment of the actual parameter to the formal parameter code_assignt assignment(symbol_exprt(identifier, arg_type), actual); assignment.location()=location; dest.add_instruction(ASSIGN); dest.instructions.back().location=location; migrate_expr(assignment, dest.instructions.back().code); dest.instructions.back().local_variables=local_variables; dest.instructions.back().function=location.get_function(); } it1++; } if(it1!=arguments.end()) { // too many arguments -- we just ignore that, no harm done } }
void remove_virtual_functionst::remove_virtual_function( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const auto &vcall_source_loc=target->source_location; const exprt &function=code.function(); assert(function.id()==ID_virtual_function); assert(!code.arguments().empty()); functionst functions; get_functions(function, functions); if(functions.empty()) { target->make_skip(); return; // give up } // only one option? if(functions.size()==1) { assert(target->is_function_call()); if(functions.begin()->symbol_expr==symbol_exprt()) target->make_skip(); else to_code_function_call(target->code).function()= functions.begin()->symbol_expr; return; } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->source_location=vcall_source_loc; t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; exprt this_expr=code.arguments()[0]; // If necessary, cast to the last candidate function to // get the object's clsid. By the structure of get_functions, // this is the parent of all other classes under consideration. const auto &base_classid=functions.back().class_id; const auto &base_function_symbol=functions.back().symbol_expr; symbol_typet suggested_type(base_classid); exprt c_id2=get_class_identifier_field(this_expr, suggested_type, ns); std::map<irep_idt, goto_programt::targett> calls; // Note backwards iteration, to get the least-derived candidate first. for(auto it=functions.crbegin(), itend=functions.crend(); it!=itend; ++it) { const auto &fun=*it; auto insertit=calls.insert( {fun.symbol_expr.get_identifier(), goto_programt::targett()}); // Only create one call sequence per possible target: if(insertit.second) { goto_programt::targett t1=new_code_calls.add_instruction(); t1->source_location=vcall_source_loc; if(!fun.symbol_expr.get_identifier().empty()) { // call function t1->make_function_call(code); auto &newcall=to_code_function_call(t1->code); newcall.function()=fun.symbol_expr; pointer_typet need_type(symbol_typet(fun.symbol_expr.get(ID_C_class))); if(!type_eq(newcall.arguments()[0].type(), need_type, ns)) newcall.arguments()[0].make_typecast(need_type); } else { // No definition for this type; shouldn't be possible... t1->make_assertion(false_exprt()); } insertit.first->second=t1; // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->source_location=vcall_source_loc; t3->make_goto(t_final, true_exprt()); } // If this calls the base function we just fall through. // Otherwise branch to the right call: if(fun.symbol_expr!=base_function_symbol) { exprt c_id1=constant_exprt(fun.class_id, string_typet()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->source_location=vcall_source_loc; t4->make_goto(insertit.first->second, equal_exprt(c_id1, c_id2)); } } goto_programt new_code; // patch them all together new_code.destructive_append(new_code_gotos); new_code.destructive_append(new_code_calls); new_code.destructive_append(final_skip); // set locations Forall_goto_program_instructions(it, new_code) { const irep_idt property_class=it->source_location.get_property_class(); const irep_idt comment=it->source_location.get_comment(); it->source_location=target->source_location; it->function=target->function; if(!property_class.empty()) it->source_location.set_property_class(property_class); if(!comment.empty()) it->source_location.set_comment(comment); } goto_programt::targett next_target=target; next_target++; goto_program.destructive_insert(next_target, new_code); // finally, kill original invocation target->make_skip(); }
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++; } }
void convert( const irept &irep, goto_programt &program ) { assert(irep.id()=="goto-program"); program.instructions.clear(); std::list< std::list<unsigned> > number_targets_list; // convert instructions back const irept::subt &subs = irep.get_sub(); for (irept::subt::const_iterator it=subs.begin(); it!=subs.end(); it++) { program.instructions.push_back(goto_programt::instructiont()); convert(*it, program.instructions.back()); number_targets_list.push_back(std::list<unsigned>()); const irept &targets=it->find(ID_targets); const irept::subt &tsubs=targets.get_sub(); for (irept::subt::const_iterator tit=tsubs.begin(); tit!=tsubs.end(); tit++) { number_targets_list.back().push_back( unsafe_string2unsigned(tit->id_string())); } } program.compute_location_numbers(); // resolve targets std::list< std::list<unsigned> >::iterator nit= number_targets_list.begin(); for(goto_programt::instructionst::iterator lit= program.instructions.begin(); lit!=program.instructions.end() && nit!=number_targets_list.end(); lit++, nit++) { for (std::list<unsigned>::iterator tit=nit->begin(); tit!=nit->end(); tit++) { goto_programt::targett fit=program.instructions.begin(); for(;fit!=program.instructions.end();fit++) { if (fit->location_number==*tit) { lit->targets.push_back(fit); break; } } if (fit==program.instructions.end()) { std::cout << "Warning: could not resolve target link " << "during irep->goto_program translation." << std::endl; throw 0; } } } program.update(); }
void goto_inlinet::replace_return( goto_programt &dest, const exprt &lhs, const exprt &constrain __attribute__((unused)) /* ndebug */) { for(goto_programt::instructionst::iterator it=dest.instructions.begin(); it!=dest.instructions.end(); it++) { if(it->is_return()) { if(lhs.is_not_nil()) { goto_programt tmp; goto_programt::targett assignment=tmp.add_instruction(ASSIGN); const code_return2t &ret = to_code_return2t(it->code); code_assignt code_assign(lhs, migrate_expr_back(ret.operand)); // this may happen if the declared return type at the call site // differs from the defined return type if(code_assign.lhs().type()!= code_assign.rhs().type()) code_assign.rhs().make_typecast(code_assign.lhs().type()); migrate_expr(code_assign, assignment->code); assignment->location=it->location; assignment->local_variables=it->local_variables; assignment->function=it->location.get_function();