void goto_inlinet::replace_return( goto_programt &dest, const exprt &lhs, const exprt &constrain) { 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(); assert(constrain.is_nil()); // bp_constrain gumpf reomved dest.insert_swap(it, *assignment); it++; } else if(!is_nil_expr(it->code)) { // Encode evaluation of return expr, so that returns with pointer // derefs in them still get dereferenced, even when the result is // discarded. goto_programt tmp; goto_programt::targett expression=tmp.add_instruction(OTHER); expression->make_other(); expression->location=it->location; expression->function=it->location.get_function(); expression->local_variables=it->local_variables; const code_return2t &ret = to_code_return2t(it->code); expression->code = code_expression2tc(ret.operand); dest.insert_swap(it, *expression); it++; } it->make_goto(--dest.instructions.end()); } } }
void goto_convertt::do_java_new( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_java_new without lhs is yet to be implemented"; source_locationt location=rhs.source_location(); assert(rhs.operands().empty()); if(rhs.type().id()!=ID_pointer) throw "do_java_new returns pointer"; typet object_type=rhs.type().subtype(); // build size expression exprt object_size=size_of_expr(object_type, ns); if(object_size.is_nil()) throw "do_java_new got nil object_size"; // we produce a malloc side-effect, which stays side_effect_exprt malloc_expr(ID_malloc); malloc_expr.copy_to_operands(object_size); malloc_expr.type()=pointer_typet(object_type); goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt(lhs, malloc_expr); t_n->source_location=location; // zero-initialize the object dereference_exprt deref(lhs, object_type); exprt zero_object=zero_initializer(object_type, location, ns, get_message_handler()); set_class_identifier(to_struct_expr(zero_object), ns, to_symbol_type(object_type)); goto_programt::targett t_i=dest.add_instruction(ASSIGN); t_i->code=code_assignt(deref, zero_object); t_i->source_location=location; }
void goto_convertt::do_java_new_array( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_java_new_array without lhs is yet to be implemented"; source_locationt location=rhs.source_location(); assert(rhs.operands().size()>=1); // one per dimension if(rhs.type().id()!=ID_pointer) throw "do_java_new_array returns pointer"; typet object_type=rhs.type().subtype(); // build size expression exprt object_size=size_of_expr(object_type, ns); if(object_size.is_nil()) throw "do_java_new_array got nil object_size"; // we produce a malloc side-effect, which stays side_effect_exprt malloc_expr(ID_malloc); malloc_expr.copy_to_operands(object_size); malloc_expr.type()=pointer_typet(object_type); goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt(lhs, malloc_expr); t_n->source_location=location; // multi-dimensional? assert(ns.follow(object_type).id()==ID_struct); const struct_typet &struct_type=to_struct_type(ns.follow(object_type)); assert(struct_type.components().size()==3); // if it's an array, we need to set the length field dereference_exprt deref(lhs, object_type); member_exprt length(deref, struct_type.components()[1].get_name(), struct_type.components()[1].type()); goto_programt::targett t_s=dest.add_instruction(ASSIGN); t_s->code=code_assignt(length, rhs.op0()); t_s->source_location=location; // we also need to allocate space for the data member_exprt data(deref, struct_type.components()[2].get_name(), struct_type.components()[2].type()); side_effect_exprt data_cpp_new_expr(ID_cpp_new_array, data.type()); data_cpp_new_expr.set(ID_size, rhs.op0()); goto_programt::targett t_p=dest.add_instruction(ASSIGN); t_p->code=code_assignt(data, data_cpp_new_expr); t_p->source_location=location; // zero-initialize the data exprt zero_element=gen_zero(data.type().subtype()); codet array_set(ID_array_set); array_set.copy_to_operands(data, zero_element); goto_programt::targett t_d=dest.add_instruction(OTHER); t_d->code=array_set; t_d->source_location=location; if(rhs.operands().size()>=2) { // produce // for(int i=0; i<size; i++) tmp[i]=java_new(dim-1); // This will be converted recursively. goto_programt tmp; symbol_exprt tmp_i= new_tmp_symbol(index_type(), "index", tmp, location).symbol_expr(); code_fort for_loop; side_effect_exprt sub_java_new=rhs; sub_java_new.operands().erase(sub_java_new.operands().begin()); side_effect_exprt inc(ID_assign); inc.operands().resize(2); inc.op0()=tmp_i; inc.op1()=plus_exprt(tmp_i, gen_one(tmp_i.type())); dereference_exprt deref_expr(plus_exprt(data, tmp_i), data.type().subtype()); for_loop.init()=code_assignt(tmp_i, gen_zero(tmp_i.type())); for_loop.cond()=binary_relation_exprt(tmp_i, ID_lt, rhs.op0()); for_loop.iter()=inc; for_loop.body()=code_skipt(); for_loop.body()=code_assignt(deref_expr, sub_java_new); convert(for_loop, tmp); dest.destructive_append(tmp); } }
void goto_convertt::do_cpp_new( const exprt &lhs, const side_effect_exprt &rhs, goto_programt &dest) { if(lhs.is_nil()) throw "do_cpp_new without lhs is yet to be implemented"; // build size expression exprt object_size= static_cast<const exprt &>(rhs.find(ID_sizeof)); bool new_array=rhs.get(ID_statement)==ID_cpp_new_array; exprt count; if(new_array) { count=static_cast<const exprt &>(rhs.find(ID_size)); if(count.type()!=object_size.type()) count.make_typecast(object_size.type()); // might have side-effect clean_expr(count, dest); } exprt tmp_symbol_expr; // is this a placement new? if(rhs.operands().empty()) // no, "regular" one { // call __new or __new_array exprt new_symbol= ns.lookup(new_array?"__new_array":"__new").symbol_expr(); const code_typet &code_type= to_code_type(new_symbol.type()); const typet &return_type= code_type.return_type(); assert(code_type.parameters().size()==1 || code_type.parameters().size()==2); const symbolt &tmp_symbol= new_tmp_symbol(return_type, "new", dest, rhs.source_location()); tmp_symbol_expr=tmp_symbol.symbol_expr(); code_function_callt new_call; new_call.function()=new_symbol; if(new_array) new_call.arguments().push_back(count); new_call.arguments().push_back(object_size); new_call.set("#type", lhs.type().subtype()); new_call.lhs()=tmp_symbol_expr; new_call.add_source_location()=rhs.source_location(); convert(new_call, dest); } else if(rhs.operands().size()==1) { // call __placement_new exprt new_symbol= ns.lookup(new_array?"__placement_new_array":"__placement_new").symbol_expr(); const code_typet &code_type= to_code_type(new_symbol.type()); const typet &return_type=code_type.return_type(); assert(code_type.parameters().size()==2 || code_type.parameters().size()==3); const symbolt &tmp_symbol= new_tmp_symbol(return_type, "new", dest, rhs.source_location()); tmp_symbol_expr=tmp_symbol.symbol_expr(); code_function_callt new_call; new_call.function()=new_symbol; if(new_array) new_call.arguments().push_back(count); new_call.arguments().push_back(object_size); new_call.arguments().push_back(rhs.op0()); // memory location new_call.set("#type", lhs.type().subtype()); new_call.lhs()=tmp_symbol_expr; new_call.add_source_location()=rhs.source_location(); for(unsigned i=0; i<code_type.parameters().size(); i++) if(new_call.arguments()[i].type()!=code_type.parameters()[i].type()) new_call.arguments()[i].make_typecast(code_type.parameters()[i].type()); convert(new_call, dest); } else throw "cpp_new expected to have 0 or 1 operands"; goto_programt::targett t_n=dest.add_instruction(ASSIGN); t_n->code=code_assignt( lhs, typecast_exprt(tmp_symbol_expr, lhs.type())); t_n->source_location=rhs.find_source_location(); // grab initializer goto_programt tmp_initializer; cpp_new_initializer(lhs, rhs, tmp_initializer); dest.destructive_append(tmp_initializer); }
void goto_convertt::do_prob_uniform( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { const irep_idt &identifier=function.get(ID_identifier); // make it a side effect if there is an LHS if(arguments.size()!=2) { err_location(function); throw "`"+id2string(identifier)+"' expected to have two arguments"; } if(lhs.is_nil()) { err_location(function); throw "`"+id2string(identifier)+"' expected to have LHS"; } exprt rhs=side_effect_exprt("prob_uniform", lhs.type()); rhs.add_source_location()=function.source_location(); if(lhs.type().id()!=ID_unsignedbv && lhs.type().id()!=ID_signedbv) { err_location(function); throw "`"+id2string(identifier)+"' expected other type"; } if(arguments[0].type().id()!=lhs.type().id() || arguments[1].type().id()!=lhs.type().id()) { err_location(function); throw "`"+id2string(identifier)+"' expected operands to be of same type as LHS"; } if(!arguments[0].is_constant() || !arguments[1].is_constant()) { err_location(function); throw "`"+id2string(identifier)+"' expected operands to be constant literals"; } mp_integer lb, ub; if(to_integer(arguments[0], lb) || to_integer(arguments[1], ub)) { err_location(function); throw "error converting operands"; } if(lb > ub) { err_location(function); throw "expected lower bound to be smaller or equal to the upper bound"; } rhs.copy_to_operands(arguments[0], arguments[1]); code_assignt assignment(lhs, rhs); assignment.add_source_location()=function.source_location(); copy(assignment, ASSIGN, dest); }
void goto_convertt::do_prob_coin( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { const irep_idt &identifier=function.get(ID_identifier); // make it a side effect if there is an LHS if(arguments.size()!=2) { err_location(function); throw "`"+id2string(identifier)+"' expected to have two arguments"; } if(lhs.is_nil()) { err_location(function); throw "`"+id2string(identifier)+"' expected to have LHS"; } exprt rhs=side_effect_exprt("prob_coin", lhs.type()); rhs.add_source_location()=function.source_location(); if(lhs.type()!=bool_typet()) { err_location(function); throw "`"+id2string(identifier)+"' expected bool"; } if(arguments[0].type().id()!=ID_unsignedbv || arguments[0].id()!=ID_constant) { err_location(function); throw "`"+id2string(identifier)+"' expected first " "operand to be a constant literal of type unsigned long"; } mp_integer num, den; if(to_integer(arguments[0], num) || to_integer(arguments[1], den)) { err_location(function); throw "error converting operands"; } if(num-den > mp_integer(0)) { err_location(function); throw "probability has to be smaller than 1"; } if(den == mp_integer(0)) { err_location(function); throw "denominator may not be zero"; } rationalt numerator(num), denominator(den); rationalt prob = numerator / denominator; rhs.copy_to_operands(from_rational(prob)); code_assignt assignment(lhs, rhs); assignment.add_source_location()=function.source_location(); copy(assignment, ASSIGN, dest); }
void goto_convertt::do_function_call_symbol( const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest) { if(function.get_bool("#invalid_object")) return; // ignore // lookup symbol const irep_idt &identifier=function.get_identifier(); const symbolt *symbol; if(ns.lookup(identifier, symbol)) { err_location(function); throw "error: function `"+id2string(identifier)+"' not found"; } if(symbol->type.id()!=ID_code) { err_location(function); throw "error: function `"+id2string(identifier)+"' type mismatch: expected code"; } if(identifier==CPROVER_PREFIX "assume" || identifier=="__VERIFIER_assume") { if(arguments.size()!=1) { err_location(function); throw "`"+id2string(identifier)+"' expected to have one argument"; } goto_programt::targett t=dest.add_instruction(ASSUME); t->guard=arguments.front(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); // let's double-check the type of the argument if(t->guard.type().id()!=ID_bool) t->guard.make_typecast(bool_typet()); if(lhs.is_not_nil()) { err_location(function); throw id2string(identifier)+" expected not to have LHS"; } } else if(identifier=="__VERIFIER_error") { if(!arguments.empty()) { err_location(function); throw "`"+id2string(identifier)+"' expected to have no arguments"; } goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); if(lhs.is_not_nil()) { err_location(function); throw id2string(identifier)+" expected not to have LHS"; } } else if(has_prefix(id2string(identifier), "java::java.lang.AssertionError.<init>:")) { // insert function call anyway code_function_callt function_call; function_call.lhs()=lhs; function_call.function()=function; function_call.arguments()=arguments; function_call.add_source_location()=function.source_location(); copy(function_call, FUNCTION_CALL, dest); if(arguments.size()!=1 && arguments.size()!=2) { err_location(function); throw "`"+id2string(identifier)+"' expected to have one or two arguments"; } goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment("assertion at "+function.source_location().as_string()); } else if(identifier=="assert" && !ns.lookup(identifier).location.get_function().empty()) { if(arguments.size()!=1) { err_location(function); throw "`"+id2string(identifier)+"' expected to have one argument"; } goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=arguments.front(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment("assertion "+id2string(from_expr(ns, "", t->guard))); // let's double-check the type of the argument if(t->guard.type().id()!=ID_bool) t->guard.make_typecast(bool_typet()); if(lhs.is_not_nil()) { err_location(function); throw id2string(identifier)+" expected not to have LHS"; } } else if(identifier==CPROVER_PREFIX "assert") { if(arguments.size()!=2) { err_location(function); throw "`"+id2string(identifier)+"' expected to have two arguments"; } const irep_idt description= get_string_constant(arguments[1]); goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=arguments[0]; t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment(description); // let's double-check the type of the argument if(t->guard.type().id()!=ID_bool) t->guard.make_typecast(bool_typet()); if(lhs.is_not_nil()) { err_location(function); throw id2string(identifier)+" expected not to have LHS"; } } else if(identifier==CPROVER_PREFIX "printf") { do_printf(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "scanf") { do_scanf(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "input" || identifier=="__CPROVER::input") { do_input(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "output" || identifier=="__CPROVER::output") { do_output(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "atomic_begin" || identifier=="__CPROVER::atomic_begin" || identifier=="__VERIFIER_atomic_begin") { do_atomic_begin(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "atomic_end" || identifier=="__CPROVER::atomic_end" || identifier=="__VERIFIER_atomic_end") { do_atomic_end(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "prob_biased_coin") { do_prob_coin(lhs, function, arguments, dest); } else if(has_prefix(id2string(identifier), CPROVER_PREFIX "prob_uniform_")) { do_prob_uniform(lhs, function, arguments, dest); } else if(has_prefix(id2string(identifier), "nondet_") || has_prefix(id2string(identifier), "__VERIFIER_nondet_")) { // make it a side effect if there is an LHS if(lhs.is_nil()) return; exprt rhs; // We need to special-case for _Bool, which // can only be 0 or 1. if(lhs.type().id()==ID_c_bool) { rhs=side_effect_expr_nondett(bool_typet()); rhs.add_source_location()=function.source_location(); rhs.set(ID_C_identifier, identifier); rhs=typecast_exprt(rhs, lhs.type()); } else { rhs=side_effect_expr_nondett(lhs.type()); rhs.add_source_location()=function.source_location(); rhs.set(ID_C_identifier, identifier); } code_assignt assignment(lhs, rhs); assignment.add_source_location()=function.source_location(); copy(assignment, ASSIGN, dest); } else if(has_prefix(id2string(identifier), CPROVER_PREFIX "uninterpreted_")) { // make it a side effect if there is an LHS if(lhs.is_nil()) return; function_application_exprt rhs; rhs.type()=lhs.type(); rhs.add_source_location()=function.source_location(); rhs.function()=function; rhs.arguments()=arguments; code_assignt assignment(lhs, rhs); assignment.add_source_location()=function.source_location(); copy(assignment, ASSIGN, dest); } else if(has_prefix(id2string(identifier), CPROVER_PREFIX "array_set")) { do_array_set(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "array_equal" || identifier=="__CPROVER::array_equal") { do_array_equal(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "array_copy" || identifier=="__CPROVER::array_equal") { do_array_copy(lhs, function, arguments, dest); } else if(identifier=="printf") /* identifier=="fprintf" || identifier=="sprintf" || identifier=="snprintf") */ { do_printf(lhs, function, arguments, dest); } else if(identifier=="__assert_fail" || identifier=="_assert" || identifier=="__assert_c99" || identifier=="_wassert") { // __assert_fail is Linux // These take four arguments: // "expression", "file.c", line, __func__ // klibc has __assert_fail with 3 arguments // "expression", "file.c", line // MingW has // void _assert (const char*, const char*, int); // with three arguments: // "expression", "file.c", line // This has been seen in Solaris 11. // Signature: // void __assert_c99(const char *desc, const char *file, int line, const char *func); // _wassert is Windows. The arguments are // L"expression", L"file.c", line if(arguments.size()!=4 && arguments.size()!=3) { err_location(function); throw "`"+id2string(identifier)+"' expected to have four arguments"; } const irep_idt description= "assertion "+id2string(get_string_constant(arguments[0])); goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment(description); // we ignore any LHS } else if(identifier=="__assert_rtn" || identifier=="__assert") { // __assert_rtn has been seen on MacOS; // __assert is FreeBSD and Solaris 11. // These take four arguments: // __func__, "file.c", line, "expression" // On Solaris 11, it's three arguments: // "expression", "file", line irep_idt description; if(arguments.size()==4) { description= "assertion "+id2string(get_string_constant(arguments[3])); } else if(arguments.size()==3) { description= "assertion "+id2string(get_string_constant(arguments[1])); } else { err_location(function); throw "`"+id2string(identifier)+"' expected to have four arguments"; } goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment(description); // we ignore any LHS } else if(identifier=="__assert_func") { // __assert_func is newlib (used by, e.g., cygwin) // These take four arguments: // "file.c", line, __func__, "expression" if(arguments.size()!=4) { err_location(function); throw "`"+id2string(identifier)+"' expected to have four arguments"; } const irep_idt description= "assertion "+id2string(get_string_constant(arguments[3])); goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment(description); // we ignore any LHS } else if(identifier==CPROVER_PREFIX "fence") { if(arguments.size()<1) { err_location(function); throw "`"+id2string(identifier)+"' expected to have at least one argument"; } goto_programt::targett t=dest.add_instruction(OTHER); t->source_location=function.source_location(); t->code.set(ID_statement, ID_fence); forall_expr(it, arguments) { const irep_idt kind=get_string_constant(*it); t->code.set(kind, true); } } else if(identifier=="__builtin_prefetch")