def visitAssignmentStatement(self, ast: AssignmentStatement): lhs = ast.lhs rhs = ast.rhs if has_side_effects(lhs) or has_side_effects(rhs): ast.before_analysis = ast.before_analysis.separate_all() # visit expression self.visit(ast.lhs) self.visit(ast.rhs) # state after assignment after = ast.before_analysis.copy() recursive_assign(lhs, rhs, after) # save state ast.after_analysis = after
def test_side_effects(self): ast = get_processed_ast(self.example.code(), type_check=False, solc_check=False) e = has_side_effects(ast) if self.has_side_effects() is not None: self.assertEqual(e, self.has_side_effects())
def analyze(self, cond, before_analysis: PartitionState) -> PartitionState: if has_side_effects(cond): return before_analysis.copy().separate_all() else: self._neg = False self._analysis = before_analysis.copy() self.visit(cond) return self._analysis
def visitDoWhileStatement(self, ast: DoWhileStatement): # Body either executes with or without condition, but it is also possible that it is not executed at all # No information about condition before the body # After the loop, the condition is false # Could be subsequent loop iteration after condition with side effect cond_se = has_side_effects(ast.condition) if cond_se or has_side_effects(ast.body): ast.before_analysis = ast.before_analysis.separate_all() ast.body.before_analysis = ast.before_analysis.copy() self.visit(ast.body) # ast.before_analysis is only used by expressions inside condition -> body has already happened at that point ast.before_analysis = ast.body.after_analysis.copy() ast.after_analysis = self.cond_analyzer.analyze( ast.condition.unop('!'), ast.before_analysis)
def visitExpressionStatement(self, ast: ExpressionStatement): if has_side_effects(ast.expr): ast.before_analysis = ast.before_analysis.separate_all() # visit expression self.visit(ast.expr) # if expression has effect, we are already at TOP ast.after_analysis = ast.before_analysis.copy()
def visitWhileStatement(self, ast: WhileStatement): # Body always executes after the condition, but it is also possible that it is not executed at all # Condition is true before the body # After the loop, the condition is false if has_side_effects(ast.condition) or has_side_effects(ast.body): ast.before_analysis = ast.before_analysis.separate_all() before_body = self.cond_analyzer.analyze(ast.condition, ast.before_analysis) ast.body.before_analysis = before_body self.visit(ast.body) # Either no loop iteration or at least one loop iteration skip_loop = self.cond_analyzer.analyze(ast.condition.unop('!'), ast.before_analysis) did_loop = self.cond_analyzer.analyze(ast.condition.unop('!'), ast.body.after_analysis) # join ast.after_analysis = skip_loop.join(did_loop)
def visitForStatement(self, ast: ForStatement): last = ast.before_analysis.copy() # add names introduced in init for name in ast.names.values(): last.insert(name) if ast.init is not None: ast.init.before_analysis = last.copy() self.visit(ast.init) ast.before_analysis = ast.init.after_analysis.copy( ) # init should be taken into account when looking up things in the condition if has_side_effects(ast.condition) or has_side_effects( ast.body) or (ast.update is not None and has_side_effects(ast.update)): ast.before_analysis = last.separate_all() ast.body.before_analysis = self.cond_analyzer.analyze( ast.condition, ast.before_analysis) self.visit(ast.body) if ast.update is not None: # Update is always executed after the body (if it is executed) ast.update.before_analysis = ast.body.after_analysis.copy() self.visit(ast.update) skip_loop = self.cond_analyzer.analyze(ast.condition.unop('!'), ast.init.after_analysis) did_loop = self.cond_analyzer.analyze( ast.condition.unop('!'), ast.update.after_analysis if ast.update else ast.body.after_analysis) # join ast.after_analysis = skip_loop.join(did_loop) # drop names introduced in init for name in ast.names.values(): ast.after_analysis.remove(name)
def visitRequireStatement(self, ast: RequireStatement): if has_side_effects(ast.condition): ast.before_analysis = ast.before_analysis.separate_all() self.visit(ast.condition) # state after require after = ast.before_analysis.copy() # make state more precise c = ast.condition if isinstance(c, FunctionCallExpr) and isinstance( c.func, BuiltinFunction) and c.func.op == '==': lhs = c.args[0].privacy_annotation_label() rhs = c.args[1].privacy_annotation_label() if lhs and rhs: after.merge(lhs, rhs) ast.after_analysis = after
def visitVariableDeclarationStatement(self, ast: VariableDeclarationStatement): e = ast.expr if e and has_side_effects(e): ast.before_analysis = ast.before_analysis.separate_all() # visit expression if e: self.visit(e) # state after declaration after = ast.before_analysis.copy() # name of variable is already in list name = ast.variable_declaration.idf assert (after.has(name)) # make state more precise if e and e.privacy_annotation_label(): after.merge(name, e.privacy_annotation_label()) ast.after_analysis = after