[docs]classLocalLoopSeer(ExplorationTechnique):""" LocalLoopSeer monitors exploration and maintains all loop-related data without relying on a control flow graph. """
[docs]def__init__(self,bound=None,bound_reached=None,discard_stash="spinning"):""" :param bound: Limit the number of iterations a loop may be executed. :param bound_reached: If provided, should be a function that takes the LoopSeer and the succ_state. Will be called when loop execution reach the given bound. Default to moving states that exceed the loop limit to a discard stash. :param discard_stash: Name of the stash containing states exceeding the loop limit. """super().__init__()self.bound=boundself.bound_reached=bound_reachedself.discard_stash=discard_stashself.block_counters=defaultdict(int)self.cut_succs=[]
[docs]defsuccessors(self,simgr,state,**kwargs):succs=simgr.successors(state,**kwargs)forsucc_stateinsuccs.successors:# Processing a currently running loopifsucc_state._ip.symbolic:continuesucc_addr=succ_state.addr# If we have set a bound for symbolic/concrete loops we want to handle it hereifself.boundisnotNone:counts=succ_state.history.bbl_addrs.count(succ_addr)ifcounts>self.bound:ifself.bound_reachedisnotNone:# We want to pass self to modify the LocalLoopSeer state if needed# Users can modify succ_state in the handler to implement their own logic# or edit the state of LocalLoopSeer.self.bound_reached(self,succ_state)else:# Remove the state from the successors object# This state is going to be filtered by the self.filter functionself.cut_succs.append(succ_state)returnsuccs