void stack_depth( symbol_tablet &symbol_table, goto_functionst &goto_functions, const int depth) { const symbol_exprt sym=add_stack_depth_symbol(symbol_table); const exprt depth_expr(from_integer(depth, sym.type())); Forall_goto_functions(f_it, goto_functions) if(f_it->second.body_available && f_it->first!=CPROVER_PREFIX "initialize" && f_it->first!=ID_main) stack_depth(f_it->second.body, sym, depth, depth_expr); // initialize depth to 0 goto_functionst::function_mapt::iterator i_it=goto_functions.function_map.find(CPROVER_PREFIX "initialize"); assert(i_it!=goto_functions.function_map.end()); goto_programt &init=i_it->second.body; goto_programt::targett first=init.instructions.begin(); goto_programt::targett it=init.insert_before(first); it->make_assignment(); it->code=code_assignt(sym, from_integer(0, sym.type())); it->location=first->location; it->function=first->function; // update counters etc. goto_functions.update(); }
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 symex_target_equationt::assignment( const guardt &guard, const symbol_exprt &ssa_lhs, const symbol_exprt &original_lhs_object, const exprt &ssa_full_lhs, const exprt &original_full_lhs, const exprt &ssa_rhs, const sourcet &source, assignment_typet assignment_type) { assert(ssa_lhs.is_not_nil()); SSA_steps.push_back(SSA_stept()); SSA_stept &SSA_step=SSA_steps.back(); SSA_step.guard_expr=guard.as_expr(); SSA_step.ssa_lhs=ssa_lhs; SSA_step.original_lhs_object=original_lhs_object; SSA_step.ssa_full_lhs=ssa_full_lhs; SSA_step.original_full_lhs=original_full_lhs; SSA_step.ssa_rhs=ssa_rhs; SSA_step.assignment_type=assignment_type; SSA_step.cond_expr=equal_exprt(SSA_step.ssa_lhs, SSA_step.ssa_rhs); SSA_step.type=goto_trace_stept::ASSIGNMENT; SSA_step.source=source; }
exprt remove_const_function_pointerst::resolve_symbol( const symbol_exprt &symbol_expr) const { const symbolt &symbol= symbol_table.lookup(symbol_expr.get_identifier()); return symbol.value; }
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); }
exprt interval_domaint::make_expression(const symbol_exprt &src) const { if(is_int(src.type())) { int_mapt::const_iterator i_it=int_map.find(src.get_identifier()); if(i_it==int_map.end()) return true_exprt(); const integer_intervalt &interval=i_it->second; if(interval.is_top()) return true_exprt(); if(interval.is_bottom()) return false_exprt(); exprt::operandst conjuncts; if(interval.upper_set) { exprt tmp=from_integer(interval.upper, src.type()); conjuncts.push_back(binary_relation_exprt(src, ID_le, tmp)); } if(interval.lower_set) { exprt tmp=from_integer(interval.lower, src.type()); conjuncts.push_back(binary_relation_exprt(tmp, ID_le, src)); } return conjunction(conjuncts); } else if(is_float(src.type())) { float_mapt::const_iterator i_it=float_map.find(src.get_identifier()); if(i_it==float_map.end()) return true_exprt(); const ieee_float_intervalt &interval=i_it->second; if(interval.is_top()) return true_exprt(); if(interval.is_bottom()) return false_exprt(); exprt::operandst conjuncts; if(interval.upper_set) { exprt tmp=interval.upper.to_expr(); conjuncts.push_back(binary_relation_exprt(src, ID_le, tmp)); } if(interval.lower_set) { exprt tmp=interval.lower.to_expr(); conjuncts.push_back(binary_relation_exprt(tmp, ID_le, src)); } return conjunction(conjuncts); } else return true_exprt(); }
void symex_target_equationt::decl( const guardt &guard, const symbol_exprt &ssa_lhs, const symbol_exprt &original_lhs_object, const sourcet &source) { assert(ssa_lhs.is_not_nil()); SSA_steps.push_back(SSA_stept()); SSA_stept &SSA_step=SSA_steps.back(); SSA_step.guard_expr=guard.as_expr(); SSA_step.ssa_lhs=ssa_lhs; SSA_step.ssa_full_lhs=ssa_lhs; SSA_step.original_lhs_object=original_lhs_object; SSA_step.original_full_lhs=original_lhs_object; SSA_step.type=goto_trace_stept::DECL; SSA_step.source=source; // the condition is trivially true, and only // there so we see the symbols SSA_step.cond_expr=equal_exprt(SSA_step.ssa_lhs, SSA_step.ssa_lhs); }
void acceleratet::build_state_machine( trace_automatont::sym_mapt::iterator begin, trace_automatont::sym_mapt::iterator end, state_sett &accept_states, symbol_exprt state, symbol_exprt next_state, scratch_programt &state_machine) { std::map<unsigned int, unsigned int> successor_counts; unsigned int max_count=0; unsigned int likely_next=0; // Optimisation: find the most common successor state and initialise // next_state to that value. This reduces the size of the state machine // driver substantially. for(trace_automatont::sym_mapt::iterator p=begin; p!=end; ++p) { trace_automatont::state_pairt state_pair=p->second; unsigned int to=state_pair.second; unsigned int count=0; if(successor_counts.find(to)==successor_counts.end()) { count=1; } else { count=successor_counts[to] + 1; } successor_counts[to]=count; if(count > max_count) { max_count=count; likely_next=to; } } // Optimisation: if there is only one possible successor state, just // jump straight to it instead of driving the whole machine. if(successor_counts.size()==1) { if(accept_states.find(likely_next)!=accept_states.end()) { // It's an accept state. Just assume(false). state_machine.assume(false_exprt()); } else { state_machine.assign(state, from_integer(likely_next, next_state.type())); } return; } state_machine.assign(next_state, from_integer(likely_next, next_state.type())); for(trace_automatont::sym_mapt::iterator p=begin; p!=end; ++p) { trace_automatont::state_pairt state_pair=p->second; unsigned int from=state_pair.first; unsigned int to=state_pair.second; if(to==likely_next) { continue; } // We're encoding the transition // // from -loc-> to // // which we encode by inserting: // // next_state=(state==from) ? to : next_state; // // just before loc. equal_exprt guard(state, from_integer(from, state.type())); if_exprt rhs(guard, from_integer(to, next_state.type()), next_state); state_machine.assign(next_state, rhs); } // Update the state and assume(false) if we've hit an accept state. state_machine.assign(state, next_state); for(state_sett::iterator it=accept_states.begin(); it!=accept_states.end(); ++it) { state_machine.assume( not_exprt(equal_exprt(state, from_integer(*it, state.type())))); } }
void jsil_typecheckt::typecheck_symbol_expr(symbol_exprt &symbol_expr) { irep_idt identifier=symbol_expr.get_identifier(); // if this is a built-in identifier, check if it exists in the // symbol table and retrieve it's type // TODO: add a flag for not needing to prefix internal symbols // that do not start with hash if(has_prefix(id2string(identifier), "#") || identifier=="eval" || identifier=="nan") { symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(identifier); if(s_it==symbol_table.symbols.end()) throw "unexpected internal symbol: "+id2string(identifier); else { // symbol already exists const symbolt &symbol=s_it->second; // type the expression symbol_expr.type()=symbol.type; } } else { // if this is a variable, we need to check if we already // prefixed it and add to the symbol table if it is not there already irep_idt identifier_base = identifier; if(!has_prefix(id2string(identifier), id2string(proc_name))) { identifier = add_prefix(identifier); symbol_expr.set_identifier(identifier); } symbol_tablet::symbolst::const_iterator s_it= symbol_table.symbols.find(identifier); if(s_it==symbol_table.symbols.end()) { // create new symbol symbolt new_symbol; new_symbol.name=identifier; new_symbol.type=symbol_expr.type(); new_symbol.base_name=identifier_base; new_symbol.mode="jsil"; new_symbol.is_type=false; new_symbol.is_lvalue=new_symbol.type.id()!=ID_code; // mark as already typechecked new_symbol.is_extern=true; if(symbol_table.add(new_symbol)) { error() << "failed to add symbol `" << new_symbol.name << "' in the symbol table" << eom; throw 0; } } else { // symbol already exists assert(!s_it->second.is_type); const symbolt &symbol=s_it->second; // type the expression symbol_expr.type()=symbol.type; } } }
bool is_jsa_const(const symbol_exprt &symbol) { const std::string &id=id2string(symbol.get_identifier()); if (std::string::npos != id.find(JSA_CONSTANT_PREFIX)) return true; return symbol.type().get_bool(ID_C_constant); }
void goto_convertt::do_function_call_symbol( const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, goto_programt &dest) { if(function.get_bool("#invalid_object")) return; // ignore // lookup symbol const irep_idt &identifier=function.get_identifier(); const symbolt *symbol; if(ns.lookup(identifier, symbol)) { err_location(function); throw "error: function `"+id2string(identifier)+"' not found"; } if(symbol->type.id()!=ID_code) { err_location(function); throw "error: function `"+id2string(identifier)+"' type mismatch: expected code"; } if(identifier==CPROVER_PREFIX "assume" || identifier=="__VERIFIER_assume") { if(arguments.size()!=1) { err_location(function); throw "`"+id2string(identifier)+"' expected to have one argument"; } goto_programt::targett t=dest.add_instruction(ASSUME); t->guard=arguments.front(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); // let's double-check the type of the argument if(t->guard.type().id()!=ID_bool) t->guard.make_typecast(bool_typet()); if(lhs.is_not_nil()) { err_location(function); throw id2string(identifier)+" expected not to have LHS"; } } else if(identifier=="__VERIFIER_error") { if(!arguments.empty()) { err_location(function); throw "`"+id2string(identifier)+"' expected to have no arguments"; } goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); if(lhs.is_not_nil()) { err_location(function); throw id2string(identifier)+" expected not to have LHS"; } } else if(has_prefix(id2string(identifier), "java::java.lang.AssertionError.<init>:")) { // insert function call anyway code_function_callt function_call; function_call.lhs()=lhs; function_call.function()=function; function_call.arguments()=arguments; function_call.add_source_location()=function.source_location(); copy(function_call, FUNCTION_CALL, dest); if(arguments.size()!=1 && arguments.size()!=2) { err_location(function); throw "`"+id2string(identifier)+"' expected to have one or two arguments"; } goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment("assertion at "+function.source_location().as_string()); } else if(identifier=="assert" && !ns.lookup(identifier).location.get_function().empty()) { if(arguments.size()!=1) { err_location(function); throw "`"+id2string(identifier)+"' expected to have one argument"; } goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=arguments.front(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment("assertion "+id2string(from_expr(ns, "", t->guard))); // let's double-check the type of the argument if(t->guard.type().id()!=ID_bool) t->guard.make_typecast(bool_typet()); if(lhs.is_not_nil()) { err_location(function); throw id2string(identifier)+" expected not to have LHS"; } } else if(identifier==CPROVER_PREFIX "assert") { if(arguments.size()!=2) { err_location(function); throw "`"+id2string(identifier)+"' expected to have two arguments"; } const irep_idt description= get_string_constant(arguments[1]); goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=arguments[0]; t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment(description); // let's double-check the type of the argument if(t->guard.type().id()!=ID_bool) t->guard.make_typecast(bool_typet()); if(lhs.is_not_nil()) { err_location(function); throw id2string(identifier)+" expected not to have LHS"; } } else if(identifier==CPROVER_PREFIX "printf") { do_printf(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "scanf") { do_scanf(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "input" || identifier=="__CPROVER::input") { do_input(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "output" || identifier=="__CPROVER::output") { do_output(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "atomic_begin" || identifier=="__CPROVER::atomic_begin" || identifier=="__VERIFIER_atomic_begin") { do_atomic_begin(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "atomic_end" || identifier=="__CPROVER::atomic_end" || identifier=="__VERIFIER_atomic_end") { do_atomic_end(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "prob_biased_coin") { do_prob_coin(lhs, function, arguments, dest); } else if(has_prefix(id2string(identifier), CPROVER_PREFIX "prob_uniform_")) { do_prob_uniform(lhs, function, arguments, dest); } else if(has_prefix(id2string(identifier), "nondet_") || has_prefix(id2string(identifier), "__VERIFIER_nondet_")) { // make it a side effect if there is an LHS if(lhs.is_nil()) return; exprt rhs; // We need to special-case for _Bool, which // can only be 0 or 1. if(lhs.type().id()==ID_c_bool) { rhs=side_effect_expr_nondett(bool_typet()); rhs.add_source_location()=function.source_location(); rhs.set(ID_C_identifier, identifier); rhs=typecast_exprt(rhs, lhs.type()); } else { rhs=side_effect_expr_nondett(lhs.type()); rhs.add_source_location()=function.source_location(); rhs.set(ID_C_identifier, identifier); } code_assignt assignment(lhs, rhs); assignment.add_source_location()=function.source_location(); copy(assignment, ASSIGN, dest); } else if(has_prefix(id2string(identifier), CPROVER_PREFIX "uninterpreted_")) { // make it a side effect if there is an LHS if(lhs.is_nil()) return; function_application_exprt rhs; rhs.type()=lhs.type(); rhs.add_source_location()=function.source_location(); rhs.function()=function; rhs.arguments()=arguments; code_assignt assignment(lhs, rhs); assignment.add_source_location()=function.source_location(); copy(assignment, ASSIGN, dest); } else if(has_prefix(id2string(identifier), CPROVER_PREFIX "array_set")) { do_array_set(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "array_equal" || identifier=="__CPROVER::array_equal") { do_array_equal(lhs, function, arguments, dest); } else if(identifier==CPROVER_PREFIX "array_copy" || identifier=="__CPROVER::array_equal") { do_array_copy(lhs, function, arguments, dest); } else if(identifier=="printf") /* identifier=="fprintf" || identifier=="sprintf" || identifier=="snprintf") */ { do_printf(lhs, function, arguments, dest); } else if(identifier=="__assert_fail" || identifier=="_assert" || identifier=="__assert_c99" || identifier=="_wassert") { // __assert_fail is Linux // These take four arguments: // "expression", "file.c", line, __func__ // klibc has __assert_fail with 3 arguments // "expression", "file.c", line // MingW has // void _assert (const char*, const char*, int); // with three arguments: // "expression", "file.c", line // This has been seen in Solaris 11. // Signature: // void __assert_c99(const char *desc, const char *file, int line, const char *func); // _wassert is Windows. The arguments are // L"expression", L"file.c", line if(arguments.size()!=4 && arguments.size()!=3) { err_location(function); throw "`"+id2string(identifier)+"' expected to have four arguments"; } const irep_idt description= "assertion "+id2string(get_string_constant(arguments[0])); goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment(description); // we ignore any LHS } else if(identifier=="__assert_rtn" || identifier=="__assert") { // __assert_rtn has been seen on MacOS; // __assert is FreeBSD and Solaris 11. // These take four arguments: // __func__, "file.c", line, "expression" // On Solaris 11, it's three arguments: // "expression", "file", line irep_idt description; if(arguments.size()==4) { description= "assertion "+id2string(get_string_constant(arguments[3])); } else if(arguments.size()==3) { description= "assertion "+id2string(get_string_constant(arguments[1])); } else { err_location(function); throw "`"+id2string(identifier)+"' expected to have four arguments"; } goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment(description); // we ignore any LHS } else if(identifier=="__assert_func") { // __assert_func is newlib (used by, e.g., cygwin) // These take four arguments: // "file.c", line, __func__, "expression" if(arguments.size()!=4) { err_location(function); throw "`"+id2string(identifier)+"' expected to have four arguments"; } const irep_idt description= "assertion "+id2string(get_string_constant(arguments[3])); goto_programt::targett t=dest.add_instruction(ASSERT); t->guard=false_exprt(); t->source_location=function.source_location(); t->source_location.set("user-provided", true); t->source_location.set_property_class(ID_assertion); t->source_location.set_comment(description); // we ignore any LHS } else if(identifier==CPROVER_PREFIX "fence") { if(arguments.size()<1) { err_location(function); throw "`"+id2string(identifier)+"' expected to have at least one argument"; } goto_programt::targett t=dest.add_instruction(OTHER); t->source_location=function.source_location(); t->code.set(ID_statement, ID_fence); forall_expr(it, arguments) { const irep_idt kind=get_string_constant(*it); t->code.set(kind, true); } } else if(identifier=="__builtin_prefetch")
void goto_inlinet::expand_function_call( goto_programt &dest, goto_programt::targett &target, const exprt &lhs, const symbol_exprt &function, const exprt::operandst &arguments, const exprt &constrain, bool full) { // look it up const irep_idt identifier=function.get_identifier(); // we ignore certain calls if(identifier=="__CPROVER_cleanup" || identifier=="__CPROVER_set_must" || identifier=="__CPROVER_set_may" || identifier=="__CPROVER_clear_must" || identifier=="__CPROVER_clear_may" || identifier=="__CPROVER_cover") { target++; return; // ignore } // see if we are already expanding it if(recursion_set.find(identifier)!=recursion_set.end()) { if(!full) { target++; return; // simply ignore, we don't do full inlining, it's ok } // it's really recursive, and we need full inlining. // Uh. Buh. Give up. warning().source_location=function.find_source_location(); warning() << "recursion is ignored" << eom; target->make_skip(); target++; return; } goto_functionst::function_mapt::iterator m_it= goto_functions.function_map.find(identifier); if(m_it==goto_functions.function_map.end()) { if(!full) { target++; return; // simply ignore, we don't do full inlining, it's ok } error().source_location=function.find_source_location(); error() << "failed to find function `" << identifier << "'" << eom; throw 0; } const goto_functionst::goto_functiont &f=m_it->second; // see if we need to inline this if(!full) { if(!f.body_available() || (!f.is_inlined() && f.body.instructions.size() > smallfunc_limit)) { target++; return; } } if(f.body_available()) { recursion_set.insert(identifier); // first make sure that this one is already inlined goto_inline_rec(m_it, full); goto_programt tmp2; tmp2.copy_from(f.body); assert(tmp2.instructions.back().is_end_function()); tmp2.instructions.back().type=LOCATION; replace_return(tmp2, lhs, constrain); goto_programt tmp; parameter_assignments(target->source_location, identifier, f.type, arguments, tmp); tmp.destructive_append(tmp2); parameter_destruction(target->source_location, identifier, f.type, tmp); if(f.is_hidden()) { source_locationt new_source_location= function.find_source_location(); if(new_source_location.is_not_nil()) { new_source_location.set_hide(); Forall_goto_program_instructions(it, tmp) { if(it->function==identifier) { // don't hide assignment to lhs if(it->is_assign() && to_code_assign(it->code).lhs()==lhs) { } else { replace_location(it->source_location, new_source_location); replace_location(it->guard, new_source_location); replace_location(it->code, new_source_location); } it->function=target->function; } } }
void goto_symext::symex_decl(statet &state, const symbol_exprt &expr) { // We increase the L2 renaming to make these non-deterministic. // We also prevent propagation of old values. ssa_exprt ssa(expr); state.rename(ssa, ns, goto_symex_statet::L1); const irep_idt &l1_identifier=ssa.get_identifier(); // rename type to L2 state.rename(ssa.type(), l1_identifier, ns); ssa.update_type(); // in case of pointers, put something into the value set if(ns.follow(expr.type()).id()==ID_pointer) { exprt failed= get_failed_symbol(expr, ns); exprt rhs; if(failed.is_not_nil()) { address_of_exprt address_of_expr; address_of_expr.object()=failed; address_of_expr.type()=expr.type(); rhs=address_of_expr; } else rhs=exprt(ID_invalid); state.rename(rhs, ns, goto_symex_statet::L1); state.value_set.assign(ssa, rhs, ns, true, false); } // prevent propagation state.propagation.remove(l1_identifier); // L2 renaming // inlining may yield multiple declarations of the same identifier // within the same L1 context if(state.level2.current_names.find(l1_identifier)== state.level2.current_names.end()) state.level2.current_names[l1_identifier]=std::make_pair(ssa, 0); state.level2.increase_counter(l1_identifier); const bool record_events=state.record_events; state.record_events=false; state.rename(ssa, ns); state.record_events=record_events; // we hide the declaration of auxiliary variables // and if the statement itself is hidden bool hidden= ns.lookup(expr.get_identifier()).is_auxiliary || state.top().hidden_function || state.source.pc->source_location.get_hide(); target.decl( state.guard.as_expr(), ssa, state.source, hidden?symex_targett::HIDDEN:symex_targett::STATE); assert(state.dirty); if((*state.dirty)(ssa.get_object_name()) && state.atomic_section_id==0) target.shared_write( state.guard.as_expr(), ssa, state.atomic_section_id, state.source); }