void goto_symext::process_array_expr_rec( exprt &expr, const typet &type) const { if(expr.id()==ID_if) { if_exprt &if_expr=to_if_expr(expr); process_array_expr_rec(if_expr.true_case(), type); process_array_expr_rec(if_expr.false_case(), type); } else if(expr.id()==ID_index) { // strip index index_exprt &index_expr=to_index_expr(expr); exprt tmp=index_expr.array(); expr.swap(tmp); } else if(expr.id()==ID_typecast) { // strip exprt tmp=to_typecast_expr(expr).op0(); expr.swap(tmp); process_array_expr_rec(expr, type); } else if(expr.id()==ID_address_of) { // strip exprt tmp=to_address_of_expr(expr).op0(); expr.swap(tmp); process_array_expr_rec(expr, type); } else if(expr.id()==ID_symbol && expr.get_bool(ID_C_SSA_symbol) && to_ssa_expr(expr).get_original_expr().id()==ID_index) { const ssa_exprt &ssa=to_ssa_expr(expr); const index_exprt &index_expr=to_index_expr(ssa.get_original_expr()); exprt tmp=index_expr.array(); expr.swap(tmp); } else Forall_operands(it, expr) process_array_expr_rec(*it, it->type()); if(!base_type_eq(expr.type(), type, ns)) { byte_extract_exprt be(byte_extract_id()); be.type()=type; be.op()=expr; be.offset()=gen_zero(index_type()); expr.swap(be); } }
void goto_symext::process_array_expr(exprt &expr) { // This may change the type of the expression! if(expr.id()==ID_if) { if_exprt &if_expr=to_if_expr(expr); process_array_expr(if_expr.true_case()); process_array_expr_rec(if_expr.false_case(), if_expr.true_case().type()); if_expr.type()=if_expr.true_case().type(); } else if(expr.id()==ID_index) { // strip index index_exprt &index_expr=to_index_expr(expr); exprt tmp=index_expr.array(); expr.swap(tmp); } else if(expr.id()==ID_typecast) { // strip exprt tmp=to_typecast_expr(expr).op0(); expr.swap(tmp); process_array_expr(expr); } else if(expr.id()==ID_address_of) { // strip exprt tmp=to_address_of_expr(expr).op0(); expr.swap(tmp); process_array_expr(expr); } else if(expr.id()==ID_symbol && expr.get_bool(ID_C_SSA_symbol) && to_ssa_expr(expr).get_original_expr().id()==ID_index) { const ssa_exprt &ssa=to_ssa_expr(expr); const index_exprt &index_expr=to_index_expr(ssa.get_original_expr()); exprt tmp=index_expr.array(); expr.swap(tmp); } else Forall_operands(it, expr) process_array_expr(*it); }
std::string array_name( const namespacet &ns, const exprt &expr) { if(expr.id()==ID_index) { if(expr.operands().size()!=2) throw "index takes two operands"; return array_name(ns, expr.op0())+"[]"; } else if(is_ssa_expr(expr)) { const symbolt &symbol= ns.lookup(to_ssa_expr(expr).get_object_name()); return "array `"+id2string(symbol.base_name)+"'"; } else if(expr.id()==ID_symbol) { const symbolt &symbol=ns.lookup(expr); return "array `"+id2string(symbol.base_name)+"'"; } else if(expr.id()==ID_string_constant) { return "string constant"; } else if(expr.id()==ID_member) { assert(expr.operands().size()==1); return array_name(ns, expr.op0())+"."+ expr.get_string(ID_component_name); } return "array"; }
void value_set_dereferencet::valid_check( const exprt &object, const guardt &guard, const modet mode) { if(!options.get_bool_option("pointer-check")) return; const exprt &symbol_expr=get_symbol(object); if(symbol_expr.id()==ID_string_constant) { // always valid, but can't write if(mode==modet::WRITE) { dereference_callback.dereference_failure( "pointer dereference", "write access to string constant", guard); } } else if(symbol_expr.is_nil() || symbol_expr.get_bool(ID_C_invalid_object)) { // always "valid", shut up return; } else if(symbol_expr.id()==ID_symbol) { const irep_idt identifier= is_ssa_expr(symbol_expr)? to_ssa_expr(symbol_expr).get_object_name(): to_symbol_expr(symbol_expr).get_identifier(); const symbolt &symbol=ns.lookup(identifier); if(symbol.type.get_bool(ID_C_is_failed_symbol)) { dereference_callback.dereference_failure( "pointer dereference", "invalid pointer", guard); } #if 0 if(dereference_callback.is_valid_object(identifier)) return; // always ok #endif } }
void goto_symext::symex_dead(statet &state) { const goto_programt::instructiont &instruction=*state.source.pc; const codet &code=to_code(instruction.code); if(code.operands().size()!=1) throw "dead expects one operand"; if(code.op0().id()!=ID_symbol) throw "dead expects symbol as first operand"; // We increase the L2 renaming to make these non-deterministic. // We also prevent propagation of old values. ssa_exprt ssa(to_symbol_expr(code.op0())); state.rename(ssa, ns, goto_symex_statet::L1); // in case of pointers, put something into the value set if(ns.follow(code.op0().type()).id()==ID_pointer) { exprt failed= get_failed_symbol(to_symbol_expr(code.op0()), ns); exprt rhs; if(failed.is_not_nil()) { address_of_exprt address_of_expr; address_of_expr.object()=failed; address_of_expr.type()=code.op0().type(); rhs=address_of_expr; } else rhs=exprt(ID_invalid); state.rename(rhs, ns, goto_symex_statet::L1); state.value_set.assign(ssa, rhs, ns, true, false); } ssa_exprt ssa_lhs=to_ssa_expr(ssa); const irep_idt &l1_identifier=ssa_lhs.get_identifier(); // prevent propagation state.propagation.remove(l1_identifier); // L2 renaming if(state.level2.current_names.find(l1_identifier)!= state.level2.current_names.end()) state.level2.increase_counter(l1_identifier); }
void goto_symext::rewrite_quantifiers(exprt &expr, statet &state) { if(expr.id()==ID_forall) { // forall X. P -> P // we keep the quantified variable unique by means of L2 renaming assert(expr.operands().size()==2); assert(expr.op0().id()==ID_symbol); symbol_exprt tmp0= to_symbol_expr(to_ssa_expr(expr.op0()).get_original_expr()); symex_decl(state, tmp0); exprt tmp=expr.op1(); expr.swap(tmp); } }
exprt goto_symext::address_arithmetic( const exprt &expr, statet &state, guardt &guard, bool keep_array) { exprt result; if(expr.id()==ID_byte_extract_little_endian || expr.id()==ID_byte_extract_big_endian) { // address_of(byte_extract(op, offset, t)) is // address_of(op) + offset with adjustments for arrays const byte_extract_exprt &be=to_byte_extract_expr(expr); // recursive call result=address_arithmetic(be.op(), state, guard, keep_array); if(ns.follow(be.op().type()).id()==ID_array && result.id()==ID_address_of) { address_of_exprt &a=to_address_of_expr(result); // turn &a of type T[i][j] into &(a[0][0]) for(const typet *t=&(ns.follow(a.type().subtype())); t->id()==ID_array && !base_type_eq(expr.type(), *t, ns); t=&(ns.follow(*t).subtype())) a.object()=index_exprt(a.object(), from_integer(0, index_type())); } // do (expr.type() *)(((char *)op)+offset) result=typecast_exprt(result, pointer_typet(char_type())); // there could be further dereferencing in the offset exprt offset=be.offset(); dereference_rec(offset, state, guard, false); result=plus_exprt(result, offset); // treat &array as &array[0] const typet &expr_type=ns.follow(expr.type()); pointer_typet dest_type; if(expr_type.id()==ID_array && !keep_array) dest_type.subtype()=expr_type.subtype(); else dest_type.subtype()=expr_type; result=typecast_exprt(result, dest_type); } else if(expr.id()==ID_index || expr.id()==ID_member) { object_descriptor_exprt ode; ode.build(expr, ns); byte_extract_exprt be(byte_extract_id()); be.type()=expr.type(); be.op()=ode.root_object(); be.offset()=ode.offset(); // recursive call result=address_arithmetic(be, state, guard, keep_array); do_simplify(result); } else if(expr.id()==ID_dereference) { // ANSI-C guarantees &*p == p no matter what p is, // even if it's complete garbage // just grab the pointer, but be wary of further dereferencing // in the pointer itself result=to_dereference_expr(expr).pointer(); dereference_rec(result, state, guard, false); } else if(expr.id()==ID_if) { if_exprt if_expr=to_if_expr(expr); // the condition is not an address dereference_rec(if_expr.cond(), state, guard, false); // recursive call if_expr.true_case()= address_arithmetic(if_expr.true_case(), state, guard, keep_array); if_expr.false_case()= address_arithmetic(if_expr.false_case(), state, guard, keep_array); result=if_expr; } else if(expr.id()==ID_symbol || expr.id()==ID_string_constant || expr.id()==ID_label || expr.id()==ID_array) { // give up, just dereference result=expr; dereference_rec(result, state, guard, false); // turn &array into &array[0] if(ns.follow(result.type()).id()==ID_array && !keep_array) result=index_exprt(result, from_integer(0, index_type())); // handle field-sensitive SSA symbol mp_integer offset=0; if(expr.id()==ID_symbol && expr.get_bool(ID_C_SSA_symbol)) { offset=compute_pointer_offset(expr, ns); assert(offset>=0); } if(offset>0) { byte_extract_exprt be(byte_extract_id()); be.type()=expr.type(); be.op()=to_ssa_expr(expr).get_l1_object(); be.offset()=from_integer(offset, index_type()); result=address_arithmetic(be, state, guard, keep_array); do_simplify(result); } else result=address_of_exprt(result); } else throw "goto_symext::address_arithmetic does not handle "+expr.id_string(); const typet &expr_type=ns.follow(expr.type()); assert((expr_type.id()==ID_array && !keep_array) || base_type_eq(pointer_typet(expr_type), result.type(), ns)); return result; }