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 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); }
void mutex_init_instrumentation( const symbol_tablet &symbol_table, goto_programt &goto_program, typet lock_type) { symbol_tablet::symbolst::const_iterator f_it= symbol_table.symbols.find("__CPROVER_set_must"); if(f_it==symbol_table.symbols.end()) return; Forall_goto_program_instructions(it, goto_program) { if(it->is_assign()) { const code_assignt &code_assign= to_code_assign(it->code); if(code_assign.lhs().type()==lock_type) { goto_programt::targett t=goto_program.insert_after(it); code_function_callt call; call.function()=f_it->second.symbol_expr(); call.arguments().resize(2); call.arguments()[0]=address_of_exprt(code_assign.lhs()); call.arguments()[1]=address_of_exprt(string_constantt("mutex-init")); t->make_function_call(call); t->source_location=it->source_location; } } } }
void java_record_outputs( const symbolt &function, const exprt::operandst &main_arguments, code_blockt &init_code, symbol_tablet &symbol_table) { const code_typet::parameterst ¶meters= to_code_type(function.type).parameters(); exprt::operandst result; result.reserve(parameters.size()+1); bool has_return_value= to_code_type(function.type).return_type()!=empty_typet(); if(has_return_value) { // record return value codet output(ID_output); output.operands().resize(2); const symbolt &return_symbol=symbol_table.lookup("return'"); output.op0()= address_of_exprt( index_exprt( string_constantt(return_symbol.base_name), from_integer(0, index_type()))); output.op1()=return_symbol.symbol_expr(); output.add_source_location()=function.location; init_code.move_to_operands(output); } for(std::size_t param_number=0; param_number<parameters.size(); param_number++) { const symbolt &p_symbol= symbol_table.lookup(parameters[param_number].get_identifier()); if(p_symbol.type.id()==ID_pointer) { // record as an output codet output(ID_output); output.operands().resize(2); output.op0()= address_of_exprt( index_exprt( string_constantt(p_symbol.base_name), from_integer(0, index_type()))); output.op1()=main_arguments[param_number]; output.add_source_location()=function.location; init_code.move_to_operands(output); } } }
void thread_exit_instrumentation(goto_programt &goto_program) { if(goto_program.instructions.empty()) return; // add assertion that all may flags for mutex-locked are gone // at the end goto_programt::targett end=goto_program.instructions.end(); end--; assert(end->is_end_function()); source_locationt source_location=end->source_location; irep_idt function=end->function; goto_program.insert_before_swap(end); exprt mutex_locked_string= string_constantt("mutex-locked"); binary_exprt get_may("get_may"); // NULL is any get_may.op0()=constant_exprt(ID_NULL, pointer_typet(empty_typet())); get_may.op1()=address_of_exprt(mutex_locked_string); end->make_assertion(not_exprt(get_may)); end->source_location=source_location; end->source_location.set_comment("mutexes must not be locked on thread exit"); end->function=function; }
code_function_callt function_to_call( symbol_tablet &symbol_table, const irep_idt &id, const irep_idt &argument) { // already there? symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(id); if(s_it==symbol_table.symbols.end()) { // not there pointer_typet p(char_type()); p.subtype().set(ID_C_constant, true); code_typet function_type; function_type.return_type()=empty_typet(); function_type.parameters().push_back( code_typet::parametert(p)); symbolt new_symbol; new_symbol.name=id; new_symbol.base_name=id; new_symbol.type=function_type; symbol_table.move(new_symbol); s_it=symbol_table.symbols.find(id); assert(s_it!=symbol_table.symbols.end()); } // signature is expected to be // (type *) -> ... if(s_it->second.type.id()!=ID_code || to_code_type(s_it->second.type).parameters().size()!=1 || to_code_type(s_it->second.type).parameters()[0].type().id()!=ID_pointer) { std::string error="function `"+id2string(id)+"' has wrong signature"; throw error; } string_constantt function_id_string(argument); code_function_callt call; call.lhs().make_nil(); call.function()= symbol_exprt(s_it->second.name, s_it->second.type); call.arguments().resize(1); call.arguments()[0]= typecast_exprt( address_of_exprt( index_exprt( function_id_string, from_integer(0, index_type()))), to_code_type(s_it->second.type).parameters()[0].type()); return call; }
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 simplify_exprt::simplify_inequality_address_of(exprt &expr) { assert(expr.type().id()==ID_bool); assert(expr.operands().size()==2); assert(expr.id()==ID_equal || expr.id()==ID_notequal); exprt tmp0=expr.op0(); if(tmp0.id()==ID_typecast) tmp0=expr.op0().op0(); if(tmp0.op0().id()==ID_index && to_index_expr(tmp0.op0()).index().is_zero()) tmp0=address_of_exprt(to_index_expr(tmp0.op0()).array()); exprt tmp1=expr.op1(); if(tmp1.id()==ID_typecast) tmp1=expr.op1().op0(); if(tmp1.op0().id()==ID_index && to_index_expr(tmp1.op0()).index().is_zero()) tmp1=address_of_exprt(to_index_expr(tmp1.op0()).array()); assert(tmp0.id()==ID_address_of); assert(tmp1.id()==ID_address_of); if(tmp0.operands().size()!=1) return true; if(tmp1.operands().size()!=1) return true; if(tmp0.op0().id()==ID_symbol && tmp1.op0().id()==ID_symbol) { bool equal= tmp0.op0().get(ID_identifier)== tmp1.op0().get(ID_identifier); expr.make_bool(expr.id()==ID_equal?equal:!equal); return false; } return true; }
void assume_renondet_inputs_valid(jsa_programt &prog) { if (prog.counterexample_locations.empty()) return; const symbol_tablet &st=prog.st; goto_programt &body=get_entry_body(prog.gf); for (const goto_programt::targett &pos : prog.inductive_step_renondets) { const irep_idt &id=get_affected_variable(*pos); const symbol_exprt lhs(st.lookup(id).symbol_expr()); const typet &type=lhs.type(); if (is_jsa_heap(type)) assume_valid_heap(st, body, pos, address_of_exprt(lhs)); } }
void c_typecastt::do_typecast(exprt &expr, const typet &type) { // special case: array -> pointer is actually // something like address_of const typet &expr_type=ns.follow(expr.type()); if(expr_type.id()==ID_array) { index_exprt index; index.array()=expr; index.index()=gen_zero(index_type()); index.type()=expr_type.subtype(); expr=address_of_exprt(index); if(ns.follow(expr.type())!=ns.follow(type)) expr.make_typecast(type); return; } if(expr_type!=type) { // C booleans are special: we compile to ?0:1 if(type.get(ID_C_c_type)==ID_bool) { if(expr_type.id()==ID_bool) // bool -> _Bool { exprt result=if_exprt(expr, gen_one(type), gen_zero(type)); expr.swap(result); } else // * -> _Bool { equal_exprt equal_zero(expr, gen_zero(expr_type)); exprt result=if_exprt(equal_zero, gen_zero(type), gen_one(type)); expr.swap(result); } } else { expr.make_typecast(type); } } }
void c_typecastt::do_typecast(exprt &expr, const typet &dest_type) { // special case: array -> pointer is actually // something like address_of const typet &src_type=ns.follow(expr.type()); if(src_type.id()==ID_array) { index_exprt index; index.array()=expr; index.index()=gen_zero(index_type()); index.type()=src_type.subtype(); expr=address_of_exprt(index); if(ns.follow(expr.type())!=ns.follow(dest_type)) expr.make_typecast(dest_type); return; } if(src_type!=dest_type) { // C booleans are special; we produce the // explicit comparision with zero. // Note that this requires ieee_float_notequal // in case of floating-point numbers. if(dest_type.get(ID_C_c_type)==ID_bool) { expr=is_not_zero(expr, ns); expr.make_typecast(dest_type); } else if(dest_type.id()==ID_bool) { expr=is_not_zero(expr, ns); } else { expr.make_typecast(dest_type); } } }
void execute_inv_prog(const symbol_tablet &st, goto_functionst &gf, const size_t max_solution_size, const goto_programt::targett &decl, const std::string &prog_base_name) { goto_programt &body=get_entry_body(gf); goto_programt::targett pos=decl; goto_programt::targett execution=body.insert_after(++pos); execution->type=goto_program_instruction_typet::FUNCTION_CALL; execution->source_location=default_cegis_source_location(); code_function_callt call; call.function()=st.lookup(DANGER_EXECUTE).symbol_expr(); const std::string prog_name(get_cegis_meta_name(prog_base_name)); const symbol_exprt prog_symbol(st.lookup(prog_name).symbol_expr()); const typet size_type(unsigned_int_type()); const constant_exprt index(from_integer(0u, size_type)); const index_exprt first_elem(prog_symbol, index); call.arguments().push_back(address_of_exprt(first_elem)); const constant_exprt size(from_integer(max_solution_size, size_type)); call.arguments().push_back(size); execution->code=call; }
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; }
exprt::operandst java_build_arguments( const symbolt &function, code_blockt &init_code, symbol_tablet &symbol_table, bool assume_init_pointers_not_null, unsigned max_nondet_array_length, message_handlert &message_handler) { const code_typet::parameterst ¶meters= to_code_type(function.type).parameters(); exprt::operandst main_arguments; main_arguments.resize(parameters.size()); for(std::size_t param_number=0; param_number<parameters.size(); param_number++) { bool is_this=(param_number==0) && parameters[param_number].get_this(); bool is_default_entry_point(config.main.empty()); bool is_main=is_default_entry_point; if(!is_main) { bool named_main=has_suffix(config.main, ".main"); const typet &string_array_type= java_type_from_string("[Ljava.lang.String;"); bool has_correct_type= to_code_type(function.type).return_type().id()==ID_empty && (!to_code_type(function.type).has_this()) && parameters.size()==1 && parameters[0].type().full_eq(string_array_type); is_main=(named_main && has_correct_type); } bool allow_null=(!is_main) && (!is_this) && !assume_init_pointers_not_null; main_arguments[param_number]= object_factory( parameters[param_number].type(), init_code, allow_null, symbol_table, max_nondet_array_length, function.location, message_handler); const symbolt &p_symbol= symbol_table.lookup(parameters[param_number].get_identifier()); // record as an input codet input(ID_input); input.operands().resize(2); input.op0()= address_of_exprt( index_exprt( string_constantt(p_symbol.base_name), from_integer(0, index_type()))); input.op1()=main_arguments[param_number]; input.add_source_location()=function.location; init_code.move_to_operands(input); } return main_arguments; }
void goto_checkt::goto_check(goto_functiont &goto_function) { { const symbolt *init_symbol; if(!ns.lookup(CPROVER_PREFIX "initialize", init_symbol)) mode=init_symbol->mode; } assertions.clear(); local_bitvector_analysist local_bitvector_analysis_obj(goto_function); local_bitvector_analysis=&local_bitvector_analysis_obj; goto_programt &goto_program=goto_function.body; Forall_goto_program_instructions(it, goto_program) { t=it; goto_programt::instructiont &i=*it; new_code.clear(); // we clear all recorded assertions if // 1) we want to generate all assertions or // 2) the instruction is a branch target if(retain_trivial || i.is_target()) assertions.clear(); check(i.guard); // magic ERROR label? for(optionst::value_listt::const_iterator l_it=error_labels.begin(); l_it!=error_labels.end(); l_it++) { if(std::find(i.labels.begin(), i.labels.end(), *l_it)!=i.labels.end()) { goto_program_instruction_typet type= enable_assert_to_assume?ASSUME:ASSERT; goto_programt::targett t=new_code.add_instruction(type); t->guard=false_exprt(); t->source_location=i.source_location; t->source_location.set_property_class("error label"); t->source_location.set_comment("error label "+*l_it); t->source_location.set("user-provided", true); } } if(i.is_other()) { const irep_idt &statement=i.code.get(ID_statement); if(statement==ID_expression) { check(i.code); } else if(statement==ID_printf) { forall_operands(it, i.code) check(*it); } } else if(i.is_assign()) { const code_assignt &code_assign=to_code_assign(i.code); check(code_assign.lhs()); check(code_assign.rhs()); // the LHS might invalidate any assertion invalidate(code_assign.lhs()); } else if(i.is_function_call()) { const code_function_callt &code_function_call= to_code_function_call(i.code); // for Java, need to check whether 'this' is null // on non-static method invocations if(mode==ID_java && enable_pointer_check && !code_function_call.arguments().empty() && code_function_call.function().type().id()==ID_code && to_code_type(code_function_call.function().type()).has_this()) { exprt pointer=code_function_call.arguments()[0]; local_bitvector_analysist::flagst flags= local_bitvector_analysis->get(t, pointer); if(flags.is_unknown() || flags.is_null()) { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "this is null on method invokation", "pointer dereference", i.source_location, pointer, guardt()); } } forall_operands(it, code_function_call) check(*it); // the call might invalidate any assertion assertions.clear(); } else if(i.is_return()) { if(i.code.operands().size()==1) { check(i.code.op0()); // the return value invalidate any assertion invalidate(i.code.op0()); } } else if(i.is_throw()) { if(i.code.get_statement()==ID_expression && i.code.operands().size()==1 && i.code.op0().operands().size()==1) { // must not throw NULL exprt pointer=i.code.op0().op0(); if(pointer.type().subtype().get(ID_identifier)!="java::java.lang.AssertionError") { notequal_exprt not_eq_null(pointer, gen_zero(pointer.type())); add_guarded_claim( not_eq_null, "throwing null", "pointer dereference", i.source_location, pointer, guardt()); } } // this has no successor assertions.clear(); } else if(i.is_assert()) { if(i.source_location.get_bool("user-provided") && i.source_location.get_property_class()!="error label" && !enable_assertions) i.type=SKIP; } else if(i.is_assume()) { if(!enable_assumptions) i.type=SKIP; } else if(i.is_dead()) { if(enable_pointer_check) { assert(i.code.operands().size()==1); const symbol_exprt &variable=to_symbol_expr(i.code.op0()); // is it dirty? if(local_bitvector_analysis->dirty(variable)) { // need to mark the dead variable as dead goto_programt::targett t=new_code.add_instruction(ASSIGN); exprt address_of_expr=address_of_exprt(variable); exprt lhs=ns.lookup(CPROVER_PREFIX "dead_object").symbol_expr(); if(!base_type_eq(lhs.type(), address_of_expr.type(), ns)) address_of_expr.make_typecast(lhs.type()); exprt rhs=if_exprt( side_effect_expr_nondett(bool_typet()), address_of_expr, lhs, lhs.type()); t->source_location=i.source_location; t->code=code_assignt(lhs, rhs); t->code.add_source_location()=i.source_location; } } } else if(i.is_end_function()) { if(i.function==goto_functionst::entry_point() && enable_memory_leak_check) { const symbolt &leak=ns.lookup(CPROVER_PREFIX "memory_leak"); const symbol_exprt leak_expr=leak.symbol_expr(); // add self-assignment to get helpful counterexample output goto_programt::targett t=new_code.add_instruction(); t->make_assignment(); t->code=code_assignt(leak_expr, leak_expr); source_locationt source_location; source_location.set_function(i.function); equal_exprt eq(leak_expr, gen_zero(ns.follow(leak.type))); add_guarded_claim( eq, "dynamically allocated memory never freed", "memory-leak", source_location, eq, guardt()); } } for(goto_programt::instructionst::iterator i_it=new_code.instructions.begin(); i_it!=new_code.instructions.end(); i_it++) { if(i_it->source_location.is_nil()) { i_it->source_location.id(irep_idt()); if(it->source_location.get_file()!=irep_idt()) i_it->source_location.set_file(it->source_location.get_file()); if(it->source_location.get_line()!=irep_idt()) i_it->source_location.set_line(it->source_location.get_line()); if(it->source_location.get_function()!=irep_idt()) i_it->source_location.set_function(it->source_location.get_function()); if(it->source_location.get_column()!=irep_idt()) i_it->source_location.set_column(it->source_location.get_column()); } if(i_it->function==irep_idt()) i_it->function=it->function; } // insert new instructions -- make sure targets are not moved while(!new_code.instructions.empty()) { goto_program.insert_before_swap(it, new_code.instructions.front()); new_code.instructions.pop_front(); it++; } }
void string_instrumentationt::do_format_string_read( 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) { 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(it->type==format_tokent::STRING) { const exprt &arg = arguments[argument_start_inx+args]; const typet &arg_type = ns.follow(arg.type()); if(arg.id()!=ID_string_constant) // we don't need to check constants { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("zero-termination of string argument of "); comment += function_name; assertion->location.set("comment", comment); exprt temp(arg); if(arg_type.id()!="pointer") { index_exprt index; index.array()=temp; index.index()=gen_zero(uint_type()); index.type()=arg_type.subtype(); temp=address_of_exprt(index); } assertion->make_assertion(is_zero_string(temp)); } } if(it->type!=format_tokent::TEXT && it->type!=format_tokent::UNKNOWN) args++; if(find(it->flags.begin(), it->flags.end(), format_tokent::ASTERISK)!= it->flags.end()) args++; // just eat the additional argument } } else // non-const format string { goto_programt::targett format_ass=dest.add_instruction(); format_ass->make_assertion(is_zero_string(arguments[1])); format_ass->location=target->location; format_ass->location.set("property", "string"); std::string comment("zero-termination of format string of "); comment += function_name; format_ass->location.set("comment", comment); for(unsigned i=2; i<arguments.size(); i++) { const exprt &arg = arguments[i]; const typet &arg_type=ns.follow(arguments[i].type()); if(arguments[i].id()!=ID_string_constant && is_string_type(arg_type)) { goto_programt::targett assertion=dest.add_instruction(); assertion->location=target->location; assertion->location.set("property", "string"); std::string comment("zero-termination of string argument of "); comment += function_name; assertion->location.set("comment", comment); exprt temp(arg); if(arg_type.id()!="pointer") { index_exprt index; index.array()=temp; index.index()=gen_zero(uint_type()); index.type()=arg_type.subtype(); temp=address_of_exprt(index); } assertion->make_assertion(is_zero_string(temp)); } } } }
void string_instrumentationt::invalidate_buffer( goto_programt &dest, goto_programt::const_targett target, const exprt &buffer, const typet &buf_type, const mp_integer &limit) { irep_idt cntr_id="string_instrumentation::$counter"; if(context.symbols.find(cntr_id)==context.symbols.end()) { symbolt new_symbol; new_symbol.base_name="$counter"; new_symbol.pretty_name=new_symbol.base_name; new_symbol.name=cntr_id; new_symbol.mode="C"; new_symbol.type=uint_type(); new_symbol.is_statevar=true; new_symbol.lvalue=true; new_symbol.static_lifetime=true; context.move(new_symbol); } const symbolt &cntr_sym=ns.lookup(cntr_id); // create a loop that runs over the buffer // and invalidates every element goto_programt::targett init=dest.add_instruction(ASSIGN); init->location=target->location; init->code=code_assignt(symbol_expr(cntr_sym), gen_zero(cntr_sym.type)); goto_programt::targett check=dest.add_instruction(); check->location=target->location; goto_programt::targett invalidate=dest.add_instruction(ASSIGN); invalidate->location=target->location; goto_programt::targett increment=dest.add_instruction(ASSIGN); increment->location=target->location; exprt plus("+", uint_type()); plus.copy_to_operands(symbol_expr(cntr_sym)); plus.copy_to_operands(gen_one(uint_type())); increment->code=code_assignt(symbol_expr(cntr_sym), plus); goto_programt::targett back=dest.add_instruction(); back->location=target->location; back->make_goto(check); back->guard=true_exprt(); goto_programt::targett exit=dest.add_instruction(); exit->location=target->location; exit->make_skip(); exprt cnt_bs, bufp; if(buf_type.id()=="pointer") bufp = buffer; else { index_exprt index; index.array()=buffer; index.index()=gen_zero(uint_type()); index.type()=buf_type.subtype(); bufp = address_of_exprt(index); } exprt deref("dereference", buf_type.subtype()); exprt b_plus_i("+", bufp.type()); b_plus_i.copy_to_operands(bufp); b_plus_i.copy_to_operands(symbol_expr(cntr_sym)); deref.copy_to_operands(b_plus_i); check->make_goto(exit); if(limit==0) check->guard= binary_relation_exprt(symbol_expr(cntr_sym), ">=", buffer_size(bufp)); else check->guard= binary_relation_exprt(symbol_expr(cntr_sym), ">", from_integer(limit, uint_type())); exprt nondet=side_effect_expr_nondett(buf_type.subtype()); invalidate->code=code_assignt(deref, nondet); }
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); } }