From cbc3077a65e6cefc21537aeb59ef57f1963212ba Mon Sep 17 00:00:00 2001 From: Simone Date: Fri, 6 Jan 2023 01:18:41 +0100 Subject: [PATCH 1/4] Fix using for with alias import --- slither/solc_parsing/declarations/contract.py | 78 +++++++++++-------- .../declarations/using_for_top_level.py | 38 ++++++--- 2 files changed, 74 insertions(+), 42 deletions(-) diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py index 3095b6854..a93914449 100644 --- a/slither/solc_parsing/declarations/contract.py +++ b/slither/solc_parsing/declarations/contract.py @@ -616,39 +616,55 @@ class ContractSolc(CallerContextExpression): def _analyze_function_list(self, function_list: List, type_name: Type): for f in function_list: - function_name = f["function"]["name"] - if function_name.find(".") != -1: - # Library function - self._analyze_library_function(function_name, type_name) - else: + full_name_split = f["function"]["name"].split(".") + if len(full_name_split) == 1: # Top level function - for tl_function in self.compilation_unit.functions_top_level: - if tl_function.name == function_name: - self._contract.using_for[type_name].append(tl_function) - - def _analyze_library_function(self, function_name: str, type_name: Type) -> None: - function_name_split = function_name.split(".") - # TODO this doesn't handle the case if there is an import with an alias - # e.g. MyImport.MyLib.a - if len(function_name_split) == 2: - library_name = function_name_split[0] - function_name = function_name_split[1] - # Get the library function - found = False - for c in self.compilation_unit.contracts: - if found: - break - if c.name == library_name: - for f in c.functions: - if f.name == function_name: - self._contract.using_for[type_name].append(f) - found = True - break - if not found: - self.log_incorrect_parsing(f"Library function not found {function_name}") - else: + function_name = full_name_split[0] + self._analyze_top_level_function(function_name, type_name) + elif len(full_name_split) == 2: + # It can be a top level function behind an aliased import + # or a library function + first_part = full_name_split[0] + function_name = full_name_split[1] + self._check_aliased_import(first_part, function_name, type_name) + else: + # MyImport.MyLib.a we don't care of the alias + library_name = full_name_split[1] + function_name = full_name_split[2] + self._analyze_library_function(library_name, function_name, type_name) + + def _check_aliased_import(self, first_part: str, function_name: str, type_name: Type): + # We check if the first part appear as alias for an import + # if it is then function_name must be a top level function + # otherwise it's a library function + for i in self._contract.file_scope.imports: + if i.alias == first_part: + self._analyze_top_level_function(function_name, type_name) + return + self._analyze_library_function(first_part, function_name, type_name) + + def _analyze_top_level_function(self, function_name: str, type_name: Type): + for tl_function in self.compilation_unit.functions_top_level: + if tl_function.name == function_name: + self._contract.using_for[type_name].append(tl_function) + + def _analyze_library_function( + self, library_name: str, function_name: str, type_name: Type + ) -> None: + # Get the library function + found = False + for c in self.compilation_unit.contracts: + if found: + break + if c.name == library_name: + for f in c.functions: + if f.name == function_name: + self._contract.using_for[type_name].append(f) + found = True + break + if not found: self.log_incorrect_parsing( - f"Expected library function instead received {function_name}" + f"Contract level using for: Library {library_name} - function {function_name} not found" ) def analyze_enums(self): diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py index 3ec191d46..ad4dd008d 100644 --- a/slither/solc_parsing/declarations/using_for_top_level.py +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -61,17 +61,31 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- function_name = full_name_split[0] self._analyze_top_level_function(function_name, type_name) elif len(full_name_split) == 2: - # Library function - library_name = full_name_split[0] + # It can be a top level function behind an aliased import + # or a library function + first_part = full_name_split[0] function_name = full_name_split[1] - self._analyze_library_function(function_name, library_name, type_name) + self._check_aliased_import(first_part, function_name, type_name) else: - # probably case if there is an import with an alias we don't handle it for now - # e.g. MyImport.MyLib.a - LOGGER.warning( - f"Using for directive for function {f['function']['name']} not supported" - ) - continue + # MyImport.MyLib.a we don't care of the alias + library_name = full_name_split[1] + function_name = full_name_split[2] + self._analyze_library_function(library_name, function_name, type_name) + + def _check_aliased_import( + self, + first_part: str, + function_name: str, + type_name: Union[TypeAliasTopLevel, UserDefinedType], + ): + # We check if the first part appear as alias for an import + # if it is then function_name must be a top level function + # otherwise it's a library function + for i in self._using_for.file_scope.imports: + if i.alias == first_part: + self._analyze_top_level_function(function_name, type_name) + return + self._analyze_library_function(first_part, function_name, type_name) def _analyze_top_level_function( self, function_name: str, type_name: Union[TypeAliasTopLevel, UserDefinedType] @@ -84,8 +98,8 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- def _analyze_library_function( self, - function_name: str, library_name: str, + function_name: str, type_name: Union[TypeAliasTopLevel, UserDefinedType], ) -> None: found = False @@ -100,7 +114,9 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- found = True break if not found: - LOGGER.warning(f"Library {library_name} - function {function_name} not found") + LOGGER.warning( + f"Top level using for: Library {library_name} - function {function_name} not found" + ) def _propagate_global(self, type_name: Union[TypeAliasTopLevel, UserDefinedType]) -> None: if self._global: From 794b3b9aa4c2fb28f6b54d7472f13d21c40e1067 Mon Sep 17 00:00:00 2001 From: Simone Date: Fri, 6 Jan 2023 13:07:26 +0100 Subject: [PATCH 2/4] Add tests --- ...lias-contract-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 3932 bytes ...ias-top-level-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 3954 bytes ...ias-contract-0.8.0.sol-0.8.15-compact.json | 9 +++++ ...as-top-level-0.8.0.sol-0.8.15-compact.json | 9 +++++ .../using-for-alias-contract-0.8.0.sol | 14 +++++++ tests/ast-parsing/using-for-alias-dep1.sol | 11 +++++ tests/ast-parsing/using-for-alias-dep2.sol | 9 +++++ .../using-for-alias-top-level-0.8.0.sol | 15 +++++++ tests/test_ast_parsing.py | 2 + tests/test_features.py | 38 +++++++++++++++++- 10 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 tests/ast-parsing/compile/using-for-alias-contract-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/using-for-alias-top-level-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/expected/using-for-alias-contract-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/using-for-alias-top-level-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/using-for-alias-contract-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-alias-dep1.sol create mode 100644 tests/ast-parsing/using-for-alias-dep2.sol create mode 100644 tests/ast-parsing/using-for-alias-top-level-0.8.0.sol diff --git a/tests/ast-parsing/compile/using-for-alias-contract-0.8.0.sol-0.8.15-compact.zip b/tests/ast-parsing/compile/using-for-alias-contract-0.8.0.sol-0.8.15-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..c460e057fd112f592da92afa73d60bdad3f43c54 GIT binary patch literal 3932 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

