void goto_checkt::bounds_check( const index_exprt &expr, const guardt &guard) { if(!enable_bounds_check) return; if(expr.find("bounds_check").is_not_nil() && !expr.get_bool("bounds_check")) return; typet array_type=ns.follow(expr.array().type()); if(array_type.id()==ID_pointer) return; // done by the pointer code else if(array_type.id()==ID_incomplete_array) throw "index got incomplete array"; else if(array_type.id()!=ID_array && array_type.id()!=ID_vector) throw "bounds check expected array or vector type, got " +array_type.id_string(); std::string name=array_name(expr.array()); const exprt &index=expr.index(); object_descriptor_exprt ode; ode.build(expr, ns); if(index.type().id()!=ID_unsignedbv) { // we undo typecasts to signedbv if(index.id()==ID_typecast && index.operands().size()==1 && index.op0().type().id()==ID_unsignedbv) { // ok } else { mp_integer i; if(!to_integer(index, i) && i>=0) { // ok } else { exprt effective_offset=ode.offset(); if(ode.root_object().id()==ID_dereference) { exprt p_offset=pointer_offset( to_dereference_expr(ode.root_object()).pointer()); assert(p_offset.type()==effective_offset.type()); effective_offset=plus_exprt(p_offset, effective_offset); } exprt zero=gen_zero(ode.offset().type()); assert(zero.is_not_nil()); // the final offset must not be negative binary_relation_exprt inequality(effective_offset, ID_ge, zero); add_guarded_claim( inequality, name+" lower bound", "array bounds", expr.find_source_location(), expr, guard); } } } if(ode.root_object().id()==ID_dereference) { const exprt &pointer= to_dereference_expr(ode.root_object()).pointer(); if_exprt size( dynamic_object(pointer), typecast_exprt(dynamic_size(ns), object_size(pointer).type()), object_size(pointer)); plus_exprt effective_offset(ode.offset(), pointer_offset(pointer)); assert(effective_offset.op0().type()==effective_offset.op1().type()); assert(effective_offset.type()==size.type()); binary_relation_exprt inequality(effective_offset, ID_lt, size); or_exprt precond( and_exprt( dynamic_object(pointer), not_exprt(malloc_object(pointer, ns))), inequality); add_guarded_claim( precond, name+" upper bound", "array bounds", expr.find_source_location(), expr, guard); return; } const exprt &size=array_type.id()==ID_array ? to_array_type(array_type).size() : to_vector_type(array_type).size(); if(size.is_nil()) { // Linking didn't complete, we don't have a size. // Not clear what to do. } else if(size.id()==ID_infinity) { } else if(size.is_zero() && expr.array().id()==ID_member) { // a variable sized struct member } else { binary_relation_exprt inequality(index, ID_lt, size); // typecast size if(inequality.op1().type()!=inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); // typecast size if(inequality.op1().type()!=inequality.op0().type()) inequality.op1().make_typecast(inequality.op0().type()); add_guarded_claim( inequality, name+" upper bound", "array bounds", expr.find_source_location(), expr, guard); } }
void value_set_dereferencet::bounds_check( const index_exprt &expr, const guardt &guard) { if(!options.get_bool_option("pointer-check")) return; if(!options.get_bool_option("bounds-check")) return; const typet &array_type=ns.follow(expr.op0().type()); if(array_type.id()!=ID_array) throw "bounds check expected array type"; std::string name=array_name(ns, expr.array()); { mp_integer i; if(!to_integer(expr.index(), i) && i>=0) { } else { exprt zero=from_integer(0, expr.index().type()); if(zero.is_nil()) throw "no zero constant of index type "+ expr.index().type().pretty(); binary_relation_exprt inequality(expr.index(), ID_lt, zero); guardt tmp_guard(guard); tmp_guard.add(inequality); dereference_callback.dereference_failure( "array bounds", name+" lower bound", tmp_guard); } } const exprt &size_expr= to_array_type(array_type).size(); if(size_expr.id()==ID_infinity) { } else if(size_expr.is_zero() && expr.array().id()==ID_member) { // this is a variable-sized struct field } else { if(size_expr.is_nil()) throw "index array operand of wrong type"; binary_relation_exprt inequality(expr.index(), ID_ge, size_expr); if(c_implicit_typecast( inequality.op0(), inequality.op1().type(), ns)) throw "index address of wrong type"; guardt tmp_guard(guard); tmp_guard.add(inequality); dereference_callback.dereference_failure( "array bounds", name+" upper bound", tmp_guard); } }
void arrayst::record_array_index(const index_exprt &index) { unsigned number=arrays.number(index.array()); if(number>=index_map.size()) index_map.resize(number+1); index_map[number].insert(index.index()); }
void boolbvt::convert_index(const index_exprt &expr, bvt &bv) { if(expr.id()!=ID_index) throw "expected index expression"; if(expr.operands().size()!=2) throw "index takes two operands"; const exprt &array=expr.array(); const exprt &index=expr.index(); const array_typet &array_type= to_array_type(ns.follow(array.type())); // see if the array size is constant if(is_unbounded_array(array_type)) { // use array decision procedure unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); // free variables bv.resize(width); for(unsigned i=0; i<width; i++) bv[i]=prop.new_variable(); record_array_index(expr); // record type if array is a symbol if(array.id()==ID_symbol) map.get_map_entry( to_symbol_expr(array).get_identifier(), array_type); // make sure we have the index in the cache convert_bv(index); return; } // see if the index address is constant mp_integer index_value; if(!to_integer(index, index_value)) return convert_index(array, index_value, bv); unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); mp_integer array_size; if(to_integer(array_type.size(), array_size)) { std::cout << to_array_type(array.type()).size().pretty() << std::endl; throw "failed to convert array size"; } // get literals for the whole array const bvt &array_bv=convert_bv(array); if(array_size*width!=array_bv.size()) throw "unexpected array size"; // TODO: maybe a shifter-like construction would be better if(prop.has_set_to()) { // free variables bv.resize(width); for(unsigned i=0; i<width; i++) bv[i]=prop.new_variable(); // add implications equal_exprt index_equality; index_equality.lhs()=index; // index operand bvt equal_bv; equal_bv.resize(width); for(mp_integer i=0; i<array_size; i=i+1) { index_equality.rhs()=from_integer(i, index_equality.lhs().type()); if(index_equality.rhs().is_nil()) throw "number conversion failed (1)"; mp_integer offset=i*width; for(unsigned j=0; j<width; j++) equal_bv[j]=prop.lequal(bv[j], array_bv[integer2long(offset+j)]); prop.l_set_to_true( prop.limplies(convert(index_equality), prop.land(equal_bv))); } } else { bv.resize(width); equal_exprt equality; equality.lhs()=index; // index operand typet constant_type=index.type(); // type of index operand assert(array_size>0); for(mp_integer i=0; i<array_size; i=i+1) { equality.op1()=from_integer(i, constant_type); literalt e=convert(equality); mp_integer offset=i*width; for(unsigned j=0; j<width; j++) { literalt l=array_bv[integer2long(offset+j)]; if(i==0) // this initializes bv bv[j]=l; else bv[j]=prop.lselect(e, l, bv[j]); } } } }
bool remove_const_function_pointerst::try_resolve_index_of( const index_exprt &index_expr, expressionst &out_expressions, bool &out_is_const) { // Get the array(s) it belongs to expressionst potential_array_exprs; bool array_const=false; bool resolved_array= try_resolve_expression( index_expr.array(), potential_array_exprs, array_const); if(resolved_array) { bool all_possible_const=true; for(const exprt &potential_array_expr : potential_array_exprs) { all_possible_const= all_possible_const && is_const_type(potential_array_expr.type().subtype()); if(potential_array_expr.id()==ID_array) { // Get the index if we can mp_integer value; if(try_resolve_index_value(index_expr.index(), value)) { expressionst array_out_functions; const exprt &func_expr= potential_array_expr.operands()[integer2size_t(value)]; bool value_const=false; bool resolved_value= try_resolve_expression(func_expr, array_out_functions, value_const); if(resolved_value) { out_expressions.insert( out_expressions.end(), array_out_functions.begin(), array_out_functions.end()); } else { LOG("Failed to resolve array value", func_expr); return false; } } else { // We don't know what index it is, // but we know the value is from the array for(const exprt &array_entry : potential_array_expr.operands()) { expressionst array_contents; bool is_entry_const; bool resolved_value= try_resolve_expression( array_entry, array_contents, is_entry_const); if(!resolved_value) { LOG("Failed to resolve array value", array_entry); return false; } for(const exprt &resolved_array_entry : array_contents) { if(!resolved_array_entry.is_zero()) { out_expressions.push_back(resolved_array_entry); } } } } } else { LOG( "Squashing index of did not result in an array", potential_array_expr); return false; } } out_is_const=all_possible_const || array_const; return true; } else { LOG("Failed to squash index of to array expression", index_expr); return false; } }