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 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); } }
bool remove_virtual_functionst::remove_virtual_functions( goto_programt &goto_program) { bool did_something=false; Forall_goto_program_instructions(target, goto_program) if(target->is_function_call()) { const code_function_callt &code= to_code_function_call(target->code); if(code.function().id()==ID_virtual_function) { remove_virtual_function(goto_program, target); did_something=true; } } if(did_something) { goto_program.update(); } return did_something; }
void thread_exit_instrumentation(goto_functionst &goto_functions) { // we'll look for START THREAD std::set<irep_idt> thread_fkts; forall_goto_functions(f_it, goto_functions) { if(has_start_thread(f_it->second.body)) { // now look for functions called for(const auto &instruction : f_it->second.body.instructions) if(instruction.is_function_call()) { const exprt &function=to_code_function_call(instruction.code).function(); if(function.id()==ID_symbol) thread_fkts.insert(to_symbol_expr(function).get_identifier()); } } } // now instrument for(const auto &fkt : thread_fkts) { thread_exit_instrumentation(goto_functions.function_map[fkt].body); } }
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); } } }
goto_programt::const_targett termination_baset::find_next_loop( goto_programt::const_targett current, const goto_programt &program, std::list<goto_programt::const_targett> &recursion_stack) const { /* The program contains only termination-assertions, i.e., we look only for assertions. */ current++; while(current!=program.instructions.end()) { switch(current->type) { case ASSERT: return current; case FUNCTION_CALL: { const code_function_callt &code=to_code_function_call(current->code); const irep_idt &fid=code.function().get("identifier"); goto_functionst::function_mapt::const_iterator fit= goto_functions.function_map.find(fid); if(fit==goto_functions.function_map.end() || fit->second.body.instructions.empty()) current++; // ignore the call else { if(std::find(recursion_stack.begin(), recursion_stack.end(), current) == recursion_stack.end()) { recursion_stack.push_back(current); current=fit->second.body.instructions.begin(); } else current++; // no recursion necessary } } break; case END_FUNCTION: if(!recursion_stack.empty()) { current=recursion_stack.back(); recursion_stack.pop_back(); } current++; break; default: current++; } } assert(recursion_stack.empty()); // no more assertions return program.instructions.end(); }
Forall_goto_program_instructions(i_it, goto_program) { if(i_it->is_function_call()) { code_function_callt &function_call=to_code_function_call(i_it->code); code_typet old_type=to_code_type(function_call.function().type()); // Do we return anything? if(old_type.return_type()!=empty_typet()) { // replace "lhs=f(...)" by "f(...); lhs=f#return_value; DEAD f#return_value;" assert(function_call.function().id()==ID_symbol); const irep_idt function_id= to_symbol_expr(function_call.function()).get_identifier(); // see if we have a body goto_functionst::function_mapt::const_iterator f_it=goto_functions.function_map.find(function_id); if(f_it==goto_functions.function_map.end()) throw "failed to find function `"+id2string(function_id)+"' in function map"; // fix the type to_code_type(function_call.function().type()).return_type()=empty_typet(); if(function_call.lhs().is_not_nil()) { exprt rhs; symbol_exprt return_value; return_value.type()=function_call.lhs().type(); return_value.set_identifier(id2string(function_id)+RETURN_VALUE_SUFFIX); rhs=return_value; goto_programt::targett t_a=goto_program.insert_after(i_it); t_a->make_assignment(); t_a->source_location=i_it->source_location; t_a->code=code_assignt(function_call.lhs(), rhs); t_a->function=i_it->function; // fry the previous assignment function_call.lhs().make_nil(); if(f_it->second.body_available()) { goto_programt::targett t_d=goto_program.insert_after(t_a); t_d->make_dead(); t_d->source_location=i_it->source_location; t_d->code=code_deadt(rhs); t_d->function=i_it->function; } } } } }
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 goto_program_dereferencet::dereference_instruction( goto_programt::targett target, bool checks_only) { current_target=target; #if 0 valid_local_variables=&target->local_variables; #endif goto_programt::instructiont &i=*target; dereference_expr(i.guard, checks_only, value_set_dereferencet::READ); if(i.is_assign()) { if(i.code.operands().size()!=2) throw "assignment expects two operands"; dereference_expr(i.code.op0(), checks_only, value_set_dereferencet::WRITE); dereference_expr(i.code.op1(), checks_only, value_set_dereferencet::READ); } else if(i.is_function_call()) { code_function_callt &function_call=to_code_function_call(to_code(i.code)); if(function_call.lhs().is_not_nil()) dereference_expr(function_call.lhs(), checks_only, value_set_dereferencet::WRITE); dereference_expr(function_call.function(), checks_only, value_set_dereferencet::READ); dereference_expr(function_call.op2(), checks_only, value_set_dereferencet::READ); } else if(i.is_return()) { Forall_operands(it, i.code) dereference_expr(*it, checks_only, value_set_dereferencet::READ); } else if(i.is_other()) { const irep_idt &statement=i.code.get(ID_statement); if(statement==ID_expression) { if(i.code.operands().size()!=1) throw "expression expects one operand"; dereference_expr(i.code.op0(), checks_only, value_set_dereferencet::READ); } else if(statement==ID_printf) { Forall_operands(it, i.code) dereference_expr(*it, checks_only, value_set_dereferencet::READ); } } }
void jsil_typecheckt::typecheck_try_catch(code_try_catcht &code) { // A special case of try catch with one catch clause if(code.operands().size()!=3) throw "try_catch expected to have three operands"; // function call typecheck_function_call(to_code_function_call(code.try_code())); // catch decl is not used, but is required by goto-programs typecheck_code(code.get_catch_code(0)); }
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()=="symbol") { const irep_idt &identifier= to_symbol_expr(function).get_identifier(); if(identifier=="c::strcoll") { } else if(identifier=="c::strncmp") do_strncmp(dest, target, call); else if(identifier=="c::strxfrm") { } else if(identifier=="c::strchr") do_strchr(dest, target, call); else if(identifier=="c::strcspn") { } else if(identifier=="c::strpbrk") { } else if(identifier=="c::strrchr") do_strrchr(dest, target, call); else if(identifier=="c::strspn") { } else if(identifier=="c::strerror") do_strerror(dest, target, call); else if(identifier=="c::strstr") do_strstr(dest, target, call); else if(identifier=="c::strtok") do_strtok(dest, target, call); else if(identifier=="c::sprintf") do_sprintf(dest, target, call); else if(identifier=="c::snprintf") do_snprintf(dest, target, call); else if(identifier=="c::fscanf") do_fscanf(dest, target, call); dest.update(); } }
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: { } } }
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(); }
std::string expr2javat::convert_code( const codet &src, unsigned indent) { const irep_idt &statement=src.get(ID_statement); if(statement==ID_java_new || statement==ID_java_new_array) return convert_java_new(src,indent); if(statement==ID_function_call) return convert_code_function_call(to_code_function_call(src), indent); return expr2ct::convert_code(src, indent); }
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()); } } }
exprt static_analysis_baset::get_return_lhs(locationt to) { // get predecessor of "to" to--; if(to->is_end_function()) return static_cast<const exprt &>(get_nil_irep()); // must be the function call assert(to->is_function_call()); const code_function_callt &code= to_code_function_call(to->code); return code.lhs(); }
exprt flow_insensitive_abstract_domain_baset::get_return_lhs(locationt to) const { // get predecessor of "to" to--; if(to->is_end_function()) return static_cast<const exprt &>(get_nil_irep()); // must be the function call assert(to->is_function_call()); const code_function_callt &code= to_code_function_call(to_code(to->code)); return code.lhs(); }
Forall_goto_program_instructions(i_it, goto_program) { if(i_it->is_function_call()) { code_function_callt &function_call=to_code_function_call(i_it->code); // add x=y for f(y) where x is the parameter assert(function_call.function().id()==ID_symbol); const irep_idt &identifier= to_symbol_expr(function_call.function()).get_identifier(); // see if we have it const namespacet ns(symbol_table); const symbolt &function_symbol=ns.lookup(identifier); const code_typet &code_type=to_code_type(function_symbol.type); goto_programt tmp; for(std::size_t nr=0; nr<code_type.parameters().size(); nr++) { irep_idt p_identifier=code_type.parameters()[nr].get_identifier(); if(p_identifier.empty()) continue; if(nr<function_call.arguments().size()) { goto_programt::targett t=tmp.add_instruction(); t->make_assignment(); t->source_location=i_it->source_location; const symbolt &lhs_symbol=ns.lookup(p_identifier); symbol_exprt lhs=lhs_symbol.symbol_expr(); exprt rhs=function_call.arguments()[nr]; if(rhs.type()!=lhs.type()) rhs.make_typecast(lhs.type()); t->code=code_assignt(lhs, rhs); t->function=i_it->function; } } std::size_t count=tmp.instructions.size(); goto_program.insert_before_swap(i_it, tmp); for(; count!=0; count--) i_it++; } }
bool value_set_domain_fivrnst::transform( const namespacet &ns, locationt from_l, locationt to_l) { value_set.set_from(from_l->function, from_l->location_number); value_set.set_to(to_l->function, to_l->location_number); #if 0 std::cout << "Transforming: " << from_l->function << " " << from_l->location_number << " to " << to_l->function << " " << to_l->location_number << '\n'; #endif switch(from_l->type) { case END_FUNCTION: value_set.do_end_function(get_return_lhs(to_l), ns); break; case RETURN: case OTHER: case ASSIGN: value_set.apply_code(from_l->code, ns); break; case FUNCTION_CALL: { const code_function_callt &code= to_code_function_call(from_l->code); value_set.do_function_call(to_l->function, code.arguments(), ns); break; } default: { } } return value_set.handover(); }
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 value_set_domain_fivrnst::transform( locationt from_l, locationt to_l, ai_baset &ai, const namespacet &ns) { value_set.set_from(from_l->function, from_l->location_number); value_set.set_to(to_l->function, to_l->location_number); #if 0 std::cout << "Transforming: " << from_l->function << " " << from_l->location_number << " to " << to_l->function << " " << to_l->location_number << std::endl; #endif switch(from_l->type) { case END_FUNCTION: value_set.do_end_function(value_set_domaint::get_return_lhs(to_l), ns); break; case RETURN: case OTHER: case ASSIGN: value_set.apply_code(from_l->code, ns); break; case FUNCTION_CALL: { const code_function_callt &code= to_code_function_call(from_l->code); value_set.do_function_call(to_l->function, code.arguments(), ns); break; } default:; } // return value_set.handover(); //TODO: not sure what to do with this }
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 remove_function_pointerst::remove_function_pointer( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const exprt &function=code.function(); // this better have the right type code_typet call_type=to_code_type(function.type()); // refine the type in case the forward declaration was incomplete if(call_type.has_ellipsis() && call_type.parameters().empty()) { call_type.remove_ellipsis(); forall_expr(it, code.arguments()) call_type.parameters().push_back( code_typet::parametert(it->type())); } assert(function.id()==ID_dereference); assert(function.operands().size()==1); bool found_functions; const exprt &pointer=function.op0(); remove_const_function_pointerst::functionst functions; does_remove_constt const_removal_check(goto_program, ns); if(const_removal_check()) { warning() << "Cast from const to non-const pointer found, only worst case" << " function pointer removal will be done." << eom; found_functions=false; } else { remove_const_function_pointerst fpr( get_message_handler(), pointer, ns, symbol_table); found_functions=fpr(functions); // Either found_functions is true therefore the functions should not // be empty // Or found_functions is false therefore the functions should be empty assert(found_functions != functions.empty()); if(functions.size()==1) { to_code_function_call(target->code).function()=*functions.cbegin(); return; } } if(!found_functions) { if(only_resolve_const_fps) { // If this mode is enabled, we only remove function pointers // that we can resolve either to an exact funciton, or an exact subset // (e.g. a variable index in a constant array). // Since we haven't found functions, we would now resort to // replacing the function pointer with any function with a valid signature // Since we don't want to do that, we abort. return; } bool return_value_used=code.lhs().is_not_nil(); // get all type-compatible functions // whose address is ever taken for(const auto &t : type_map) { // address taken? if(address_taken.find(t.first)==address_taken.end()) continue; // type-compatible? if(!is_type_compatible(return_value_used, call_type, t.second)) continue; if(t.first=="pthread_mutex_cleanup") continue; symbol_exprt expr; expr.type()=t.second; expr.set_identifier(t.first); functions.insert(expr); } } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; for(const auto &fun : functions) { // call function goto_programt::targett t1=new_code_calls.add_instruction(); t1->make_function_call(code); to_code_function_call(t1->code).function()=fun; // the signature of the function might not match precisely fix_argument_types(to_code_function_call(t1->code)); fix_return_type(to_code_function_call(t1->code), new_code_calls); // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); // goto to call address_of_exprt address_of; address_of.object()=fun; address_of.type()=pointer_typet(); address_of.type().subtype()=fun.type(); if(address_of.type()!=pointer.type()) address_of.make_typecast(pointer.type()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, equal_exprt(pointer, address_of)); } // fall-through if(add_safety_assertion) { goto_programt::targett t=new_code_gotos.add_instruction(); t->make_assertion(false_exprt()); t->source_location.set_property_class("pointer dereference"); t->source_location.set_comment("invalid function pointer"); } 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) { irep_idt property_class=it->source_location.get_property_class(); 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); }
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 } }
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 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 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 } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; for(functionst::const_iterator it=functions.begin(); it!=functions.end(); it++) { // call function goto_programt::targett t1=new_code_calls.add_instruction(); t1->make_function_call(code); to_code_function_call(t1->code).function()=it->symbol_expr; // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); exprt this_expr=code.arguments()[0]; if(this_expr.type().id()!=ID_pointer || this_expr.type().id()!=ID_struct) { symbol_typet symbol_type(it->class_id); this_expr=typecast_exprt(this_expr, pointer_typet(symbol_type)); } exprt deref=dereference_exprt(this_expr, this_expr.type().subtype()); exprt c_id1=constant_exprt(it->class_id, string_typet()); exprt c_id2=build_class_identifier(deref); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, 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) { irep_idt property_class=it->source_location.get_property_class(); 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); }
void remove_function_pointerst::remove_function_pointer( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const exprt &function=code.function(); // this better have the right type code_typet call_type=to_code_type(function.type()); // refine the type in case the forward declaration was incomplete if(call_type.has_ellipsis() && call_type.parameters().empty()) { call_type.remove_ellipsis(); forall_expr(it, code.arguments()) call_type.parameters().push_back( code_typet::parametert(it->type())); } assert(function.id()==ID_dereference); assert(function.operands().size()==1); const exprt &pointer=function.op0(); // Is this simple? if(pointer.id()==ID_address_of && to_address_of_expr(pointer).object().id()==ID_symbol) { to_code_function_call(target->code).function()= to_address_of_expr(pointer).object(); return; } typedef std::list<exprt> functionst; functionst functions; bool return_value_used=code.lhs().is_not_nil(); // get all type-compatible functions // whose address is ever taken for(type_mapt::const_iterator f_it= type_map.begin(); f_it!=type_map.end(); f_it++) { // address taken? if(address_taken.find(f_it->first)==address_taken.end()) continue; // type-compatible? if(!is_type_compatible(return_value_used, call_type, f_it->second)) continue; if(f_it->first=="pthread_mutex_cleanup") continue; symbol_exprt expr; expr.type()=f_it->second; expr.set_identifier(f_it->first); functions.push_back(expr); } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; for(functionst::const_iterator it=functions.begin(); it!=functions.end(); it++) { // call function goto_programt::targett t1=new_code_calls.add_instruction(); t1->make_function_call(code); to_code_function_call(t1->code).function()=*it; // the signature of the function might not match precisely fix_argument_types(to_code_function_call(t1->code)); fix_return_type(to_code_function_call(t1->code), new_code_calls); // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); // goto to call address_of_exprt address_of; address_of.object()=*it; address_of.type()=pointer_typet(); address_of.type().subtype()=it->type(); if(address_of.type()!=pointer.type()) address_of.make_typecast(pointer.type()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, equal_exprt(pointer, address_of)); } // fall-through if(add_safety_assertion) { goto_programt::targett t=new_code_gotos.add_instruction(); t->make_assertion(false_exprt()); t->source_location.set_property_class("pointer dereference"); t->source_location.set_comment("invalid function pointer"); } 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) { irep_idt property_class=it->source_location.get_property_class(); 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); }
void remove_function_pointerst::remove_function_pointer( goto_programt &goto_program, goto_programt::targett target) { const code_function_callt &code= to_code_function_call(target->code); const exprt &function=code.function(); // this better have the right type const code_typet &call_type=to_code_type(function.type()); assert(function.id()==ID_dereference); assert(function.operands().size()==1); const exprt &pointer=function.op0(); typedef std::list<exprt> functionst; functionst functions; // get all type-compatible functions // whose address is ever taken for(type_mapt::const_iterator f_it= type_map.begin(); f_it!=type_map.end(); f_it++) { // address taken? if(address_taken.find(f_it->first)==address_taken.end()) continue; // type-compatible? if(!is_type_compatible(call_type, f_it->second)) continue; symbol_exprt expr; expr.type()=f_it->second; expr.set_identifier(f_it->first); functions.push_back(expr); } // the final target is a skip goto_programt final_skip; goto_programt::targett t_final=final_skip.add_instruction(); t_final->make_skip(); // build the calls and gotos goto_programt new_code_calls; goto_programt new_code_gotos; for(functionst::const_iterator it=functions.begin(); it!=functions.end(); it++) { // call function goto_programt::targett t1=new_code_calls.add_instruction(); t1->make_function_call(code); to_code_function_call(t1->code).function()=*it; // the signature of the function might not match precisely fix_argument_types(to_code_function_call(t1->code)); fix_return_type(to_code_function_call(t1->code), new_code_calls); // goto final goto_programt::targett t3=new_code_calls.add_instruction(); t3->make_goto(t_final, true_exprt()); // goto to call address_of_exprt address_of; address_of.object()=*it; address_of.type()=pointer_typet(); address_of.type().subtype()=it->type(); if(address_of.type()!=pointer.type()) address_of.make_typecast(pointer.type()); goto_programt::targett t4=new_code_gotos.add_instruction(); t4->make_goto(t1, equal_exprt(pointer, address_of)); } // fall-through if(add_safety_assertion) { goto_programt::targett t=new_code_gotos.add_instruction(); t->make_assertion(false_exprt()); t->location.set(ID_property, "pointer dereference"); t->location.set(ID_comment, "invalid function pointer"); } 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) { irep_idt property=it->location.get_property(); irep_idt comment=it->location.get_comment(); it->location=target->location; it->function=target->function; if(!property.empty()) it->location.set_property(property); if(!comment.empty()) it->location.set_comment(comment); }