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_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 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=new_tmp_symbol(); tmp_symbol.type=code_type.return_type(); tmp_symbol.location=function_call.location(); 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_convertt::convert_msc_leave( const codet &code, goto_programt &dest) { if(!targets.leave_set) { error().source_location=code.find_source_location(); error() << "leave without target" << eom; throw 0; } // 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 goto_convertt::convert_java_try_catch( const codet &code, goto_programt &dest) { assert(!code.operands().empty()); // add the CATCH instruction to 'dest' goto_programt::targett catch_instruction=dest.add_instruction(); catch_instruction->make_catch(); catch_instruction->code.set_statement(ID_catch); catch_instruction->source_location=code.source_location(); catch_instruction->function=code.source_location().get_function(); // the CATCH instruction is annotated with a list of exception IDs const irept exceptions=code.op0().find(ID_exception_list); if(exceptions.is_not_nil()) { irept::subt exceptions_sub=exceptions.get_sub(); irept::subt &exception_list= catch_instruction->code.add(ID_exception_list).get_sub(); exception_list.resize(exceptions_sub.size()); for(size_t i=0; i<exceptions_sub.size(); ++i) exception_list[i].id(exceptions_sub[i].id()); } // the CATCH instruction is also annotated with a list of handle labels const irept handlers=code.op0().find(ID_label); if(handlers.is_not_nil()) { irept::subt handlers_sub=handlers.get_sub(); irept::subt &handlers_list= catch_instruction->code.add(ID_label).get_sub(); handlers_list.resize(handlers_sub.size()); for(size_t i=0; i<handlers_sub.size(); ++i) handlers_list[i].id(handlers_sub[i].id()); } // the CATCH instruction may also signal a handler if(code.op0().has_operands()) { catch_instruction->code.get_sub().resize(1); catch_instruction->code.get_sub()[0]=code.op0().op0(); } // add a SKIP target for the end of everything goto_programt end; goto_programt::targett end_target=end.add_instruction(); end_target->make_skip(); end_target->source_location=code.source_location(); end_target->function=code.source_location().get_function(); // add the end-target dest.destructive_append(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_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_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 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 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(); }
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 string_instrumentationt::invalidate_buffer( goto_programt &dest, goto_programt::const_targett target, const exprt &buffer, const typet &buf_type, const mp_integer &limit) { irep_idt cntr_id="string_instrumentation::$counter"; if(context.symbols.find(cntr_id)==context.symbols.end()) { symbolt new_symbol; new_symbol.base_name="$counter"; new_symbol.pretty_name=new_symbol.base_name; new_symbol.name=cntr_id; new_symbol.mode="C"; new_symbol.type=uint_type(); new_symbol.is_statevar=true; new_symbol.lvalue=true; new_symbol.static_lifetime=true; context.move(new_symbol); } const symbolt &cntr_sym=ns.lookup(cntr_id); // create a loop that runs over the buffer // and invalidates every element goto_programt::targett init=dest.add_instruction(ASSIGN); init->location=target->location; init->code=code_assignt(symbol_expr(cntr_sym), gen_zero(cntr_sym.type)); goto_programt::targett check=dest.add_instruction(); check->location=target->location; goto_programt::targett invalidate=dest.add_instruction(ASSIGN); invalidate->location=target->location; goto_programt::targett increment=dest.add_instruction(ASSIGN); increment->location=target->location; exprt plus("+", uint_type()); plus.copy_to_operands(symbol_expr(cntr_sym)); plus.copy_to_operands(gen_one(uint_type())); increment->code=code_assignt(symbol_expr(cntr_sym), plus); goto_programt::targett back=dest.add_instruction(); back->location=target->location; back->make_goto(check); back->guard=true_exprt(); goto_programt::targett exit=dest.add_instruction(); exit->location=target->location; exit->make_skip(); exprt cnt_bs, bufp; if(buf_type.id()=="pointer") bufp = buffer; else { index_exprt index; index.array()=buffer; index.index()=gen_zero(uint_type()); index.type()=buf_type.subtype(); bufp = address_of_exprt(index); } exprt deref("dereference", buf_type.subtype()); exprt b_plus_i("+", bufp.type()); b_plus_i.copy_to_operands(bufp); b_plus_i.copy_to_operands(symbol_expr(cntr_sym)); deref.copy_to_operands(b_plus_i); check->make_goto(exit); if(limit==0) check->guard= binary_relation_exprt(symbol_expr(cntr_sym), ">=", buffer_size(bufp)); else check->guard= binary_relation_exprt(symbol_expr(cntr_sym), ">", from_integer(limit, uint_type())); exprt nondet=side_effect_expr_nondett(buf_type.subtype()); invalidate->code=code_assignt(deref, nondet); }
void goto_inlinet::parameter_assignments( const source_locationt &source_location, const irep_idt &function_name, const code_typet &code_type, const exprt::operandst &arguments, goto_programt &dest) { // iterates over the operands exprt::operandst::const_iterator it1=arguments.begin(); const code_typet::parameterst ¶meter_types= code_type.parameters(); // iterates over the types of the parameters for(code_typet::parameterst::const_iterator it2=parameter_types.begin(); it2!=parameter_types.end(); it2++) { const code_typet::parametert ¶meter=*it2; // this is the type the n-th argument should be const typet &par_type=ns.follow(parameter.type()); 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 decl=dest.add_instruction(); decl->make_decl(); decl->code=code_declt(symbol.symbol_expr()); decl->code.add_source_location()=source_location; decl->source_location=source_location; decl->function=function_name; } // this is the actual parameter exprt actual; // if you run out of actual arguments there was a mismatch if(it1==arguments.end()) { warning().source_location=source_location; warning() << "call to `" << function_name << "': " << "not enough arguments, " << "inserting non-deterministic value" << eom; actual=side_effect_expr_nondett(par_type); } else actual=*it1; // nil means "don't assign" if(actual.is_nil()) { } else { // it should be the same exact type as the parameter, // subject to some exceptions if(!base_type_eq(par_type, actual.type(), ns)) { const typet &f_partype = ns.follow(par_type); const typet &f_acttype = ns.follow(actual.type()); // we are willing to do some conversion if((f_partype.id()==ID_pointer && f_acttype.id()==ID_pointer) || (f_partype.id()==ID_pointer && f_acttype.id()==ID_array && f_partype.subtype()==f_acttype.subtype())) { actual.make_typecast(par_type); } else if((f_partype.id()==ID_signedbv || f_partype.id()==ID_unsignedbv || f_partype.id()==ID_bool) && (f_acttype.id()==ID_signedbv || f_acttype.id()==ID_unsignedbv || f_acttype.id()==ID_bool)) { actual.make_typecast(par_type); } else { error().source_location=actual.find_source_location(); error() << "function call: argument `" << identifier << "' type mismatch: argument is `" // << from_type(ns, identifier, actual.type()) << actual.type().pretty() << "', parameter is `" << from_type(ns, identifier, par_type) << "'" << eom; throw 0; } } // adds an assignment of the actual parameter to the formal parameter code_assignt assignment(symbol_exprt(identifier, par_type), actual); assignment.add_source_location()=source_location; dest.add_instruction(ASSIGN); dest.instructions.back().source_location=source_location; dest.instructions.back().code.swap(assignment); dest.instructions.back().function=function_name; } if(it1!=arguments.end()) ++it1; } if(it1!=arguments.end()) { // too many arguments -- we just ignore that, no harm done } }
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")
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 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 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();
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 string_instrumentationt::do_format_string_write( goto_programt &dest, goto_programt::const_targett target, const code_function_callt::argumentst &arguments, unsigned format_string_inx, unsigned argument_start_inx, const std::string &function_name) { const exprt &format_arg = arguments[format_string_inx]; if(format_arg.id()=="address_of" && format_arg.op0().id()=="index" && format_arg.op0().op0().id()==ID_string_constant) // constant format { format_token_listt token_list; parse_format_string(format_arg.op0().op0(), token_list); unsigned args=0; for(format_token_listt::const_iterator it=token_list.begin(); it!=token_list.end(); it++) { if(find(it->flags.begin(), it->flags.end(), format_tokent::ASTERISK)!= it->flags.end()) continue; // asterisk means `ignore this' switch(it->type) { case format_tokent::STRING: { const exprt &argument=arguments[argument_start_inx+args]; const typet &arg_type=ns.follow(argument.type()); goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("format string buffer overflow in "); comment += function_name; assertion->location.set("comment", comment); if(it->field_width!=0) { exprt fwidth = from_integer(it->field_width, uint_type()); exprt fw_1("+", uint_type()); exprt one = gen_one(uint_type()); fw_1.move_to_operands(fwidth); fw_1.move_to_operands(one); // +1 for 0-char exprt fw_lt_bs; if(arg_type.id()=="pointer") fw_lt_bs=binary_relation_exprt(fw_1, "<=", buffer_size(argument)); else { index_exprt index; index.array()=argument; index.index()=gen_zero(uint_type()); address_of_exprt aof(index); fw_lt_bs=binary_relation_exprt(fw_1, "<=", buffer_size(aof)); } assertion->make_assertion(fw_lt_bs); } else { // this is a possible overflow. assertion->make_assertion(false_exprt()); } // now kill the contents invalidate_buffer(dest, target, argument, arg_type, it->field_width); args++; break; } case format_tokent::TEXT: case format_tokent::UNKNOWN: { // nothing break; } default: // everything else { const exprt &argument=arguments[argument_start_inx+args]; const typet &arg_type=ns.follow(argument.type()); goto_programt::targett assignment=dest.add_instruction(ASSIGN); assignment->location=target->location; exprt lhs("dereference", arg_type.subtype()); lhs.copy_to_operands(argument); exprt rhs=side_effect_expr_nondett(lhs.type()); rhs.location()=target->location; assignment->code=code_assignt(lhs, rhs); args++; break; } } } } else // non-const format string { for(unsigned i=argument_start_inx; i<arguments.size(); i++) { const typet &arg_type=ns.follow(arguments[i].type()); // Note: is_string_type() is a `good guess' here. Actually // any of the pointers could point into an array. But it // would suck if we had to invalidate all variables. // Luckily this case isn't needed too often. if(is_string_type(arg_type)) { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("format string buffer overflow in "); comment += function_name; assertion->location.set("comment", comment); // as we don't know any field width for the %s that // should be here during runtime, we just report a // possibly false positive assertion->make_assertion(false_exprt()); invalidate_buffer(dest, target, arguments[i], arg_type, 0); } else { goto_programt::targett assignment = dest.add_instruction(ASSIGN); assignment->location=target->location; exprt lhs("dereference", arg_type.subtype()); lhs.copy_to_operands(arguments[i]); exprt rhs=side_effect_expr_nondett(lhs.type()); rhs.location()=target->location; assignment->code=code_assignt(lhs, rhs); } } } }
void string_instrumentationt::do_format_string_read( goto_programt &dest, goto_programt::const_targett target, const code_function_callt::argumentst &arguments, unsigned format_string_inx, unsigned argument_start_inx, const std::string &function_name) { const exprt &format_arg = arguments[format_string_inx]; if(format_arg.id()=="address_of" && format_arg.op0().id()=="index" && format_arg.op0().op0().id()==ID_string_constant) { format_token_listt token_list; parse_format_string(format_arg.op0().op0(), token_list); unsigned args=0; for(format_token_listt::const_iterator it=token_list.begin(); it!=token_list.end(); it++) { if(it->type==format_tokent::STRING) { const exprt &arg = arguments[argument_start_inx+args]; const typet &arg_type = ns.follow(arg.type()); if(arg.id()!=ID_string_constant) // we don't need to check constants { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("zero-termination of string argument of "); comment += function_name; assertion->location.set("comment", comment); exprt temp(arg); if(arg_type.id()!="pointer") { index_exprt index; index.array()=temp; index.index()=gen_zero(uint_type()); index.type()=arg_type.subtype(); temp=address_of_exprt(index); } assertion->make_assertion(is_zero_string(temp)); } } if(it->type!=format_tokent::TEXT && it->type!=format_tokent::UNKNOWN) args++; if(find(it->flags.begin(), it->flags.end(), format_tokent::ASTERISK)!= it->flags.end()) args++; // just eat the additional argument } } else // non-const format string { goto_programt::targett format_ass=dest.add_instruction(); format_ass->make_assertion(is_zero_string(arguments[1])); format_ass->location=target->location; format_ass->location.set("property", "string"); std::string comment("zero-termination of format string of "); comment += function_name; format_ass->location.set("comment", comment); for(unsigned i=2; i<arguments.size(); i++) { const exprt &arg = arguments[i]; const typet &arg_type=ns.follow(arguments[i].type()); if(arguments[i].id()!=ID_string_constant && is_string_type(arg_type)) { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("zero-termination of string argument of "); comment += function_name; assertion->location.set("comment", comment); exprt temp(arg); if(arg_type.id()!="pointer") { index_exprt index; index.array()=temp; index.index()=gen_zero(uint_type()); index.type()=arg_type.subtype(); temp=address_of_exprt(index); } assertion->make_assertion(is_zero_string(temp)); } } } }
void convert(const xmlt &xml, goto_programt &goto_program) { goto_program.clear(); goto_programt::instructionst &instructions = goto_program.instructions; xmlt::elementst::const_iterator it = xml.elements.begin(); for(; it != xml.elements.end(); it++) { goto_programt::targett inst = goto_program.add_instruction(); inst->targets.clear(); if(it->name=="goto") { inst->type = GOTO; } else if(it->name=="assume") { inst->type = ASSUME; } else if(it->name=="assert") { inst->type = ASSERT; } else if(it->name=="skip") { inst->type = SKIP; } else if(it->name=="end_function") { inst->type = END_FUNCTION; } else if(it->name=="location") { inst->type = LOCATION; } else if(it->name=="dead") { inst->type = DEAD; } else if(it->name=="atomic_begin") { inst->type = ATOMIC_BEGIN; } else if(it->name=="atomic_end") { inst->type = ATOMIC_END; } else if(it->name=="return") { inst->make_return(); } else if(it->name=="instruction") // OTHER { inst->make_other(); } else if(it->name=="assign") { inst->make_other(); inst->type=ASSIGN; } else if(it->name=="functioncall") { inst->make_other(); inst->type=FUNCTION_CALL; } else if(it->name=="thread_start") { inst->type = START_THREAD; } else if(it->name=="thread_end") { inst->type = END_THREAD; } else { std::cout << "Unknown instruction type encountered (" << it->name << ")"; std::cout << std::endl; return; } xmlt::elementst::const_iterator eit = it->elements.begin(); for(; eit != it->elements.end(); eit++) { if(eit->name=="location") { convert(*eit, inst->location); } else if(eit->name=="variables") { } else if(eit->name=="labels") { xmlt::elementst::const_iterator lit = eit->elements.begin(); for(; lit != eit->elements.end(); lit++) { if(lit->name=="label") { std::string ls = lit->get_attribute("name"); inst->labels.push_back(ls); } else { std::cout << "Unknown node in labels section." << std::endl; return; } } } else if(eit->name=="guard") { inst->guard.remove("value"); convert(*eit, inst->guard); } else if(eit->name=="code") { convert(*eit, inst->code); } else if(eit->name=="targets") { // Don't do anything here, we'll need a second run for that } else if(eit->name=="comment") { inst->location.set("comment", eit->data); } else if(eit->name=="function") { inst->function = eit->data; } } } // assign line numbers goto_program.compute_location_numbers(); // second run, for targets goto_programt::targett ins_it = instructions.begin(); it = xml.elements.begin(); for(; it != xml.elements.end() && ins_it!=instructions.end(); it++) { xmlt::elementst::const_iterator eit = it->elements.begin(); for(; eit != it->elements.end(); eit++) { if(eit->name=="targets") { xmlt::elementst::const_iterator tit = eit->elements.begin(); for(; tit != eit->elements.end(); tit++) { if(tit->name=="target") { goto_programt::targett tins = find_instruction(xml, instructions, tit->data); if(tins != instructions.end()) { // Here we insert the iterators that somehow seem // to be strange afterwards (see line 87) ins_it->targets.push_back(tins); } else { std::cout << "Warning: instruction not found when " "resolving target links." << std::endl; } } else { std::cout << "Unknown node in targets section." << std::endl; return; } } } } ins_it++; } // resolve links goto_program.update(); // std::cout << "TNI: " << goto_program.target_numbers.size() << std::endl; }
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); } }