void string_instrumentationt::do_strtok( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()!=2) { err_location(target->location); throw "strtok expected to have two arguments"; } goto_programt tmp; goto_programt::targett assertion0=tmp.add_instruction(); assertion0->make_assertion(is_zero_string(arguments[0])); assertion0->location=target->location; assertion0->location.set("property", "string"); assertion0->location.set("comment", "zero-termination of 1st string argument of strtok"); goto_programt::targett assertion1=tmp.add_instruction(); assertion1->make_assertion(is_zero_string(arguments[1])); assertion1->location=target->location; assertion1->location.set("property", "string"); assertion1->location.set("comment", "zero-termination of 2nd string argument of strtok"); target->make_skip(); dest.insert_before_swap(target, tmp); }
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; }
void string_instrumentationt::do_fscanf( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()<2) { err_location(target->location); throw "fscanf expected to have two or more arguments"; } goto_programt tmp; do_format_string_write(tmp, target, arguments, 1, 2, "fscanf"); if(call.lhs().is_not_nil()) { goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN); return_assignment->location=target->location; exprt rhs=side_effect_expr_nondett(call.lhs().type()); rhs.location()=target->location; return_assignment->code=code_assignt(call.lhs(), rhs); } target->make_skip(); dest.insert_before_swap(target, tmp); }
void string_instrumentationt::do_strstr( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()!=2) { error().source_location=target->source_location; error() << "strstr expected to have two arguments" << eom; throw 0; } goto_programt tmp; goto_programt::targett assertion0=tmp.add_instruction(); assertion0->make_assertion(is_zero_string(arguments[0])); assertion0->source_location=target->source_location; assertion0->source_location.set_property_class("string"); assertion0->source_location.set_comment("zero-termination of 1st string argument of strstr"); goto_programt::targett assertion1=tmp.add_instruction(); assertion1->make_assertion(is_zero_string(arguments[1])); assertion1->source_location=target->source_location; assertion1->source_location.set_property_class("string"); assertion1->source_location.set_comment("zero-termination of 2nd string argument of strstr"); target->make_skip(); dest.insert_before_swap(target, tmp); }
void string_instrumentationt::do_snprintf( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()<3) { error().source_location=target->source_location; error() << "snprintf expected to have three or more arguments" << eom; throw 0; } goto_programt tmp; goto_programt::targett assertion=tmp.add_instruction(); assertion->source_location=target->source_location; assertion->source_location.set_property_class("string"); assertion->source_location.set_comment("snprintf buffer overflow"); exprt bufsize=buffer_size(arguments[0]); assertion->make_assertion( binary_relation_exprt(bufsize, ID_ge, arguments[1])); do_format_string_read(tmp, target, arguments, 2, 3, "snprintf"); if(call.lhs().is_not_nil()) { goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN); return_assignment->source_location=target->source_location; exprt rhs=side_effect_expr_nondett(call.lhs().type()); rhs.add_source_location()=target->source_location; return_assignment->code=code_assignt(call.lhs(), rhs); } target->make_skip(); dest.insert_before_swap(target, tmp); }
void loop_transformt::transform_do_while( goto_programt &program, goto_programt::targett &begin, goto_programt::targett &end) const { if(!end->guard.is_true()) { #if 0 std::cout << "TRANSFORM DO-WHILE" << std::endl; #endif goto_programt::targett next = end; next++; assert(next!=program.instructions.end()); goto_programt::instructiont newguard; newguard.make_goto(next); newguard.guard = end->guard; newguard.guard.make_not(); newguard.location = end->location; end->guard.make_true(); unsigned ln = end->location_number; // doesn't get swapped program.insert_before_swap(end, newguard); // end now points to the new guard goto_programt::targett old_guard = end; old_guard++; end->location_number=ln; old_guard->location_number=ln; program.update(); #if 0 std::cout << "Transformed: " << std::endl; goto_programt::const_targett it = begin; for (; it!=end; it++) program.output_instruction(ns, "", std::cout, it); program.output_instruction(ns, "", std::cout, it); #endif } }
void string_instrumentationt::do_sprintf( goto_programt &dest, goto_programt::targett target, code_function_callt &call) { const code_function_callt::argumentst &arguments=call.arguments(); if(arguments.size()<2) { error().source_location=target->source_location; error() << "sprintf expected to have two or more arguments" << eom; throw 0; } goto_programt tmp; goto_programt::targett assertion=tmp.add_instruction(); assertion->source_location=target->source_location; assertion->source_location.set_property_class("string"); assertion->source_location.set_comment("sprintf buffer overflow"); // in the abstract model, we have to report a // (possibly false) positive here assertion->make_assertion(false_exprt()); do_format_string_read(tmp, target, arguments, 1, 2, "sprintf"); if(call.lhs().is_not_nil()) { goto_programt::targett return_assignment=tmp.add_instruction(ASSIGN); return_assignment->source_location=target->source_location; exprt rhs=side_effect_expr_nondett(call.lhs().type()); rhs.add_source_location()=target->source_location; return_assignment->code=code_assignt(call.lhs(), rhs); } target->make_skip(); dest.insert_before_swap(target, tmp); }
void stack_depth( goto_programt &goto_program, const symbol_exprt &symbol, const int i_depth, const exprt &max_depth) { assert(!goto_program.instructions.empty()); goto_programt::targett first=goto_program.instructions.begin(); binary_relation_exprt guard(symbol, ID_le, max_depth); goto_programt::targett assert_ins=goto_program.insert_before(first); assert_ins->make_assertion(guard); assert_ins->location=first->location; assert_ins->function=first->function; assert_ins->location.set_comment("Stack depth exceeds "+i2string(i_depth)); assert_ins->location.set_property("stack-depth"); goto_programt::targett plus_ins=goto_program.insert_before(first); plus_ins->make_assignment(); plus_ins->code=code_assignt(symbol, plus_exprt(symbol, from_integer(1, symbol.type()))); plus_ins->location=first->location; plus_ins->function=first->function; goto_programt::targett last=--goto_program.instructions.end(); assert(last->is_end_function()); goto_programt::instructiont minus_ins; minus_ins.make_assignment(); minus_ins.code=code_assignt(symbol, minus_exprt(symbol, from_integer(1, symbol.type()))); minus_ins.location=last->location; minus_ins.function=last->function; goto_program.insert_before_swap(last, minus_ins); }
void goto_program_dereferencet::dereference_program( goto_programt &goto_program, bool checks_only) { for(goto_programt::instructionst::iterator it=goto_program.instructions.begin(); it!=goto_program.instructions.end(); it++) { new_code.clear(); assertions.clear(); dereference_instruction(it, checks_only); // insert new instructions 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_strerror( goto_programt &dest, goto_programt::targett it, code_function_callt &call) { if(call.lhs().is_nil()) { it->make_skip(); return; } irep_idt identifier_buf="c::__strerror_buffer"; irep_idt identifier_size="c::__strerror_buffer_size"; if(context.symbols.find(identifier_buf)==context.symbols.end()) { symbolt new_symbol_size; new_symbol_size.base_name="__strerror_buffer_size"; new_symbol_size.pretty_name=new_symbol_size.base_name; new_symbol_size.name=identifier_size; new_symbol_size.mode="C"; new_symbol_size.type=uint_type(); new_symbol_size.is_statevar=true; new_symbol_size.lvalue=true; new_symbol_size.static_lifetime=true; array_typet type; type.subtype()=char_type(); type.size()=symbol_expr(new_symbol_size); symbolt new_symbol_buf; new_symbol_buf.mode="C"; new_symbol_buf.type=type; new_symbol_buf.is_statevar=true; new_symbol_buf.lvalue=true; new_symbol_buf.static_lifetime=true; new_symbol_buf.base_name="__strerror_buffer"; new_symbol_buf.pretty_name=new_symbol_buf.base_name; new_symbol_buf.name="c::"+id2string(new_symbol_buf.base_name); context.move(new_symbol_buf); context.move(new_symbol_size); } const symbolt &symbol_size=ns.lookup(identifier_size); const symbolt &symbol_buf=ns.lookup(identifier_buf); goto_programt tmp; { goto_programt::targett assignment1=tmp.add_instruction(ASSIGN); exprt nondet_size=side_effect_expr_nondett(uint_type()); assignment1->code=code_assignt(symbol_expr(symbol_size), nondet_size); assignment1->location=it->location; goto_programt::targett assumption1=tmp.add_instruction(); assumption1->make_assumption(binary_relation_exprt( symbol_expr(symbol_size), "notequal", gen_zero(symbol_size.type))); assumption1->location=it->location; } // return a pointer to some magic buffer exprt index=exprt("index", char_type()); index.copy_to_operands(symbol_expr(symbol_buf), gen_zero(uint_type())); exprt ptr=exprt("address_of", pointer_typet()); ptr.type().subtype()=char_type(); ptr.copy_to_operands(index); // make that zero-terminated { goto_programt::targett assignment2=tmp.add_instruction(ASSIGN); assignment2->code=code_assignt(is_zero_string(ptr, true), true_exprt()); assignment2->location=it->location; } // assign address { goto_programt::targett assignment3=tmp.add_instruction(ASSIGN); exprt rhs=ptr; make_type(rhs, call.lhs().type()); assignment3->code=code_assignt(call.lhs(), rhs); assignment3->location=it->location; } it->make_skip(); dest.insert_before_swap(it, tmp); }
void goto_inlinet::replace_return( goto_programt &dest, const exprt &lhs, const exprt &constrain) { for(goto_programt::instructionst::iterator it=dest.instructions.begin(); it!=dest.instructions.end(); it++) { if(it->is_return()) { #if 0 if(lhs.is_not_nil()) { if(it->code.operands().size()!=1) { error().source_location=it->code.find_source_location(); str << "return expects one operand!"; warning_msg(); continue; } goto_programt tmp; goto_programt::targett assignment=tmp.add_instruction(ASSIGN); code_assignt code_assign(lhs, it->code.op0()); // this may happen if the declared return type at the call site // differs from the defined return type if(code_assign.lhs().type()!= code_assign.rhs().type()) code_assign.rhs().make_typecast(code_assign.lhs().type()); assignment->code=code_assign; assignment->source_location=it->source_location; assignment->function=it->function; if(constrain.is_not_nil() && !constrain.is_true()) { codet constrain(ID_bp_constrain); constrain.reserve_operands(2); constrain.move_to_operands(assignment->code); constrain.copy_to_operands(constrain); } dest.insert_before_swap(it, *assignment); it++; } else if(!it->code.operands().empty()) { goto_programt tmp; goto_programt::targett expression=tmp.add_instruction(OTHER); expression->code=codet(ID_expression); expression->code.move_to_operands(it->code.op0()); expression->source_location=it->source_location; expression->function=it->function; dest.insert_before_swap(it, *expression); it++; } it->make_goto(--dest.instructions.end()); #else if(lhs.is_not_nil()) { if(it->code.operands().size()!=1) { warning().source_location=it->code.find_source_location(); warning() << "return expects one operand!\n" << it->code.pretty() << eom; continue; } code_assignt code_assign(lhs, it->code.op0()); // this may happen if the declared return type at the call site // differs from the defined return type if(code_assign.lhs().type()!= code_assign.rhs().type()) code_assign.rhs().make_typecast(code_assign.lhs().type()); if(constrain.is_not_nil() && !constrain.is_true()) { codet constrain(ID_bp_constrain); constrain.reserve_operands(2); constrain.move_to_operands(code_assign); constrain.copy_to_operands(constrain); it->code=constrain; it->type=OTHER; } else { it->code=code_assign; it->type=ASSIGN; } it++; } else if(!it->code.operands().empty()) { codet expression(ID_expression); expression.move_to_operands(it->code.op0()); it->code=expression; it->type=OTHER; it++; } #endif } } }
void string_instrumentationt::do_strerror( goto_programt &dest, goto_programt::targett it, code_function_callt &call) { if(call.lhs().is_nil()) { it->make_skip(); return; } irep_idt identifier_buf="__strerror_buffer"; irep_idt identifier_size="__strerror_buffer_size"; if(symbol_table.symbols.find(identifier_buf)==symbol_table.symbols.end()) { symbolt new_symbol_size; new_symbol_size.base_name="__strerror_buffer_size"; new_symbol_size.pretty_name=new_symbol_size.base_name; new_symbol_size.name=identifier_size; new_symbol_size.mode=ID_C; new_symbol_size.type=size_type(); new_symbol_size.is_state_var=true; new_symbol_size.is_lvalue=true; new_symbol_size.is_static_lifetime=true; array_typet type; type.subtype()=char_type(); type.size()=new_symbol_size.symbol_expr(); symbolt new_symbol_buf; new_symbol_buf.mode=ID_C; new_symbol_buf.type=type; new_symbol_buf.is_state_var=true; new_symbol_buf.is_lvalue=true; new_symbol_buf.is_static_lifetime=true; new_symbol_buf.base_name="__strerror_buffer"; new_symbol_buf.pretty_name=new_symbol_buf.base_name; new_symbol_buf.name=new_symbol_buf.base_name; symbol_table.move(new_symbol_buf); symbol_table.move(new_symbol_size); } const symbolt &symbol_size=ns.lookup(identifier_size); const symbolt &symbol_buf=ns.lookup(identifier_buf); goto_programt tmp; { goto_programt::targett assignment1=tmp.add_instruction(ASSIGN); exprt nondet_size=side_effect_expr_nondett(size_type()); assignment1->code=code_assignt(symbol_size.symbol_expr(), nondet_size); assignment1->source_location=it->source_location; goto_programt::targett assumption1=tmp.add_instruction(); assumption1->make_assumption( binary_relation_exprt( symbol_size.symbol_expr(), ID_notequal, from_integer(0, symbol_size.type))); assumption1->source_location=it->source_location; } // return a pointer to some magic buffer index_exprt index( symbol_buf.symbol_expr(), from_integer(0, index_type()), char_type()); address_of_exprt ptr(index); // make that zero-terminated { goto_programt::targett assignment2=tmp.add_instruction(ASSIGN); assignment2->code=code_assignt(is_zero_string(ptr, true), true_exprt()); assignment2->source_location=it->source_location; } // assign address { goto_programt::targett assignment3=tmp.add_instruction(ASSIGN); exprt rhs=ptr; make_type(rhs, call.lhs().type()); assignment3->code=code_assignt(call.lhs(), rhs); assignment3->source_location=it->source_location; } it->make_skip(); dest.insert_before_swap(it, tmp); }