%SImM!l}C%O__r{{>gfRQvQVmhG?!_ss){TV#G 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/expected/using-for-alias-contract-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-alias-contract-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..809fcb486 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-alias-contract-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,9 @@ +{ + "C": { + "topLevel(uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "libCall(uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "Lib": { + "b(uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/using-for-alias-top-level-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-alias-top-level-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..d16a34808 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-alias-top-level-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,9 @@ +{ + "Lib": { + "b(uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "topLevel(uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "libCall(uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/using-for-alias-contract-0.8.0.sol b/tests/ast-parsing/using-for-alias-contract-0.8.0.sol new file mode 100644 index 000000000..d6906d5ab --- /dev/null +++ b/tests/ast-parsing/using-for-alias-contract-0.8.0.sol @@ -0,0 +1,14 @@ +import "./using-for-alias-dep1.sol"; + +contract C { + using {T3.a, T3.Lib.b} for uint256; + + function topLevel(uint256 value) public { + value.a(); + } + + function libCall(uint256 value) public { + value.b(); + } + +} diff --git a/tests/ast-parsing/using-for-alias-dep1.sol b/tests/ast-parsing/using-for-alias-dep1.sol new file mode 100644 index 000000000..db28e4a71 --- /dev/null +++ b/tests/ast-parsing/using-for-alias-dep1.sol @@ -0,0 +1,11 @@ +import "./using-for-alias-dep2.sol" as T3; + +function b(uint256 value) returns(bool) { + return true; +} + +library Lib { + function a(uint256 value) public returns(bool) { + return true; + } +} diff --git a/tests/ast-parsing/using-for-alias-dep2.sol b/tests/ast-parsing/using-for-alias-dep2.sol new file mode 100644 index 000000000..17ff96452 --- /dev/null +++ b/tests/ast-parsing/using-for-alias-dep2.sol @@ -0,0 +1,9 @@ +function a(uint256 value) returns(bool) { + return true; +} + +library Lib { + function b(uint256 value) public returns(bool) { + return true; + } +} \ No newline at end of file diff --git a/tests/ast-parsing/using-for-alias-top-level-0.8.0.sol b/tests/ast-parsing/using-for-alias-top-level-0.8.0.sol new file mode 100644 index 000000000..ed7e22bac --- /dev/null +++ b/tests/ast-parsing/using-for-alias-top-level-0.8.0.sol @@ -0,0 +1,15 @@ +import "./using-for-alias-dep1.sol"; + +using {T3.a, T3.Lib.b} for uint256; + +contract C { + + function topLevel(uint256 value) public { + value.a(); + } + + function libCall(uint256 value) public { + value.b(); + } + +} diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 96aad1a63..04927b7f4 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -428,6 +428,8 @@ ALL_TESTS = [ Test("using-for-2-0.8.0.sol", ["0.8.15"]), Test("using-for-3-0.8.0.sol", ["0.8.15"]), Test("using-for-4-0.8.0.sol", ["0.8.15"]), + Test("using-for-alias-contract-0.8.0.sol", ["0.8.15"]), + Test("using-for-alias-top-level-0.8.0.sol", ["0.8.15"]), Test("using-for-functions-list-1-0.8.0.sol", ["0.8.15"]), Test("using-for-functions-list-2-0.8.0.sol", ["0.8.15"]), Test("using-for-functions-list-3-0.8.0.sol", ["0.8.15"]), diff --git a/tests/test_features.py b/tests/test_features.py index e6e781881..a5541b589 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -7,7 +7,7 @@ from solc_select import solc_select from slither import Slither from slither.detectors import all_detectors from slither.detectors.abstract_detector import AbstractDetector -from slither.slithir.operations import LibraryCall +from slither.slithir.operations import LibraryCall, InternalCall def _run_all_detectors(slither: Slither) -> None: @@ -92,3 +92,39 @@ def test_using_for_top_level_implicit_conversion() -> None: if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "f": return assert False + + +def test_using_for_alias_top_level() -> None: + solc_select.switch_global_version("0.8.15", always_install=True) + slither = Slither("./tests/ast-parsing/using-for-alias-top-level-0.8.0.sol") + contract_c = slither.get_contract_from_name("C")[0] + libCall = contract_c.get_function_from_full_name("libCall(uint256)") + ok = False + for ir in libCall.all_slithir_operations(): + if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "b": + ok = True + if not ok: + assert False + topLevelCall = contract_c.get_function_from_full_name("topLevel(uint256)") + for ir in topLevelCall.all_slithir_operations(): + if isinstance(ir, InternalCall) and ir.function_name == "a": + return + assert False + + +def test_using_for_alias_contract() -> None: + solc_select.switch_global_version("0.8.15", always_install=True) + slither = Slither("./tests/ast-parsing/using-for-alias-contract-0.8.0.sol") + contract_c = slither.get_contract_from_name("C")[0] + libCall = contract_c.get_function_from_full_name("libCall(uint256)") + ok = False + for ir in libCall.all_slithir_operations(): + if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "b": + ok = True + if not ok: + assert False + topLevelCall = contract_c.get_function_from_full_name("topLevel(uint256)") + for ir in topLevelCall.all_slithir_operations(): + if isinstance(ir, InternalCall) and ir.function_name == "a": + return + assert False From ed9cbf8320b38b6e1f4eebb46d28288f5c063906 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Fri, 6 Jan 2023 14:13:19 +0100 Subject: [PATCH 3/4] Fix types --- .../solc_parsing/declarations/using_for_top_level.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py index ad4dd008d..4037a52a3 100644 --- a/slither/solc_parsing/declarations/using_for_top_level.py +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -58,7 +58,7 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- full_name_split = f["function"]["name"].split(".") if len(full_name_split) == 1: # Top level function - function_name = full_name_split[0] + function_name: str = full_name_split[0] self._analyze_top_level_function(function_name, type_name) elif len(full_name_split) == 2: # It can be a top level function behind an aliased import @@ -68,9 +68,9 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- self._check_aliased_import(first_part, function_name, type_name) else: # MyImport.MyLib.a we don't care of the alias - library_name = full_name_split[1] + library_name_str = full_name_split[1] function_name = full_name_split[2] - self._analyze_library_function(library_name, function_name, type_name) + self._analyze_library_function(library_name_str, function_name, type_name) def _check_aliased_import( self, @@ -132,9 +132,7 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- f"Error when propagating global using for {type_name} {type(type_name)}" ) - def _propagate_global_UserDefinedType( - self, scope: Dict[Any, FileScope], type_name: UserDefinedType - ): + def _propagate_global_UserDefinedType(self, scope: FileScope, type_name: UserDefinedType): underlying = type_name.type if isinstance(underlying, StructureTopLevel): for struct in scope.structures.values(): From 8e4d388961f833c04b45a3c5bd942a470fe3189c Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Fri, 6 Jan 2023 14:27:55 +0100 Subject: [PATCH 4/4] improve import --- .../solc_parsing/declarations/using_for_top_level.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py index 4037a52a3..16e3666b0 100644 --- a/slither/solc_parsing/declarations/using_for_top_level.py +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -2,19 +2,19 @@ Using For Top Level module """ import logging -from typing import TYPE_CHECKING, Dict, Union, Any +from typing import TYPE_CHECKING, Dict, Union from slither.core.compilation_unit import SlitherCompilationUnit -from slither.core.declarations.using_for_top_level import UsingForTopLevel -from slither.core.scope.scope import FileScope -from slither.core.solidity_types import TypeAliasTopLevel from slither.core.declarations import ( StructureTopLevel, EnumTopLevel, ) +from slither.core.declarations.using_for_top_level import UsingForTopLevel +from slither.core.scope.scope import FileScope +from slither.core.solidity_types import TypeAliasTopLevel +from slither.core.solidity_types.user_defined_type import UserDefinedType from slither.solc_parsing.declarations.caller_context import CallerContextExpression from slither.solc_parsing.solidity_types.type_parsing import parse_type -from slither.core.solidity_types.user_defined_type import UserDefinedType if TYPE_CHECKING: from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc