std::set<symbol_exprt> concurrency_aware_abstractort::targets_of_lvalue(const exprt& lvalue, goto_programt::const_targett program_location) { std::set<symbol_exprt> result; if(lvalue.id() == ID_index) { exprt array_name = lvalue.op0(); if(array_name.id() == ID_symbol) { result.insert(to_symbol_expr(array_name)); } else { return targets_of_lvalue(array_name, program_location); } } else if(lvalue.id() == ID_member) { assert(lvalue.operands().size() == 1); return targets_of_lvalue(lvalue.op0(), program_location); } else if(lvalue.id() == ID_symbol) { result.insert(to_symbol_expr(lvalue)); } else if(lvalue.id() == ID_dereference) { // We would like to add anything the pointer can point to, // but not the pointer itself value_setst::valuest value_set; pointer_info.get_values(program_location, lvalue.op0(), value_set); for(value_setst::valuest::iterator it = value_set.begin(); it != value_set.end(); it++) { if(it->id() != ID_object_descriptor) { // TODO: We may need to deal with this situation more carefully continue; } object_descriptor_exprt& object_descriptor = to_object_descriptor_expr(*it); if(object_descriptor.offset() != from_integer(0, index_type())) { std::cout << "Pointer " << from_expr(lvalue.op0()) << " can point to " << from_expr(*it) << " at line " << program_location->location.get_line() << ", we cannot handle this" << std::endl; exit(1); } if(object_descriptor.object().id() != ID_symbol) { std::cout << "Pointer " << from_expr(lvalue.op0()) << " can point to " << from_expr(*it) << " at line " << program_location->location.get_line() << ", we cannot handle this" << std::endl; exit(1); } result.insert(to_symbol_expr(object_descriptor.object())); } } else { std::cout << "Cannot currently handle lvalue: " << from_expr(lvalue) << std::endl; assert(false); } return result; }
std::set<symbol_exprt> locations_of_expression_rec(const predicatet& phi, const goto_programt::const_targett program_location, value_set_analysist& pointer_info, const namespacet& ns) { if(phi.id()==ID_address_of) { // Addresses are constant -- don't need to read the symbol whose address we are taking return std::set<symbol_exprt>(); } if(phi.id()==ID_constant) { // No symbols associated with a constant return std::set<symbol_exprt>(); } if(phi.id()==ID_symbol) { std::set<symbol_exprt> result; result.insert(to_symbol_expr(phi)); return result; } if(phi.id()==ID_dereference) { // We would like to add the pointer itself (which for now we require to be a variable) // and anything it can point to std::set<symbol_exprt> result; result = locations_of_expression_rec(phi.op0(), program_location, pointer_info, ns); // if we have *p, we insert the locations of p itself value_setst::valuest value_set; pointer_info.get_values(program_location, phi.op0(), value_set); for(value_setst::valuest::iterator it = value_set.begin(); it != value_set.end(); it++) { if(it->id() != ID_object_descriptor) { // TODO: We may need to deal with this situation more carefully continue; } object_descriptor_exprt& object_descriptor = to_object_descriptor_expr(*it); if(object_descriptor.object().id() == "NULL-object") { // No locations associated with NULL continue; } if(object_descriptor.offset() != from_integer(0, index_type())) { std::cout << "(*) Warning: pointer " << from_expr(ns, "", phi.op0()) << " can point to " << from_expr(ns, "", *it) << " at " << program_location->location << ", this needs further investigation" << std::endl; continue; } if(object_descriptor.object().id() != ID_symbol) { std::cout << "(**) Warning: pointer " << from_expr(ns, "", phi.op0()) << " can point to " << from_expr(ns, "", *it) << " at " << program_location->location << ", this needs further investigation" << std::endl; continue; } result.insert(to_symbol_expr(object_descriptor.object())); } return result; } if(phi.id()=="invalid-pointer" || phi.id()=="pointer_arithmetic" || phi.id()=="pointer_difference") { std::cout << "(***) Warning: cannot yet handle " << from_expr(ns, "", phi) << ", ignoring it" << std::endl; return std::set<symbol_exprt>(); } { /* Default case: iterate through the operands of the expression, adding all locations referenced therein */ std::set<symbol_exprt> result; for(unsigned int i = 0; i < phi.operands().size(); i++) { std::set<symbol_exprt> symbols_i = locations_of_expression_rec(phi.operands()[i], program_location, pointer_info, ns); for(std::set<symbol_exprt>::iterator it = symbols_i.begin(); it != symbols_i.end(); it++) { result.insert(*it); } } return result; } }
value_set_dereferencet::valuet value_set_dereferencet::build_reference_to( const exprt &what, const modet mode, const exprt &pointer_expr, const guardt &guard) { const typet &dereference_type= ns.follow(pointer_expr.type()).subtype(); if(what.id()==ID_unknown || what.id()==ID_invalid) { invalid_pointer(pointer_expr, guard); return valuet(); } if(what.id()!=ID_object_descriptor) throw "unknown points-to: "+what.id_string(); const object_descriptor_exprt &o=to_object_descriptor_expr(what); const exprt &root_object=o.root_object(); const exprt &object=o.object(); #if 0 std::cout << "O: " << from_expr(ns, "", root_object) << '\n'; #endif valuet result; if(root_object.id()=="NULL-object") { if(options.get_bool_option("pointer-check")) { guardt tmp_guard(guard); if(o.offset().is_zero()) { tmp_guard.add(null_pointer(pointer_expr)); dereference_callback.dereference_failure( "pointer dereference", "NULL pointer", tmp_guard); } else { tmp_guard.add(null_object(pointer_expr)); dereference_callback.dereference_failure( "pointer dereference", "NULL plus offset pointer", tmp_guard); } } } else if(root_object.id()==ID_dynamic_object) { // const dynamic_object_exprt &dynamic_object= // to_dynamic_object_expr(root_object); // the object produced by malloc exprt malloc_object= ns.lookup(CPROVER_PREFIX "malloc_object").symbol_expr(); exprt is_malloc_object=same_object(pointer_expr, malloc_object); // constraint that it actually is a dynamic object exprt dynamic_object_expr(ID_dynamic_object, bool_typet()); dynamic_object_expr.copy_to_operands(pointer_expr); // this is also our guard result.pointer_guard=dynamic_object_expr; // can't remove here, turn into *p result.value=dereference_exprt(pointer_expr, dereference_type); if(options.get_bool_option("pointer-check")) { // if(!dynamic_object.valid().is_true()) { // check if it is still alive guardt tmp_guard(guard); tmp_guard.add(deallocated(pointer_expr, ns)); dereference_callback.dereference_failure( "pointer dereference", "dynamic object deallocated", tmp_guard); } if(options.get_bool_option("bounds-check")) { if(!o.offset().is_zero()) { // check lower bound guardt tmp_guard(guard); tmp_guard.add(is_malloc_object); tmp_guard.add( dynamic_object_lower_bound( pointer_expr, ns, nil_exprt())); dereference_callback.dereference_failure( "pointer dereference", "dynamic object lower bound", tmp_guard); } { // check upper bound // we check SAME_OBJECT(__CPROVER_malloc_object, p) && // POINTER_OFFSET(p)+size>__CPROVER_malloc_size guardt tmp_guard(guard); tmp_guard.add(is_malloc_object); tmp_guard.add( dynamic_object_upper_bound( pointer_expr, dereference_type, ns, size_of_expr(dereference_type, ns))); dereference_callback.dereference_failure( "pointer dereference", "dynamic object upper bound", tmp_guard); } } } } else if(root_object.id()==ID_integer_address) { // This is stuff like *((char *)5). // This is turned into an access to __CPROVER_memory[...]. if(language_mode==ID_java) { result.value=nil_exprt(); return result; } const symbolt &memory_symbol=ns.lookup(CPROVER_PREFIX "memory"); exprt symbol_expr=symbol_exprt(memory_symbol.name, memory_symbol.type); if(base_type_eq( ns.follow(memory_symbol.type).subtype(), dereference_type, ns)) { // Types match already, what a coincidence! // We can use an index expression. exprt index_expr=index_exprt(symbol_expr, pointer_offset(pointer_expr)); index_expr.type()=ns.follow(memory_symbol.type).subtype(); result.value=index_expr; } else if(dereference_type_compare( ns.follow(memory_symbol.type).subtype(), dereference_type)) { exprt index_expr=index_exprt(symbol_expr, pointer_offset(pointer_expr)); index_expr.type()=ns.follow(memory_symbol.type).subtype(); result.value=typecast_exprt(index_expr, dereference_type); } else { // We need to use byte_extract. // Won't do this without a commitment to an endianness. if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::NO_ENDIANNESS) { } else { exprt byte_extract(byte_extract_id(), dereference_type); byte_extract.copy_to_operands( symbol_expr, pointer_offset(pointer_expr)); result.value=byte_extract; } } } else { // something generic -- really has to be a symbol address_of_exprt object_pointer(object); if(o.offset().is_zero()) { equal_exprt equality(pointer_expr, object_pointer); if(ns.follow(equality.lhs().type())!=ns.follow(equality.rhs().type())) equality.lhs().make_typecast(equality.rhs().type()); result.pointer_guard=equality; } else { result.pointer_guard=same_object(pointer_expr, object_pointer); } guardt tmp_guard(guard); tmp_guard.add(result.pointer_guard); valid_check(object, tmp_guard, mode); const typet &object_type=ns.follow(object.type()); const exprt &root_object=o.root_object(); const typet &root_object_type=ns.follow(root_object.type()); exprt root_object_subexpression=root_object; if(dereference_type_compare(object_type, dereference_type) && o.offset().is_zero()) { // The simplest case: types match, and offset is zero! // This is great, we are almost done. result.value=object; if(object_type!=ns.follow(dereference_type)) result.value.make_typecast(dereference_type); } else if(root_object_type.id()==ID_array && dereference_type_compare( root_object_type.subtype(), dereference_type)) { // We have an array with a subtype that matches // the dereferencing type. // We will require well-alignedness! exprt offset; // this should work as the object is essentially the root object if(o.offset().is_constant()) offset=o.offset(); else offset=pointer_offset(pointer_expr); exprt adjusted_offset; // are we doing a byte? mp_integer element_size= dereference_type.id()==ID_empty? pointer_offset_size(char_type(), ns): pointer_offset_size(dereference_type, ns); if(element_size==1) { // no need to adjust offset adjusted_offset=offset; } else if(element_size<=0) { throw "unknown or invalid type size of:\n"+dereference_type.pretty(); } else { exprt element_size_expr= from_integer(element_size, offset.type()); adjusted_offset=binary_exprt( offset, ID_div, element_size_expr, offset.type()); // TODO: need to assert well-alignedness } index_exprt index_expr= index_exprt(root_object, adjusted_offset, root_object_type.subtype()); bounds_check(index_expr, tmp_guard); result.value=index_expr; if(ns.follow(result.value.type())!=ns.follow(dereference_type)) result.value.make_typecast(dereference_type); } else if(get_subexpression_at_offset( root_object_subexpression, o.offset(), dereference_type, ns)) { // Successfully found a member, array index, or combination thereof // that matches the desired type and offset: result.value=root_object_subexpression; } else { // we extract something from the root object result.value=o.root_object(); // this is relative to the root object const exprt offset=pointer_offset(pointer_expr); if(memory_model(result.value, dereference_type, tmp_guard, offset)) { // ok, done } else { if(options.get_bool_option("pointer-check")) { std::string msg="memory model not applicable (got `"; msg+=from_type(ns, "", result.value.type()); msg+="', expected `"; msg+=from_type(ns, "", dereference_type); msg+="')"; dereference_callback.dereference_failure( "pointer dereference", msg, tmp_guard); } return valuet(); // give up, no way that this is ok } } } return result; }