Loading slowbeast/analysis/scc.py +1 −1 Original line number Diff line number Diff line Loading @@ -303,6 +303,7 @@ class StronglyConnectedComponents: edges = {l: [succ.target() for succ in l.successors()] for l in G.locations()} yield from strongly_connected_components_iterative(G.locations(), edges) class SCCCondensation: class SCC: def __init__(self, nodes): Loading Loading @@ -350,4 +351,3 @@ class SCCCondensation: def get(self, n): return self._node_to_scc[n] slowbeast/bse/bse.py +3 −3 Original line number Diff line number Diff line Loading @@ -248,9 +248,9 @@ class BackwardSymbolicInterpreter(SymbolicInterpreter): if state.join_prestate(ready[0], fromInit): # This assertion must hold only if the execution was maximal # - but that may not be tru #assert ( # not fromInit or not state.inputs() #), f"Initial state has unresolved inputs: {state}" # assert ( # not fromInit or not state.inputs() # ), f"Initial state has unresolved inputs: {state}" return [state] return [] Loading slowbeast/bse/bself.py +22 −20 Original line number Diff line number Diff line Loading @@ -126,19 +126,23 @@ def _overapprox_with_assumptions(E, L, S, executor, s, target): if not R0: return yielded = False prestates = None #executor._extend_one_step(L, S) prestates = None # executor._extend_one_step(L, S) if prestates: Rc = set(get_const_cmp_relations(S.get_se_state())) for p in prestates: # check whether the relation from R0 holds in 'p' # R1 = set(get_var_relations([p], prevsafe=S)) P = create_set(p) rels = [r0 for r0 in R0 if not intersection(P, r0).is_empty()] P = create_set(p) rels = [r0 for r0 in R0 if not intersection(P, r0).is_empty()] yielded |= bool(rels) yield from _yield_overapprox_with_assumption(E, L, S, executor, rels, s, target) yield from _yield_overapprox_with_assumption( E, L, S, executor, rels, s, target ) # try constant relations too - if they hold in more steps, they may be invariant rels = [rc for rc in Rc if not intersection(P, rc).is_empty()] yield from _yield_overapprox_with_assumption(E, L, S, executor, rels, s, target) rels = [rc for rc in Rc if not intersection(P, rc).is_empty()] yield from _yield_overapprox_with_assumption( E, L, S, executor, rels, s, target ) if not yielded: yield from _yield_overapprox_with_assumption(E, L, S, executor, R0, s, target) Loading @@ -162,11 +166,11 @@ def _yield_overapprox_with_assumption(E, L, S, executor, rels, s, target): def is_seq_inductive(seq, executor, L: LoopInfo): return L.set_is_inductive(seq.as_set()) def is_set_inductive(S, executor, L: LoopInfo): return L.set_is_inductive(S) class BSELFChecker(BaseBSE): """ An executor that recursively checks the validity of one particular assertion. Loading Loading @@ -508,7 +512,7 @@ class BSELFChecker(BaseBSE): # cont. of the workaround -- the same problem. The set may not # be inductive due to dynamic inputs or array variables. # see, e.g., array_3-2.c #assert Is, "Failed getting sequence for first visit" # assert Is, "Failed getting sequence for first visit" else: dbg("... (joining with previously unfinished sequences)") Is = self.initial_sets_from_is(E, L) Loading Loading @@ -547,7 +551,7 @@ class BSELFChecker(BaseBSE): create_set = self.create_set target = seq0[-1] S = seq0.as_set().copy() # we're going to change S S = seq0.as_set().copy() # we're going to change S assert not S.is_empty(), f"Starting sequence is infeasible!: {seq0}" EM = getGlobalExprManager() Loading @@ -566,11 +570,7 @@ class BSELFChecker(BaseBSE): yield InductiveSequence(A) # try without relations seq = InductiveSequence( overapprox_set( self, EM, S, unsafe, target, None, L ) ) seq = InductiveSequence(overapprox_set(self, EM, S, unsafe, target, None, L)) if is_seq_inductive(seq, self, L): # check if seq is a subset of some previously yielded sequence Loading Loading @@ -622,7 +622,7 @@ class BSELFChecker(BaseBSE): # execute the safe path that avoids error and then jumps out of the loop # and also only paths that jump out of the loop, so that the set is inductive cE = complement(E) tmpsets = self._last_k_iterations_states(L, k = 0) tmpsets = self._last_k_iterations_states(L, k=0) sets = [] for tmp in tmpsets: tmp.intersect(cE) Loading @@ -639,9 +639,7 @@ class BSELFChecker(BaseBSE): for s in sets: # gather the sets that subsume 's' and are disjunctive with unsafe # states cov = [ I for I in isets if intersection(E, s).is_empty() and I.includes(s) ] cov = [I for I in isets if intersection(E, s).is_empty() and I.includes(s)] if cov: dbg("Matched stored inductive sequences") S = create_set() if union_matched else None Loading Loading @@ -739,7 +737,9 @@ class BSELFChecker(BaseBSE): if __debug__: for seq0 in seqs0: assert intersection(seq0.as_set(), E).is_empty(), "Initial sequence contains error states" assert intersection( seq0.as_set(), E ).is_empty(), "Initial sequence contains error states" # now we do not support empty sequences assert all(map(lambda s: s is not None, seqs0)), "A sequence is none" Loading Loading @@ -793,7 +793,9 @@ class BSELFChecker(BaseBSE): dbg(f"{seq}", color="dark_blue") if __debug__: assert intersection( seq.as_set(), E ).is_empty(), "Sequence is not safe" assert intersection( seq.as_set(), E ).is_empty(), "Sequence is not safe" if len(seq) >= max_seq_len: dbg("Give up extending the sequence, it is too long") Loading slowbeast/bse/bsestate.py +9 −3 Original line number Diff line number Diff line Loading @@ -136,9 +136,15 @@ class BSEState(LazySEState): if mo.is_global() and mo.is_zeroed(): constraints.append(em.Eq(val[0], ConcreteInt(0, val[0].bitwidth()))) else: for g, ptr in ((g, ptr) for (g, ptr) in IM.bound_globals() if g.is_zeroed()): constraints.append(em.Or(em.Ne(obj, ptr.object()), em.Eq(val[0], ConcreteInt(0, val[0].bitwidth())))) for g, ptr in ( (g, ptr) for (g, ptr) in IM.bound_globals() if g.is_zeroed() ): constraints.append( em.Or( em.Ne(obj, ptr.object()), em.Eq(val[0], ConcreteInt(0, val[0].bitwidth())), ) ) return constraints def _memory_constraints(self): Loading slowbeast/bse/inductivesequence.py +0 −1 Original line number Diff line number Diff line Loading @@ -121,4 +121,3 @@ class InductiveSequence: def check_ind_on_paths(self, executor, paths, target=None): return self.check_on_paths(executor, paths, target=target, self_as_pre=True) Loading
slowbeast/analysis/scc.py +1 −1 Original line number Diff line number Diff line Loading @@ -303,6 +303,7 @@ class StronglyConnectedComponents: edges = {l: [succ.target() for succ in l.successors()] for l in G.locations()} yield from strongly_connected_components_iterative(G.locations(), edges) class SCCCondensation: class SCC: def __init__(self, nodes): Loading Loading @@ -350,4 +351,3 @@ class SCCCondensation: def get(self, n): return self._node_to_scc[n]
slowbeast/bse/bse.py +3 −3 Original line number Diff line number Diff line Loading @@ -248,9 +248,9 @@ class BackwardSymbolicInterpreter(SymbolicInterpreter): if state.join_prestate(ready[0], fromInit): # This assertion must hold only if the execution was maximal # - but that may not be tru #assert ( # not fromInit or not state.inputs() #), f"Initial state has unresolved inputs: {state}" # assert ( # not fromInit or not state.inputs() # ), f"Initial state has unresolved inputs: {state}" return [state] return [] Loading
slowbeast/bse/bself.py +22 −20 Original line number Diff line number Diff line Loading @@ -126,19 +126,23 @@ def _overapprox_with_assumptions(E, L, S, executor, s, target): if not R0: return yielded = False prestates = None #executor._extend_one_step(L, S) prestates = None # executor._extend_one_step(L, S) if prestates: Rc = set(get_const_cmp_relations(S.get_se_state())) for p in prestates: # check whether the relation from R0 holds in 'p' # R1 = set(get_var_relations([p], prevsafe=S)) P = create_set(p) rels = [r0 for r0 in R0 if not intersection(P, r0).is_empty()] P = create_set(p) rels = [r0 for r0 in R0 if not intersection(P, r0).is_empty()] yielded |= bool(rels) yield from _yield_overapprox_with_assumption(E, L, S, executor, rels, s, target) yield from _yield_overapprox_with_assumption( E, L, S, executor, rels, s, target ) # try constant relations too - if they hold in more steps, they may be invariant rels = [rc for rc in Rc if not intersection(P, rc).is_empty()] yield from _yield_overapprox_with_assumption(E, L, S, executor, rels, s, target) rels = [rc for rc in Rc if not intersection(P, rc).is_empty()] yield from _yield_overapprox_with_assumption( E, L, S, executor, rels, s, target ) if not yielded: yield from _yield_overapprox_with_assumption(E, L, S, executor, R0, s, target) Loading @@ -162,11 +166,11 @@ def _yield_overapprox_with_assumption(E, L, S, executor, rels, s, target): def is_seq_inductive(seq, executor, L: LoopInfo): return L.set_is_inductive(seq.as_set()) def is_set_inductive(S, executor, L: LoopInfo): return L.set_is_inductive(S) class BSELFChecker(BaseBSE): """ An executor that recursively checks the validity of one particular assertion. Loading Loading @@ -508,7 +512,7 @@ class BSELFChecker(BaseBSE): # cont. of the workaround -- the same problem. The set may not # be inductive due to dynamic inputs or array variables. # see, e.g., array_3-2.c #assert Is, "Failed getting sequence for first visit" # assert Is, "Failed getting sequence for first visit" else: dbg("... (joining with previously unfinished sequences)") Is = self.initial_sets_from_is(E, L) Loading Loading @@ -547,7 +551,7 @@ class BSELFChecker(BaseBSE): create_set = self.create_set target = seq0[-1] S = seq0.as_set().copy() # we're going to change S S = seq0.as_set().copy() # we're going to change S assert not S.is_empty(), f"Starting sequence is infeasible!: {seq0}" EM = getGlobalExprManager() Loading @@ -566,11 +570,7 @@ class BSELFChecker(BaseBSE): yield InductiveSequence(A) # try without relations seq = InductiveSequence( overapprox_set( self, EM, S, unsafe, target, None, L ) ) seq = InductiveSequence(overapprox_set(self, EM, S, unsafe, target, None, L)) if is_seq_inductive(seq, self, L): # check if seq is a subset of some previously yielded sequence Loading Loading @@ -622,7 +622,7 @@ class BSELFChecker(BaseBSE): # execute the safe path that avoids error and then jumps out of the loop # and also only paths that jump out of the loop, so that the set is inductive cE = complement(E) tmpsets = self._last_k_iterations_states(L, k = 0) tmpsets = self._last_k_iterations_states(L, k=0) sets = [] for tmp in tmpsets: tmp.intersect(cE) Loading @@ -639,9 +639,7 @@ class BSELFChecker(BaseBSE): for s in sets: # gather the sets that subsume 's' and are disjunctive with unsafe # states cov = [ I for I in isets if intersection(E, s).is_empty() and I.includes(s) ] cov = [I for I in isets if intersection(E, s).is_empty() and I.includes(s)] if cov: dbg("Matched stored inductive sequences") S = create_set() if union_matched else None Loading Loading @@ -739,7 +737,9 @@ class BSELFChecker(BaseBSE): if __debug__: for seq0 in seqs0: assert intersection(seq0.as_set(), E).is_empty(), "Initial sequence contains error states" assert intersection( seq0.as_set(), E ).is_empty(), "Initial sequence contains error states" # now we do not support empty sequences assert all(map(lambda s: s is not None, seqs0)), "A sequence is none" Loading Loading @@ -793,7 +793,9 @@ class BSELFChecker(BaseBSE): dbg(f"{seq}", color="dark_blue") if __debug__: assert intersection( seq.as_set(), E ).is_empty(), "Sequence is not safe" assert intersection( seq.as_set(), E ).is_empty(), "Sequence is not safe" if len(seq) >= max_seq_len: dbg("Give up extending the sequence, it is too long") Loading
slowbeast/bse/bsestate.py +9 −3 Original line number Diff line number Diff line Loading @@ -136,9 +136,15 @@ class BSEState(LazySEState): if mo.is_global() and mo.is_zeroed(): constraints.append(em.Eq(val[0], ConcreteInt(0, val[0].bitwidth()))) else: for g, ptr in ((g, ptr) for (g, ptr) in IM.bound_globals() if g.is_zeroed()): constraints.append(em.Or(em.Ne(obj, ptr.object()), em.Eq(val[0], ConcreteInt(0, val[0].bitwidth())))) for g, ptr in ( (g, ptr) for (g, ptr) in IM.bound_globals() if g.is_zeroed() ): constraints.append( em.Or( em.Ne(obj, ptr.object()), em.Eq(val[0], ConcreteInt(0, val[0].bitwidth())), ) ) return constraints def _memory_constraints(self): Loading
slowbeast/bse/inductivesequence.py +0 −1 Original line number Diff line number Diff line Loading @@ -121,4 +121,3 @@ class InductiveSequence: def check_ind_on_paths(self, executor, paths, target=None): return self.check_on_paths(executor, paths, target=target, self_as_pre=True)