void c_typecheck_baset::designator_enter( const typet &type, designatort &designator) { designatort::entryt entry; entry.type=type; assert(entry.type.id()!=ID_symbol); if(entry.type.id()==ID_struct) { entry.size=to_struct_type(entry.type).components().size(); if(entry.size!=0) entry.subtype=to_struct_type(entry.type).components().front().type(); else entry.subtype.make_nil(); } else if(entry.type.id()==ID_union) { if(to_union_type(entry.type).components().empty()) { entry.size=0; entry.subtype.make_nil(); } else { entry.size=1; entry.subtype=to_union_type(entry.type).components().front().type(); } } else if(entry.type.id()==ID_array) { mp_integer array_size; if(to_integer(to_array_type(entry.type).size(), array_size)) { err_location(to_array_type(entry.type).size()); str << "array has non-constant size `" << to_string(to_array_type(entry.type).size()) << "'"; throw 0; } entry.size=integer2long(array_size); entry.subtype=entry.type.subtype(); } else if(entry.type.id()==ID_incomplete_array) { entry.size=0; entry.subtype=entry.type.subtype(); } else assert(false); designator.push_entry(entry); }
void linkingt::duplicate_type_symbol( symbolt &old_symbol, symbolt &new_symbol, bool &move) { // check if it is really the same // -- use base_type_eq, not linking_type_eq // first make sure that base_type_eq can soundly use ns/main_context only find_symbols_sett symbols; find_type_and_expr_symbols(new_symbol.type, symbols); bool ok=true; for(find_symbols_sett::const_iterator s_it=symbols.begin(); ok && s_it!=symbols.end(); s_it++) ok&=completed.find(*s_it)!=completed.end(); if(ok && base_type_eq(old_symbol.type, new_symbol.type, ns)) { move=false; return; } // they are different if(old_symbol.type.id()==ID_incomplete_struct && new_symbol.type.id()==ID_struct) { if(move) old_symbol.type=new_symbol.type; // store new type move=false; } else if(old_symbol.type.id()==ID_struct && new_symbol.type.id()==ID_incomplete_struct) { // ignore move=false; } else if(ns.follow(old_symbol.type).id()==ID_array && ns.follow(new_symbol.type).id()==ID_array) { if(move && to_array_type(ns.follow(old_symbol.type)).size().is_nil() && to_array_type(ns.follow(new_symbol.type)).size().is_not_nil()) old_symbol.type=new_symbol.type; // store new type move=false; } else { if(move) rename_type_symbol(new_symbol); move=true; } }
smt_astt array_sym_smt_ast::select(smt_convt *ctx, const expr2tc &idx) const { const array_type2t &array_type = to_array_type(sort->get_tuple_type()); const struct_union_data &data = ctx->get_type_def(array_type.subtype); smt_sortt result_sort = ctx->convert_sort(array_type.subtype); std::string name = ctx->mk_fresh_name("tuple_array_select::") + "."; tuple_sym_smt_astt result = new tuple_sym_smt_ast(ctx, result_sort, name); unsigned int i = 0; for(auto const &it : data.members) { type2tc arrtype( new array_type2t(it, array_type.array_size, array_type.size_is_infinite)); smt_astt result_field = result->project(ctx, i); smt_astt sub_array = project(ctx, i); smt_astt selected = sub_array->select(ctx, idx); ctx->assert_ast(result_field->eq(ctx, selected)); i++; } return result; }
void c_typecheck_baset::do_initializer( exprt &initializer, const typet &type, bool force_constant) { exprt result=do_initializer_rec(initializer, type, force_constant); if(type.id()==ID_array) { // any arrays must have a size const typet &result_type=follow(result.type()); assert(result_type.id()==ID_array && to_array_type(result_type).size().is_not_nil()); // we don't allow initialisation with symbols of array type if(result.id()!=ID_array) { err_location(result); error() << "invalid array initializer " << to_string(result) << eom; throw 0; } } initializer=result; }
bool c_typecheck_baset::is_complete_type(const typet &type) const { if(type.id()==ID_incomplete_struct || type.id()==ID_incomplete_union) return false; else if(type.id()==ID_array) { if(to_array_type(type).size().is_nil()) return false; return is_complete_type(type.subtype()); } else if(type.id()==ID_struct || type.id()==ID_union) { const struct_union_typet::componentst &components= to_struct_union_type(type).components(); for(struct_union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) if(!is_complete_type(it->type())) return false; } else if(type.id()==ID_vector) return is_complete_type(type.subtype()); else if(type.id()==ID_symbol) return is_complete_type(follow(type)); return true; }
smt_astt array_sym_smt_ast::eq(smt_convt *ctx, smt_astt other) const { // We have two tuple_sym_smt_asts and need to create a boolean ast representing // their equality: iterate over all their members, compute an equality for // each of them, and then combine that into a final ast. tuple_sym_smt_astt ta = this; tuple_sym_smt_astt tb = to_tuple_sym_ast(other); assert(is_array_type(sort->get_tuple_type())); const array_type2t &arrtype = to_array_type(sort->get_tuple_type()); const struct_union_data &data = ctx->get_type_def(arrtype.subtype); smt_convt::ast_vec eqs; eqs.reserve(data.members.size()); // Iterate through each field and encode an equality. unsigned int i = 0; for(auto const &it : data.members) { type2tc tmparrtype( new array_type2t(it, arrtype.array_size, arrtype.size_is_infinite)); smt_astt side1 = ta->project(ctx, i); smt_astt side2 = tb->project(ctx, i); eqs.push_back(side1->eq(ctx, side2)); i++; } // Create an ast representing the fact that all the members are equal. return ctx->make_n_ary(ctx, &smt_convt::mk_and, eqs); }
void boolbvt::convert_with( const typet &type, const exprt &op1, const exprt &op2, const bvt &prev_bv, bvt &next_bv) { // we only do that on arrays, bitvectors, structs, and unions next_bv.resize(prev_bv.size()); if(type.id()==ID_array) return convert_with_array(to_array_type(type), op1, op2, prev_bv, next_bv); else if(type.id()==ID_bv || type.id()==ID_unsignedbv || type.id()==ID_signedbv) return convert_with_bv(type, op1, op2, prev_bv, next_bv); else if(type.id()==ID_struct) return convert_with_struct(to_struct_type(type), op1, op2, prev_bv, next_bv); else if(type.id()==ID_union) return convert_with_union(to_union_type(type), op1, op2, prev_bv, next_bv); else if(type.id()==ID_symbol) return convert_with(ns.follow(type), op1, op2, prev_bv, next_bv); error().source_location=type.source_location(); error() << "unexpected with type: " << type.id(); throw 0; }
void boolbvt::convert_index( const exprt &array, const mp_integer &index, bvt &bv) { const array_typet &array_type= to_array_type(ns.follow(array.type())); unsigned width=boolbv_width(array_type.subtype()); if(width==0) return conversion_failed(array, bv); bv.resize(width); const bvt &tmp=convert_bv(array); // recursive call mp_integer offset=index*width; if(offset>=0 && offset+width<=mp_integer(tmp.size())) { // in bounds for(unsigned i=0; i<width; i++) bv[i]=tmp[integer2long(offset+i)]; } else { // out of bounds for(unsigned i=0; i<width; i++) bv[i]=prop.new_variable(); } }
smt_astt array_sym_smt_ast::project(smt_convt *ctx, unsigned int idx) const { // Pull struct type out, access the relevent element, then wrap it in an // array type. const array_type2t &arr = to_array_type(sort->get_tuple_type()); const struct_union_data &data = ctx->get_type_def(arr.subtype); assert( idx < data.members.size() && "Out-of-bounds tuple-array element accessed"); const std::string &fieldname = data.member_names[idx].as_string(); std::string sym_name = name + fieldname; const type2tc &restype = data.members[idx]; type2tc new_arr_type( new array_type2t(restype, arr.array_size, arr.size_is_infinite)); smt_sortt s = ctx->convert_sort(new_arr_type); if(is_tuple_ast_type(restype) || is_tuple_array_ast_type(restype)) { // This is a struct within a struct, so just generate the name prefix of // the internal struct being projected. sym_name = sym_name + "."; return new array_sym_smt_ast(ctx, s, sym_name); } // This is a normal variable, so create a normal symbol of its name. return ctx->mk_smt_symbol(sym_name, s); }
void base_type_rec( typet &type, const namespacet &ns, std::set<irep_idt> &symb) { if(type.id()==ID_symbol || type.id()==ID_c_enum_tag || type.id()==ID_struct_tag || type.id()==ID_union_tag) { const symbolt *symbol; if(!ns.lookup(type.get(ID_identifier), symbol) && symbol->is_type && !symbol->type.is_nil()) { type=symbol->type; base_type_rec(type, ns, symb); // recursive call return; } } else if(type.id()==ID_array) { base_type_rec(to_array_type(type).subtype(), ns, symb); } else if(type.id()==ID_struct || type.id()==ID_union) { struct_union_typet::componentst &components= to_struct_union_type(type).components(); for(auto &component : components) base_type_rec(component.type(), ns, symb); } else if(type.id()==ID_pointer) { typet &subtype=to_pointer_type(type).subtype(); // we need to avoid running into an infinite loop if(subtype.id()==ID_symbol || subtype.id()==ID_c_enum_tag || subtype.id()==ID_struct_tag || subtype.id()==ID_union_tag) { const irep_idt &id=subtype.get(ID_identifier); if(symb.find(id)!=symb.end()) return; symb.insert(id); base_type_rec(subtype, ns, symb); symb.erase(id); } else base_type_rec(subtype, ns, symb); } }
void c_typecheck_baset::do_initializer(symbolt &symbol) { // this one doesn't need initialization if(has_prefix(id2string(symbol.name), CPROVER_PREFIX "constant_infinity")) return; if(symbol.is_static_lifetime) { if(symbol.value.is_not_nil()) { typecheck_expr(symbol.value); do_initializer(symbol.value, symbol.type, true); // need to adjust size? if(follow(symbol.type).id()==ID_array && to_array_type(follow(symbol.type)).size().is_nil()) symbol.type=symbol.value.type(); } } else if(!symbol.is_type) { if(symbol.is_macro) { // these must have a constant value assert(symbol.value.is_not_nil()); typecheck_expr(symbol.value); source_locationt location=symbol.value.source_location(); do_initializer(symbol.value, symbol.type, true); make_constant(symbol.value); } else if(symbol.value.is_not_nil()) { typecheck_expr(symbol.value); do_initializer(symbol.value, symbol.type, true); // need to adjust size? if(follow(symbol.type).id()==ID_array && to_array_type(follow(symbol.type)).size().is_nil()) symbol.type=symbol.value.type(); } } }
void c_typecheck_baset::typecheck_type(typet &type) { // we first convert, and then check // do we have alignment? if(type.find(ID_C_alignment).is_not_nil()) { exprt &alignment=static_cast<exprt &>(type.add(ID_C_alignment)); if(alignment.id()!=ID_default) { typecheck_expr(alignment); make_constant(alignment); } } if(type.id()==ID_code) typecheck_code_type(to_code_type(type)); else if(type.id()==ID_array) typecheck_array_type(to_array_type(type)); else if(type.id()==ID_pointer) typecheck_type(type.subtype()); else if(type.id()==ID_struct || type.id()==ID_union) typecheck_compound_type(to_struct_union_type(type)); else if(type.id()==ID_c_enum) { } else if(type.id()==ID_c_bitfield) typecheck_c_bit_field_type(type); else if(type.id()==ID_typeof) typecheck_typeof_type(type); else if(type.id()==ID_symbol) typecheck_symbol_type(type); else if(type.id()==ID_vector) typecheck_vector_type(to_vector_type(type)); else if(type.id()==ID_custom_unsignedbv || type.id()==ID_custom_signedbv || type.id()==ID_custom_floatbv || type.id()==ID_custom_fixedbv) typecheck_custom_type(type); // do a bit of rule checking if(type.get_bool(ID_C_restricted) && type.id()!=ID_pointer && type.id()!=ID_array) { err_location(type); error("only a pointer can be 'restrict'"); throw 0; } }
void cpp_typecheckt::check_fixed_size_array(typet &type) { if(type.id()==ID_array) { array_typet &array_type=to_array_type(type); if(array_type.size().is_not_nil()) make_constant_index(array_type.size()); // recursive call for multi-dimensional arrays check_fixed_size_array(array_type.subtype()); } }
exprt path_symex_statet::array_theory(const exprt &src, bool propagate) { // top-level constant-sized arrays only right now if(src.id()==ID_index) { const index_exprt &index_expr=to_index_expr(src); exprt index_tmp1=read(index_expr.index(), propagate); exprt index_tmp2=simplify_expr(index_tmp1, var_map.ns); if(!index_tmp2.is_constant()) { const array_typet &array_type=to_array_type(index_expr.array().type()); const typet &subtype=array_type.subtype(); if(array_type.size().is_constant()) { mp_integer size; if(to_integer(array_type.size(), size)) throw "failed to convert array size"; std::size_t size_int=integer2size_t(size); exprt result=nil_exprt(); // split it up for(std::size_t i=0; i<size_int; ++i) { exprt index=from_integer(i, index_expr.index().type()); exprt new_src=index_exprt(index_expr.array(), index, subtype); if(result.is_nil()) result=new_src; else { equal_exprt index_equal(index_expr.index(), index); result=if_exprt(index_equal, new_src, result); } } return result; // done } else { // TODO: variable-sized array } } } return src; }
exprt boolbvt::get(const exprt &expr) const { if(expr.id()==ID_symbol || expr.id()==ID_nondet_symbol) { const irep_idt &identifier=expr.get(ID_identifier); boolbv_mapt::mappingt::const_iterator it= map.mapping.find(identifier); if(it!=map.mapping.end()) { const boolbv_mapt::map_entryt &map_entry=it->second; if(is_unbounded_array(map_entry.type)) return bv_get_unbounded_array(identifier, to_array_type(map_entry.type)); std::vector<bool> unknown; bvt bv; unsigned width=map_entry.width; bv.resize(width); unknown.resize(width); for(unsigned bit_nr=0; bit_nr<width; bit_nr++) { assert(bit_nr<map_entry.literal_map.size()); if(map_entry.literal_map[bit_nr].is_set) { unknown[bit_nr]=false; bv[bit_nr]=map_entry.literal_map[bit_nr].l; } else { unknown[bit_nr]=true; bv[bit_nr].clear(); } } return bv_get_rec(bv, unknown, 0, map_entry.type); } } else if(expr.id()==ID_constant) return expr; else if(expr.id()==ID_infinity) return expr; return SUB::get(expr); }
void c_typecheck_baset::typecheck_new_symbol(symbolt &symbol) { if(symbol.is_parameter) adjust_function_parameter(symbol.type); // check initializer, if needed if(symbol.type.id()==ID_code) { if(symbol.value.is_not_nil()) typecheck_function_body(symbol); else { // we don't need the identifiers code_typet &code_type=to_code_type(symbol.type); for(code_typet::parameterst::iterator it=code_type.parameters().begin(); it!=code_type.parameters().end(); it++) it->set_identifier(irep_idt()); } } else { if(symbol.type.id()==ID_array && to_array_type(symbol.type).size().is_nil() && !symbol.is_type) { // Insert a new type symbol for the array. // We do this because we want a convenient way // of adjusting the size of the type later on. type_symbolt new_symbol(symbol.type); new_symbol.name=id2string(symbol.name)+"$type"; new_symbol.base_name=id2string(symbol.base_name)+"$type"; new_symbol.location=symbol.location; new_symbol.mode=symbol.mode; new_symbol.module=symbol.module; symbol.type=symbol_typet(new_symbol.name); symbolt *new_sp; symbol_table.move(new_symbol, new_sp); } // check the initializer do_initializer(symbol); } }
bvt boolbvt::convert_array_of(const array_of_exprt &expr) { if(expr.type().id()!=ID_array) throw "array_of must be array-typed"; const array_typet &array_type=to_array_type(expr.type()); if(is_unbounded_array(array_type)) return conversion_failed(expr); std::size_t width=boolbv_width(array_type); if(width==0) { // A zero-length array is acceptable; // an element with unknown size is not. if(boolbv_width(array_type.subtype())==0) return conversion_failed(expr); else return bvt(); } const exprt &array_size=array_type.size(); mp_integer size; if(to_integer(array_size, size)) return conversion_failed(expr); const bvt &tmp=convert_bv(expr.op0()); bvt bv; bv.resize(width); if(size*tmp.size()!=width) throw "convert_array_of: unexpected operand width"; std::size_t offset=0; for(mp_integer i=0; i<size; i=i+1) { for(std::size_t j=0; j<tmp.size(); j++, offset++) bv[offset]=tmp[j]; } assert(offset==bv.size()); return bv; }
void c_typecheck_baset::increment_designator(designatort &designator) { assert(!designator.empty()); while(true) { designatort::entryt &entry=designator[designator.size()-1]; const typet &full_type=follow(entry.type); entry.index++; if(full_type.id()==ID_array && to_array_type(full_type).size().is_nil()) return; // we will keep going forever if(full_type.id()==ID_struct && entry.index<entry.size) { // need to adjust subtype const struct_typet &struct_type= to_struct_type(full_type); const struct_typet::componentst &components= struct_type.components(); assert(components.size()==entry.size); // we skip over any padding or code while(entry.index<entry.size && (components[entry.index].get_is_padding() || components[entry.index].type().id()==ID_code)) entry.index++; if(entry.index<entry.size) entry.subtype=components[entry.index].type(); } if(entry.index<entry.size) return; // done if(designator.size()==1) return; // done // pop entry designator.pop_entry(); assert(!designator.empty()); } }
smt_astt array_sym_smt_ast::update( smt_convt *ctx, smt_astt value, unsigned int idx, expr2tc idx_expr) const { const array_type2t array_type = to_array_type(sort->get_tuple_type()); const struct_union_data &data = ctx->get_type_def(array_type.subtype); expr2tc index; if(is_nil_expr(idx_expr)) { index = constant_int2tc(ctx->make_array_domain_type(array_type), BigInt(idx)); } else { index = idx_expr; } std::string name = ctx->mk_fresh_name("tuple_array_update::") + "."; tuple_sym_smt_astt result = new array_sym_smt_ast(ctx, sort, name); // Iterate over all members. They are _all_ indexed and updated. unsigned int i = 0; for(auto const &it : data.members) { type2tc arrtype( new array_type2t(it, array_type.array_size, array_type.size_is_infinite)); // Project and update a field in 'this' smt_astt field = project(ctx, i); smt_astt resval = value->project(ctx, i); smt_astt updated = field->update(ctx, resval, 0, index); // Now equality it into the result object smt_astt res_field = result->project(ctx, i); updated->assign(ctx, res_field); i++; } return result; }
void array_sym_smt_ast::assign(smt_convt *ctx, smt_astt sym) const { // We have two tuple_sym_smt_asts and need to call assign on all of their // components. array_sym_smt_astt src = this; array_sym_smt_astt dst = to_array_sym_ast(sym); const array_type2t &arrtype = to_array_type(sort->get_tuple_type()); const struct_union_data &data = ctx->get_type_def(arrtype.subtype); unsigned int i = 0; for(auto const &it : data.members) { array_type2tc tmparrtype(it, arrtype.array_size, arrtype.size_is_infinite); smt_astt source = src->project(ctx, i); smt_astt destination = dst->project(ctx, i); source->assign(ctx, destination); i++; } }
void java_bytecode_typecheckt::typecheck_type(typet &type) { if(type.id()==ID_symbol) { irep_idt identifier=to_symbol_type(type).get_identifier(); symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(identifier); // must exist already in the symbol table if(s_it==symbol_table.symbols.end()) { error() << "failed to find type symbol "<< identifier << eom; throw 0; } assert(s_it->second.is_type); } else if(type.id()==ID_pointer) { typecheck_type(type.subtype()); } else if(type.id()==ID_array) { typecheck_type(type.subtype()); typecheck_expr(to_array_type(type).size()); } else if(type.id()==ID_code) { code_typet &code_type=to_code_type(type); typecheck_type(code_type.return_type()); code_typet::parameterst ¶meters=code_type.parameters(); for(code_typet::parameterst::iterator it=parameters.begin(); it!=parameters.end(); it++) typecheck_type(it->type()); } }
bool goto_symex_statet::constant_propagation(const expr2tc &expr) const { static unsigned int with_counter=0; // Don't permit const propagaion of infinite-size arrays. They're going to // be special modelling arrays that require special handling either at SMT // or some other level, so attempting to optimse them is a Bad Plan (TM). if (is_array_type(expr) && to_array_type(expr->type).size_is_infinite) return false; if (is_nil_expr(expr)) { return true; // It's fine to constant propagate something that's absent. } else if (is_constant_expr(expr)) { return true; } else if (is_symbol2t(expr) && to_symbol2t(expr).thename == "NULL") { // Null is also essentially a constant. return true; } else if (is_address_of2t(expr)) { return constant_propagation_reference(to_address_of2t(expr).ptr_obj); } else if (is_typecast2t(expr)) { return constant_propagation(to_typecast2t(expr).from); } else if (is_add2t(expr)) { forall_operands2(it, idx, expr) if(!constant_propagation(*it)) return false; return true; } else if (is_constant_array_of2t(expr))
smt_astt array_sym_smt_ast::ite(smt_convt *ctx, smt_astt cond, smt_astt falseop) const { // Similar to tuple ite's, but the leafs are arrays. tuple_sym_smt_astt true_val = this; tuple_sym_smt_astt false_val = to_tuple_sym_ast(falseop); assert(is_array_type(sort->get_tuple_type())); const array_type2t &array_type = to_array_type(sort->get_tuple_type()); std::string name = ctx->mk_fresh_name("tuple_array_ite::") + "."; symbol2tc result(sort->get_tuple_type(), name); smt_astt result_sym = ctx->convert_ast(result); const struct_union_data &data = ctx->get_type_def(array_type.subtype); // Iterate through each field and encode an ite. unsigned int i = 0; for(auto const &it : data.members) { array_type2tc arrtype( it, array_type.array_size, array_type.size_is_infinite); smt_astt truepart = true_val->project(ctx, i); smt_astt falsepart = false_val->project(ctx, i); smt_astt result_ast = truepart->ite(ctx, cond, falsepart); smt_astt result_sym_ast = result_sym->project(ctx, i); ctx->assert_ast(result_sym_ast->eq(ctx, result_ast)); i++; } return ctx->convert_ast(result); }
exprt flatten_byte_extract( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_extract_little_endian || src.id()==ID_byte_extract_big_endian); assert(src.operands().size()==2); bool little_endian; if(src.id()==ID_byte_extract_little_endian) little_endian=true; else if(src.id()==ID_byte_extract_big_endian) little_endian=false; else assert(false); if(src.id()==ID_byte_extract_big_endian) throw "byte_extract flattening of big endian not done yet"; unsigned width= integer2long(pointer_offset_size(ns, src.type())); const typet &t=src.op0().type(); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // byte-array? if((subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv) && subtype.get_int(ID_width)==8) { // get 'width'-many bytes, and concatenate exprt::operandst op; op.resize(width); for(unsigned i=0; i<width; i++) { // the most significant byte comes first in the concatenation! unsigned offset_i= little_endian?(width-i-1):i; plus_exprt offset(from_integer(offset_i, src.op1().type()), src.op1()); index_exprt index_expr(subtype); index_expr.array()=src.op0(); index_expr.index()=offset; op[i]=index_expr; } if(width==1) return op[0]; else // width>=2 { concatenation_exprt concatenation(src.type()); concatenation.operands().swap(op); return concatenation; } } else // non-byte array { const exprt &root=src.op0(); const exprt &offset=src.op1(); const typet &array_type=ns.follow(root.type()); const typet &offset_type=ns.follow(offset.type()); const typet &element_type=ns.follow(array_type.subtype()); mp_integer element_width=pointer_offset_size(ns, element_type); if(element_width==-1) // failed throw "failed to flatten non-byte array with unknown element width"; mp_integer result_width=pointer_offset_size(ns, src.type()); mp_integer num_elements=(element_width+result_width-2)/element_width+1; // compute new root and offset concatenation_exprt concat( unsignedbv_typet(integer2long(element_width*8*num_elements))); exprt first_index= (element_width==1)?offset : div_exprt(offset, from_integer(element_width, offset_type)); // 8*offset/el_w for(mp_integer i=num_elements; i>0; --i) { plus_exprt index(first_index, from_integer(i-1, offset_type)); concat.copy_to_operands(index_exprt(root, index)); } // the new offset is width%offset exprt new_offset= (element_width==1)?from_integer(0, offset_type): mod_exprt(offset, from_integer(element_width, offset_type)); // build new byte-extract expression exprt tmp(src.id(), src.type()); tmp.copy_to_operands(concat, new_offset); return tmp; } } else // non-array { // We turn that into logical right shift and extractbits const exprt &offset=src.op1(); const typet &offset_type=ns.follow(offset.type()); mult_exprt times_eight(offset, from_integer(8, offset_type)); lshr_exprt left_shift(src.op0(), times_eight); extractbits_exprt extractbits; extractbits.src()=left_shift; extractbits.type()=src.type(); extractbits.upper()=from_integer(width*8-1, offset_type); extractbits.lower()=from_integer(0, offset_type); return extractbits; } }
exprt flatten_byte_update( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_update_little_endian || src.id()==ID_byte_update_big_endian); assert(src.operands().size()==3); mp_integer element_size= pointer_offset_size(ns, src.op2().type()); const typet &t=ns.follow(src.op0().type()); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // array of bitvectors? if(subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv || subtype.id()==ID_floatbv) { mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size==-1) throw "can't flatten byte_update for sub-type without size"; // byte array? if(sub_size==1) { // apply 'array-update-with' element_size times exprt result=src.op0(); for(mp_integer i=0; i<element_size; ++i) { exprt i_expr=from_integer(i, ns.follow(src.op1().type())); exprt new_value; if(i==0 && element_size==1) // bytes? { new_value=src.op2(); if(new_value.type()!=subtype) new_value.make_typecast(subtype); } else { exprt byte_extract_expr( src.id()==ID_byte_update_little_endian?ID_byte_extract_little_endian: src.id()==ID_byte_update_big_endian?ID_byte_extract_big_endian: throw "unexpected src.id()", subtype); byte_extract_expr.copy_to_operands(src.op2(), i_expr); new_value=flatten_byte_extract(byte_extract_expr, ns); } exprt where=plus_exprt(src.op1(), i_expr); with_exprt with_expr; with_expr.type()=src.type(); with_expr.old()=result; with_expr.where()=where; with_expr.new_value()=new_value; result.swap(with_expr); } return result; } else // sub_size!=1 { if(element_size==1) // byte-granularity update { div_exprt div_offset(src.op1(), from_integer(sub_size, src.op1().type())); mod_exprt mod_offset(src.op1(), from_integer(sub_size, src.op1().type())); index_exprt index_expr(src.op0(), div_offset, array_type.subtype()); exprt byte_update_expr(src.id(), array_type.subtype()); byte_update_expr.copy_to_operands(index_expr, mod_offset, src.op2()); // Call recurisvely, the array is gone! exprt flattened_byte_update_expr= flatten_byte_update(byte_update_expr, ns); with_exprt with_expr( src.op0(), div_offset, flattened_byte_update_expr); return with_expr; } else throw "flatten_byte_update can only do byte updates of non-byte arrays right now"; } } else { throw "flatten_byte_update can only do arrays of scalars right now"; } } else if(t.id()==ID_signedbv || t.id()==ID_unsignedbv || t.id()==ID_floatbv) { // do a shift, mask and OR unsigned width=to_bitvector_type(t).get_width(); if(element_size*8>width) throw "flatten_byte_update to update element that is too large"; // build mask exprt mask= bitnot_exprt( from_integer(power(2, element_size*8)-1, unsignedbv_typet(width))); const typet &offset_type=ns.follow(src.op1().type()); mult_exprt offset_times_eight(src.op1(), from_integer(8, offset_type)); // shift the mask shl_exprt shl_expr(mask, offset_times_eight); // do the 'AND' bitand_exprt bitand_expr(src.op0(), mask); // zero-extend the value concatenation_exprt value_extended( from_integer(0, unsignedbv_typet(width-integer2long(element_size)*8)), src.op2(), t); // shift the value shl_exprt value_shifted(value_extended, offset_times_eight); // do the 'OR' bitor_exprt bitor_expr(bitand_expr, value_shifted); return bitor_expr; } else { throw "flatten_byte_update can only do array and scalars right now"; } }
void add_padding(struct_typet &type, const namespacet &ns) { struct_typet::componentst &components=type.components(); // first do padding for bit-fields { unsigned padding_counter=0; unsigned bit_field_bits=0; for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(it->get_is_bit_field()) { // count the bits bit_field_bits+=it->type().get_int(ID_width); } else if(bit_field_bits!=0) { // not on a byte-boundary? if((bit_field_bits%8)!=0) { unsigned pad=8-bit_field_bits%8; unsignedbv_typet padding_type; padding_type.set_width(pad); struct_typet::componentt component; component.type()=padding_type; component.set_name("$bit_field_pad"+i2string(padding_counter++)); component.set_is_padding(true); component.set_is_bit_field(true); it=components.insert(it, component); it++; // skip over bit_field_bits+=pad; } bit_field_bits=0; } } // Add padding at the end? if((bit_field_bits%8)!=0) { unsigned pad=8-bit_field_bits%8; unsignedbv_typet padding_type; padding_type.set_width(pad); struct_typet::componentt component; component.type()=padding_type; component.set_name("$bit_field_pad"+i2string(padding_counter++)); component.set_is_padding(true); component.set_is_bit_field(true); components.push_back(component); } } // packed? if(type.get_bool(ID_packed)) return; // done mp_integer offset=0; unsigned padding_counter=0; unsigned max_alignment=0; unsigned bit_field_bits=0; for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { // ANSI-C says that bit-fields do not get padded! if(it->get_is_bit_field()) { // count the bits bit_field_bits+=it->type().get_int(ID_width); // we consider the type for max_alignment, however unsigned a=alignment(it->get_bit_field_type(), ns); if(max_alignment<a) max_alignment=a; continue; } else if(bit_field_bits!=0) { // these are now assumed to be multiples of 8 offset+=bit_field_bits/8; bit_field_bits=0; } const typet &it_type=it->type(); unsigned a=alignment(it_type, ns); // check minimum alignment if(a<config.ansi_c.alignment) a=config.ansi_c.alignment; if(max_alignment<a) max_alignment=a; if(a!=1) { // we may need to align it unsigned displacement=integer2long(offset%a); if(displacement!=0) { unsigned pad=a-displacement; unsignedbv_typet padding_type; padding_type.set_width(pad*8); struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"+i2string(padding_counter++)); component.set_is_padding(true); it=components.insert(it, component); it++; // skip over offset+=pad; } } mp_integer size=pointer_offset_size(ns, it_type); if(size!=-1) offset+=size; } if(bit_field_bits!=0) { // these are now assumed to be multiples of 8 offset+=bit_field_bits/8; } // There may be a need for 'end of struct' padding. // We use 'max_alignment'. if(max_alignment>1) { // we may need to align it unsigned displacement=integer2long(offset%max_alignment); if(displacement!=0) { unsigned pad=max_alignment-displacement; unsignedbv_typet padding_type; padding_type.set_width(pad*8); struct_typet::componentst::iterator it; // we need to insert before any 'flexible member' if(!components.empty() && components.back().type().id()==ID_array && to_array_type(components.back().type()).size().is_zero()) { it=components.end(); it--; } else it=components.end(); struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"+i2string(padding_counter++)); component.set_is_padding(true); components.insert(it, component); } } }
bool static_lifetime_init( symbol_tablet &symbol_table, const source_locationt &source_location, message_handlert &message_handler) { namespacet ns(symbol_table); symbol_tablet::symbolst::iterator s_it= symbol_table.symbols.find(INITIALIZE_FUNCTION); if(s_it==symbol_table.symbols.end()) return false; symbolt &init_symbol=s_it->second; init_symbol.value=code_blockt(); init_symbol.value.add_source_location()=source_location; code_blockt &dest=to_code_block(to_code(init_symbol.value)); // add the magic label to hide dest.add(code_labelt("__CPROVER_HIDE", code_skipt())); // do assignments based on "value" // sort alphabetically for reproducible results std::set<std::string> symbols; forall_symbols(it, symbol_table.symbols) symbols.insert(id2string(it->first)); for(const std::string &id : symbols) { const symbolt &symbol=ns.lookup(id); const irep_idt &identifier=symbol.name; if(!symbol.is_static_lifetime) continue; if(symbol.is_type || symbol.is_macro) continue; // special values if(identifier==CPROVER_PREFIX "constant_infinity_uint" || identifier==CPROVER_PREFIX "memory" || identifier=="__func__" || identifier=="__FUNCTION__" || identifier=="__PRETTY_FUNCTION__" || identifier=="argc'" || identifier=="argv'" || identifier=="envp'" || identifier=="envp_size'") continue; // just for linking if(has_prefix(id, CPROVER_PREFIX "architecture_")) continue; const typet &type=ns.follow(symbol.type); // check type if(type.id()==ID_code || type.id()==ID_empty) continue; // We won't try to initialize any symbols that have // remained incomplete. if(symbol.value.is_nil() && symbol.is_extern) // Compilers would usually complain about these // symbols being undefined. continue; if(type.id()==ID_array && to_array_type(type).size().is_nil()) { // C standard 6.9.2, paragraph 5 // adjust the type to an array of size 1 symbol_tablet::symbolst::iterator it= symbol_table.symbols.find(identifier); assert(it!=symbol_table.symbols.end()); it->second.type=type; it->second.type.set(ID_size, from_integer(1, size_type())); } if(type.id()==ID_incomplete_struct || type.id()==ID_incomplete_union) continue; // do not initialize if(symbol.value.id()==ID_nondet) continue; // do not initialize exprt rhs; if(symbol.value.is_nil()) { try { namespacet ns(symbol_table); rhs=zero_initializer(symbol.type, symbol.location, ns, message_handler); assert(rhs.is_not_nil()); } catch(...) { return true; } } else rhs=symbol.value; code_assignt code(symbol.symbol_expr(), rhs); code.add_source_location()=symbol.location; dest.move_to_operands(code); } // call designated "initialization" functions for(const std::string &id : symbols) { const symbolt &symbol=ns.lookup(id); if(symbol.type.id()==ID_code && to_code_type(symbol.type).return_type().id()==ID_constructor) { code_function_callt function_call; function_call.function()=symbol.symbol_expr(); function_call.add_source_location()=source_location; dest.move_to_operands(function_call); } } return false; }
const typet &control_array_size_type(const symbol_tablet &st) { const struct_typet::componentt &c=get_comp(st, CEGIS_CONTROL_A_MEMBER_NAME); return to_array_type(c.type()).size().type(); }
const array_typet &control_vector_solution_type(const symbol_tablet &st) { return to_array_type(st.lookup(CEGIS_CONTROL_VECTOR_SOLUTION_VAR_NAME).type); }
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); }