From e36e0f887515727a889a7d88b93967437a1b9204 Mon Sep 17 00:00:00 2001 From: rajeevgopalakrishna Date: Fri, 22 Mar 2019 14:43:46 +0530 Subject: [PATCH 1/5] Fixed data dependency to propagate return values of functions to call sites. --- examples/scripts/data_dependency.sol | 13 ++++++++++++ .../data_dependency/data_dependency.py | 21 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/examples/scripts/data_dependency.sol b/examples/scripts/data_dependency.sol index 40653a212..a4f64870a 100644 --- a/examples/scripts/data_dependency.sol +++ b/examples/scripts/data_dependency.sol @@ -102,3 +102,16 @@ contract PropagateThroughArguments { var_not_tainted = y; } } + +contract PropagateThroughReturnValue { + uint var_dependant; + uint var_state; + + function foo() public { + var_dependant = bar(); + } + + function bar() internal returns (uint) { + return (var_state); + } +} diff --git a/slither/analyses/data_dependency/data_dependency.py b/slither/analyses/data_dependency/data_dependency.py index d22c73773..307c87ad5 100644 --- a/slither/analyses/data_dependency/data_dependency.py +++ b/slither/analyses/data_dependency/data_dependency.py @@ -4,7 +4,7 @@ from slither.core.declarations import (Contract, Enum, Function, SolidityFunction, SolidityVariable, SolidityVariableComposed, Structure) -from slither.slithir.operations import Index, OperationWithLValue +from slither.slithir.operations import Index, OperationWithLValue, Return, InternalCall from slither.slithir.variables import (Constant, LocalIRVariable, ReferenceVariable, ReferenceVariableSSA, StateIRVariable, TemporaryVariable, @@ -161,11 +161,28 @@ def pprint_dependency(context): ################################################################################### ################################################################################### +return_values = {} + def compute_dependency(slither): slither.context[KEY_INPUT] = set() slither.context[KEY_INPUT_SSA] = set() + # Generate a mapping of functions to their return values + for contract in slither.contracts: + for function in contract.all_functions_called: + found_return = False + if (not found_return): + for node in function.nodes: + if (not found_return): + for ir in node.irs_ssa: + if isinstance(ir, Return): + return_values[function] = ir.values + found_return = True + break + else: + break + for contract in slither.contracts: compute_dependency_contract(contract, slither) @@ -230,6 +247,8 @@ def add_dependency(lvalue, function, ir, is_protected): function.context[KEY_SSA_UNPROTECTED][lvalue] = set() if isinstance(ir, Index): read = [ir.variable_left] + elif isinstance(ir, InternalCall): + read = return_values.get(ir.function,[]) else: read = ir.read [function.context[KEY_SSA][lvalue].add(v) for v in read if not isinstance(v, Constant)] From 897930f2c1afcd228e61c86d0db3f1025307efb5 Mon Sep 17 00:00:00 2001 From: rajeevgopalakrishna Date: Fri, 22 Mar 2019 15:39:28 +0530 Subject: [PATCH 2/5] Fixed data dependency to propagate return values to call sites --- slither/analyses/data_dependency/data_dependency.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slither/analyses/data_dependency/data_dependency.py b/slither/analyses/data_dependency/data_dependency.py index 307c87ad5..d189c47a0 100644 --- a/slither/analyses/data_dependency/data_dependency.py +++ b/slither/analyses/data_dependency/data_dependency.py @@ -10,6 +10,7 @@ from slither.slithir.variables import (Constant, LocalIRVariable, StateIRVariable, TemporaryVariable, TemporaryVariableSSA, TupleVariableSSA) from slither.core.solidity_types.type import Type +from slither.core.cfg.node import NodeType ################################################################################### ################################################################################### @@ -174,13 +175,12 @@ def compute_dependency(slither): found_return = False if (not found_return): for node in function.nodes: - if (not found_return): + if (node.type == NodeType.RETURN): + found_return = True for ir in node.irs_ssa: if isinstance(ir, Return): return_values[function] = ir.values - found_return = True break - else: break for contract in slither.contracts: From 5bf963b35d031853327806c56f0e11682c5e0ee8 Mon Sep 17 00:00:00 2001 From: rajeevgopalakrishna Date: Fri, 22 Mar 2019 20:58:47 +0530 Subject: [PATCH 3/5] Moved the capturing of return values (with memoization) to core/declarations/function.py from analyses/data_dependency/data_dependency.py. Fixed the bug where multiple returns within a function would be missed. --- .../data_dependency/data_dependency.py | 21 ++---------- slither/core/declarations/function.py | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/slither/analyses/data_dependency/data_dependency.py b/slither/analyses/data_dependency/data_dependency.py index d189c47a0..d8ffd0e54 100644 --- a/slither/analyses/data_dependency/data_dependency.py +++ b/slither/analyses/data_dependency/data_dependency.py @@ -4,13 +4,12 @@ from slither.core.declarations import (Contract, Enum, Function, SolidityFunction, SolidityVariable, SolidityVariableComposed, Structure) -from slither.slithir.operations import Index, OperationWithLValue, Return, InternalCall +from slither.slithir.operations import Index, OperationWithLValue, InternalCall from slither.slithir.variables import (Constant, LocalIRVariable, ReferenceVariable, ReferenceVariableSSA, StateIRVariable, TemporaryVariable, TemporaryVariableSSA, TupleVariableSSA) from slither.core.solidity_types.type import Type -from slither.core.cfg.node import NodeType ################################################################################### ################################################################################### @@ -162,27 +161,11 @@ def pprint_dependency(context): ################################################################################### ################################################################################### -return_values = {} - def compute_dependency(slither): slither.context[KEY_INPUT] = set() slither.context[KEY_INPUT_SSA] = set() - # Generate a mapping of functions to their return values - for contract in slither.contracts: - for function in contract.all_functions_called: - found_return = False - if (not found_return): - for node in function.nodes: - if (node.type == NodeType.RETURN): - found_return = True - for ir in node.irs_ssa: - if isinstance(ir, Return): - return_values[function] = ir.values - break - break - for contract in slither.contracts: compute_dependency_contract(contract, slither) @@ -248,7 +231,7 @@ def add_dependency(lvalue, function, ir, is_protected): if isinstance(ir, Index): read = [ir.variable_left] elif isinstance(ir, InternalCall): - read = return_values.get(ir.function,[]) + read = ir.function.return_values_ssa else: read = ir.read [function.context[KEY_SSA][lvalue].add(v) for v in read if not isinstance(v, Constant)] diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index 483a618af..e86f30ab6 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -43,6 +43,8 @@ class Function(ChildContract, SourceMapping): self._parameters_ssa = [] self._returns = [] self._returns_ssa = [] + self._return_values = None + self._return_values_ssa = None self._vars_read = [] self._vars_written = [] self._state_vars_read = [] @@ -468,6 +470,36 @@ class Function(ChildContract, SourceMapping): self._expressions = expressions return self._expressions + @property + def return_values(self): + """ + list(Return Values): List of the return values + """ + from slither.core.cfg.node import NodeType + from slither.slithir.operations import Return + + if self._return_values is None: + return_values = list() + returns = [n for n in self.nodes if n.type == NodeType.RETURN] + [return_values.extend(ir.values) for node in returns for ir in node.irs if isinstance(ir, Return)] + self._return_values = return_values + return self._return_values + + @property + def return_values_ssa(self): + """ + list(Return Values in SSA form): List of the return values in ssa form + """ + from slither.core.cfg.node import NodeType + from slither.slithir.operations import Return + + if self._return_values_ssa is None: + return_values_ssa = list() + returns = [n for n in self.nodes if n.type == NodeType.RETURN] + [return_values_ssa.extend(ir.values) for node in returns for ir in node.irs_ssa if isinstance(ir, Return)] + self._return_values_ssa = return_values_ssa + return self._return_values_ssa + # endregion ################################################################################### ################################################################################### From 404a2ad72d4e6f454164eecdb2d760b98b046591 Mon Sep 17 00:00:00 2001 From: Josselin Date: Mon, 1 Apr 2019 11:12:39 +0100 Subject: [PATCH 4/5] return_values/return_values_ssa: Remove dupplicate --- slither/core/declarations/function.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index e86f30ab6..318116d13 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -477,14 +477,14 @@ class Function(ChildContract, SourceMapping): """ from slither.core.cfg.node import NodeType from slither.slithir.operations import Return - + if self._return_values is None: return_values = list() returns = [n for n in self.nodes if n.type == NodeType.RETURN] [return_values.extend(ir.values) for node in returns for ir in node.irs if isinstance(ir, Return)] - self._return_values = return_values + self._return_values = list(set(return_values)) return self._return_values - + @property def return_values_ssa(self): """ @@ -492,12 +492,12 @@ class Function(ChildContract, SourceMapping): """ from slither.core.cfg.node import NodeType from slither.slithir.operations import Return - + if self._return_values_ssa is None: return_values_ssa = list() returns = [n for n in self.nodes if n.type == NodeType.RETURN] [return_values_ssa.extend(ir.values) for node in returns for ir in node.irs_ssa if isinstance(ir, Return)] - self._return_values_ssa = return_values_ssa + self._return_values_ssa = list(set(return_values_ssa)) return self._return_values_ssa # endregion From acb6d4585fe00a585d9a1968e3f14f6a7987d6f6 Mon Sep 17 00:00:00 2001 From: Josselin Date: Mon, 1 Apr 2019 11:14:21 +0100 Subject: [PATCH 5/5] core.declaration.function: re-order import --- slither/core/declarations/function.py | 6 ++---- slither/core/expressions/__init__.py | 1 + 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index 318116d13..d47072266 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -9,10 +9,8 @@ from slither.core.children.child_contract import ChildContract from slither.core.declarations.solidity_variables import (SolidityFunction, SolidityVariable, SolidityVariableComposed) -from slither.core.expressions.identifier import Identifier -from slither.core.expressions.index_access import IndexAccess -from slither.core.expressions.member_access import MemberAccess -from slither.core.expressions.unary_operation import UnaryOperation +from slither.core.expressions import (Identifier, IndexAccess, MemberAccess, + UnaryOperation) from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.variables.state_variable import StateVariable diff --git a/slither/core/expressions/__init__.py b/slither/core/expressions/__init__.py index 23690aca0..42554bf0b 100644 --- a/slither/core/expressions/__init__.py +++ b/slither/core/expressions/__init__.py @@ -6,6 +6,7 @@ from .elementary_type_name_expression import ElementaryTypeNameExpression from .identifier import Identifier from .index_access import IndexAccess from .literal import Literal +from .member_access import MemberAccess from .new_array import NewArray from .new_contract import NewContract from .new_elementary_type import NewElementaryType