void arrayst::add_array_constraints( const index_sett &index_set, const exprt &expr) { if(expr.id()==ID_with) return add_array_constraints_with(index_set, to_with_expr(expr)); else if(expr.id()==ID_if) return add_array_constraints_if(index_set, to_if_expr(expr)); else if(expr.id()==ID_array_of) return add_array_constraints_array_of(index_set, to_array_of_expr(expr)); else if(expr.id()==ID_symbol || expr.id()==ID_nondet_symbol || expr.id()==ID_constant || expr.id()=="zero_string" || expr.id()==ID_array || expr.id()==ID_string_constant) { } else if(expr.id()==ID_member && to_member_expr(expr).struct_op().id()==ID_symbol) { } else throw "unexpected array expression: `"+expr.id_string()+"'"; }
void goto_checkt::invalidate(const exprt &lhs) { if(lhs.id()==ID_index) invalidate(to_index_expr(lhs).array()); else if(lhs.id()==ID_member) invalidate(to_member_expr(lhs).struct_op()); else if(lhs.id()==ID_symbol) { // clear all assertions about 'symbol' find_symbols_sett find_symbols_set; find_symbols_set.insert(to_symbol_expr(lhs).get_identifier()); for(assertionst::iterator it=assertions.begin(); it!=assertions.end(); ) // no it++ { assertionst::iterator next=it; next++; if(has_symbol(*it, find_symbols_set) || has_dereference(*it)) assertions.erase(it); it=next; } } else { // give up, clear all assertions.clear(); } }
exprt local_SSAt::read_rhs_address_of_rec( const exprt &expr, locationt loc) const { if(expr.id()==ID_dereference) { // We 'read' the pointer only, the dereferencing expression stays. dereference_exprt tmp=to_dereference_expr(expr); tmp.pointer()=read_rhs_rec(tmp.pointer(), loc); return tmp; } else if(expr.id()==ID_member) { member_exprt tmp=to_member_expr(expr); tmp.struct_op()=read_rhs_address_of_rec(tmp.struct_op(), loc); return tmp; } else if(expr.id()==ID_index) { index_exprt tmp=to_index_expr(expr); tmp.array()=read_rhs_address_of_rec(tmp.array(), loc); tmp.index()=read_rhs_rec(tmp.index(), loc); return tmp; } else if(expr.id()==ID_if) { if_exprt tmp=to_if_expr(expr); tmp.cond()=read_rhs_rec(tmp.cond(), loc); tmp.true_case()=read_rhs_address_of_rec(tmp.true_case(), loc); tmp.false_case()=read_rhs_address_of_rec(tmp.false_case(), loc); return tmp; } else return expr; }
bool remove_const_function_pointerst::try_resolve_expression( const exprt &expr, expressionst &out_resolved_expression, bool &out_is_const) { exprt simplified_expr=simplify_expr(expr, ns); bool resolved; expressionst resolved_expressions; bool is_resolved_expression_const; if(simplified_expr.id()==ID_index) { const index_exprt &index_expr=to_index_expr(simplified_expr); resolved= try_resolve_index_of( index_expr, resolved_expressions, is_resolved_expression_const); } else if(simplified_expr.id()==ID_member) { const member_exprt &member_expr=to_member_expr(simplified_expr); resolved=try_resolve_member( member_expr, resolved_expressions, is_resolved_expression_const); } else if(simplified_expr.id()==ID_dereference) { const dereference_exprt &deref=to_dereference_expr(simplified_expr); resolved= try_resolve_dereference( deref, resolved_expressions, is_resolved_expression_const); } else if(simplified_expr.id()==ID_typecast) { typecast_exprt typecast_expr=to_typecast_expr(simplified_expr); resolved= try_resolve_typecast( typecast_expr, resolved_expressions, is_resolved_expression_const); } else if(simplified_expr.id()==ID_symbol) { LOG("Non const symbol will not be squashed", simplified_expr); resolved=false; } else { resolved_expressions.push_back(simplified_expr); is_resolved_expression_const=is_const_expression(simplified_expr); resolved=true; } if(resolved) { out_resolved_expression.insert( out_resolved_expression.end(), resolved_expressions.begin(), resolved_expressions.end()); out_is_const=is_resolved_expression_const; return true; } else { return false; } }
void rd_range_domaint::assign( const namespacet &ns, locationt from, const exprt &lhs, const mp_integer &range_start, const mp_integer &size) { if(lhs.id()==ID_member) assign(ns, from, to_member_expr(lhs).struct_op(), range_start, size); else if(lhs.id()==ID_index) assign(ns, from, to_index_expr(lhs).array(), range_start, size); else { const symbol_exprt &symbol=to_symbol_expr(lhs); const irep_idt identifier=symbol.get_identifier(); if(range_start>=0) { kill(from, identifier, range_start, size); gen(from, identifier, range_start, size); } else { mp_integer full_size=pointer_offset_size(ns, symbol.type()); gen(from, identifier, 0, full_size); } } }
static void build_object_descriptor_rec( const namespacet &ns, const exprt &expr, object_descriptor_exprt &dest) { const signedbv_typet index_type(config.ansi_c.pointer_width); if(expr.id()==ID_index) { const index_exprt &index=to_index_expr(expr); build_object_descriptor_rec(ns, index.array(), dest); exprt sub_size=size_of_expr(expr.type(), ns); assert(sub_size.is_not_nil()); dest.offset()= plus_exprt(dest.offset(), mult_exprt(typecast_exprt(index.index(), index_type), typecast_exprt(sub_size, index_type))); } else if(expr.id()==ID_member) { const member_exprt &member=to_member_expr(expr); const exprt &struct_op=member.struct_op(); build_object_descriptor_rec(ns, struct_op, dest); exprt offset=member_offset_expr(member, ns); assert(offset.is_not_nil()); dest.offset()= plus_exprt(dest.offset(), typecast_exprt(offset, index_type)); } else if(expr.id()==ID_byte_extract_little_endian || expr.id()==ID_byte_extract_big_endian) { const byte_extract_exprt &be=to_byte_extract_expr(expr); dest.object()=be.op(); build_object_descriptor_rec(ns, be.op(), dest); dest.offset()= plus_exprt(dest.offset(), typecast_exprt(to_byte_extract_expr(expr).offset(), index_type)); } else if(expr.id()==ID_typecast) { const typecast_exprt &tc=to_typecast_expr(expr); dest.object()=tc.op(); build_object_descriptor_rec(ns, tc.op(), dest); } }
void uninitialized_domaint::assign(const exprt &lhs) { if(lhs.id()==ID_index) assign(to_index_expr(lhs).array()); else if(lhs.id()==ID_member) assign(to_member_expr(lhs).struct_op()); else if(lhs.id()==ID_symbol) uninitialized.erase(to_symbol_expr(lhs).get_identifier()); }
static void build_ssa_identifier_rec( const exprt &expr, const irep_idt &l0, const irep_idt &l1, const irep_idt &l2, std::ostream &os, std::ostream &l1_object_os) { if(expr.id()==ID_member) { const member_exprt &member=to_member_expr(expr); build_ssa_identifier_rec(member.struct_op(), l0, l1, l2, os, l1_object_os); os << '.' << member.get_component_name(); } else if(expr.id()==ID_index) { const index_exprt &index=to_index_expr(expr); build_ssa_identifier_rec(index.array(), l0, l1, l2, os, l1_object_os); mp_integer idx; if(to_integer(to_constant_expr(index.index()), idx)) assert(false); os << '[' << idx << ']'; } else if(expr.id()==ID_symbol) { auto symid=to_symbol_expr(expr).get_identifier(); os << symid; l1_object_os << symid; if(!l0.empty()) { os << '!' << l0; l1_object_os << '!' << l0; } if(!l1.empty()) { os << '@' << l1; l1_object_os << '@' << l1; } if(!l2.empty()) os << '#' << l2; } else assert(false); }
bool is_lvalue(const exprt &expr) { if(expr.id()==ID_index) return is_lvalue(to_index_expr(expr).op0()); else if(expr.id()==ID_member) return is_lvalue(to_member_expr(expr).op0()); else if(expr.id()==ID_dereference) return true; else if(expr.id()==ID_symbol) return true; else return false; }
void goto_symext::dereference_rec_address_of( exprt &expr, statet &state, guardt &guard) { // Could be member, could be if, could be index. if(expr.id()==ID_member) dereference_rec_address_of( to_member_expr(expr).struct_op(), state, guard); else if(expr.id()==ID_if) { // the condition is not an address dereference_rec( to_if_expr(expr).cond(), state, guard, false); // add to guard? dereference_rec_address_of( to_if_expr(expr).true_case(), state, guard); dereference_rec_address_of( to_if_expr(expr).false_case(), state, guard); } else if(expr.id()==ID_index) { // the index is not an address dereference_rec( to_index_expr(expr).index(), state, guard, false); // the array _is_ an address dereference_rec_address_of( to_index_expr(expr).array(), state, guard); } else { // give up and dereference dereference_rec(expr, state, guard, false); } }
/// Use the information in the domain to simplify the expression on the LHS of /// an assignment. This for example won't simplify symbols to their values, but /// does simplify indices in arrays, members of structs and dereferencing of /// pointers /// \param condition: the expression to simplify /// \param ns: the namespace /// \return True if condition did not change. False otherwise. condition will be /// updated with the simplified condition if it has worked bool ai_domain_baset::ai_simplify_lhs( exprt &condition, const namespacet &ns) const { // Care must be taken here to give something that is still writable if(condition.id()==ID_index) { index_exprt ie=to_index_expr(condition); bool no_simplification=ai_simplify(ie.index(), ns); if(!no_simplification) condition=simplify_expr(ie, ns); return no_simplification; } else if(condition.id()==ID_dereference) { dereference_exprt de=to_dereference_expr(condition); bool no_simplification=ai_simplify(de.pointer(), ns); if(!no_simplification) condition=simplify_expr(de, ns); // So *(&x) -> x return no_simplification; } else if(condition.id()==ID_member) { member_exprt me=to_member_expr(condition); // Since simplify_ai_lhs is required to return an addressable object // (so remains a valid left hand side), to simplify // `(something_simplifiable).b` we require that `something_simplifiable` // must also be addressable bool no_simplification=ai_simplify_lhs(me.compound(), ns); if(!no_simplification) condition=simplify_expr(me, ns); return no_simplification; } else return true; }
bool goto_symext::is_index_member_symbol_if(const exprt &expr) { // Could be member, could be if, could be index. if(expr.id()==ID_member) { return is_index_member_symbol_if( to_member_expr(expr).struct_op()); } else if(expr.id()==ID_if) { return is_index_member_symbol_if(to_if_expr(expr).true_case()) && is_index_member_symbol_if(to_if_expr(expr).false_case()); } else if(expr.id()==ID_index) { return is_index_member_symbol_if(to_index_expr(expr).array()); } else if(expr.id()==ID_symbol) return true; else return false; }
exprt build_full_lhs_rec( const prop_convt &prop_conv, const namespacet &ns, const exprt &src_original, // original identifiers const exprt &src_ssa) // renamed identifiers { if(src_ssa.id()!=src_original.id()) return src_original; const irep_idt id=src_original.id(); if(id==ID_index) { // get index value from src_ssa exprt index_value=prop_conv.get(to_index_expr(src_ssa).index()); if(index_value.is_not_nil()) { simplify(index_value, ns); index_exprt tmp=to_index_expr(src_original); tmp.index()=index_value; tmp.array()= build_full_lhs_rec(prop_conv, ns, to_index_expr(src_original).array(), to_index_expr(src_ssa).array()); return tmp; } return src_original; } else if(id==ID_member) { member_exprt tmp=to_member_expr(src_original); tmp.struct_op()=build_full_lhs_rec( prop_conv, ns, to_member_expr(src_original).struct_op(), to_member_expr(src_ssa).struct_op()); } else if(id==ID_if) { if_exprt tmp2=to_if_expr(src_original); tmp2.false_case()=build_full_lhs_rec(prop_conv, ns, tmp2.false_case(), to_if_expr(src_ssa).false_case()); tmp2.true_case()=build_full_lhs_rec(prop_conv, ns, tmp2.true_case(), to_if_expr(src_ssa).true_case()); exprt tmp=prop_conv.get(to_if_expr(src_ssa).cond()); if(tmp.is_true()) return tmp2.true_case(); else if(tmp.is_false()) return tmp2.false_case(); else return tmp2; } else if(id==ID_typecast) { typecast_exprt tmp=to_typecast_expr(src_original); tmp.op()=build_full_lhs_rec(prop_conv, ns, to_typecast_expr(src_original).op(), to_typecast_expr(src_ssa).op()); return tmp; } else if(id==ID_byte_extract_little_endian || id==ID_byte_extract_big_endian) { exprt tmp=src_original; assert(tmp.operands().size()==2); tmp.op0()=build_full_lhs_rec(prop_conv, ns, tmp.op0(), src_ssa.op0()); // re-write into big case-split } return src_original; }
bool ssa_may_alias( const exprt &e1, const exprt &e2, const namespacet &ns) { #ifdef DEBUG std::cout << "MAY ALIAS1 " << from_expr(ns, "", e1) << " " << from_expr(ns, "", e2) << "\n"; #endif // The same? if(e1==e2) return true; // Both symbol? if(e1.id()==ID_symbol && e2.id()==ID_symbol) { return to_symbol_expr(e1).get_identifier()== to_symbol_expr(e2).get_identifier(); } // __CPROVER symbols if(e1.id()==ID_symbol && has_prefix( id2string(to_symbol_expr(e1).get_identifier()), CPROVER_PREFIX)) return false; if(e2.id()==ID_symbol && has_prefix( id2string(to_symbol_expr(e2).get_identifier()), CPROVER_PREFIX)) return false; if(e1.id()==ID_symbol && has_suffix( id2string(to_symbol_expr(e1).get_identifier()), "#return_value")) return false; if(e2.id()==ID_symbol && has_suffix( id2string(to_symbol_expr(e2).get_identifier()), "#return_value")) return false; // Both member? if(e1.id()==ID_member && e2.id()==ID_member) { const member_exprt &m1=to_member_expr(e1); const member_exprt &m2=to_member_expr(e2); // same component? if(m1.get_component_name()!=m2.get_component_name()) return false; return ssa_may_alias(m1.struct_op(), m2.struct_op(), ns); } // Both index? if(e1.id()==ID_index && e2.id()==ID_index) { const index_exprt &i1=to_index_expr(e1); const index_exprt &i2=to_index_expr(e2); return ssa_may_alias(i1.array(), i2.array(), ns); } const typet &t1=ns.follow(e1.type()); const typet &t2=ns.follow(e2.type()); // If one is an array and the other not, consider the elements if(t1.id()==ID_array && t2.id()!=ID_array) if(ssa_may_alias( index_exprt(e1, gen_zero(index_type()), t1.subtype()), e2, ns)) return true; if(t2.id()==ID_array && t2.id()!=ID_array) if(ssa_may_alias( e1, index_exprt(e2, gen_zero(index_type()), t2.subtype()), ns)) return true; // Pointers only alias with other pointers, // which is a restriction. if(t1.id()==ID_pointer) return t2.id()==ID_pointer; if(t2.id()==ID_pointer) return t1.id()==ID_pointer; // Is one a scalar pointer? if(e1.id()==ID_dereference && (t1.id()==ID_signedbv || t1.id()==ID_unsignedbv || t1.id()==ID_floatbv)) return true; if(e2.id()==ID_dereference && (t2.id()==ID_signedbv || t2.id()==ID_unsignedbv || t1.id()==ID_floatbv)) return true; // Is one a pointer? if(e1.id()==ID_dereference || e2.id()==ID_dereference) { // look at the types // same type? if(base_type_eq(t1, t2, ns)) { return true; } // should consider further options, e.g., struct prefixes return false; } return false; // both different objects }
exprt dereference_rec( const exprt &src, const ssa_value_domaint &ssa_value_domain, const std::string &nondet_prefix, const namespacet &ns) { if(src.id()==ID_dereference) { const exprt &pointer=dereference_rec( to_dereference_expr(src).pointer(), ssa_value_domain, nondet_prefix, ns); const typet &pointed_type=ns.follow(pointer.type().subtype()); const ssa_value_domaint::valuest values=ssa_value_domain(pointer, ns); exprt result; if(values.value_set.empty()) { result=pointed_object(pointer, ns); } else { auto it=values.value_set.begin(); if(values.null || values.unknown || (values.value_set.size()>1 && it->type().get_bool("#dynamic"))) { std::string dyn_type_name=pointed_type.id_string(); if(pointed_type.id()==ID_struct) dyn_type_name+="_"+id2string(to_struct_type(pointed_type).get_tag()); irep_idt identifier="ssa::"+dyn_type_name+"_obj$unknown"; result=symbol_exprt(identifier, src.type()); result.set("#unknown_obj", true); } else { result=ssa_alias_value(src, (it++)->get_expr(), ns); result.set("#heap_access", result.type().get_bool("#dynamic")); } for(; it!=values.value_set.end(); ++it) { exprt guard=ssa_alias_guard(src, it->get_expr(), ns); exprt value=ssa_alias_value(src, it->get_expr(), ns); result=if_exprt(guard, value, result); result.set( "#heap_access", result.get_bool("#heap_access") || value.type().get_bool("#dynamic")); } } return result; } else if(src.id()==ID_member) { member_exprt tmp=to_member_expr(src); tmp.struct_op()= dereference_rec(tmp.struct_op(), ssa_value_domain, nondet_prefix, ns); tmp.set("#heap_access", tmp.struct_op().get_bool("#heap_access")); #ifdef DEBUG std::cout << "dereference_rec tmp: " << from_expr(ns, "", tmp) << '\n'; #endif if(tmp.struct_op().is_nil()) return nil_exprt(); return lift_if(tmp); } else if(src.id()==ID_address_of) { address_of_exprt tmp=to_address_of_expr(src); tmp.object()= dereference_rec(tmp.object(), ssa_value_domain, nondet_prefix, ns); tmp.set("#heap_access", tmp.object().get_bool("#heap_access")); if(tmp.object().is_nil()) return nil_exprt(); return lift_if(tmp); } else { exprt tmp=src; Forall_operands(it, tmp) { *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns); if(it->get_bool("#heap_access")) tmp.set("#heap_access", true); } return tmp; }
void cvc_convt::convert_address_of_rec(const exprt &expr) { if(expr.id()==ID_symbol || expr.id()==ID_constant || expr.id()==ID_string_constant) { out << "(# object:=" << pointer_logic.add_object(expr) << ", offset:=" << bin_zero(config.ansi_c.pointer_width) << " #)"; } else if(expr.id()==ID_index) { if(expr.operands().size()!=2) throw "index takes two operands"; const exprt &array=expr.op0(); const exprt &index=expr.op1(); if(index.is_zero()) { if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); } else { out << "(LET P: "; out << cvc_pointer_type(); out << " = "; if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } } else if(expr.id()==ID_member) { if(expr.operands().size()!=1) throw "member takes one operand"; const exprt &struct_op=expr.op0(); out << "(LET P: "; out << cvc_pointer_type(); out << " = "; convert_address_of_rec(struct_op); const irep_idt &component_name= to_member_expr(expr).get_component_name(); mp_integer offset=member_offset( to_struct_type(struct_op.type()), component_name, ns); typet index_type(ID_unsignedbv); index_type.set(ID_width, config.ansi_c.pointer_width); exprt index=from_integer(offset, index_type); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } else throw "don't know how to take address of: "+expr.id_string(); }
bool remove_const_function_pointerst::try_resolve_function_call( const exprt &expr, functionst &out_functions) { assert(out_functions.empty()); const exprt &simplified_expr=simplify_expr(expr, ns); bool resolved=false; functionst resolved_functions; if(simplified_expr.id()==ID_index) { const index_exprt &index_expr=to_index_expr(simplified_expr); resolved=try_resolve_index_of_function_call(index_expr, resolved_functions); } else if(simplified_expr.id()==ID_member) { const member_exprt &member_expr=to_member_expr(simplified_expr); resolved=try_resolve_member_function_call(member_expr, resolved_functions); } else if(simplified_expr.id()==ID_address_of) { address_of_exprt address_expr=to_address_of_expr(simplified_expr); resolved=try_resolve_address_of_function_call( address_expr, resolved_functions); } else if(simplified_expr.id()==ID_dereference) { const dereference_exprt &deref=to_dereference_expr(simplified_expr); resolved=try_resolve_dereference_function_call(deref, resolved_functions); } else if(simplified_expr.id()==ID_typecast) { typecast_exprt typecast_expr=to_typecast_expr(simplified_expr); resolved= try_resolve_typecast_function_call(typecast_expr, resolved_functions); } else if(simplified_expr.id()==ID_symbol) { if(simplified_expr.type().id()==ID_code) { resolved_functions.insert(simplified_expr); resolved=true; } else { LOG("Non const symbol wasn't squashed", simplified_expr); resolved=false; } } else { LOG("Unrecognised expression", simplified_expr); resolved=false; } if(resolved) { out_functions.insert(resolved_functions.begin(), resolved_functions.end()); return true; } else { return false; } }
void local_SSAt::assign_rec( const exprt &lhs, const exprt &rhs, const exprt &guard, locationt loc) { const typet &type=ns.follow(lhs.type()); if(is_symbol_struct_member(lhs, ns)) { if(type.id()==ID_struct) { // need to split up const struct_typet &struct_type=to_struct_type(type); const struct_typet::componentst &components=struct_type.components(); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { member_exprt new_lhs(lhs, it->get_name(), it->type()); member_exprt new_rhs(rhs, it->get_name(), it->type()); assign_rec(new_lhs, new_rhs, guard, loc); } return; } ssa_objectt lhs_object(lhs, ns); const std::set<ssa_objectt> &assigned= assignments.get(loc); if(assigned.find(lhs_object)!=assigned.end()) { exprt ssa_rhs=read_rhs(rhs, loc); const symbol_exprt ssa_symbol=name(lhs_object, OUT, loc); equal_exprt equality(ssa_symbol, ssa_rhs); nodes[loc].equalities.push_back(equality); } } else if(lhs.id()==ID_index) { const index_exprt &index_expr=to_index_expr(lhs); exprt ssa_array=index_expr.array(); exprt new_rhs=with_exprt(ssa_array, index_expr.index(), rhs); assign_rec(index_expr.array(), new_rhs, guard, loc); } else if(lhs.id()==ID_member) { // These are non-flattened struct or union members. const member_exprt &member_expr=to_member_expr(lhs); const exprt &compound=member_expr.struct_op(); const typet &compound_type=ns.follow(compound.type()); if(compound_type.id()==ID_union) { union_exprt new_rhs(member_expr.get_component_name(), rhs, compound.type()); assign_rec(member_expr.struct_op(), new_rhs, guard, loc); } else if(compound_type.id()==ID_struct) { exprt member_name(ID_member_name); member_name.set(ID_component_name, member_expr.get_component_name()); with_exprt new_rhs(compound, member_name, rhs); assign_rec(compound, new_rhs, guard, loc); } } else if(lhs.id()==ID_complex_real) { assert(lhs.operands().size()==1); const exprt &op=lhs.op0(); const complex_typet &complex_type=to_complex_type(op.type()); exprt imag_op=unary_exprt(ID_complex_imag, op, complex_type.subtype()); complex_exprt new_rhs(rhs, imag_op, complex_type); assign_rec(op, new_rhs, guard, loc); } else if(lhs.id()==ID_complex_imag) { assert(lhs.operands().size()==1); const exprt &op=lhs.op0(); const complex_typet &complex_type=to_complex_type(op.type()); exprt real_op=unary_exprt(ID_complex_real, op, complex_type.subtype()); complex_exprt new_rhs(real_op, rhs, complex_type); assign_rec(op, new_rhs, guard, loc); } else if(lhs.id()==ID_if) { const if_exprt &if_expr=to_if_expr(lhs); assign_rec(if_expr.true_case(), rhs, and_exprt(guard, if_expr.cond()), loc); assign_rec(if_expr.false_case(), rhs, and_exprt(guard, not_exprt(if_expr.cond())), loc); } else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) { const byte_extract_exprt &byte_extract_expr=to_byte_extract_expr(lhs); exprt new_lhs=byte_extract_expr.op(); exprt new_rhs=byte_extract_exprt( byte_extract_expr.id(), rhs, byte_extract_expr.offset(), new_lhs.type()); assign_rec(new_lhs, new_rhs, guard, loc); } else throw "UNKNOWN LHS: "+lhs.id_string(); }
void arrayst::collect_arrays(const exprt &a) { const array_typet &array_type= to_array_type(ns.follow(a.type())); if(a.id()==ID_with) { if(a.operands().size()!=3) throw "with expected to have three operands"; // check types if(!base_type_eq(array_type, a.op0().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got with without matching types"; } arrays.make_union(a, a.op0()); collect_arrays(a.op0()); // make sure this shows as an application index_exprt index_expr; index_expr.type()=array_type.subtype(); index_expr.array()=a.op0(); index_expr.index()=a.op1(); record_array_index(index_expr); } else if(a.id()==ID_if) { if(a.operands().size()!=3) throw "if expected to have three operands"; // check types if(!base_type_eq(array_type, a.op1().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got if without matching types"; } // check types if(!base_type_eq(array_type, a.op2().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got if without matching types"; } arrays.make_union(a, a.op1()); arrays.make_union(a, a.op2()); collect_arrays(a.op1()); collect_arrays(a.op2()); } else if(a.id()==ID_symbol) { } else if(a.id()==ID_nondet_symbol) { } else if(a.id()==ID_member) { if(to_member_expr(a).struct_op().id()!=ID_symbol) throw "unexpected array expression: member with `"+a.op0().id_string()+"'"; } else if(a.id()==ID_constant || a.id()==ID_array || a.id()==ID_string_constant) { } else if(a.id()==ID_array_of) { } else throw "unexpected array expression: `"+a.id_string()+"'"; }
exprt dereference_rec( const exprt &src, const ssa_value_domaint &ssa_value_domain, const std::string &nondet_prefix, const namespacet &ns) { if(src.id()==ID_dereference) { const exprt &pointer=to_dereference_expr(src).pointer(); exprt pointer_deref=dereference(pointer, ssa_value_domain, nondet_prefix, ns); // We use the identifier produced by // local_SSAt::replace_side_effects_rec exprt result=symbol_exprt(nondet_prefix, src.type()); // query the value sets const ssa_value_domaint::valuest values= ssa_value_domain(pointer, ns); for(ssa_value_domaint::valuest::value_sett::const_iterator it=values.value_set.begin(); it!=values.value_set.end(); it++) { exprt guard=ssa_alias_guard(src, it->get_expr(), ns); exprt value=ssa_alias_value(src, it->get_expr(), ns); result=if_exprt(guard, value, result); } return result; } else if(src.id()==ID_member) { member_exprt tmp=to_member_expr(src); tmp.struct_op()=dereference_rec(tmp.struct_op(), ssa_value_domain, nondet_prefix, ns); #ifdef DEBUG std::cout << "dereference_rec tmp: " << from_expr(ns, "", tmp) << '\n'; #endif if(tmp.struct_op().is_nil()) return nil_exprt(); return lift_if(tmp); } else if(src.id()==ID_address_of) { address_of_exprt tmp=to_address_of_expr(src); tmp.object()=dereference_rec(tmp.object(), ssa_value_domain, nondet_prefix, ns); if(tmp.object().is_nil()) return nil_exprt(); return lift_if(tmp); } else { exprt tmp=src; Forall_operands(it, tmp) *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns); return tmp; } }
exprt path_symex_statet::instantiate_rec( const exprt &src, bool propagate) { #ifdef DEBUG std::cout << "instantiate_rec: " << from_expr(var_map.ns, "", src) << '\n'; #endif // check whether this is a symbol(.member|[index])* if(is_symbol_member_index(src)) { exprt tmp_symbol_member_index= read_symbol_member_index(src, propagate); assert(tmp_symbol_member_index.is_not_nil()); return tmp_symbol_member_index; // yes! } if(src.id()==ID_address_of) { assert(src.operands().size()==1); exprt tmp=src; tmp.op0()=instantiate_rec_address(tmp.op0(), propagate); return tmp; } else if(src.id()==ID_side_effect) { // could be done separately const irep_idt &statement=to_side_effect_expr(src).get_statement(); if(statement==ID_nondet) { irep_idt id="symex::nondet"+std::to_string(var_map.nondet_count); var_map.nondet_count++; return symbol_exprt(id, src.type()); } else throw "instantiate_rec: unexpected side effect "+id2string(statement); } else if(src.id()==ID_dereference) { // dereferencet has run already, so we should only be left with // integer addresses. Will transform into __CPROVER_memory[] // eventually. } else if(src.id()==ID_member) { const typet &compound_type= var_map.ns.follow(to_member_expr(src).struct_op().type()); if(compound_type.id()==ID_struct) { // do nothing } else if(compound_type.id()==ID_union) { // should already have been rewritten to byte_extract throw "unexpected union member"; } else { throw "member expects struct or union type"+src.pretty(); } } else if(src.id()==ID_byte_extract_little_endian || src.id()==ID_byte_extract_big_endian) { } else if(src.id()==ID_symbol) { // must be SSA already, or code assert(src.type().id()==ID_code || src.get_bool(ID_C_SSA_symbol)); } if(!src.has_operands()) return src; exprt src2=src; // recursive calls on structure of 'src' Forall_operands(it, src2) { exprt tmp_op=instantiate_rec(*it, propagate); *it=tmp_op; }
exprt path_symex_statet::instantiate_rec( const exprt &src, bool propagate) { #ifdef DEBUG std::cout << "instantiate_rec: " << from_expr(var_map.ns, "", src) << std::endl; #endif const typet &src_type=var_map.ns.follow(src.type()); if(src_type.id()==ID_struct) // src is a struct { const struct_typet &struct_type=to_struct_type(src_type); const struct_typet::componentst &components=struct_type.components(); struct_exprt result(src.type()); result.operands().resize(components.size()); // split it up into components for(unsigned i=0; i<components.size(); i++) { const typet &subtype=components[i].type(); const irep_idt &component_name=components[i].get_name(); exprt new_src; if(src.id()==ID_struct) // struct constructor? { assert(src.operands().size()==components.size()); new_src=src.operands()[i]; } else new_src=member_exprt(src, component_name, subtype); // recursive call result.operands()[i]=instantiate_rec(new_src, propagate); } return result; // done } else if(src_type.id()==ID_array) // src is an array { const array_typet &array_type=to_array_type(src_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"; unsigned long long size_int=integer2unsigned(size); array_exprt result(array_type); result.operands().resize(size_int); // split it up into elements for(unsigned long long i=0; i<size_int; ++i) { exprt index=from_integer(i, array_type.size().type()); exprt new_src=index_exprt(src, index, subtype); // array constructor? if(src.id()==ID_array) new_src=simplify_expr(new_src, var_map.ns); // recursive call result.operands()[i]=instantiate_rec(new_src, propagate); } return result; // done } else { // TODO } } else if(src_type.id()==ID_vector) // src is a vector { const vector_typet &vector_type=to_vector_type(src_type); const typet &subtype=vector_type.subtype(); if(!vector_type.size().is_constant()) throw "vector with non-constant size"; mp_integer size; if(to_integer(vector_type.size(), size)) throw "failed to convert vector size"; unsigned long long int size_int=integer2unsigned(size); vector_exprt result(vector_type); exprt::operandst &operands=result.operands(); operands.resize(size_int); // split it up into elements for(unsigned long long i=0; i<size_int; ++i) { exprt index=from_integer(i, vector_type.size().type()); exprt new_src=index_exprt(src, index, subtype); // vector constructor? if(src.id()==ID_vector) new_src=simplify_expr(new_src, var_map.ns); // recursive call operands[i]=instantiate_rec(new_src, propagate); } return result; // done } // check whether this is a symbol(.member|[index])* { exprt tmp_symbol_member_index= read_symbol_member_index(src, propagate); if(tmp_symbol_member_index.is_not_nil()) return tmp_symbol_member_index; // yes! } if(src.id()==ID_address_of) { assert(src.operands().size()==1); exprt tmp=src; tmp.op0()=instantiate_rec_address(tmp.op0(), propagate); return tmp; } else if(src.id()==ID_sideeffect) { // could be done separately const irep_idt &statement=to_side_effect_expr(src).get_statement(); if(statement==ID_nondet) { irep_idt id="symex::nondet"+i2string(var_map.nondet_count); var_map.nondet_count++; return symbol_exprt(id, src.type()); } else throw "instantiate_rec: unexpected side effect "+id2string(statement); } else if(src.id()==ID_dereference) { // dereferencet has run already, so we should only be left with // integer addresses. Will transform into __CPROVER_memory[] // eventually. } else if(src.id()==ID_index) { // avoids indefinite recursion above return src; } else if(src.id()==ID_member) { const typet &compound_type= var_map.ns.follow(to_member_expr(src).struct_op().type()); if(compound_type.id()==ID_struct) { // avoids indefinite recursion above return src; } else if(compound_type.id()==ID_union) { member_exprt tmp=to_member_expr(src); tmp.struct_op()=instantiate_rec(tmp.struct_op(), propagate); return tmp; } else { throw "member expects struct or union type"+src.pretty(); } } if(!src.has_operands()) return src; exprt src2=src; // recursive calls on structure of 'src' Forall_operands(it, src2) { exprt tmp_op=instantiate_rec(*it, propagate); *it=tmp_op; }
bool simplify_exprt::simplify_address_of_arg(exprt &expr) { if(expr.id()==ID_index) { if(expr.operands().size()==2) { bool result=true; if(!simplify_address_of_arg(expr.op0())) result=false; if(!simplify_rec(expr.op1())) result=false; // rewrite (*(type *)int) [index] by // pushing the index inside mp_integer address; if(is_dereference_integer_object(expr.op0(), address)) { // push index into address mp_integer step_size, index; step_size=pointer_offset_size(expr.type(), ns); if(!to_integer(expr.op1(), index) && step_size!=-1) { unsignedbv_typet int_type(config.ansi_c.pointer_width); pointer_typet pointer_type; pointer_type.subtype()=expr.type(); typecast_exprt typecast_expr( from_integer(step_size*index+address, int_type), pointer_type); exprt new_expr=dereference_exprt(typecast_expr, expr.type()); expr=new_expr; result=true; } } return result; } } else if(expr.id()==ID_member) { if(expr.operands().size()==1) { bool result=true; if(!simplify_address_of_arg(expr.op0())) result=false; const typet &op_type=ns.follow(expr.op0().type()); if(op_type.id()==ID_struct) { // rewrite NULL -> member by // pushing the member inside mp_integer address; if(is_dereference_integer_object(expr.op0(), address)) { const struct_typet &struct_type=to_struct_type(op_type); const irep_idt &member=to_member_expr(expr).get_component_name(); mp_integer offset=member_offset(struct_type, member, ns); if(offset!=-1) { unsignedbv_typet int_type(config.ansi_c.pointer_width); pointer_typet pointer_type; pointer_type.subtype()=expr.type(); typecast_exprt typecast_expr( from_integer(address+offset, int_type), pointer_type); exprt new_expr=dereference_exprt(typecast_expr, expr.type()); expr=new_expr; result=true; } } } return result; } } else if(expr.id()==ID_dereference) { if(expr.operands().size()==1) return simplify_rec(expr.op0()); } else if(expr.id()==ID_if) { if(expr.operands().size()==3) { bool result=true; if(!simplify_rec(expr.op0())) result=false; if(!simplify_address_of_arg(expr.op1())) result=false; if(!simplify_address_of_arg(expr.op2())) result=false; // op0 is a constant? if(expr.op0().is_true()) { result=false; exprt tmp; tmp.swap(expr.op1()); expr.swap(tmp); } else if(expr.op0().is_false()) { result=false; exprt tmp; tmp.swap(expr.op2()); expr.swap(tmp); } return result; } } return true; }
exprt dereferencet::read_object( const exprt &object, const exprt &offset, const typet &type) { const typet &object_type=ns.follow(object.type()); const typet &dest_type=ns.follow(type); // is the object an array with matching subtype? exprt simplified_offset=simplify_expr(offset, ns); // check if offset is zero if(simplified_offset.is_zero()) { // check type if(base_type_eq(object_type, dest_type, ns)) { return object; // trivial case } else if(type_compatible(object_type, dest_type)) { // the type differs, but we can do this with a typecast return typecast_exprt(object, dest_type); } } if(object.id()==ID_index) { const index_exprt &index_expr=to_index_expr(object); exprt index=index_expr.index(); // multiply index by object size exprt size=size_of_expr(object_type, ns); if(size.is_nil()) throw "dereference failed to get object size for index"; index.make_typecast(simplified_offset.type()); size.make_typecast(index.type()); exprt new_offset=plus_exprt(simplified_offset, mult_exprt(index, size)); return read_object(index_expr.array(), new_offset, type); } else if(object.id()==ID_member) { const member_exprt &member_expr=to_member_expr(object); const typet &compound_type= ns.follow(member_expr.struct_op().type()); if(compound_type.id()==ID_struct) { const struct_typet &struct_type= to_struct_type(compound_type); exprt member_offset=member_offset_expr( struct_type, member_expr.get_component_name(), ns); if(member_offset.is_nil()) throw "dereference failed to get member offset"; member_offset.make_typecast(simplified_offset.type()); exprt new_offset=plus_exprt(simplified_offset, member_offset); return read_object(member_expr.struct_op(), new_offset, type); } else if(compound_type.id()==ID_union) { // Unions are easy: the offset is always zero, // so simply pass down. return read_object(member_expr.struct_op(), offset, type); } } // check if we have an array with the right subtype if(object_type.id()==ID_array && base_type_eq(object_type.subtype(), dest_type, ns)) { // check proper alignment exprt size=size_of_expr(dest_type, ns); if(size.is_not_nil()) { mp_integer size_constant, offset_constant; if(!to_integer(simplify_expr(size, ns), size_constant) && !to_integer(simplified_offset, offset_constant) && (offset_constant%size_constant)==0) { // Yes! Can use index expression! mp_integer index_constant=offset_constant/size_constant; exprt index_expr=from_integer(index_constant, size.type()); return index_exprt(object, index_expr, dest_type); } } } // give up and use byte_extract return binary_exprt(object, byte_extract_id(), simplified_offset, dest_type); }
exprt address_canonizer( const exprt &address, const namespacet &ns) { assert(ns.follow(address.type()).id()==ID_pointer); if(address.id()==ID_address_of) { const address_of_exprt &address_of_expr= to_address_of_expr(address); const exprt &object=address_of_expr.object(); if(object.id()==ID_dereference) { // &*x ---> x return to_dereference_expr(object).pointer(); } else if(object.id()==ID_member) { // get offset exprt offset=member_offset_expr(to_member_expr(object), ns); // &x.m ---> (&x)+offset address_of_exprt address_of_expr(to_member_expr(object).struct_op()); exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call pointer_typet byte_pointer(unsigned_char_type()); typecast_exprt typecast_expr(rec_result, byte_pointer); plus_exprt sum(typecast_expr, offset); if(sum.type()!=address.type()) sum.make_typecast(address.type()); return sum; } else if(object.id()==ID_index) { // &(x[i]) ---> (&x)+i address_of_exprt address_of_expr(to_index_expr(object).array()); exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call pointer_typet pointer_type; pointer_type.subtype()=object.type(); typecast_exprt typecast_expr(rec_result, pointer_type); plus_exprt sum(typecast_expr, to_index_expr(object).index()); if(sum.type()!=address.type()) sum.make_typecast(address.type()); return sum; } else if(object.id()==ID_symbol && is_iterator(object)) { // address of iterator is dereferenced to a corresponding symbol - // will be bound to real address during analysis symbol_exprt iterator_addr( id2string(to_symbol_expr(object).get_identifier())+"'addr", address.type()); return iterator_addr; } else return address; } else if(address.id()==ID_plus || address.id()==ID_minus) { // one of the operands needs to be a pointer assert(address.operands().size()==2); exprt tmp=address; if(ns.follow(tmp.op0().type()).id()==ID_pointer) { tmp.op0()=address_canonizer(tmp.op0(), ns); return tmp; } else if(ns.follow(tmp.op1().type()).id()==ID_pointer) { tmp.op1()=address_canonizer(tmp.op1(), ns); return tmp; } else return tmp; } else if(address.id()==ID_if) { if_exprt tmp=to_if_expr(address); tmp.true_case()=address_canonizer(tmp.true_case(), ns); tmp.false_case()=address_canonizer(tmp.false_case(), ns); return tmp; } else if(address.id()==ID_typecast) { typecast_exprt tmp=to_typecast_expr(address); // cast from another pointer? if(tmp.op().type().id()==ID_pointer) { tmp.op()=address_canonizer(tmp.op(), ns); return tmp; } return address; } else return address; }