1/*******************************************************************\
3Module: Symbolic Execution
5Author: Daniel Kroening, kroening@kroening.com
7\*******************************************************************/
36 // It would be better to call try_filter_value_sets after apply_condition,
37 // and pass nullptr for value sets which apply_condition successfully updated
38 // already. However, try_filter_value_sets calls rename to do constant
39 // propagation, and apply_condition can update the constant propagator. Since
40 // apply condition will never succeed on both jump_taken_state and
41 // jump_not_taken_state, it should be possible to pass a reference to an
42 // unmodified goto_statet to use for renaming. But renaming needs a
43 // goto_symex_statet, not just a goto_statet, and we only have access to one
44 // of those. A future improvement would be to split rename into two parts:
45 // one part on goto_symex_statet which is non-const and deals with
46 // l2 thread reads, and one part on goto_statet which is const and could be
47 // used in try_filter_value_sets.
62 // Could use not_exprt + simplify, but let's avoid paying that cost on quite
90 return;
// nothing to do
96 !instruction.
targets.empty(),
"goto should have at least one target");
98 // we only do deterministic gotos for now
100 instruction.
targets.size() == 1,
"no support for non-deterministic gotos");
109 // is it label: goto label; or while(cond); - popular in SV-COMP
112 // label: goto label; or do {} while(cond);
119 // generate assume(false) or a suitable negation if this
120 // instruction is a conditional goto
124 << state.
source.
pc->source_location() <<
" by assume("
130 <<
"no unwinding assertion will be generated for self-loop at "
158 // we continue executing the loop
164 return;
// nothing else to do
168 // No point executing both branches of an unconditional goto.
170 new_guard ==
true &&
// We have an unconditional goto, AND
171 // either there are no reachable blocks between us and the target in the
172 // surrounding scope (because state.guard == true implies there is no path
173 // around this GOTO instruction)
175 // or there is another block, but we're doing path exploration so
176 // we're going to skip over it for now and return to it later.
180 instruction.
targets.size() > 0,
181 "Instruction is an unconditional goto with no target: " +
182 instruction.
code().pretty());
196 // skip dead instructions
204 return;
// nothing else to do
214 // Normally the next instruction to execute would be state_pc and we save
215 // new_state_pc for later. But if we're executing from a saved state, then
216 // new_state_pc should be the state that we saved from earlier, so let's
217 // execute that instead.
222 "Tried to explore the other path of a branch, but the next "
223 "instruction along that path is not the same as the instruction "
224 "that we saved at the branch point. Saved instruction is " +
226 "\nwe were intending "
230 "instruction we think we saw on a previous path exploration is " +
241 log.
debug() <<
"Resuming from next instruction '"
246 // We should save both the instruction after this goto, and the target of
256 // `forward` tells us where the branch we're _currently_ executing is
257 // pointing to; this needs to be inverted for the branch that we're saving,
258 // so let its truth value for `backwards` be the same as ours for `forward`.
260 log.
debug() <<
"Saving next instruction '"
263 log.
debug() <<
"Saving jump target '"
264 <<
jump_target.state.saved_target->source_location() <<
"'"
269 // It is now up to the caller of symex to decide which path to continue
270 // executing. Signal to the caller that states have been pushed (therefore
271 // symex has not yet completed and must be resumed), and bail out.
276 // put a copy of the current state into the state-queue, to be used by
277 // merge_gotos when we visit new_state_pc
281 // On an unconditional GOTO we don't need our state, as it will be overwritten
282 // by merge_goto. Therefore we move it onto goto_state_list instead of copying
286 // The move here only moves goto_statet, the base class of goto_symex_statet
287 // and not the entire thing.
303 // This doesn't work for --paths (single-path mode) yet, as in multi-path
304 // mode we remove the implied constants at a control-flow merge, but in
305 // single-path mode we don't run merge_gotos.
318 // produce new guard symbol
345 mstream <<
"Assignment to " << new_lhs.identifier() <<
" ["
346 << pointer_offset_bits(new_lhs.type(), ns).value_or(0)
347 <<
" bits]" << messaget::eom;
387 // This is like symex_goto, except the state is unreachable. We try to take
388 // some arbitrary choice that maintains the state guard in a reasonable state
389 // in order that it simplifies properly when states are merged (in
390 // merge_gotos). Note we can't try to evaluate the actual GOTO guard because
391 // our constant propagator might be out of date, since we haven't been
392 // executing assign instructions.
394 // If the guard is already false then there's no value in this state; just
395 // carry on and check the next instruction.
419 // Give up trying to salvage the guard
420 // (this state's guard is squashed, without queueing it at the target)
432 // Arbitrarily assume a conditional branch is not-taken, except for when
433 // there's an incoming backedge, when we guess that the taken case is less
434 // likely to lead to that backedge than the not-taken case.
439 return predecessor->location_number > instruction.location_number;
444 // Assume branch not taken (fall through)
448 // Assume branch taken:
459 // dummy implementation
467 // first, see if this is a target at all
471 return;
// nothing to do
482 // clean up to save some memory
489 // adjust guard, even using guards from unreachable states. This helps to
490 // shrink the state guard if the incoming edge is from a path that was
491 // truncated by config.unwind, config.depth or an assume-false instruction.
493 // Note when an unreachable state contributes its guard, merging it in is
494 // optional, since the formula already implies the unreachable guard is
495 // impossible. Therefore we only integrate it when to do so simplifies the
498 // This function can trash either state's guards, since goto_state is dying
499 // and state's guard will shortly be overwritten.
506 return std::move(state.
guard);
514 return std::move(state.
guard);
523 // check atomic section
526 "atomic sections differ across branches",
527 state.
source.
pc->source_location());
529 // Merge guards. Don't write this to `state` yet because we might move
530 // goto_state over it below.
533 // Merge constant propagator, value-set etc. only if the incoming state is
539 // Important to note that we're moving into our base class here.
540 // Note this overwrites state.guard, but we restore it below.
545 // do SSA phi functions
556 // Save the new state guard
581 const bool do_simplify,
592 return;
// just a guard, don't bother
595 return;
// not at all changed
597 // changed - but only on a branch that is now dead, and the other branch is
598 // uninitialized/invalid
606 // field sensitivity: only merge on individual fields
610 // shared variables are renamed on every access anyway, we don't need to
619 return;
// no phi nodes for shared stuff
622 // don't merge (thread-)locals across different threads, which
623 // may have been introduced by symex_start_thread (and will
624 // only later be removed from level2.current_names by pop_frame
625 // once the thread is executed)
656 // Don't add a conditional to the assignment when:
657 // 1. Either guard is false, so we can't follow that branch.
658 // 2. Either identifier is of generation zero, and so hasn't been
659 // initialized and therefore an invalid target.
661 // These rules only apply to dynamic objects and locals.
675 // Do not value-set supported filtering here as neither dest_state nor
676 // goto_state necessarily have a comprehensive value set.
686 log.conditional_output(
690 mstream <<
"Assignment to " << new_lhs.identifier() <<
" ["
691 << pointer_offset_bits(new_lhs.type(), ns).value_or(0) <<
" bits]"
710 goto_state.get_level2().current_names.empty() &&
711 dest_state.get_level2().current_names.empty())
715 // this gets the diff between the guards
719 goto_state.get_level2().current_names.get_delta_view(
722 std::map<std::string, symex_renaming_levelt::delta_viewt::const_iterator>
757 dest_state.get_level2().current_names.get_delta_view(
763 if(it->is_in_both_maps())
799 const std::string loop_number = std::to_string(state.
source.
pc->loop_number);
805 // Generate VCC for unwinding assertion.
806 const std::string property_id =
808 ".unwind." + loop_number;
812 "unwinding assertion loop " + loop_number,
818 // generate unwinding assumption, unless we permit partial loops
828 // by default, we keep going
static exprt guard(const exprt::operandst &guards, exprt cond)
virtual void clear()
Reset the abstract state.
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Base class for all expressions.
The Boolean constant false.
Stack frames – these are used for function calls and for exceptions.
std::list< std::pair< symex_targett::sourcet, goto_statet > > goto_state_listt
std::unordered_map< irep_idt, loop_infot > loop_iterations
std::map< goto_programt::const_targett, goto_state_listt, goto_programt::target_less_than > goto_state_map
This class represents an instruction in the GOTO intermediate representation.
const goto_instruction_codet & code() const
Get the code represented by this instruction.
targetst targets
The list of successor instructions.
bool is_backwards_goto() const
Returns true if the instruction is a backwards branch.
std::set< targett, target_less_than > incoming_edges
const exprt & condition() const
Get the condition of gotos, assume, assert.
const_targett get_target() const
Returns the first (and only) successor for the usual case of a single target.
static irep_idt loop_id(const irep_idt &function_id, const instructiont &instruction)
Human-readable loop name.
instructionst::const_iterator const_targett
Container for data that varies per program point, e.g.
unsigned depth
Distance from entry.
bool reachable
Is this code reachable? If not we can take shortcuts such as not entering function calls,...
unsigned atomic_section_id
Threads.
value_sett value_set
Uses level 1 names, and is used to do dereferencing.
Central data structure: state.
goto_programt::const_targett saved_target
call_stackt & call_stack()
static irep_idt guard_identifier()
renamedt< ssa_exprt, L2 > assignment(ssa_exprt lhs, const exprt &rhs, const namespacet &ns, bool rhs_is_simplified, bool record_value, bool allow_pointer_unsoundness=false)
guard_managert & guard_manager
renamedt< exprt, level > rename(exprt expr, const namespacet &ns)
Rewrites symbol expressions in exprt, applying a suffix to each symbol reflecting its most recent ver...
symex_targett::sourcet source
bool has_saved_jump_target
This state is saved, with the PC pointing to the target of a GOTO.
renamedt< ssa_exprt, level > rename_ssa(ssa_exprt ssa, const namespacet &ns)
Version of rename which is specialized for SSA exprt.
bool has_saved_next_instruction
This state is saved, with the PC pointing to the next instruction of a GOTO.
virtual bool should_stop_unwind(const symex_targett::sourcet &source, const call_stackt &context, unsigned unwind)
Determine whether to unwind a loop.
void try_filter_value_sets(goto_symex_statet &state, exprt condition, const value_sett &original_value_set, value_sett *jump_taken_value_set, value_sett *jump_not_taken_value_set, const namespacet &ns)
Try to filter value sets based on whether possible values of a pointer-typed symbol make the conditio...
void apply_goto_condition(goto_symex_statet ¤t_state, goto_statet &jump_taken_state, goto_statet &jump_not_taken_state, const exprt &original_guard, const exprt &new_guard, const namespacet &ns)
Propagate constants and points-to information implied by a GOTO condition.
virtual bool check_break(const irep_idt &loop_id, unsigned unwind)
Defines condition for interrupting symbolic execution for a specific loop.
void symex_unreachable_goto(statet &state)
Symbolically execute a GOTO instruction in the context of unreachable code.
irep_idt language_mode
language_mode: ID_java, ID_C or another language identifier if we know the source language in use,...
virtual void symex_goto(statet &state)
Symbolically execute a GOTO instruction.
void phi_function(const goto_statet &goto_state, statet &dest_state)
Merge the SSA assignments from goto_state into dest_state.
path_storaget & path_storage
Symbolic execution paths to be resumed later.
symex_target_equationt & target
The equation that this execution is building up.
guard_managert & guard_manager
Used to create guards.
exprt clean_expr(exprt expr, statet &state, bool write)
Clean up an expression.
virtual void loop_bound_exceeded(statet &state, const exprt &guard)
namespacet ns
Initialized just before symbolic execution begins, to point to both outer_symbol_table and the symbol...
virtual void vcc(const exprt &cond, const irep_idt &property_id, const std::string &msg, statet &state)
Symbolically execute a verification condition (assertion).
virtual void merge_goto(const symex_targett::sourcet &source, goto_statet &&goto_state, statet &state)
Merge a single branch, the symbolic state of which is held in goto_state, into the current overall sy...
virtual void do_simplify(exprt &expr, const value_sett &value_set)
messaget log
The messaget to write log messages to.
const symex_configt symex_config
The configuration to use for this symbolic execution.
bool should_pause_symex
Set when states are pushed onto the workqueue If this flag is set at the end of a symbolic execution ...
void symex_assume_l2(statet &, const exprt &cond)
void merge_gotos(statet &state)
Merge all branches joining at the current program point.
void add(const exprt &expr)
bool disjunction_may_simplify(const guard_exprt &other_guard)
Returns true if operator|= with other_guard may result in a simpler expression.
The trinary if-then-else operator.
Thrown when a goto program that's being processed is in an invalid format, for example passing the wr...
Wrapper for dirtyt that permits incremental population, ensuring each function is analysed exactly on...
Class that provides messages with a built-in verbosity 'level'.
mstreamt & statistics() const
mstreamt & warning() const
void conditional_output(mstreamt &mstream, const std::function< void(mstreamt &)> &output_generator) const
Generate output to message_stream using output_generator if the configured verbosity is at least as h...
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
bool lookup(const irep_idt &name, const symbolt *&symbol) const override
See documentation for namespace_baset::lookup().
incremental_dirtyt dirty
Local variables are considered 'dirty' if they've had an address taken and therefore may be referred ...
virtual void push(const patht &)=0
Add a path to resume to the storage.
std::vector< delta_view_itemt > delta_viewt
Delta view of the key-value pairs in two maps.
Expression providing an SSA-renamed symbol of expressions.
Expression to hold a symbol (variable)
irep_idt name
The unique identifier.
Inheriting the interface of symex_targett this class represents the SSA form of the input program as ...
virtual void goto_instruction(const exprt &guard, const renamedt< exprt, L2 > &cond, const sourcet &source)
Record a goto instruction.
virtual void location(const exprt &guard, const sourcet &source)
Record a location.
virtual void assignment(const exprt &guard, const ssa_exprt &ssa_lhs, const exprt &ssa_full_lhs, const exprt &original_full_lhs, const exprt &ssa_rhs, const sourcet &source, assignment_typet assignment_type)
Write to a local variable.
The Boolean constant true.
bool make_union(object_mapt &dest, const object_mapt &src) const
Merges two RHS expression sets.
exprt boolean_negate(const exprt &src)
negate a Boolean expression, possibly removing a not_exprt, and swapping false and true
Deprecated expression utility functions.
void symex_transition(goto_symext::statet &state)
Transition to the next instruction, which increments the internal program counter and initializes the...
const std::string & id2string(const irep_idt &d)
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
Storage of symbolic execution paths to resume.
bool simplify(exprt &expr, const namespacet &ns)
#define CHECK_RETURN(CONDITION)
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
#define PRECONDITION(CONDITION)
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
const ssa_exprt & to_ssa_expr(const exprt &expr)
Cast a generic exprt to an ssa_exprt.
API to expression classes.
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Information saved at a conditional goto to resume execution.
Identifies source in the context of symbolic execution.
goto_programt::const_targett pc
static void merge_names(const goto_statet &goto_state, goto_symext::statet &dest_state, const namespacet &ns, const guardt &diff_guard, messaget &log, const bool do_simplify, symex_target_equationt &target, const incremental_dirtyt &dirty, const ssa_exprt &ssa, const std::size_t goto_count, const std::size_t dest_count)
Helper function for phi_function which merges the names of an identifier for two different states.
static guardt merge_state_guards(goto_statet &goto_state, goto_symex_statet &state)