def increment(self): self.count += 1 # reset variable list if we're incrementing our count self.variable = BitVec('{1}{0}'.format(self.varName, self.count), ctx=self.ctx, size=self.size, state=self.state)
def __init__(self, varName, ctx, count=None, variable=None, state=None, increment=False): assert type(varName) is str assert type(ctx) is int assert type(count) in [int, type(None)] self.size = 16 self.count = 0 if count is None else count self.varName = varName self.ctx = ctx self.variable = BitVec( '{1}{0}'.format(self.varName, self.count), ctx=self.ctx, size=self.size) if variable is None else variable if state is not None: self.setState(state) if increment: self.increment()
def test_pyObjectManager_List_setitem(): b = ast_parse.parse(test1).body p = Path(b, source=test1) pg = PathGroup(p) pg.explore() assert len(pg.completed) == 1 l = pg.completed[0].state.getVar('l') s = pg.completed[0].state # Base check assert l[1].count == 0 assert type(l[1]) == Real # Assign an Int l[1] = Int(varName='x', ctx=0, state=s) assert l[1].count == 1 assert type(l[1]) == Int # Assign back to Real l[1] = Real(varName='x', ctx=0, state=s) assert l[1].count == 2 assert type(l[1]) == Real # Assign to BitVec l[1] = BitVec(varName='x', ctx=0, size=32, state=s) assert l[1].count == 3 assert type(l[1]) == BitVec # Assign List l[1] = List(varName='x', ctx=0, state=s) #assert l[1].count == 4 assert type(l[1]) == List
def __setitem__(self, key, value): """ Sets value at index key. Checks for variable type, updates counter according, similar to getVar call """ # Attempt to return variable assert type(key) is int assert type(value) in [Int, Real, BitVec, List, String] # Get that index's current count count = self.variables[key].count + 1 if type(value) is Int: logger.debug("__setitem__: setting Int") self.variables[key] = Int('{2}{0}[{1}]'.format( self.varName, key, self.count), ctx=self.ctx, count=count, state=self.state) self.variables[key].setTo(value) elif type(value) is Real: logger.debug("__setitem__: setting Real") self.variables[key] = Real('{2}{0}[{1}]'.format( self.varName, key, self.count), ctx=self.ctx, count=count, state=self.state) self.variables[key].setTo(value) elif type(value) is BitVec: logger.debug("__setitem__: setting BitVec") self.variables[key] = BitVec('{2}{0}[{1}]'.format( self.varName, key, self.count), ctx=self.ctx, count=count, size=value.size, state=self.state) self.variables[key].setTo(value) elif type(value) in [List, String]: logger.debug("__setitem__: setting {0}".format(type(value))) self.variables[key] = value #value.count = count else: err = "__setitem__: Don't know how to set object '{0}'".format( value) logger.error(err) raise Exception(err)
def append(self, var, kwargs=None): """ Input: var = pyObjectManager oject to append (i.e.: Int/Real/etc) (optional) kwargs = optional keyword args needed to instantiate type Action: Resolves object, creates variable if needed Returns: Nothing """ # Variable names in list are "<verson><varName>[<index>]". This is in addition to base naming conventions if type(var) is Int or var is Int: logger.debug("append: adding Int") self.variables.append( Int('{2}{0}[{1}]'.format(self.varName, len(self.variables), self.count), ctx=self.ctx, state=self.state, **kwargs if kwargs is not None else {})) # We're being given an object. Let's make sure we link it to Z3 appropriately if type(var) is Int: self.variables[-1].setTo(var) elif type(var) is Real or var is Real: logger.debug("append: adding Real") self.variables.append( Real('{2}{0}[{1}]'.format(self.varName, len(self.variables), self.count), ctx=self.ctx, state=self.state)) if type(var) is Real: self.variables[-1].setTo(var) elif type(var) is BitVec or var is BitVec: logger.debug("append: adding BitVec") kwargs = {'size': var.size} if kwargs is None else kwargs self.variables.append( BitVec('{2}{0}[{1}]'.format(self.varName, len(self.variables), self.count), ctx=self.ctx, state=self.state, **kwargs if kwargs is not None else {})) if type(var) is BitVec: self.variables[-1].setTo(var) elif type(var) is Char or var is Char: logger.debug("append: adding Char") self.variables.append( Char('{2}{0}[{1}]'.format(self.varName, len(self.variables), self.count), ctx=self.ctx, state=self.state)) if type(var) is Char: self.variables[-1].setTo(var) elif type(var) in [List, String]: logger.debug("append: adding {0}".format(type(var))) self.variables.append(var) else: err = "append: Don't know how to append/resolve object '{0}'".format( type(var)) logger.error(err) raise Exception(err)
class Char: """ Define a Char (Character) """ def __init__(self, varName, ctx, count=None, variable=None, state=None, increment=False): assert type(varName) is str assert type(ctx) is int assert type(count) in [int, type(None)] self.size = 16 self.count = 0 if count is None else count self.varName = varName self.ctx = ctx self.variable = BitVec( '{1}{0}'.format(self.varName, self.count), ctx=self.ctx, size=self.size) if variable is None else variable if state is not None: self.setState(state) if increment: self.increment() def __deepcopy__(self, _): return self.copy() def __copy__(self): return self.copy() def copy(self): return Char( varName=self.varName, ctx=self.ctx, count=self.count, variable=self.variable.copy(), state=self.state if hasattr(self, "state") else None, ) def __str__(self): return chr(self.state.any_int(self)) def setTo(self, var): """ Sets this Char to the variable. Raises exception on failure. """ if type(var) not in [str, String, Char]: err = "setTo: Invalid argument type {0}".format(type(var)) logger.error(err) raise Exception(err) if (type(var) is String and var.length() != 1) or (type(var) is str and len(var) != 1): err = "setTo: Cannot set Char element to more than 1 length" logger.error(err) raise Exception(err) # Go ahead and add the constraints if type(var) is str: self.variable.setTo(ord(var)) else: if type(var) is String: var = var[0] self.variable.setTo(var.variable) def setState(self, state): """ This is a bit strange, but State won't copy correctly due to Z3, so I need to bypass this a bit by setting State each time I copy """ assert type(state) == pyState.State self.state = state self.variable.setState(state) def increment(self): self.count += 1 # reset variable list if we're incrementing our count self.variable = BitVec('{1}{0}'.format(self.varName, self.count), ctx=self.ctx, size=self.size, state=self.state) def _isSame(self, **args): """ Checks if variables for this object are the same as those entered. Assumes checks of type will be done prior to calling. """ return True def getZ3Object(self): return self.variable.getZ3Object() def isStatic(self): """ Returns True if this object is a static variety (i.e.: "a"). Also returns True if object has only one possibility """ return self.variable.isStatic() #if len(self.state.any_n_int(self,2)) == 1: # return True #return False def getValue(self): """ Resolves the value of this Char. Assumes that isStatic method is called before this is called to ensure the value is not symbolic """ #return chr(self.state.any_int(self)) return chr(self.variable.getValue()) def mustBe(self, var): """ Return True if this Char must be equivalent to input (str/Char). False otherwise. """ assert type(var) in [str, Char] # If we can't be, then mustBe is also False if not self.canBe(var): return False # Utilize the BitVec's methods here if type(var) is str: return self.variable.mustBe(ord(var)) if type(var) is Char: return self.variable.mustBe(var.variable) # If we can be, determine if this is the only option #if len(self.state.any_n_int(self,2)) == 1 and len(self.state.any_n_int(var,2)) == 1: # return True # Looks like we're only one option return False def canBe(self, var): """ Test if this Char can be equal to the given variable Returns True or False """ assert type(var) in [str, Char] if type(var) is str and len(var) != 1: return False if type(var) is str: return self.variable.canBe(ord(var)) #s = self.state.copy() #s.addConstraint(self.getZ3Object() == ord(var)) #if s.isSat(): # return True #return False elif type(var) is Char: return self.variable.canBe(var.variable)
def _handleNum(state, element, value, op): """ Handle the case where we're AugAssigning numbers """ # Find the parent object oldTargets = state.resolveObject(element.target) # Normalize oldTargets = [oldTargets] if type(oldTargets) is not list else oldTargets # Resolve calls if we need to retObjs = [x for x in oldTargets if type(x) is pyState.ReturnObject] if len(retObjs) > 0: return retObjs ret = [] # Loop through resolved objects for oldTarget in oldTargets: parent = state.objectManager.getParent(oldTarget) index = parent.index(oldTarget) # Basic sanity checks complete. For augment assigns we will always need to update the vars. # Grab the old var and create a new now #oldTargetVar = oldTarget.getZ3Object() # Match up the right hand side oldTargetVar, valueVar = z3Helpers.z3_matchLeftAndRight( oldTarget, value, op) if hasRealComponent(valueVar) or hasRealComponent(oldTargetVar): parent[index] = Real(oldTarget.varName, ctx=state.ctx, state=state) #newTargetVar = parent[index].getZ3Object(increment=True) elif type(valueVar) in [z3.BitVecRef, z3.BitVecNumRef]: parent[index] = BitVec(oldTarget.varName, ctx=state.ctx, size=valueVar.size(), state=state) #newTargetVar = parent[index].getZ3Object(increment=True) else: parent[index] = Int(oldTarget.varName, ctx=state.ctx, state=state) #newTargetVar = parent[index].getZ3Object(increment=True) newTargetObj = parent[index] newTargetObj.increment() newTargetVar = newTargetObj.getZ3Object() # Figure out what the op is and add constraint if type(op) == ast.Add: if type(newTargetVar) in [z3.BitVecRef, z3.BitVecNumRef]: # Check for over and underflows state.solver.add( pyState.z3Helpers.bvadd_safe(oldTargetVar, valueVar)) # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() + value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar + valueVar) elif type(op) == ast.Sub: if type(newTargetVar) in [z3.BitVecRef, z3.BitVecNumRef]: # Check for over and underflows state.solver.add( pyState.z3Helpers.bvsub_safe(oldTargetVar, valueVar)) # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() - value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar - valueVar) elif type(op) == ast.Mult: if type(newTargetVar) in [z3.BitVecRef, z3.BitVecNumRef]: # Check for over and underflows state.solver.add( pyState.z3Helpers.bvmul_safe(oldTargetVar, valueVar)) # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() * value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar * valueVar) elif type(op) == ast.Div: if type(newTargetVar) in [z3.BitVecRef, z3.BitVecNumRef]: # Check for over and underflows state.solver.add( pyState.z3Helpers.bvdiv_safe(oldTargetVar, valueVar)) # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() / value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar / valueVar) elif type(op) == ast.Mod: # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() % value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar % valueVar) elif type(op) == ast.BitXor: logger.debug("{0} = {1} ^ {2}".format(newTargetVar, oldTargetVar, valueVar)) # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() ^ value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar ^ valueVar) elif type(op) == ast.BitOr: # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() | value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar | valueVar) elif type(op) == ast.BitAnd: # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() & value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar & valueVar) elif type(op) == ast.LShift: # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() << value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar << valueVar) elif type(op) == ast.RShift: # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue() >> value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar >> valueVar) # TODO: This will fail with BitVec objects... elif type(op) == ast.Pow: # Keep clutter out of z3 if oldTarget.isStatic() and value.isStatic(): newTargetObj.setTo(oldTarget.getValue()**value.getValue()) else: state.addConstraint(newTargetVar == oldTargetVar**valueVar) else: err = "Don't know how to handle op type {0} at line {1} col {2}".format( type(op), op.lineno, op.col_offset) logger.error(err) raise Exception(err) ret.append(state) # Pop the instruction off state.path.pop(0) # Return the state return ret
def __setitem__(self,key,value): """ Sets value at index key. Checks for variable type, updates counter according, similar to getVar call """ # Attempt to return variable assert type(value) in [Int, Real, BitVec, List, String, Char] # Things get weird if our variable names don't match up... #assert key == value.varName # Get that index's current count if key in self.variables: count = self.variables[key].count + 1 else: count = 0 # If the variable comes in with a higher count, that's the one to use #count = max(count, #print("Setting",value.getZ3Object()) #self.variables[key] = value #value.count = count #print("Set",self.variables[key].getZ3Object()) #return if type(value) is Int: logger.debug("__setitem__: setting Int") self.variables[key] = Int('{0}'.format(key),ctx=self.ctx,count=count,state=self.state) # Don't add a constraint if it's the same thing! if self.variables[key].getZ3Object().get_id() != value.getZ3Object().get_id(): #self.state.addConstraint(self.variables[key].getZ3Object() == value.getZ3Object()) self.variables[key].setTo(value) elif type(value) is Real: logger.debug("__setitem__: setting Real") self.variables[key] = Real('{0}'.format(key),ctx=self.ctx,count=count,state=self.state) # Don't add a constraint if it's the same thing! if self.variables[key].getZ3Object().get_id() != value.getZ3Object().get_id(): #self.state.addConstraint(self.variables[key].getZ3Object() == value.getZ3Object()) self.variables[key].setTo(value) elif type(value) is BitVec: logger.debug("__setitem__: setting BitVec") self.variables[key] = BitVec('{0}'.format(key),ctx=self.ctx,count=count,size=value.size,state=self.state) # Don't add a constraint if it's the same thing! if self.variables[key].getZ3Object().get_id() != value.getZ3Object().get_id(): #self.state.addConstraint(self.variables[key].getZ3Object() == value.getZ3Object()) self.variables[key].setTo(value) elif type(value) in [List, String]: logger.debug("__setitem__: setting {0}".format(type(value))) self.variables[key] = value.copy() self.variables[key].setState(self.state) #value.count = count elif type(value) is Char: logger.debug("__setitem__: setting Char") self.variables[key] = Char('{0}'.format(key),ctx=self.ctx,count=count,state=self.state) # Don't add a constraint if it's the same thing! if self.variables[key].getZ3Object().get_id() != value.getZ3Object().get_id(): #self.state.addConstraint(self.variables[key].getZ3Object() == value.getZ3Object()) self.variables[key].setTo(value) else: err = "__setitem__: Don't know how to set object '{0}'".format(value) logger.error(err) raise Exception(err)