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; } }
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 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); } }
exprt dereferencet::dereference_rec( const exprt &address, const exprt &offset, const typet &type) { 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(); return read_object(object, offset, type); } else if(address.id()==ID_typecast) { const typecast_exprt &typecast_expr=to_typecast_expr(address); return dereference_typecast(typecast_expr, offset, type); } else if(address.id()==ID_plus) { // pointer arithmetic if(address.operands().size()<2) throw "plus with less than two operands"; return dereference_plus(address, offset, type); } else if(address.id()==ID_if) { const if_exprt &if_expr=to_if_expr(address); return dereference_if(if_expr, offset, type); } else if(address.id()==ID_constant) { const typet result_type=ns.follow(address.type()).subtype(); // pointer-typed constant if(to_constant_expr(address).get_value()==ID_NULL) // NULL { // we turn this into (type *)0 exprt zero=gen_zero(index_type()); return dereference_rec( typecast_exprt(zero, address.type()), offset, type); } else throw "dereferencet: unexpected pointer constant "+address.pretty(); } else { throw "failed to dereference `"+address.id_string()+"'"; } }
static bool is_skip(goto_programt::instructionst::iterator it) { // we won't remove labelled statements // (think about error labels or the like) if(!it->labels.empty()) return false; if(it->is_skip()) return !it->code.get_bool(ID_explicit); if(it->is_goto()) { if(it->guard.is_false()) return true; if(it->targets.size()!=1) return false; goto_programt::instructionst::iterator next_it=it; next_it++; // a branch to the next instruction is a skip return it->targets.front()==next_it; } if(it->is_other()) { if(it->code.is_nil()) return true; const irep_idt &statement=it->code.get_statement(); if(statement==ID_skip) return true; else if(statement==ID_expression) { const code_expressiont &code_expression=to_code_expression(it->code); const exprt &expr=code_expression.expression(); if(expr.id()==ID_typecast && expr.type().id()==ID_empty && to_typecast_expr(expr).op().is_constant()) { // something like (void)0 return true; } } return false; } return false; }
exprt make_va_list(const exprt &expr) { // we first strip any typecast if(expr.id()==ID_typecast) return make_va_list(to_typecast_expr(expr).op()); // if it's an address of an lvalue, we take that if(expr.id()==ID_address_of && expr.operands().size()==1 && is_lvalue(expr.op0())) return expr.op0(); return expr; }
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); }
void interval_domaint::havoc_rec(const exprt &lhs) { if(lhs.id()==ID_if) { havoc_rec(to_if_expr(lhs).true_case()); havoc_rec(to_if_expr(lhs).false_case()); } else if(lhs.id()==ID_symbol) { irep_idt identifier=to_symbol_expr(lhs).get_identifier(); if(is_int(lhs.type())) int_map.erase(identifier); else if(is_float(lhs.type())) float_map.erase(identifier); } else if(lhs.id()==ID_typecast) { havoc_rec(to_typecast_expr(lhs).op()); } }
void rd_range_domaint::assign( const namespacet &ns, locationt from, const exprt &lhs, const mp_integer &size) { if(lhs.id()==ID_typecast) assign(ns, from, to_typecast_expr(lhs).op(), size); else if(lhs.id()==ID_if) assign_if(ns, from, to_if_expr(lhs), size); else if(lhs.id()==ID_dereference) assign_dereference(ns, from, to_dereference_expr(lhs), size); else if(lhs.id()==ID_byte_extract_little_endian || lhs.id()==ID_byte_extract_big_endian) assign_byte_extract(ns, from, to_byte_extract_expr(lhs), size); else if(lhs.id()==ID_symbol || lhs.id()==ID_index || lhs.id()==ID_member) assign(ns, from, lhs, compute_pointer_offset(ns, lhs), size); else throw "assignment to `"+lhs.id_string()+"' not handled"; }
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; }
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; }
void interval_domaint::assume_rec( const exprt &lhs, irep_idt id, const exprt &rhs) { if(lhs.id()==ID_typecast) return assume_rec(to_typecast_expr(lhs).op(), id, rhs); if(rhs.id()==ID_typecast) return assume_rec(lhs, id, to_typecast_expr(rhs).op()); if(id==ID_equal) { assume_rec(lhs, ID_ge, rhs); assume_rec(lhs, ID_le, rhs); return; } if(id==ID_ge) return assume_rec(rhs, ID_le, lhs); if(id==ID_gt) return assume_rec(rhs, ID_lt, lhs); // we now have lhs < rhs or // lhs <= rhs assert(id==ID_lt || id==ID_le); #ifdef DEBUG std::cout << "assume_rec: " << from_expr(lhs) << " " << id << " " << from_expr(rhs) << "\n"; #endif if(lhs.id()==ID_symbol && rhs.id()==ID_constant) { irep_idt lhs_identifier=to_symbol_expr(lhs).get_identifier(); if(is_int(lhs.type()) && is_int(rhs.type())) { mp_integer tmp; to_integer(rhs, tmp); if(id==ID_lt) --tmp; int_map[lhs_identifier].make_le_than(tmp); } else if(is_float(lhs.type()) && is_float(rhs.type())) { ieee_floatt tmp(to_constant_expr(rhs)); if(id==ID_lt) tmp.decrement(); float_map[lhs_identifier].make_le_than(tmp); } } else if(lhs.id()==ID_constant && rhs.id()==ID_symbol) { irep_idt rhs_identifier=to_symbol_expr(rhs).get_identifier(); if(is_int(lhs.type()) && is_int(rhs.type())) { mp_integer tmp; to_integer(lhs, tmp); if(id==ID_lt) ++tmp; int_map[rhs_identifier].make_ge_than(tmp); } else if(is_float(lhs.type()) && is_float(rhs.type())) { ieee_floatt tmp(to_constant_expr(lhs)); if(id==ID_lt) tmp.increment(); float_map[rhs_identifier].make_ge_than(tmp); } } else if(lhs.id()==ID_symbol && rhs.id()==ID_symbol) { irep_idt lhs_identifier=to_symbol_expr(lhs).get_identifier(); irep_idt rhs_identifier=to_symbol_expr(rhs).get_identifier(); if(is_int(lhs.type()) && is_int(rhs.type())) { integer_intervalt &lhs_i=int_map[lhs_identifier]; integer_intervalt &rhs_i=int_map[rhs_identifier]; lhs_i.meet(rhs_i); rhs_i=lhs_i; } else if(is_float(lhs.type()) && is_float(rhs.type())) { ieee_float_intervalt &lhs_i=float_map[lhs_identifier]; ieee_float_intervalt &rhs_i=float_map[rhs_identifier]; lhs_i.meet(rhs_i); rhs_i=lhs_i; } } }
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 goto_symext::dereference_rec( exprt &expr, statet &state, guardt &guard, const bool write) { if(expr.id()==ID_dereference) { if(expr.operands().size()!=1) throw "dereference takes one operand"; exprt tmp1; tmp1.swap(expr.op0()); // first make sure there are no dereferences in there dereference_rec(tmp1, state, guard, false); // we need to set up some elaborate call-backs symex_dereference_statet symex_dereference_state(*this, state); value_set_dereferencet dereference( ns, new_symbol_table, options, symex_dereference_state, language_mode); // std::cout << "**** " << from_expr(ns, "", tmp1) << std::endl; exprt tmp2=dereference.dereference( tmp1, guard, write?value_set_dereferencet::WRITE:value_set_dereferencet::READ); //std::cout << "**** " << from_expr(ns, "", tmp2) << std::endl; expr.swap(tmp2); // this may yield a new auto-object trigger_auto_object(expr, state); } else if(expr.id()==ID_index && to_index_expr(expr).array().id()==ID_member && to_array_type(ns.follow(to_index_expr(expr).array().type())). size().is_zero()) { // This is an expression of the form x.a[i], // where a is a zero-sized array. This gets // re-written into *(&x.a+i) index_exprt index_expr=to_index_expr(expr); address_of_exprt address_of_expr(index_expr.array()); address_of_expr.type()=pointer_typet(expr.type()); dereference_exprt tmp; tmp.pointer()=plus_exprt(address_of_expr, index_expr.index()); tmp.type()=expr.type(); tmp.add_source_location()=expr.source_location(); // recursive call dereference_rec(tmp, state, guard, write); expr.swap(tmp); } else if(expr.id()==ID_index && to_index_expr(expr).array().type().id()==ID_pointer) { // old stuff, will go away assert(false); } else if(expr.id()==ID_address_of) { address_of_exprt &address_of_expr=to_address_of_expr(expr); exprt &object=address_of_expr.object(); const typet &expr_type=ns.follow(expr.type()); expr=address_arithmetic(object, state, guard, expr_type.subtype().id()==ID_array); } else if(expr.id()==ID_typecast) { exprt &tc_op=to_typecast_expr(expr).op(); // turn &array into &array[0] when casting to pointer-to-element-type if(tc_op.id()==ID_address_of && to_address_of_expr(tc_op).object().type().id()==ID_array && base_type_eq( expr.type(), pointer_typet(to_address_of_expr(tc_op).object().type().subtype()), ns)) { expr= address_of_exprt( index_exprt( to_address_of_expr(tc_op).object(), from_integer(0, index_type()))); dereference_rec(expr, state, guard, write); } else { dereference_rec(tc_op, state, guard, write); } } else { Forall_operands(it, expr) dereference_rec(*it, state, guard, write); } }