exprt ssa_alias_guard( const exprt &e1, const exprt &e2, const namespacet &ns) { exprt a1=address_canonizer(address_of_exprt(e1), ns); // TODO: We should compare 'base' pointers here because // we have a higher chance that there was no pointer arithmetic // on the base pointer than that the result of the pointer // arithmetic points to a base pointer. // The following hack does that: if(a1.id()==ID_plus) a1=a1.op0(); exprt a2=address_canonizer(address_of_exprt(e2), ns); // in some cases, we can use plain address equality, // as we assume well-aligned-ness mp_integer size1=pointer_offset_size(e1.type(), ns); mp_integer size2=pointer_offset_size(e2.type(), ns); if(size1>=size2) { exprt lhs=a1; exprt rhs=a2; if(ns.follow(rhs.type())!=ns.follow(lhs.type())) rhs=typecast_exprt(rhs, lhs.type()); return equal_exprt(lhs, rhs); } return same_object(a1, a2); }
exprt ssa_alias_guard( const exprt &e1, const exprt &e2, const namespacet &ns) { exprt a1=address_canonizer(address_of_exprt(e1), ns); exprt a2=address_canonizer(address_of_exprt(e2), ns); // in some cases, we can use plain address equality, // as we assume well-aligned-ness mp_integer size1=pointer_offset_size(e1.type(), ns); mp_integer size2=pointer_offset_size(e2.type(), ns); if(size1>=size2) { exprt lhs=a1; exprt rhs=a2; if(ns.follow(rhs.type())!=ns.follow(lhs.type())) rhs=typecast_exprt(rhs, lhs.type()); return equal_exprt(lhs, rhs); } return same_object(a1, a2); }
exprt get_component_rec( const exprt &struct_union, const irep_idt &component_name, const namespacet &ns) { const struct_union_typet &struct_union_type= to_struct_union_type(ns.follow(struct_union.type())); const struct_union_typet::componentst &components= struct_union_type.components(); for(struct_union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &type=ns.follow(it->type()); if(it->get_name()==component_name) { return make_member_expr(struct_union, *it, ns); } else if(it->get_anonymous() && (type.id()==ID_struct || type.id()==ID_union)) { exprt tmp=make_member_expr(struct_union, *it, ns); exprt result=get_component_rec(tmp, component_name, ns); if(result.is_not_nil()) return result; } } return nil_exprt(); }
mp_integer compute_pointer_offset( const namespacet &ns, const exprt &expr) { if(expr.id()==ID_symbol) return 0; else if(expr.id()==ID_index) { assert(expr.operands().size()==2); const typet &array_type=ns.follow(expr.op0().type()); assert(array_type.id()==ID_array); mp_integer o=compute_pointer_offset(ns, expr.op0()); if(o!=-1) { mp_integer sub_size= pointer_offset_size(ns, array_type.subtype()); mp_integer i; if(sub_size!=0 && !to_integer(expr.op1(), i)) return o+i*sub_size; } // don't know } else if(expr.id()==ID_member) { assert(expr.operands().size()==1); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_struct || type.id()==ID_union); mp_integer o=compute_pointer_offset(ns, expr.op0()); if(o!=-1) { if(type.id()==ID_union) return o; return o+member_offset( ns, to_struct_type(type), expr.get(ID_component_name)); } } else if(expr.id()==ID_string_constant) return 0; return -1; // don't know }
std::string counterexample_value_binary( const exprt &expr, const namespacet &ns) { const typet &type=ns.follow(expr.type()); if(expr.id()==ID_constant) { if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_bv || type.id()==ID_fixedbv || type.id()==ID_floatbv || type.id()==ID_pointer) { return expr.get_string(ID_value); } else if(type.id()==ID_bool) { return expr.is_true()?"1":"0"; } } else if(expr.id()==ID_array) { std::string result; forall_operands(it, expr) { if(result=="") result="{ "; else result+=", "; result+=counterexample_value_binary(*it, ns); } return result+" }"; }
exprt remove_virtual_functionst::build_class_identifier( const exprt &src) { // the class identifier is in the root class exprt e=src; while(1) { const typet &type=ns.follow(e.type()); assert(type.id()==ID_struct); const struct_typet &struct_type=to_struct_type(type); const struct_typet::componentst &components=struct_type.components(); assert(!components.empty()); member_exprt member_expr( e, components.front().get_name(), components.front().type()); if(components.front().get_name()=="@class_identifier") { // found it return member_expr; } else { e=member_expr; } } }
void remove_function_pointerst::fix_return_type( code_function_callt &function_call, goto_programt &dest) { // are we returning anything at all? if(function_call.lhs().is_nil()) return; const code_typet &code_type= to_code_type(ns.follow(function_call.function().type())); // type already ok? if(type_eq( function_call.lhs().type(), code_type.return_type(), ns)) return; symbolt &tmp_symbol=new_tmp_symbol(); tmp_symbol.type=code_type.return_type(); tmp_symbol.location=function_call.location(); symbol_exprt tmp_symbol_expr; tmp_symbol_expr.type()=tmp_symbol.type; tmp_symbol_expr.set_identifier(tmp_symbol.name); exprt old_lhs=function_call.lhs(); function_call.lhs()=tmp_symbol_expr; goto_programt::targett t_assign=dest.add_instruction(); t_assign->make_assignment(); t_assign->code=code_assignt( old_lhs, typecast_exprt(tmp_symbol_expr, old_lhs.type())); }
bool has_component_rec( const typet &type, const irep_idt &component_name, const namespacet &ns) { const struct_union_typet &struct_union_type= to_struct_union_type(ns.follow(type)); const struct_union_typet::componentst &components= struct_union_type.components(); for(struct_union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { if(it->get_name()==component_name) { return true; } else if(it->get_anonymous()) { if(has_component_rec(it->type(), component_name, ns)) return true; } } return false; }
code_function_callt get_destructor( const namespacet &ns, const typet &type) { if(type.id()==ID_symbol) { return get_destructor(ns, ns.follow(type)); } else if(type.id()==ID_struct) { 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++) { if(it->type().id()==ID_code) { const code_typet &code_type=to_code_type(it->type()); if(code_type.return_type().id()==ID_destructor && code_type.parameters().size()==1) { const typet &arg_type=code_type.parameters().front().type(); if(arg_type.id()==ID_pointer && ns.follow(arg_type.subtype())==type) { exprt symbol_expr(ID_symbol, it->type()); symbol_expr.set(ID_identifier, it->get(ID_name)); code_function_callt function_call; function_call.function()=symbol_expr; return function_call; } } } } } return static_cast<const code_function_callt &>(get_nil_irep()); }
unsigned safe_width(const exprt &e, const namespacet &ns) { const typet &type=ns.follow(e.type()); if(type.id()=="pointer" || type.id()=="reference") return config.ansi_c.pointer_width; return boolbv_widtht(ns)(type); }
void constant_propagator_domaint::assign_rec( valuest &values, const exprt &lhs, const exprt &rhs, const namespacet &ns) { const typet & lhs_type = ns.follow(lhs.type()); const typet & rhs_type = ns.follow(rhs.type()); #ifdef DEBUG std::cout << "assign: " << from_expr(ns, "", lhs) << " := " << from_type(ns, "", rhs_type) << '\n'; #endif if(lhs.id()==ID_symbol && rhs.id()==ID_if) { exprt cond=rhs.op0(); assert(cond.operands().size()==2); if(values.is_constant(cond.op0()) && values.is_constant(cond.op1())) { if(cond.op0().id()==ID_index) { exprt index=cond.op0(); exprt new_expr=concatenate_array_id(index.op0(), index.op1(), index.type()); values.replace_const(new_expr); cond.op0()=new_expr; cond = simplify_expr(cond,ns); } else assert(0); assign(values, to_symbol_expr(lhs), cond, ns); } } else if(lhs.id()==ID_symbol && rhs_type.id()!=ID_array && rhs_type.id()!=ID_struct && rhs_type.id()!=ID_union) { if(values.is_constant(rhs)) assign(values, to_symbol_expr(lhs), rhs, ns); else values.set_to_top(to_symbol_expr(lhs)); } else if(lhs.id()==ID_symbol && lhs_type.id()==ID_array && rhs_type.id()==ID_array) { exprt new_expr; mp_integer idx=0; forall_operands(it, rhs) { new_expr=concatenate_array_id(lhs, idx, it->type()); assign(values, to_symbol_expr(new_expr), *it, ns); idx = idx +1; }
code_function_callt get_destructor( const namespacet &ns, const typet &type) { if(type.id()==ID_symbol) { return get_destructor(ns, ns.follow(type)); } else if(type.id()==ID_struct) { const exprt &methods=static_cast<const exprt&>(type.find(ID_methods)); forall_operands(it, methods) { if(it->type().id()==ID_code) { const code_typet &code_type=to_code_type(it->type()); if(code_type.return_type().id()==ID_destructor && code_type.parameters().size()==1) { const typet &arg_type=code_type.parameters().front().type(); if(arg_type.id()==ID_pointer && ns.follow(arg_type.subtype())==type) { exprt symbol_expr(ID_symbol, it->type()); symbol_expr.set(ID_identifier, it->get(ID_name)); code_function_callt function_call; function_call.function()=symbol_expr; return function_call; } } } } } return static_cast<const code_function_callt &>(get_nil_irep()); }
exprt ssa_alias_value( const exprt &e1, const exprt &e2, const namespacet &ns) { const typet &e1_type=ns.follow(e1.type()); const typet &e2_type=ns.follow(e2.type()); // type matches? if(e1_type==e2_type) return e2; exprt a1=address_canonizer(address_of_exprt(e1), ns); exprt a2=address_canonizer(address_of_exprt(e2), ns); exprt offset1=pointer_offset(a1); // array index possible? if(e2_type.id()==ID_array && e1_type==ns.follow(e2_type.subtype())) { // this assumes well-alignedness mp_integer element_size=pointer_offset_size(e2_type.subtype(), ns); if(element_size==1) return index_exprt(e2, offset1, e1.type()); else if(element_size>1) { exprt index= div_exprt(offset1, from_integer(element_size, offset1.type())); return index_exprt(e2, index, e1.type()); } } byte_extract_exprt byte_extract(byte_extract_id(), e1.type()); byte_extract.op()=e2; byte_extract.offset()=offset1; return byte_extract; }
bool value_sett::field_sensitive( const irep_idt &id, const typet &type, const namespacet &ns) { // we always track fields on these if(has_prefix(id2string(id), "value_set::dynamic_object") || id=="value_set::return_value" || id=="value_set::memory") return true; // otherwise it has to be a struct return ns.follow(type).id()==ID_struct; }
unsigned alignment(const typet &type, const namespacet &ns) { if(type.id()==ID_array || type.id()==ID_incomplete_array) return alignment(type.subtype(), ns); else if(type.id()==ID_struct || type.id()==ID_union) { const struct_union_typet::componentst &components= to_struct_union_type(type).components(); unsigned result=1; // get the max // (should really be the smallest common denominator) for(struct_union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) result=std::max(result, alignment(it->type(), ns)); return result; } else if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_fixedbv || type.id()==ID_floatbv) { unsigned width=type.get_int(ID_width); return width%8?width/8+1:width/8; } else if(type.id()==ID_pointer) { unsigned width=config.ansi_c.pointer_width; return width%8?width/8+1:width/8; } else if(type.id()==ID_symbol) return alignment(ns.follow(type), ns); return 1; }
static exprt make_member_expr( const exprt &struct_union, const struct_union_typet::componentt &component, const namespacet &ns) { member_exprt result( struct_union, component.get_name(), component.type()); if(struct_union.get_bool(ID_C_lvalue)) result.set(ID_C_lvalue, true); // todo: should to typedef chains properly const typet &type= ns.follow(struct_union.type()); if(result.get_bool(ID_C_constant) || type.get_bool(ID_C_constant) || struct_union.type().get_bool(ID_C_constant)) result.set(ID_C_constant, true); return result; }
void set_class_identifier( struct_exprt &expr, const namespacet &ns, const symbol_typet &class_type) { const struct_typet &struct_type= to_struct_type(ns.follow(expr.type())); const struct_typet::componentst &components=struct_type.components(); if(components.empty()) return; assert(!expr.operands().empty()); if(components.front().get_name()=="@class_identifier") { assert(expr.op0().id()==ID_constant); expr.op0()=constant_exprt(class_type.get_identifier(), string_typet()); } else { assert(expr.op0().id()==ID_struct); set_class_identifier(to_struct_expr(expr.op0()), ns, class_type); } }
void remove_function_pointerst::fix_argument_types( code_function_callt &function_call) { const code_typet &code_type= to_code_type(ns.follow(function_call.function().type())); const code_typet::parameterst &function_parameters= code_type.parameters(); code_function_callt::argumentst &call_arguments= function_call.arguments(); for(unsigned i=0; i<function_parameters.size(); i++) { if(i<call_arguments.size()) { if(!type_eq(call_arguments[i].type(), function_parameters[i].type(), ns)) { call_arguments[i].make_typecast(function_parameters[i].type()); } } } }
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 string_instrumentationt::do_format_string_write( goto_programt &dest, goto_programt::const_targett target, const code_function_callt::argumentst &arguments, unsigned format_string_inx, unsigned argument_start_inx, const std::string &function_name) { const exprt &format_arg = arguments[format_string_inx]; if(format_arg.id()=="address_of" && format_arg.op0().id()=="index" && format_arg.op0().op0().id()==ID_string_constant) // constant format { format_token_listt token_list; parse_format_string(format_arg.op0().op0(), token_list); unsigned args=0; for(format_token_listt::const_iterator it=token_list.begin(); it!=token_list.end(); it++) { if(find(it->flags.begin(), it->flags.end(), format_tokent::ASTERISK)!= it->flags.end()) continue; // asterisk means `ignore this' switch(it->type) { case format_tokent::STRING: { const exprt &argument=arguments[argument_start_inx+args]; const typet &arg_type=ns.follow(argument.type()); goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("format string buffer overflow in "); comment += function_name; assertion->location.set("comment", comment); if(it->field_width!=0) { exprt fwidth = from_integer(it->field_width, uint_type()); exprt fw_1("+", uint_type()); exprt one = gen_one(uint_type()); fw_1.move_to_operands(fwidth); fw_1.move_to_operands(one); // +1 for 0-char exprt fw_lt_bs; if(arg_type.id()=="pointer") fw_lt_bs=binary_relation_exprt(fw_1, "<=", buffer_size(argument)); else { index_exprt index; index.array()=argument; index.index()=gen_zero(uint_type()); address_of_exprt aof(index); fw_lt_bs=binary_relation_exprt(fw_1, "<=", buffer_size(aof)); } assertion->make_assertion(fw_lt_bs); } else { // this is a possible overflow. assertion->make_assertion(false_exprt()); } // now kill the contents invalidate_buffer(dest, target, argument, arg_type, it->field_width); args++; break; } case format_tokent::TEXT: case format_tokent::UNKNOWN: { // nothing break; } default: // everything else { const exprt &argument=arguments[argument_start_inx+args]; const typet &arg_type=ns.follow(argument.type()); goto_programt::targett assignment=dest.add_instruction(ASSIGN); assignment->location=target->location; exprt lhs("dereference", arg_type.subtype()); lhs.copy_to_operands(argument); exprt rhs=side_effect_expr_nondett(lhs.type()); rhs.location()=target->location; assignment->code=code_assignt(lhs, rhs); args++; break; } } } } else // non-const format string { for(unsigned i=argument_start_inx; i<arguments.size(); i++) { const typet &arg_type=ns.follow(arguments[i].type()); // Note: is_string_type() is a `good guess' here. Actually // any of the pointers could point into an array. But it // would suck if we had to invalidate all variables. // Luckily this case isn't needed too often. if(is_string_type(arg_type)) { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("format string buffer overflow in "); comment += function_name; assertion->location.set("comment", comment); // as we don't know any field width for the %s that // should be here during runtime, we just report a // possibly false positive assertion->make_assertion(false_exprt()); invalidate_buffer(dest, target, arguments[i], arg_type, 0); } else { goto_programt::targett assignment = dest.add_instruction(ASSIGN); assignment->location=target->location; exprt lhs("dereference", arg_type.subtype()); lhs.copy_to_operands(arguments[i]); exprt rhs=side_effect_expr_nondett(lhs.type()); rhs.location()=target->location; assignment->code=code_assignt(lhs, rhs); } } } }
exprt flatten_byte_extract( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_extract_little_endian || src.id()==ID_byte_extract_big_endian); assert(src.operands().size()==2); bool little_endian; if(src.id()==ID_byte_extract_little_endian) little_endian=true; else if(src.id()==ID_byte_extract_big_endian) little_endian=false; else assert(false); if(src.id()==ID_byte_extract_big_endian) throw "byte_extract flattening of big endian not done yet"; unsigned width= integer2long(pointer_offset_size(ns, src.type())); const typet &t=src.op0().type(); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // byte-array? if((subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv) && subtype.get_int(ID_width)==8) { // get 'width'-many bytes, and concatenate exprt::operandst op; op.resize(width); for(unsigned i=0; i<width; i++) { // the most significant byte comes first in the concatenation! unsigned offset_i= little_endian?(width-i-1):i; plus_exprt offset(from_integer(offset_i, src.op1().type()), src.op1()); index_exprt index_expr(subtype); index_expr.array()=src.op0(); index_expr.index()=offset; op[i]=index_expr; } if(width==1) return op[0]; else // width>=2 { concatenation_exprt concatenation(src.type()); concatenation.operands().swap(op); return concatenation; } } else // non-byte array { const exprt &root=src.op0(); const exprt &offset=src.op1(); const typet &array_type=ns.follow(root.type()); const typet &offset_type=ns.follow(offset.type()); const typet &element_type=ns.follow(array_type.subtype()); mp_integer element_width=pointer_offset_size(ns, element_type); if(element_width==-1) // failed throw "failed to flatten non-byte array with unknown element width"; mp_integer result_width=pointer_offset_size(ns, src.type()); mp_integer num_elements=(element_width+result_width-2)/element_width+1; // compute new root and offset concatenation_exprt concat( unsignedbv_typet(integer2long(element_width*8*num_elements))); exprt first_index= (element_width==1)?offset : div_exprt(offset, from_integer(element_width, offset_type)); // 8*offset/el_w for(mp_integer i=num_elements; i>0; --i) { plus_exprt index(first_index, from_integer(i-1, offset_type)); concat.copy_to_operands(index_exprt(root, index)); } // the new offset is width%offset exprt new_offset= (element_width==1)?from_integer(0, offset_type): mod_exprt(offset, from_integer(element_width, offset_type)); // build new byte-extract expression exprt tmp(src.id(), src.type()); tmp.copy_to_operands(concat, new_offset); return tmp; } } else // non-array { // We turn that into logical right shift and extractbits const exprt &offset=src.op1(); const typet &offset_type=ns.follow(offset.type()); mult_exprt times_eight(offset, from_integer(8, offset_type)); lshr_exprt left_shift(src.op0(), times_eight); extractbits_exprt extractbits; extractbits.src()=left_shift; extractbits.type()=src.type(); extractbits.upper()=from_integer(width*8-1, offset_type); extractbits.lower()=from_integer(0, offset_type); return extractbits; } }
exprt flatten_byte_update( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_update_little_endian || src.id()==ID_byte_update_big_endian); assert(src.operands().size()==3); mp_integer element_size= pointer_offset_size(ns, src.op2().type()); const typet &t=ns.follow(src.op0().type()); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // array of bitvectors? if(subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv || subtype.id()==ID_floatbv) { mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size==-1) throw "can't flatten byte_update for sub-type without size"; // byte array? if(sub_size==1) { // apply 'array-update-with' element_size times exprt result=src.op0(); for(mp_integer i=0; i<element_size; ++i) { exprt i_expr=from_integer(i, ns.follow(src.op1().type())); exprt new_value; if(i==0 && element_size==1) // bytes? { new_value=src.op2(); if(new_value.type()!=subtype) new_value.make_typecast(subtype); } else { exprt byte_extract_expr( src.id()==ID_byte_update_little_endian?ID_byte_extract_little_endian: src.id()==ID_byte_update_big_endian?ID_byte_extract_big_endian: throw "unexpected src.id()", subtype); byte_extract_expr.copy_to_operands(src.op2(), i_expr); new_value=flatten_byte_extract(byte_extract_expr, ns); } exprt where=plus_exprt(src.op1(), i_expr); with_exprt with_expr; with_expr.type()=src.type(); with_expr.old()=result; with_expr.where()=where; with_expr.new_value()=new_value; result.swap(with_expr); } return result; } else // sub_size!=1 { if(element_size==1) // byte-granularity update { div_exprt div_offset(src.op1(), from_integer(sub_size, src.op1().type())); mod_exprt mod_offset(src.op1(), from_integer(sub_size, src.op1().type())); index_exprt index_expr(src.op0(), div_offset, array_type.subtype()); exprt byte_update_expr(src.id(), array_type.subtype()); byte_update_expr.copy_to_operands(index_expr, mod_offset, src.op2()); // Call recurisvely, the array is gone! exprt flattened_byte_update_expr= flatten_byte_update(byte_update_expr, ns); with_exprt with_expr( src.op0(), div_offset, flattened_byte_update_expr); return with_expr; } else throw "flatten_byte_update can only do byte updates of non-byte arrays right now"; } } else { throw "flatten_byte_update can only do arrays of scalars right now"; } } else if(t.id()==ID_signedbv || t.id()==ID_unsignedbv || t.id()==ID_floatbv) { // do a shift, mask and OR unsigned width=to_bitvector_type(t).get_width(); if(element_size*8>width) throw "flatten_byte_update to update element that is too large"; // build mask exprt mask= bitnot_exprt( from_integer(power(2, element_size*8)-1, unsignedbv_typet(width))); const typet &offset_type=ns.follow(src.op1().type()); mult_exprt offset_times_eight(src.op1(), from_integer(8, offset_type)); // shift the mask shl_exprt shl_expr(mask, offset_times_eight); // do the 'AND' bitand_exprt bitand_expr(src.op0(), mask); // zero-extend the value concatenation_exprt value_extended( from_integer(0, unsignedbv_typet(width-integer2long(element_size)*8)), src.op2(), t); // shift the value shl_exprt value_shifted(value_extended, offset_times_eight); // do the 'OR' bitor_exprt bitor_expr(bitand_expr, value_shifted); return bitor_expr; } else { throw "flatten_byte_update can only do array and scalars right now"; } }
void make_type(exprt &dest, const typet &type) { if(ns.follow(dest.type())!=ns.follow(type)) dest.make_typecast(type); }
Expression::Expression(const exprt& e, const namespacet& ns) :_expr(e), _ns(ns), _type(ns.follow(e.type()), ns){}
xmlt xml( const exprt &expr, const namespacet &ns) { const typet &type=ns.follow(expr.type()); xmlt result; if(expr.id()==ID_constant) { if(type.id()==ID_unsignedbv || type.id()==ID_signedbv) { result.name="integer"; result.set_attribute("binary", expr.get_string(ID_value)); mp_integer i; if(!to_integer(expr, i)) result.data=integer2string(i); } else if(type.id()==ID_bv) { result.name="bitvector"; result.set_attribute("binary", expr.get_string(ID_value)); result.data=expr.get_string(ID_value); } else if(type.id()==ID_fixedbv) { result.name="fixed"; result.set_attribute("binary", expr.get_string(ID_value)); result.data=fixedbvt(to_constant_expr(expr)).to_ansi_c_string(); } else if(type.id()==ID_floatbv) { result.name="float"; result.set_attribute("binary", expr.get_string(ID_value)); result.data=ieee_floatt(to_constant_expr(expr)).to_ansi_c_string(); } else if(type.id()==ID_pointer) { result.name="pointer"; result.set_attribute("binary", expr.get_string(ID_value)); if(expr.get(ID_value)==ID_NULL) result.data="NULL"; } else if(type.id()==ID_bool) { result.name="boolean"; result.set_attribute("binary", expr.is_true()?"1":"0"); result.data=expr.is_true()?"TRUE":"FALSE"; } else { result.name="unknown"; } } else if(expr.id()==ID_array) { result.name="array"; unsigned index=0; forall_operands(it, expr) { xmlt &e=result.new_element("element"); e.set_attribute("index", index); e.new_element(xml(*it, ns)); index++; }
xmlt xml( const exprt &expr, const namespacet &ns) { xmlt result; const typet &type=ns.follow(expr.type()); if(expr.id()==ID_constant) { if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_c_bit_field) { std::size_t width=to_bitvector_type(type).get_width(); result.name="integer"; result.set_attribute("binary", expr.get_string(ID_value)); result.set_attribute("width", width); const typet &underlying_type= type.id()==ID_c_bit_field?type.subtype(): type; bool is_signed=underlying_type.id()==ID_signedbv; std::string sig=is_signed?"":"unsigned "; if(width==config.ansi_c.char_width) result.set_attribute("c_type", sig+"char"); else if(width==config.ansi_c.int_width) result.set_attribute("c_type", sig+"int"); else if(width==config.ansi_c.short_int_width) result.set_attribute("c_type", sig+"short int"); else if(width==config.ansi_c.long_int_width) result.set_attribute("c_type", sig+"long int"); else if(width==config.ansi_c.long_long_int_width) result.set_attribute("c_type", sig+"long long int"); mp_integer i; if(!to_integer(expr, i)) result.data=integer2string(i); } else if(type.id()==ID_c_enum) { result.name="integer"; result.set_attribute("binary", expr.get_string(ID_value)); result.set_attribute("width", type.subtype().get_string(ID_width)); result.set_attribute("c_type", "enum"); mp_integer i; if(!to_integer(expr, i)) result.data=integer2string(i); } else if(type.id()==ID_c_enum_tag) { constant_exprt tmp; tmp.type()=ns.follow_tag(to_c_enum_tag_type(type)); tmp.set_value(to_constant_expr(expr).get_value()); return xml(tmp, ns); } else if(type.id()==ID_bv) { result.name="bitvector"; result.set_attribute("binary", expr.get_string(ID_value)); } else if(type.id()==ID_fixedbv) { result.name="fixed"; result.set_attribute("width", type.get_string(ID_width)); result.set_attribute("binary", expr.get_string(ID_value)); result.data=fixedbvt(to_constant_expr(expr)).to_ansi_c_string(); } else if(type.id()==ID_floatbv) { result.name="float"; result.set_attribute("width", type.get_string(ID_width)); result.set_attribute("binary", expr.get_string(ID_value)); result.data=ieee_floatt(to_constant_expr(expr)).to_ansi_c_string(); } else if(type.id()==ID_pointer) { result.name="pointer"; result.set_attribute("binary", expr.get_string(ID_value)); if(expr.get(ID_value)==ID_NULL) result.data="NULL"; } else if(type.id()==ID_bool) { result.name="boolean"; result.set_attribute("binary", expr.is_true()?"1":"0"); result.data=expr.is_true()?"TRUE":"FALSE"; } else { result.name="unknown"; } } else if(expr.id()==ID_array) { result.name="array"; unsigned index=0; forall_operands(it, expr) { xmlt &e=result.new_element("element"); e.set_attribute("index", index); e.new_element(xml(*it, ns)); index++; }
xmlt xml( const typet &type, const namespacet &ns) { if(type.id()==ID_symbol) return xml(ns.follow(type), ns); xmlt result; if(type.id()==ID_unsignedbv) { result.name="integer"; result.set_attribute("width", to_unsignedbv_type(type).get_width()); } else if(type.id()==ID_signedbv) { result.name="integer"; result.set_attribute("width", to_signedbv_type(type).get_width()); } else if(type.id()==ID_floatbv) { result.name="float"; result.set_attribute("width", to_floatbv_type(type).get_width()); } else if(type.id()==ID_bv) { result.name="integer"; result.set_attribute("width", to_bv_type(type).get_width()); } else if(type.id()==ID_c_bit_field) { result.name="integer"; result.set_attribute("width", to_c_bit_field_type(type).get_width()); } else if(type.id()==ID_c_enum_tag) { // we return the base type return xml(ns.follow_tag(to_c_enum_tag_type(type)).subtype(), ns); } else if(type.id()==ID_fixedbv) { result.name="fixed"; result.set_attribute("width", to_fixedbv_type(type).get_width()); } else if(type.id()==ID_pointer) { result.name="pointer"; result.new_element("subtype").new_element()=xml(type.subtype(), ns); } else if(type.id()==ID_bool) { result.name="boolean"; } else if(type.id()==ID_array) { result.name="array"; result.new_element("subtype").new_element()=xml(type.subtype(), ns); } else if(type.id()==ID_vector) { result.name="vector"; result.new_element("subtype").new_element()=xml(type.subtype(), ns); result.new_element("size").new_element()=xml(to_vector_type(type).size(), ns); } else if(type.id()==ID_struct) { result.name="struct"; const struct_typet::componentst &components= to_struct_type(type).components(); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { xmlt &e=result.new_element("member"); e.set_attribute("name", id2string(it->get_name())); e.new_element("type").new_element()=xml(it->type(), ns); } } else if(type.id()==ID_union) { result.name="union"; const union_typet::componentst &components= to_union_type(type).components(); for(union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { xmlt &e=result.new_element("member"); e.set_attribute("name", id2string(it->get_name())); e.new_element("type").new_element()=xml(it->type(), ns); } } else result.name="unknown"; return result; }
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 }
std::string as_vcd_binary( const exprt &expr, const namespacet &ns) { const typet &type=ns.follow(expr.type()); if(expr.id()==ID_constant) { if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_bv || type.id()==ID_fixedbv || type.id()==ID_floatbv || type.id()==ID_pointer) return expr.get_string(ID_value); } else if(expr.id()==ID_array) { std::string result; forall_operands(it, expr) result+=as_vcd_binary(*it, ns); return result; } else if(expr.id()==ID_struct) { std::string result; forall_operands(it, expr) result+=as_vcd_binary(*it, ns); return result; } else if(expr.id()==ID_union) { assert(expr.operands().size()==1); return as_vcd_binary(expr.op0(), ns); } // build "xxx" mp_integer width; if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_floatbv || type.id()==ID_fixedbv || type.id()==ID_pointer || type.id()==ID_bv) width=string2integer(type.get_string(ID_width)); else width=pointer_offset_size(type, ns)*8; if(width>=0) { std::string result; for(; width!=0; --width) result+='x'; return result; } return ""; }
void value_sett::get_value_set_rec( const exprt &expr, object_mapt &dest, const std::string &suffix, const typet &original_type, const namespacet &ns) const { #if 0 std::cout << "GET_VALUE_SET_REC EXPR: " << from_expr(ns, "", expr) << "\n"; std::cout << "GET_VALUE_SET_REC SUFFIX: " << suffix << std::endl; #endif const typet &expr_type=ns.follow(expr.type()); if(expr.id()==ID_unknown || expr.id()==ID_invalid) { insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_index) { assert(expr.operands().size()==2); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_array || type.id()==ID_incomplete_array); get_value_set_rec(expr.op0(), dest, "[]"+suffix, original_type, ns); } else if(expr.id()==ID_member) { assert(expr.operands().size()==1); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_struct || type.id()==ID_union || type.id()==ID_incomplete_struct || type.id()==ID_incomplete_union); const std::string &component_name= expr.get_string(ID_component_name); get_value_set_rec(expr.op0(), dest, "."+component_name+suffix, original_type, ns); } else if(expr.id()==ID_symbol) { irep_idt identifier=to_symbol_expr(expr).get_identifier(); // is it a pointer, integer, array or struct? if(expr_type.id()==ID_pointer || expr_type.id()==ID_signedbv || expr_type.id()==ID_unsignedbv || expr_type.id()==ID_struct || expr_type.id()==ID_union || expr_type.id()==ID_array) { // look it up valuest::const_iterator v_it= values.find(id2string(identifier)+suffix); // try first component name as suffix if not yet found if(v_it==values.end() && (expr_type.id()==ID_struct || expr_type.id()==ID_union)) { const struct_union_typet &struct_union_type= to_struct_union_type(expr_type); const std::string first_component_name= struct_union_type.components().front().get_string(ID_name); v_it=values.find( id2string(identifier)+"."+first_component_name+suffix); } // not found? try without suffix if(v_it==values.end()) v_it=values.find(identifier); if(v_it!=values.end()) make_union(dest, v_it->second.object_map); else insert(dest, exprt(ID_unknown, original_type)); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three operands"; get_value_set_rec(expr.op1(), dest, suffix, original_type, ns); get_value_set_rec(expr.op2(), dest, suffix, original_type, ns); } else if(expr.id()==ID_address_of) { if(expr.operands().size()!=1) throw expr.id_string()+" expected to have one operand"; get_reference_set(expr.op0(), dest, ns); } else if(expr.id()==ID_dereference) { object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it1=object_map.begin(); it1!=object_map.end(); it1++) { const exprt &object=object_numbering[it1->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.id()=="reference_to") { // old stuff, will go away object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it=object_map.begin(); it!=object_map.end(); it++) { const exprt &object=object_numbering[it->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.is_constant()) { // check if NULL if(expr.get(ID_value)==ID_NULL && expr_type.id()==ID_pointer) { insert(dest, exprt("NULL-object", expr_type.subtype()), 0); } else if(expr_type.id()==ID_unsignedbv || expr_type.id()==ID_signedbv) { // an integer constant got turned into a pointer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_typecast) { if(expr.operands().size()!=1) throw "typecast takes one operand"; // let's see what gets converted to what const typet &op_type=ns.follow(expr.op0().type()); if(op_type.id()==ID_pointer) { // pointer-to-pointer -- we just ignore these get_value_set_rec(expr.op0(), dest, suffix, original_type, ns); } else if(op_type.id()==ID_unsignedbv || op_type.id()==ID_signedbv) { // integer-to-pointer if(expr.op0().is_zero()) insert(dest, exprt("NULL-object", expr_type.subtype()), 0); else { // see if we have something for the integer object_mapt tmp; get_value_set_rec(expr.op0(), tmp, suffix, original_type, ns); if(tmp.read().size()==0) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else if(tmp.read().size()==1 && object_numbering[tmp.read().begin()->first].id()==ID_unknown) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else { // use as is dest.write().insert(tmp.read().begin(), tmp.read().end()); } } } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_plus || expr.id()==ID_minus) { if(expr.operands().size()<2) throw expr.id_string()+" expected to have at least two operands"; object_mapt pointer_expr_set; mp_integer i; bool i_is_set=false; // special case for pointer+integer if(expr.operands().size()==2 && expr_type.id()==ID_pointer) { exprt ptr_operand; if(expr.op0().type().id()!=ID_pointer && expr.op0().is_constant()) { i_is_set=!to_integer(expr.op0(), i); ptr_operand=expr.op1(); } else { i_is_set=!to_integer(expr.op1(), i); ptr_operand=expr.op0(); } if(i_is_set) { i*=pointer_offset_size(ptr_operand.type().subtype(), ns); if(expr.id()==ID_minus) i.negate(); } get_value_set_rec( ptr_operand, pointer_expr_set, "", ptr_operand.type(), ns); } else { // we get the points-to for all operands, even integers forall_operands(it, expr) { get_value_set_rec( *it, pointer_expr_set, "", it->type(), ns); } } for(object_map_dt::const_iterator it=pointer_expr_set.read().begin(); it!=pointer_expr_set.read().end(); it++) { objectt object=it->second; // adjust by offset if(object.offset_is_zero() && i_is_set) object.offset=i; else object.offset_is_set=false; insert(dest, it->first, object); } }