void goto_convertt::do_printf( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { const irep_idt &f_id=function.get(ID_identifier); if(f_id==CPROVER_PREFIX "printf" || f_id=="printf") { typet return_type=static_cast<const typet &>(function.type().find(ID_return_type)); side_effect_exprt printf_code(ID_printf, return_type); printf_code.operands()=arguments; printf_code.add_source_location()=function.source_location(); if(lhs.is_not_nil()) { code_assignt assignment(lhs, printf_code); assignment.add_source_location()=function.source_location(); copy(assignment, ASSIGN, dest); } else { printf_code.id(ID_code); printf_code.type()=typet(ID_code); copy(to_code(printf_code), OTHER, dest); } } else assert(false); }
typet struct_union_typet::component_type( const irep_idt &component_name) const { const exprt c=get_component(component_name); assert(c.is_not_nil()); return c.type(); }
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_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_convertt::do_array_equal( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { if(arguments.size()!=2) { err_location(function); throw "array_equal expects two arguments"; } const typet &arg0_type=ns.follow(arguments[0].type()); const typet &arg1_type=ns.follow(arguments[1].type()); if(arg0_type.id()!=ID_pointer || arg1_type.id()!=ID_pointer) { err_location(function); throw "array_equal expects pointer arguments"; } if(lhs.is_not_nil()) { code_assignt assignment; // add dereferencing here dereference_exprt lhs_array, rhs_array; lhs_array.op0()=arguments[0]; rhs_array.op0()=arguments[1]; lhs_array.type()=arg0_type.subtype(); rhs_array.type()=arg1_type.subtype(); assignment.lhs()=lhs; assignment.rhs()=binary_exprt( lhs_array, ID_array_equal, rhs_array, lhs.type()); convert(assignment, 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")
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 0 if(lhs.is_not_nil()) { if(it->code.operands().size()!=1) { error().source_location=it->code.find_source_location(); str << "return expects one operand!"; warning_msg(); continue; } goto_programt tmp; goto_programt::targett assignment=tmp.add_instruction(ASSIGN); code_assignt code_assign(lhs, it->code.op0()); // 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()); assignment->code=code_assign; assignment->source_location=it->source_location; assignment->function=it->function; if(constrain.is_not_nil() && !constrain.is_true()) { codet constrain(ID_bp_constrain); constrain.reserve_operands(2); constrain.move_to_operands(assignment->code); constrain.copy_to_operands(constrain); } dest.insert_before_swap(it, *assignment); it++; } else if(!it->code.operands().empty()) { goto_programt tmp; goto_programt::targett expression=tmp.add_instruction(OTHER); expression->code=codet(ID_expression); expression->code.move_to_operands(it->code.op0()); expression->source_location=it->source_location; expression->function=it->function; dest.insert_before_swap(it, *expression); it++; } it->make_goto(--dest.instructions.end()); #else if(lhs.is_not_nil()) { if(it->code.operands().size()!=1) { warning().source_location=it->code.find_source_location(); warning() << "return expects one operand!\n" << it->code.pretty() << eom; continue; } code_assignt code_assign(lhs, it->code.op0()); // 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()); if(constrain.is_not_nil() && !constrain.is_true()) { codet constrain(ID_bp_constrain); constrain.reserve_operands(2); constrain.move_to_operands(code_assign); constrain.copy_to_operands(constrain); it->code=constrain; it->type=OTHER; } else { it->code=code_assign; it->type=ASSIGN; } it++; } else if(!it->code.operands().empty()) { codet expression(ID_expression); expression.move_to_operands(it->code.op0()); it->code=expression; it->type=OTHER; it++; } #endif } } }