diff --git a/src/goto-programs/interpreter.cpp b/src/goto-programs/interpreter.cpp index 8d1565db914..ff61e53b615 100644 --- a/src/goto-programs/interpreter.cpp +++ b/src/goto-programs/interpreter.cpp @@ -597,16 +597,25 @@ exprt interpretert::get_value( exprt result=array_exprt(to_array_type(real_type)); const exprt &size_expr=static_cast(type.find(ID_size)); size_t subtype_size=get_size(type.subtype()); - mp_integer mp_count; - to_integer(size_expr, mp_count); - unsigned count=integer2unsigned(mp_count); + std::size_t count; + if(size_expr.id()!=ID_constant) + { + count=base_address_to_actual_size(offset)/subtype_size; + } + else + { + mp_integer mp_count; + to_integer(size_expr, mp_count); + count=integer2size_t(mp_count); + } // Retrieve the value for each member in the array result.reserve_operands(count); for(unsigned i=0; i0) offset++; - + std::size_t address=memory_map[id]; + std::size_t current_size=base_address_to_alloc_size(address); // current size <= size already recorded - if(size<=offset) + if(size<=current_size) return memory_map[id]; } @@ -1151,20 +1162,32 @@ mp_integer interpretert::build_memory_map( if(size==0) size=1; // This is a hack to create existence - unsigned address=memory.size(); + std::size_t address=memory.size(); memory.resize(address+size); memory_map[id]=address; + inverse_memory_map[address]=id; dynamic_types.insert(std::pair(id, alloc_type)); - for(size_t i=0; i(cell.initialized) << ")" diff --git a/src/goto-programs/interpreter_class.h b/src/goto-programs/interpreter_class.h index 83836eea072..8ea3ad620b2 100644 --- a/src/goto-programs/interpreter_class.h +++ b/src/goto-programs/interpreter_class.h @@ -12,6 +12,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include "goto_functions.h" #include "goto_trace.h" @@ -68,6 +69,9 @@ class interpretert:public messaget // List of dynamically allocated symbols that are not in the symbol table typedef std::map dynamic_typest; + typedef std::map output_valuest; + output_valuest output_values; + // An assignment list annotated with the calling context. struct function_assignments_contextt { @@ -103,27 +107,78 @@ class interpretert:public messaget const goto_functionst &goto_functions; - typedef std::unordered_map memory_mapt; + typedef std::unordered_map memory_mapt; + typedef std::map inverse_memory_mapt; memory_mapt memory_map; + inverse_memory_mapt inverse_memory_map; + + const inverse_memory_mapt::value_type &address_to_object_record( + std::size_t address) const + { + auto lower_bound=inverse_memory_map.lower_bound(address); + if(lower_bound->first!=address) + { + assert(lower_bound!=inverse_memory_map.begin()); + --lower_bound; + } + return *lower_bound; + } + + irep_idt address_to_identifier(std::size_t address) const + { + return address_to_object_record(address).second; + } + + std::size_t address_to_offset(std::size_t address) const + { + return address-(address_to_object_record(address).first); + } + + std::size_t base_address_to_alloc_size(std::size_t address) const + { + assert(address_to_offset(address)==0); + auto upper_bound=inverse_memory_map.upper_bound(address); + std::size_t next_alloc_address= + upper_bound==inverse_memory_map.end() ? + memory.size() : + upper_bound->first; + return next_alloc_address-address; + } + + std::size_t base_address_to_actual_size(std::size_t address) const + { + auto memory_iter=memory.find(address); + if(memory_iter==memory.end()) + return 0; + std::size_t ret=0; + std::size_t alloc_size=base_address_to_alloc_size(address); + while(memory_iter!=memory.end() && ret memoryt; + typedef sparse_vectort memoryt; typedef std::map parameter_sett; // mapping -> value typedef std::pair struct_member_idt; typedef std::map struct_valuest; - // The memory is being annotated/reshaped even during reads // (ie to find a read-before-write location) thus memory // properties need to be mutable to avoid making all calls nonconst @@ -135,6 +190,7 @@ class interpretert:public messaget void build_memory_map(const symbolt &symbol); mp_integer build_memory_map(const irep_idt &id, const typet &type); typet concretize_type(const typet &type); + bool unbounded_size(const typet &); size_t get_size(const typet &type); irep_idt get_component_id(const irep_idt &object, unsigned offset); @@ -169,6 +225,10 @@ class interpretert:public messaget mp_integer address, mp_vectort &dest) const; + void read_unbounded( + mp_integer address, + mp_vectort &dest) const; + virtual void command(); class stack_framet diff --git a/src/goto-programs/interpreter_evaluate.cpp b/src/goto-programs/interpreter_evaluate.cpp index 712d4b9d807..f285328aedd 100644 --- a/src/goto-programs/interpreter_evaluate.cpp +++ b/src/goto-programs/interpreter_evaluate.cpp @@ -54,6 +54,34 @@ void interpretert::read( } } +void interpretert::read_unbounded( + mp_integer address, + mp_vectort &dest) const +{ + // copy memory region + std::size_t address_val=integer2size_t(address); + const std::size_t offset=address_to_offset(address_val); + const std::size_t alloc_size= + base_address_to_actual_size(address_val-offset); + const std::size_t to_read=alloc_size-offset; + for(size_t i=0; i0) - cell.initialized=0; + if(cell.second.initialized>0) + cell.second.initialized=0; } } @@ -441,7 +469,8 @@ void interpretert::evaluate( } else if(expr.id()==ID_struct) { - dest.reserve(get_size(expr.type())); + if(!unbounded_size(expr.type())) + dest.reserve(get_size(expr.type())); bool error=false; forall_operands(it, expr) @@ -456,9 +485,9 @@ void interpretert::evaluate( mp_vectort tmp; evaluate(*it, tmp); - if(tmp.size()==sub_size) + if(unbounded_size(it->type()) || tmp.size()==sub_size) { - for(size_t i=0; i0 && address size; + if(ty.size().id()==ID_infinity) + size.push_back(0); + else + evaluate(ty.size(), size); + if(size.size()==1) + { + std::size_t size_int=integer2size_t(size[0]); + for(std::size_t i=0; i where; + std::vector new_value; + evaluate(wexpr.where(), where); + evaluate(wexpr.new_value(), new_value); + const auto &subtype=expr.type().subtype(); + if(!new_value.empty() && where.size()==1 && !unbounded_size(subtype)) + { + // Ignore indices < 0, which the string solver sometimes produces + if(where[0]<0) + return; + std::size_t where_idx=integer2size_t(where[0]); + std::size_t subtype_size=get_size(subtype); + std::size_t need_size=(where_idx+1)*subtype_size; + if(dest.size() + +template class sparse_vectort +{ +protected: + typedef std::map underlyingt; + underlyingt underlying; + uint64_t _size; + +public: + sparse_vectort() : + _size(0) {} + + const T &operator[](uint64_t idx) const + { + assert(idx<_size && "index out of range"); + return underlying[idx]; + } + + T &operator[](uint64_t idx) + { + assert(idx<_size && "index out of range"); + return underlying[idx]; + } + + uint64_t size() const + { + return _size; + } + + void resize(uint64_t new_size) + { + assert(new_size>=_size && "sparse vector can't be shrunk (yet)"); + _size=new_size; + } + + typedef typename underlyingt::iterator iteratort; + typedef typename underlyingt::const_iterator const_iteratort; + + iteratort begin() { return underlying.begin(); } + const_iteratort begin() const { return underlying.begin(); } + + iteratort end() { return underlying.end(); } + const_iteratort end() const { return underlying.end(); } + + const_iteratort find(uint64_t idx) { return underlying.find(idx); } +}; + +#endif // CPROVER_UTIL_SPARSE_VECTOR_H