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); }
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_symext::replace_nondet(exprt &expr) { if(expr.id()==ID_side_effect && expr.get(ID_statement)==ID_nondet) { exprt new_expr(ID_nondet_symbol, expr.type()); new_expr.set(ID_identifier, "symex::nondet"+std::to_string(nondet_count++)); new_expr.add_source_location()=expr.source_location(); expr.swap(new_expr); } else Forall_operands(it, expr) replace_nondet(*it); }
void goto_convertt::do_output( const exprt &lhs, const exprt &function, const exprt::operandst &arguments, goto_programt &dest) { codet output_code; output_code.set_statement(ID_output); output_code.operands()=arguments; output_code.add_source_location()=function.source_location(); if(arguments.size()<2) { err_location(function); throw "output takes at least two arguments"; } copy(output_code, OTHER, dest); }
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(); }
exprt c_typecheck_baset::do_initializer_list( const exprt &value, const typet &type, bool force_constant) { assert(value.id()==ID_initializer_list); const typet &full_type=follow(type); exprt result; if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { // start with zero everywhere result= zero_initializer( type, value.source_location(), *this, get_message_handler()); } else if(full_type.id()==ID_array) { if(to_array_type(full_type).size().is_nil()) { // start with empty array result=exprt(ID_array, full_type); result.add_source_location()=value.source_location(); } else { // start with zero everywhere result= zero_initializer( type, value.source_location(), *this, get_message_handler()); } // 6.7.9, 14: An array of character type may be initialized by a character // string literal or UTF-8 string literal, optionally enclosed in braces. if(value.operands().size()>=1 && value.op0().id()==ID_string_constant && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { if(value.operands().size()>1) { warning().source_location=value.find_source_location(); warning() << "ignoring excess initializers" << eom; } return do_initializer_rec(value.op0(), type, force_constant); } } else { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.operands().size()==1) return do_initializer_rec(value.op0(), type, force_constant); err_location(value); error() << "cannot initialize `" << to_string(full_type) << "' with an initializer list" << eom; throw 0; } designatort current_designator; designator_enter(type, current_designator); forall_operands(it, value) { do_designated_initializer( result, current_designator, *it, force_constant); // increase designator -- might go up increment_designator(current_designator); }
exprt c_typecheck_baset::do_initializer_rec( const exprt &value, const typet &type, bool force_constant) { const typet &full_type=follow(type); if(full_type.id()==ID_incomplete_struct) { err_location(value); error() << "type `" << to_string(full_type) << "' is still incomplete -- cannot initialize" << eom; throw 0; } if(value.id()==ID_initializer_list) return do_initializer_list(value, type, force_constant); if(value.id()==ID_array && value.get_bool(ID_C_string_constant) && full_type.id()==ID_array && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==value.type().subtype().get(ID_width)) { exprt tmp=value; // adjust char type tmp.type().subtype()=full_type.subtype(); Forall_operands(it, tmp) it->type()=full_type.subtype(); if(full_type.id()==ID_array && to_array_type(full_type).is_complete()) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); error() << "array size needs to be constant, got " << to_string(to_array_type(full_type).size()) << eom; throw 0; } if(array_size<0) { err_location(value); error() << "array size must not be negative" << eom; throw 0; } if(mp_integer(tmp.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp.operands().resize(integer2size_t(array_size)); tmp.type()=type; } else if(mp_integer(tmp.operands().size())<array_size) { // fill up tmp.type()=type; exprt zero= zero_initializer( full_type.subtype(), value.source_location(), *this, get_message_handler()); tmp.operands().resize(integer2size_t(array_size), zero); } } return tmp; } if(value.id()==ID_string_constant && full_type.id()==ID_array && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { // will go away, to be replaced by the above block string_constantt tmp1=to_string_constant(value); // adjust char type tmp1.type().subtype()=full_type.subtype(); exprt tmp2=tmp1.to_array_expr(); if(full_type.id()==ID_array && to_array_type(full_type).is_complete()) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); error() << "array size needs to be constant, got " << to_string(to_array_type(full_type).size()) << eom; throw 0; } if(array_size<0) { err_location(value); error() << "array size must not be negative" << eom; throw 0; } if(mp_integer(tmp2.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp2.operands().resize(integer2size_t(array_size)); tmp2.type()=type; } else if(mp_integer(tmp2.operands().size())<array_size) { // fill up tmp2.type()=type; exprt zero= zero_initializer( full_type.subtype(), value.source_location(), *this, get_message_handler()); tmp2.operands().resize(integer2size_t(array_size), zero); } } return tmp2; } if(full_type.id()==ID_array && to_array_type(full_type).size().is_nil()) { err_location(value); error() << "type `" << to_string(full_type) << "' cannot be initialized with `" << to_string(value) << "'" << eom; throw 0; } if(value.id()==ID_designated_initializer) { err_location(value); error() << "type `" << to_string(full_type) << "' cannot be initialized with designated initializer" << eom; throw 0; } exprt result=value; implicit_typecast(result, type); return result; }
void c_typecheck_baset::do_designated_initializer( exprt &result, designatort &designator, const exprt &value, bool force_constant) { assert(!designator.empty()); if(value.id()==ID_designated_initializer) { assert(value.operands().size()==1); designator= make_designator( designator.front().type, static_cast<const exprt &>(value.find(ID_designator))); assert(!designator.empty()); return do_designated_initializer( result, designator, value.op0(), force_constant); } exprt *dest=&result; // first phase: follow given designator for(size_t i=0; i<designator.size(); i++) { size_t index=designator[i].index; const typet &type=designator[i].type; const typet &full_type=follow(type); if(full_type.id()==ID_array || full_type.id()==ID_vector) { if(index>=dest->operands().size()) { if(full_type.id()==ID_array && (to_array_type(full_type).size().is_zero() || to_array_type(full_type).size().is_nil())) { // we are willing to grow an incomplete or zero-sized array exprt zero= zero_initializer( full_type.subtype(), value.source_location(), *this, get_message_handler()); dest->operands().resize(integer2size_t(index)+1, zero); // todo: adjust type! } else { err_location(value); error() << "array index designator " << index << " out of bounds (" << dest->operands().size() << ")" << eom; throw 0; } } dest=&(dest->operands()[integer2size_t(index)]); } else if(full_type.id()==ID_struct) { const struct_typet::componentst &components= to_struct_type(full_type).components(); if(index>=dest->operands().size()) { err_location(value); error() << "structure member designator " << index << " out of bounds (" << dest->operands().size() << ")" << eom; throw 0; } assert(index<components.size()); assert(components[index].type().id()!=ID_code && !components[index].get_is_padding()); dest=&(dest->operands()[index]); } else if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); const union_typet::componentst &components= union_type.components(); assert(index<components.size()); const union_typet::componentt &component=union_type.components()[index]; if(dest->id()==ID_union && dest->get(ID_component_name)==component.get_name()) { // Already right union component. We can initialize multiple submembers, // so do not overwrite this. } else { // Note that gcc issues a warning if the union component is switched. // Build a union expression from given component. union_exprt union_expr(type); union_expr.op()= zero_initializer( component.type(), value.source_location(), *this, get_message_handler()); union_expr.add_source_location()=value.source_location(); union_expr.set_component_name(component.get_name()); *dest=union_expr; } dest=&(dest->op0()); } else assert(false); } // second phase: assign value // for this, we may need to go down, adding to the designator while(true) { // see what type we have to initialize const typet &type=designator.back().subtype; const typet &full_type=follow(type); assert(full_type.id()!=ID_symbol); // do we initialize a scalar? if(full_type.id()!=ID_struct && full_type.id()!=ID_union && full_type.id()!=ID_array && full_type.id()!=ID_vector) { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.id()==ID_initializer_list && value.operands().size()==1) *dest=do_initializer_rec(value.op0(), type, force_constant); else *dest=do_initializer_rec(value, type, force_constant); assert(full_type==follow(dest->type())); return; // done } // union? The component in the zero initializer might // not be the first one. if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); const union_typet::componentst &components= union_type.components(); if(!components.empty()) { const union_typet::componentt &component= union_type.components().front(); union_exprt union_expr(type); union_expr.op()= zero_initializer( component.type(), value.source_location(), *this, get_message_handler()); union_expr.add_source_location()=value.source_location(); union_expr.set_component_name(component.get_name()); *dest=union_expr; } } // see what initializer we are given if(value.id()==ID_initializer_list) { *dest=do_initializer_rec(value, type, force_constant); return; // done } else if(value.id()==ID_string_constant) { // We stop for initializers that are string-constants, // which are like arrays. We only do so if we are to // initialize an array of scalars. if(full_type.id()==ID_array && (follow(full_type.subtype()).id()==ID_signedbv || follow(full_type.subtype()).id()==ID_unsignedbv)) { *dest=do_initializer_rec(value, type, force_constant); return; // done } } else if(follow(value.type())==full_type) { // a struct/union/vector can be initialized directly with // an expression of the right type. This doesn't // work with arrays, unfortunately. if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { *dest=value; return; // done } } assert(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_array || full_type.id()==ID_vector); // we are initializing a compound type, and enter it! // this may change the type, full_type might not be valid anymore const typet dest_type=full_type; designator_enter(type, designator); if(dest->operands().empty()) { err_location(value); error() << "cannot initialize type `" << to_string(dest_type) << "' using value `" << to_string(value) << "'" << eom; throw 0; } dest=&(dest->op0()); // we run into another loop iteration } }
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_scanf( 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 "scanf") { if(arguments.size()<1) { err_location(function); error() << "scanf takes at least one argument" << eom; throw 0; } irep_idt format_string; if(!get_string_constant(arguments[0], format_string)) { // use our model format_token_listt token_list=parse_format_string(id2string(format_string)); std::size_t argument_number=1; for(const auto & t : token_list) { typet type=get_type(t); if(type.is_not_nil()) { if(argument_number<arguments.size()) { exprt ptr= typecast_exprt(arguments[argument_number], pointer_type(type)); argument_number++; // make it nondet for now exprt lhs=dereference_exprt(ptr, type); exprt rhs=side_effect_expr_nondett(type); code_assignt assign(lhs, rhs); assign.add_source_location()=function.source_location(); copy(assign, ASSIGN, dest); } } } } else { // we'll just do nothing 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); } } else assert(false); }
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_symext::dereference_rec( exprt &expr, statet &state, guardt &guard, const bool write) { if(expr.id()==ID_dereference) { if(expr.operands().size()!=1) throw "dereference takes one operand"; exprt tmp1; tmp1.swap(expr.op0()); // first make sure there are no dereferences in there dereference_rec(tmp1, state, guard, false); // we need to set up some elaborate call-backs symex_dereference_statet symex_dereference_state(*this, state); value_set_dereferencet dereference( ns, new_symbol_table, options, symex_dereference_state, language_mode); // std::cout << "**** " << from_expr(ns, "", tmp1) << std::endl; exprt tmp2=dereference.dereference( tmp1, guard, write?value_set_dereferencet::WRITE:value_set_dereferencet::READ); //std::cout << "**** " << from_expr(ns, "", tmp2) << std::endl; expr.swap(tmp2); // this may yield a new auto-object trigger_auto_object(expr, state); } else if(expr.id()==ID_index && to_index_expr(expr).array().id()==ID_member && to_array_type(ns.follow(to_index_expr(expr).array().type())). size().is_zero()) { // This is an expression of the form x.a[i], // where a is a zero-sized array. This gets // re-written into *(&x.a+i) index_exprt index_expr=to_index_expr(expr); address_of_exprt address_of_expr(index_expr.array()); address_of_expr.type()=pointer_typet(expr.type()); dereference_exprt tmp; tmp.pointer()=plus_exprt(address_of_expr, index_expr.index()); tmp.type()=expr.type(); tmp.add_source_location()=expr.source_location(); // recursive call dereference_rec(tmp, state, guard, write); expr.swap(tmp); } else if(expr.id()==ID_index && to_index_expr(expr).array().type().id()==ID_pointer) { // old stuff, will go away assert(false); } else if(expr.id()==ID_address_of) { address_of_exprt &address_of_expr=to_address_of_expr(expr); exprt &object=address_of_expr.object(); const typet &expr_type=ns.follow(expr.type()); expr=address_arithmetic(object, state, guard, expr_type.subtype().id()==ID_array); } else if(expr.id()==ID_typecast) { exprt &tc_op=to_typecast_expr(expr).op(); // turn &array into &array[0] when casting to pointer-to-element-type if(tc_op.id()==ID_address_of && to_address_of_expr(tc_op).object().type().id()==ID_array && base_type_eq( expr.type(), pointer_typet(to_address_of_expr(tc_op).object().type().subtype()), ns)) { expr= address_of_exprt( index_exprt( to_address_of_expr(tc_op).object(), from_integer(0, index_type()))); dereference_rec(expr, state, guard, write); } else { dereference_rec(tc_op, state, guard, write); } } else { Forall_operands(it, expr) dereference_rec(*it, state, guard, write); } }