From f0439905e02b6f6c687492fb0dcdd6a4c4e35ee4 Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 25 Aug 2022 18:51:01 +0200 Subject: [PATCH 001/110] Improve using for support --- slither/core/compilation_unit.py | 6 + slither/core/declarations/__init__.py | 3 + slither/core/declarations/contract.py | 22 +++ .../core/declarations/using_for_top_level.py | 18 +++ slither/core/scope/scope.py | 5 + slither/slithir/convert.py | 29 ++-- slither/solc_parsing/declarations/contract.py | 51 ++++++- .../declarations/using_for_top_level.py | 134 ++++++++++++++++++ .../slither_compilation_unit_solc.py | 28 ++++ .../solidity_types/type_parsing.py | 8 +- 10 files changed, 291 insertions(+), 13 deletions(-) create mode 100644 slither/core/declarations/using_for_top_level.py create mode 100644 slither/solc_parsing/declarations/using_for_top_level.py diff --git a/slither/core/compilation_unit.py b/slither/core/compilation_unit.py index a2568a5de..d97b7fbf5 100644 --- a/slither/core/compilation_unit.py +++ b/slither/core/compilation_unit.py @@ -16,6 +16,7 @@ from slither.core.declarations import ( from slither.core.declarations.custom_error import CustomError from slither.core.declarations.enum_top_level import EnumTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel +from slither.core.declarations.using_for_top_level import UsingForTopLevel from slither.core.declarations.structure_top_level import StructureTopLevel from slither.core.scope.scope import FileScope from slither.core.variables.state_variable import StateVariable @@ -41,6 +42,7 @@ class SlitherCompilationUnit(Context): self._enums_top_level: List[EnumTopLevel] = [] self._variables_top_level: List[TopLevelVariable] = [] self._functions_top_level: List[FunctionTopLevel] = [] + self._using_for_top_level: List[UsingForTopLevel] = [] self._pragma_directives: List[Pragma] = [] self._import_directives: List[Import] = [] self._custom_errors: List[CustomError] = [] @@ -205,6 +207,10 @@ class SlitherCompilationUnit(Context): def functions_top_level(self) -> List[FunctionTopLevel]: return self._functions_top_level + @property + def using_for_top_level(self) -> List[UsingForTopLevel]: + return self._using_for_top_level + @property def custom_errors(self) -> List[CustomError]: return self._custom_errors diff --git a/slither/core/declarations/__init__.py b/slither/core/declarations/__init__.py index 3b619c1d1..f891ad621 100644 --- a/slither/core/declarations/__init__.py +++ b/slither/core/declarations/__init__.py @@ -12,5 +12,8 @@ from .solidity_variables import ( ) from .structure import Structure from .enum_contract import EnumContract +from .enum_top_level import EnumTopLevel from .structure_contract import StructureContract +from .structure_top_level import StructureTopLevel from .function_contract import FunctionContract +from .function_top_level import FunctionTopLevel diff --git a/slither/core/declarations/contract.py b/slither/core/declarations/contract.py index 5d65d5cc5..ba738b0f8 100644 --- a/slither/core/declarations/contract.py +++ b/slither/core/declarations/contract.py @@ -78,6 +78,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods # The only str is "*" self._using_for: Dict[Union[str, Type], List[Type]] = {} + self._using_for_complete: Dict[Union[str, Type], List[Type]] = None self._kind: Optional[str] = None self._is_interface: bool = False self._is_library: bool = False @@ -259,6 +260,27 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods def using_for(self) -> Dict[Union[str, Type], List[Type]]: return self._using_for + @property + def using_for_complete(self) -> Dict[Union[str, Type], List[Type]]: + """ + Dict[Union[str, Type], List[Type]]: Dict of merged local using for directive with top level directive + """ + + def _merge_using_for(uf1, uf2): + result = {**uf1, **uf2} + for key, value in result.items(): + if key in uf1 and key in uf2: + result[key] = value + uf1[key] + return result + + if self._using_for_complete is None: + result = self.using_for + top_level_using_for = self.file_scope.usingFor + for uftl in top_level_using_for: + result = _merge_using_for(result, uftl.using_for) + self._using_for_complete = result + return self._using_for_complete + # endregion ################################################################################### ################################################################################### diff --git a/slither/core/declarations/using_for_top_level.py b/slither/core/declarations/using_for_top_level.py new file mode 100644 index 000000000..a1b43e1c1 --- /dev/null +++ b/slither/core/declarations/using_for_top_level.py @@ -0,0 +1,18 @@ +from typing import TYPE_CHECKING, List, Dict, Union + +from slither.core.solidity_types.type import Type +from slither.core.declarations.top_level import TopLevel + +if TYPE_CHECKING: + from slither.core.scope.scope import FileScope + + +class UsingForTopLevel(TopLevel): + def __init__(self, scope: "FileScope"): + super().__init__() + self._using_for: Dict[Union[str, Type], List[Type]] = {} + self.file_scope: "FileScope" = scope + + @property + def using_for(self) -> Dict[Type, List[Type]]: + return self._using_for diff --git a/slither/core/scope/scope.py b/slither/core/scope/scope.py index c6d18556e..a27483824 100644 --- a/slither/core/scope/scope.py +++ b/slither/core/scope/scope.py @@ -5,6 +5,7 @@ from slither.core.declarations import Contract, Import, Pragma from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel from slither.core.declarations.enum_top_level import EnumTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel +from slither.core.declarations.using_for_top_level import UsingForTopLevel from slither.core.declarations.structure_top_level import StructureTopLevel from slither.core.solidity_types import TypeAlias from slither.core.variables.top_level_variable import TopLevelVariable @@ -35,6 +36,7 @@ class FileScope: # Because we parse the function signature later on # So we simplify the logic and have the scope fields all populated self.functions: Set[FunctionTopLevel] = set() + self.usingFor: Set[UsingForTopLevel] = set() self.imports: Set[Import] = set() self.pragmas: Set[Pragma] = set() self.structures: Dict[str, StructureTopLevel] = {} @@ -72,6 +74,9 @@ class FileScope: if not new_scope.functions.issubset(self.functions): self.functions |= new_scope.functions learn_something = True + if not new_scope.usingFor.issubset(self.usingFor): + self.usingFor |= new_scope.usingFor + learn_something = True if not new_scope.imports.issubset(self.imports): self.imports |= new_scope.imports learn_something = True diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 829a23e92..7658deb26 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -171,10 +171,10 @@ def _fits_under_integer(val: int, can_be_int: bool, can_be_uint) -> List[str]: assert can_be_int | can_be_uint while n <= 256: if can_be_uint: - if val <= 2**n - 1: + if val <= 2 ** n - 1: ret.append(f"uint{n}") if can_be_int: - if val <= (2**n) / 2 - 1: + if val <= (2 ** n) / 2 - 1: ret.append(f"int{n}") n = n + 8 return ret @@ -498,7 +498,9 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals # propagate the type node_function = node.function using_for = ( - node_function.contract.using_for if isinstance(node_function, FunctionContract) else {} + node_function.contract.using_for_complete + if isinstance(node_function, FunctionContract) + else {} ) if isinstance(ir, OperationWithLValue): # Force assignment in case of missing previous correct type @@ -879,7 +881,9 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]): # pylint: dis # } node_func = ins.node.function using_for = ( - node_func.contract.using_for if isinstance(node_func, FunctionContract) else {} + node_func.contract.using_for_complete + if isinstance(node_func, FunctionContract) + else {} ) targeted_libraries = ( @@ -892,10 +896,14 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]): # pylint: dis lib_contract_type.type, Contract ): continue - lib_contract = lib_contract_type.type - for lib_func in lib_contract.functions: - if lib_func.name == ins.ori.variable_right: - candidates.append(lib_func) + if isinstance(lib_contract_type, FunctionContract): + # Using for with list of functions, this is the function called + candidates.append(lib_contract_type) + else: + lib_contract = lib_contract_type.type + for lib_func in lib_contract.functions: + if lib_func.name == ins.ori.variable_right: + candidates.append(lib_func) if len(candidates) == 1: lib_func = candidates[0] @@ -1325,7 +1333,10 @@ def convert_to_pop(ir, node): def look_for_library(contract, ir, using_for, t): for destination in using_for[t]: - lib_contract = contract.file_scope.get_contract_from_name(str(destination)) + if isinstance(destination, FunctionContract) and destination.contract.is_library: + lib_contract = destination.contract + else: + lib_contract = contract.file_scope.get_contract_from_name(str(destination)) if lib_contract: lib_call = LibraryCall( lib_contract, diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py index b7f938d1d..32ca0e8ab 100644 --- a/slither/solc_parsing/declarations/contract.py +++ b/slither/solc_parsing/declarations/contract.py @@ -578,17 +578,33 @@ class ContractSolc(CallerContextExpression): try: for father in self._contract.inheritance: self._contract.using_for.update(father.using_for) - if self.is_compact_ast: for using_for in self._usingForNotParsed: - lib_name = parse_type(using_for["libraryName"], self) if "typeName" in using_for and using_for["typeName"]: type_name = parse_type(using_for["typeName"], self) else: type_name = "*" if type_name not in self._contract.using_for: self._contract.using_for[type_name] = [] - self._contract.using_for[type_name].append(lib_name) + + if "libraryName" in using_for: + self._contract.using_for[type_name].append( + parse_type(using_for["libraryName"], self) + ) + else: + # We have a list of functions. A function can be topLevel or a library function + # at this point library function are yet to be parsed so we add the function name + # and add the real function later + for f in using_for["functionList"]: + function_name = f["function"]["name"] + if function_name.find(".") != -1: + # Library function + self._contract.using_for[type_name].append(function_name) + else: + # 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) else: for using_for in self._usingForNotParsed: children = using_for[self.get_children()] @@ -606,6 +622,35 @@ class ContractSolc(CallerContextExpression): except (VariableNotFound, KeyError) as e: self.log_incorrect_parsing(f"Missing using for {e}") + def analyze_library_function_using_for(self): + for type_name, full_names in self._contract.using_for.items(): + # If it's a string is a library function e.g. L.a + # We add the actual function and remove the string + for full_name in full_names: + if isinstance(full_name, str): + full_name_split = full_name.split(".") + # TODO this doesn't handle the case if there is an import with an alias + # e.g. MyImport.MyLib.a + if len(full_name_split) == 2: + library_name = full_name_split[0] + function_name = full_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 + self._contract.using_for[type_name].remove(full_name) + else: + self.log_incorrect_parsing( + f"Expected library function instead received {full_name}" + ) + def analyze_enums(self): try: for father in self._contract.inheritance: diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py new file mode 100644 index 000000000..070ed8cf7 --- /dev/null +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -0,0 +1,134 @@ +""" + Using For Top Level module +""" +import logging +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.solidity_types import Type, TypeAliasTopLevel +from slither.core.declarations import ( + FunctionContract, + FunctionTopLevel, + StructureTopLevel, + EnumTopLevel, +) +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 + +LOGGER = logging.getLogger("UsingForTopLevelSolc") + + +class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few-public-methods + """ + UsingFor class + """ + + # elems = [(type, name)] + + def __init__( # pylint: disable=too-many-arguments + self, + uftl: UsingForTopLevel, + top_level_data: Dict, + slither_parser: "SlitherCompilationUnitSolc", + ): + # TODO think if save global here is useful + self._type_name = top_level_data["typeName"] + self._global = top_level_data["global"] + + if "libraryName" in top_level_data: + self._library_name = top_level_data["libraryName"] + else: + self._functions = top_level_data["functionList"] + + self._using_for = uftl + self._slither_parser = slither_parser + + def analyze(self): + type_name = parse_type(self._type_name, self) + self._using_for.using_for[type_name] = [] + + if hasattr(self, "_library_name"): + library_name = parse_type(self._library_name, self) + self._using_for.using_for[type_name].append(library_name) + self._propagate_global(type_name, library_name) + else: + for f in self._functions: + full_name_split = f["function"]["name"].split(".") + if len(full_name_split) == 1: + # Top level function + function_name = full_name_split[0] + for tl_function in self.compilation_unit.functions_top_level: + if tl_function.name == function_name: + self._using_for.using_for[type_name].append(tl_function) + self._propagate_global(type_name, tl_function) + elif len(full_name_split) == 2: + # Library function + library_name = full_name_split[0] + function_name = full_name_split[1] + found = False + for c in self.compilation_unit.contracts: + if found: + break + if c.name == library_name: + for cf in c.functions: + if cf.name == function_name: + self._using_for.using_for[type_name].append(cf) + self._propagate_global(type_name, cf) + found = True + break + else: + # probably case if there is an import with an alias we don't handle it for now + # e.g. MyImport.MyLib.a + return + + def _propagate_global( + self, type_name: Type, to_add: Union[FunctionTopLevel, FunctionContract, UserDefinedType] + ): + if self._global: + for scope in self.compilation_unit.scopes.values(): + if isinstance(type_name, TypeAliasTopLevel): + for alias in scope.user_defined_types.values(): + if alias == type_name: + scope.usingFor.add(self._using_for) + elif isinstance(type_name, UserDefinedType): + underlying = type_name.type + if isinstance(underlying, StructureTopLevel): + for struct in scope.structures.values(): + if struct == underlying: + scope.usingFor.add(self._using_for) + elif isinstance(underlying, EnumTopLevel): + for enum in scope.enums.values(): + if enum == underlying: + scope.usingFor.add(self._using_for) + else: + LOGGER.error( + f"Error propagating global {underlying} {type(underlying)} not a StructTopLevel or EnumTopLevel" + ) + else: + LOGGER.error( + f"Found {to_add} {type(to_add)} when propagating global using for {type_name} {type(type_name)}" + ) + + @property + def is_compact_ast(self) -> bool: + return self._slither_parser.is_compact_ast + + @property + def compilation_unit(self) -> SlitherCompilationUnit: + return self._slither_parser.compilation_unit + + def get_key(self) -> str: + return self._slither_parser.get_key() + + @property + def slither_parser(self) -> "SlitherCompilationUnitSolc": + return self._slither_parser + + @property + def underlying_using_for(self) -> UsingForTopLevel: + return self._using_for diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 3054b4470..828229c0c 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -14,6 +14,7 @@ from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.import_directive import Import from slither.core.declarations.pragma_directive import Pragma from slither.core.declarations.structure_top_level import StructureTopLevel +from slither.core.declarations.using_for_top_level import UsingForTopLevel from slither.core.scope.scope import FileScope from slither.core.solidity_types import ElementaryType, TypeAliasTopLevel from slither.core.variables.top_level_variable import TopLevelVariable @@ -22,6 +23,7 @@ from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.custom_error import CustomErrorSolc from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc +from slither.solc_parsing.declarations.using_for_top_level import UsingForTopLevelSolc from slither.solc_parsing.exceptions import VariableNotFound from slither.solc_parsing.variables.top_level_variable import TopLevelVariableSolc @@ -71,6 +73,7 @@ class SlitherCompilationUnitSolc: self._custom_error_parser: List[CustomErrorSolc] = [] self._variables_top_level_parser: List[TopLevelVariableSolc] = [] self._functions_top_level_parser: List[FunctionSolc] = [] + self._using_for_top_level_parser: List[UsingForTopLevelSolc] = [] self._is_compact_ast = False # self._core: SlitherCore = core @@ -221,6 +224,17 @@ class SlitherCompilationUnitSolc: scope.pragmas.add(pragma) pragma.set_offset(top_level_data["src"], self._compilation_unit) self._compilation_unit.pragma_directives.append(pragma) + + elif top_level_data[self.get_key()] == "UsingForDirective": + scope = self.compilation_unit.get_scope(filename) + usingFor = UsingForTopLevel(scope) + usingFor_parser = UsingForTopLevelSolc(usingFor, top_level_data, self) + usingFor.set_offset(top_level_data["src"], self._compilation_unit) + scope.usingFor.add(usingFor) + + self._compilation_unit.using_for_top_level.append(usingFor) + self._using_for_top_level_parser.append(usingFor_parser) + elif top_level_data[self.get_key()] == "ImportDirective": if self.is_compact_ast: import_directive = Import( @@ -495,6 +509,12 @@ Please rename it, this name is reserved for Slither's internals""" # Then we analyse state variables, functions and modifiers self._analyze_third_part(contracts_to_be_analyzed, libraries) + self._analyze_top_level_using_for() + + # Convert library function (at the moment are string) in using for that specifies list of functions + # to actual function + self._analyze_library_function_using_for(contracts_to_be_analyzed) + self._parsed = True def analyze_contracts(self): # pylint: disable=too-many-statements,too-many-branches @@ -605,6 +625,10 @@ Please rename it, this name is reserved for Slither's internals""" else: contracts_to_be_analyzed += [contract] + def _analyze_library_function_using_for(self, contracts_to_be_analyzed: List[ContractSolc]): + for c in contracts_to_be_analyzed: + c.analyze_library_function_using_for() + def _analyze_enums(self, contract: ContractSolc): # Enum must be analyzed first contract.analyze_enums() @@ -651,6 +675,10 @@ Please rename it, this name is reserved for Slither's internals""" func_parser.analyze_params() self._compilation_unit.add_function(func_parser.underlying_function) + def _analyze_top_level_using_for(self): + for using_for in self._using_for_top_level_parser: + using_for.analyze() + def _analyze_params_custom_error(self): for custom_error_parser in self._custom_error_parser: custom_error_parser.analyze_params() diff --git a/slither/solc_parsing/solidity_types/type_parsing.py b/slither/solc_parsing/solidity_types/type_parsing.py index 9a8ef5db2..b62f908d1 100644 --- a/slither/solc_parsing/solidity_types/type_parsing.py +++ b/slither/solc_parsing/solidity_types/type_parsing.py @@ -224,6 +224,7 @@ def parse_type( from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.function import FunctionSolc + from slither.solc_parsing.declarations.using_for_top_level import UsingForTopLevelSolc from slither.solc_parsing.declarations.custom_error import CustomErrorSolc from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc @@ -259,11 +260,16 @@ def parse_type( all_enums += enums_direct_access contracts = sl.contracts functions = [] - elif isinstance(caller_context, (StructureTopLevelSolc, CustomErrorSolc, TopLevelVariableSolc)): + elif isinstance( + caller_context, + (StructureTopLevelSolc, CustomErrorSolc, TopLevelVariableSolc, UsingForTopLevelSolc), + ): if isinstance(caller_context, StructureTopLevelSolc): scope = caller_context.underlying_structure.file_scope elif isinstance(caller_context, TopLevelVariableSolc): scope = caller_context.underlying_variable.file_scope + elif isinstance(caller_context, UsingForTopLevelSolc): + scope = caller_context.underlying_using_for.file_scope else: assert isinstance(caller_context, CustomErrorSolc) custom_error = caller_context.underlying_custom_error From 90520c591bfa0011c863094075e552e2db11e3e9 Mon Sep 17 00:00:00 2001 From: Simone Date: Fri, 26 Aug 2022 18:43:50 +0200 Subject: [PATCH 002/110] Add parsing tests --- .../using-for-1-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 4263 bytes .../using-for-2-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 4257 bytes ...ctions-list-1-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 4195 bytes ...ctions-list-2-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 3951 bytes ...ctions-list-3-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 3940 bytes ...ctions-list-4-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 4337 bytes ...ng-for-global-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 4737 bytes .../using-for-1-0.8.0.sol-0.8.15-compact.json | 10 +++++ .../using-for-2-0.8.0.sol-0.8.15-compact.json | 10 +++++ ...tions-list-1-0.8.0.sol-0.8.15-compact.json | 10 +++++ ...tions-list-2-0.8.0.sol-0.8.15-compact.json | 10 +++++ ...tions-list-3-0.8.0.sol-0.8.15-compact.json | 10 +++++ ...tions-list-4-0.8.0.sol-0.8.15-compact.json | 10 +++++ ...g-for-global-0.8.0.sol-0.8.15-compact.json | 11 +++++ tests/ast-parsing/using-for-1-0.8.0.sol | 40 +++++++++++++++++ tests/ast-parsing/using-for-2-0.8.0.sol | 40 +++++++++++++++++ .../using-for-functions-list-1-0.8.0.sol | 37 ++++++++++++++++ .../using-for-functions-list-2-0.8.0.sol | 41 ++++++++++++++++++ .../using-for-functions-list-3-0.8.0.sol | 41 ++++++++++++++++++ .../using-for-functions-list-4-0.8.0.sol | 40 +++++++++++++++++ tests/ast-parsing/using-for-global-0.8.0.sol | 15 +++++++ tests/ast-parsing/using-for-library-0.8.0.sol | 32 ++++++++++++++ tests/test_ast_parsing.py | 7 +++ 23 files changed, 364 insertions(+) create mode 100644 tests/ast-parsing/compile/using-for-1-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/using-for-2-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/using-for-functions-list-1-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/using-for-functions-list-2-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/using-for-functions-list-3-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/using-for-functions-list-4-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/using-for-global-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/expected/using-for-1-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/using-for-2-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/using-for-functions-list-1-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/using-for-functions-list-2-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/using-for-functions-list-3-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/using-for-functions-list-4-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/using-for-global-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/using-for-1-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-2-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-functions-list-1-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-functions-list-2-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-functions-list-3-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-functions-list-4-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-global-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-library-0.8.0.sol diff --git a/tests/ast-parsing/compile/using-for-1-0.8.0.sol-0.8.15-compact.zip b/tests/ast-parsing/compile/using-for-1-0.8.0.sol-0.8.15-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..6505c61e0b731ee77658aaf1120b9365b59fe246 GIT binary patch literal 4263 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/using-for-functions-list-1-0.8.0.sol-0.8.15-compact.zip b/tests/ast-parsing/compile/using-for-functions-list-1-0.8.0.sol-0.8.15-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..6a6064a153327e35ea1dec07add44437261d7480 GIT binary patch literal 4195 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 d7~X&8e%V*UFRKB7{{zLZbMXKG literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/using-for-functions-list-3-0.8.0.sol-0.8.15-compact.zip b/tests/ast-parsing/compile/using-for-functions-list-3-0.8.0.sol-0.8.15-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..3944ab586fd17cefa7ccbd4fa0d437f68e8f8e5c GIT binary patch literal 3940 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 og{_41e+!}iIHCVdIM#ph|I1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "b(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "c(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "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/expected/using-for-2-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-2-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..01536efb9 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-2-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,10 @@ +{ + "L1": { + "a(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "b(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "c(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "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/expected/using-for-functions-list-1-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-functions-list-1-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..01536efb9 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-functions-list-1-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,10 @@ +{ + "L1": { + "a(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "b(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "c(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "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/expected/using-for-functions-list-2-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-functions-list-2-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..a41d2ba18 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-functions-list-2-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,10 @@ +{ + "L1": { + "a(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "b(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "c(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "topLevelCall(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/expected/using-for-functions-list-3-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-functions-list-3-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..a41d2ba18 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-functions-list-3-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,10 @@ +{ + "L1": { + "a(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "b(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "c(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "topLevelCall(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/expected/using-for-functions-list-4-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-functions-list-4-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..01536efb9 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-functions-list-4-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,10 @@ +{ + "L1": { + "a(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "b(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "c(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "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/expected/using-for-global-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-global-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..f2119ecf1 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-global-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,11 @@ +{ + "C": { + "libCall(uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "topLevelCall(uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + }, + "L1": { + "a(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "b(Data,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n", + "c(Data,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/using-for-1-0.8.0.sol b/tests/ast-parsing/using-for-1-0.8.0.sol new file mode 100644 index 000000000..201e18527 --- /dev/null +++ b/tests/ast-parsing/using-for-1-0.8.0.sol @@ -0,0 +1,40 @@ + +struct Data { mapping(uint => bool) flags; } +using L1 for Data; + +function d(Data storage self, uint value) returns(bool){ + return true; +} + +library L1 { + function a(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function b(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function c(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + +} + +contract C { + Data knownValues; + + function libCall(uint value) public { + require(knownValues.a(value)); + } + +} diff --git a/tests/ast-parsing/using-for-2-0.8.0.sol b/tests/ast-parsing/using-for-2-0.8.0.sol new file mode 100644 index 000000000..cb0bb8ba1 --- /dev/null +++ b/tests/ast-parsing/using-for-2-0.8.0.sol @@ -0,0 +1,40 @@ + +struct Data { mapping(uint => bool) flags; } + +function d(Data storage self, uint value) returns(bool){ + return true; +} + +library L1 { + function a(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function b(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function c(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + +} + +contract C { + using L1 for Data; + Data knownValues; + + function libCall(uint value) public { + require(knownValues.a(value)); + } + +} diff --git a/tests/ast-parsing/using-for-functions-list-1-0.8.0.sol b/tests/ast-parsing/using-for-functions-list-1-0.8.0.sol new file mode 100644 index 000000000..52ed5087e --- /dev/null +++ b/tests/ast-parsing/using-for-functions-list-1-0.8.0.sol @@ -0,0 +1,37 @@ + +struct Data { mapping(uint => bool) flags; } + +library L1 { + function a(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function b(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function c(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + +} + +contract C { + + using {L1.a, L1.b} for Data; + Data knownValues; + + function libCall(uint value) public { + require(knownValues.a(value)); + } + +} diff --git a/tests/ast-parsing/using-for-functions-list-2-0.8.0.sol b/tests/ast-parsing/using-for-functions-list-2-0.8.0.sol new file mode 100644 index 000000000..d41163dee --- /dev/null +++ b/tests/ast-parsing/using-for-functions-list-2-0.8.0.sol @@ -0,0 +1,41 @@ + +struct Data { mapping(uint => bool) flags; } + +function d(Data storage self, uint value) returns(bool){ + return true; +} + +library L1 { + function a(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function b(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function c(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + +} + +contract C { + + using {L1.a, L1.b, d} for Data; + Data knownValues; + + function topLevelCall(uint value) public { + require(knownValues.d(value)); + } + +} diff --git a/tests/ast-parsing/using-for-functions-list-3-0.8.0.sol b/tests/ast-parsing/using-for-functions-list-3-0.8.0.sol new file mode 100644 index 000000000..7e5db5776 --- /dev/null +++ b/tests/ast-parsing/using-for-functions-list-3-0.8.0.sol @@ -0,0 +1,41 @@ + +struct Data { mapping(uint => bool) flags; } +using {L1.a, L1.b, d} for Data; + +function d(Data storage self, uint value) returns(bool){ + return true; +} + +library L1 { + function a(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function b(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function c(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + +} + +contract C { + + Data knownValues; + + function topLevelCall(uint value) public { + require(knownValues.d(value)); + } + +} diff --git a/tests/ast-parsing/using-for-functions-list-4-0.8.0.sol b/tests/ast-parsing/using-for-functions-list-4-0.8.0.sol new file mode 100644 index 000000000..ecce5e764 --- /dev/null +++ b/tests/ast-parsing/using-for-functions-list-4-0.8.0.sol @@ -0,0 +1,40 @@ + +struct Data { mapping(uint => bool) flags; } +using {L1.a, L1.b, d} for Data; + +function d(Data storage self, uint value) returns(bool){ + return true; +} + +library L1 { + function a(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function b(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function c(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + +} + +contract C { + Data knownValues; + + function libCall(uint value) public { + require(knownValues.a(value)); + } + +} diff --git a/tests/ast-parsing/using-for-global-0.8.0.sol b/tests/ast-parsing/using-for-global-0.8.0.sol new file mode 100644 index 000000000..c5b112259 --- /dev/null +++ b/tests/ast-parsing/using-for-global-0.8.0.sol @@ -0,0 +1,15 @@ +import "./using-for-library-0.8.0.sol"; + +contract C { + Data knownValues; + + function libCall(uint value) public { + require(knownValues.a(value)); + } + + function topLevelCall(uint value) public { + require(knownValues.d(value)); + } + + +} diff --git a/tests/ast-parsing/using-for-library-0.8.0.sol b/tests/ast-parsing/using-for-library-0.8.0.sol new file mode 100644 index 000000000..97ee39ca6 --- /dev/null +++ b/tests/ast-parsing/using-for-library-0.8.0.sol @@ -0,0 +1,32 @@ + +struct Data { mapping(uint => bool) flags; } +using L1 for Data global; +using {d} for Data global; + +function d(Data storage self, uint value) returns(bool){ + return true; +} + +library L1 { + function a(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function b(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + + function c(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + +} diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 506ee3d6b..77d0b86cd 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -420,6 +420,13 @@ ALL_TESTS = [ Test("free_functions/new_operator.sol", ["0.8.12"]), Test("free_functions/library_constant_function_collision.sol", ["0.8.12"]), Test("ternary-with-max.sol", ["0.8.15"]), + Test("using-for-1-0.8.0.sol", ["0.8.15"]), + Test("using-for-2-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"]), + Test("using-for-functions-list-4-0.8.0.sol", ["0.8.15"]), + Test("using-for-global-0.8.0.sol", ["0.8.15"]), ] # create the output folder if needed try: From cc3b342d517b7cce9804bd9e1380c5b4326b52c5 Mon Sep 17 00:00:00 2001 From: Simone Date: Sat, 27 Aug 2022 11:14:56 +0200 Subject: [PATCH 003/110] Fix ir for top level function --- slither/slithir/convert.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 7658deb26..e851acfcc 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -15,6 +15,7 @@ from slither.core.declarations import ( ) from slither.core.declarations.custom_error import CustomError from slither.core.declarations.function_contract import FunctionContract +from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.solidity_import_placeholder import SolidityImportPlaceHolder from slither.core.declarations.solidity_variables import SolidityCustomRevert from slither.core.expressions import Identifier, Literal @@ -527,9 +528,9 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals if can_be_solidity_func(ir): return convert_to_solidity_func(ir) - # convert library + # convert library or top level function if t in using_for or "*" in using_for: - new_ir = convert_to_library(ir, node, using_for) + new_ir = convert_to_library_or_top_level(ir, node, using_for) if new_ir: return new_ir @@ -1331,8 +1332,24 @@ def convert_to_pop(ir, node): return ret -def look_for_library(contract, ir, using_for, t): +def look_for_library_or_top_level(contract, ir, using_for, t): for destination in using_for[t]: + if isinstance(destination, FunctionTopLevel) and destination.name == ir.function_name: + internalcall = InternalCall(destination, ir.nbr_arguments, ir.lvalue, ir.type_call) + internalcall.set_expression(ir.expression) + internalcall.set_node(ir.node) + internalcall.call_gas = ir.call_gas + internalcall.arguments = [ir.destination] + ir.arguments + return_type = internalcall.function.return_type + if return_type: + if len(return_type) == 1: + internalcall.lvalue.set_type(return_type[0]) + elif len(return_type) > 1: + internalcall.lvalue.set_type(return_type) + else: + internalcall.lvalue = None + return internalcall + if isinstance(destination, FunctionContract) and destination.contract.is_library: lib_contract = destination.contract else: @@ -1356,19 +1373,19 @@ def look_for_library(contract, ir, using_for, t): return None -def convert_to_library(ir, node, using_for): +def convert_to_library_or_top_level(ir, node, using_for): # We use contract_declarer, because Solidity resolve the library # before resolving the inheritance. # Though we could use .contract as libraries cannot be shadowed contract = node.function.contract_declarer t = ir.destination.type if t in using_for: - new_ir = look_for_library(contract, ir, using_for, t) + new_ir = look_for_library_or_top_level(contract, ir, using_for, t) if new_ir: return new_ir if "*" in using_for: - new_ir = look_for_library(contract, ir, using_for, "*") + new_ir = look_for_library_or_top_level(contract, ir, using_for, "*") if new_ir: return new_ir From 928d7f22ceee06f376e6d227e2bf28a525f3fed7 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 19 Sep 2022 22:54:33 +0200 Subject: [PATCH 004/110] Run black --- .../core/solidity_types/elementary_type.py | 6 ++-- .../naming_convention/naming_convention.py | 12 +++++--- .../statements/type_based_tautology.py | 2 +- .../declarations/using_for_top_level.py | 29 +++++++++---------- slither/utils/integer_conversion.py | 2 +- .../visitors/expression/constants_folding.py | 2 +- 6 files changed, 27 insertions(+), 26 deletions(-) diff --git a/slither/core/solidity_types/elementary_type.py b/slither/core/solidity_types/elementary_type.py index fc248e946..c6804f9c1 100644 --- a/slither/core/solidity_types/elementary_type.py +++ b/slither/core/solidity_types/elementary_type.py @@ -43,8 +43,8 @@ Int = [ "int256", ] -Max_Int = {k: 2 ** (8 * i - 1) - 1 if i > 0 else 2**255 - 1 for i, k in enumerate(Int)} -Min_Int = {k: -(2 ** (8 * i - 1)) if i > 0 else -(2**255) for i, k in enumerate(Int)} +Max_Int = {k: 2 ** (8 * i - 1) - 1 if i > 0 else 2 ** 255 - 1 for i, k in enumerate(Int)} +Min_Int = {k: -(2 ** (8 * i - 1)) if i > 0 else -(2 ** 255) for i, k in enumerate(Int)} Uint = [ "uint", @@ -82,7 +82,7 @@ Uint = [ "uint256", ] -Max_Uint = {k: 2 ** (8 * i) - 1 if i > 0 else 2**256 - 1 for i, k in enumerate(Uint)} +Max_Uint = {k: 2 ** (8 * i) - 1 if i > 0 else 2 ** 256 - 1 for i, k in enumerate(Uint)} Min_Uint = {k: 0 for k in Uint} diff --git a/slither/detectors/naming_convention/naming_convention.py b/slither/detectors/naming_convention/naming_convention.py index 706f4ae6c..2cca9dee9 100644 --- a/slither/detectors/naming_convention/naming_convention.py +++ b/slither/detectors/naming_convention/naming_convention.py @@ -89,10 +89,14 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if func.is_constructor: continue if not self.is_mixed_case(func.name): - if func.visibility in [ - "internal", - "private", - ] and self.is_mixed_case_with_underscore(func.name): + if ( + func.visibility + in [ + "internal", + "private", + ] + and self.is_mixed_case_with_underscore(func.name) + ): continue if func.name.startswith(("echidna_", "crytic_")): continue diff --git a/slither/detectors/statements/type_based_tautology.py b/slither/detectors/statements/type_based_tautology.py index 0129ad03f..efa814713 100644 --- a/slither/detectors/statements/type_based_tautology.py +++ b/slither/detectors/statements/type_based_tautology.py @@ -11,7 +11,7 @@ from slither.core.solidity_types.elementary_type import Int, Uint def typeRange(t): bits = int(t.split("int")[1]) if t in Uint: - return 0, (2**bits) - 1 + return 0, (2 ** bits) - 1 if t in Int: v = (2 ** (bits - 1)) - 1 return -v, v diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py index 070ed8cf7..c3a6cb55e 100644 --- a/slither/solc_parsing/declarations/using_for_top_level.py +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -6,10 +6,8 @@ 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.solidity_types import Type, TypeAliasTopLevel +from slither.core.solidity_types import TypeAliasTopLevel from slither.core.declarations import ( - FunctionContract, - FunctionTopLevel, StructureTopLevel, EnumTopLevel, ) @@ -28,15 +26,12 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- UsingFor class """ - # elems = [(type, name)] - def __init__( # pylint: disable=too-many-arguments self, uftl: UsingForTopLevel, top_level_data: Dict, slither_parser: "SlitherCompilationUnitSolc", ): - # TODO think if save global here is useful self._type_name = top_level_data["typeName"] self._global = top_level_data["global"] @@ -48,14 +43,14 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- self._using_for = uftl self._slither_parser = slither_parser - def analyze(self): + def analyze(self) -> None: type_name = parse_type(self._type_name, self) self._using_for.using_for[type_name] = [] if hasattr(self, "_library_name"): library_name = parse_type(self._library_name, self) self._using_for.using_for[type_name].append(library_name) - self._propagate_global(type_name, library_name) + self._propagate_global(type_name) else: for f in self._functions: full_name_split = f["function"]["name"].split(".") @@ -65,7 +60,8 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- for tl_function in self.compilation_unit.functions_top_level: if tl_function.name == function_name: self._using_for.using_for[type_name].append(tl_function) - self._propagate_global(type_name, tl_function) + self._propagate_global(type_name) + break elif len(full_name_split) == 2: # Library function library_name = full_name_split[0] @@ -78,17 +74,18 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- for cf in c.functions: if cf.name == function_name: self._using_for.using_for[type_name].append(cf) - self._propagate_global(type_name, cf) + self._propagate_global(type_name) found = True break else: # probably case if there is an import with an alias we don't handle it for now # e.g. MyImport.MyLib.a - return + LOGGER.warning( + f"Using for directive for function {f['function']['name']} not supported" + ) + continue - def _propagate_global( - self, type_name: Type, to_add: Union[FunctionTopLevel, FunctionContract, UserDefinedType] - ): + def _propagate_global(self, type_name: Union[TypeAliasTopLevel, UserDefinedType]) -> None: if self._global: for scope in self.compilation_unit.scopes.values(): if isinstance(type_name, TypeAliasTopLevel): @@ -107,11 +104,11 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- scope.usingFor.add(self._using_for) else: LOGGER.error( - f"Error propagating global {underlying} {type(underlying)} not a StructTopLevel or EnumTopLevel" + f"Error when propagating global {underlying} {type(underlying)} not a StructTopLevel or EnumTopLevel" ) else: LOGGER.error( - f"Found {to_add} {type(to_add)} when propagating global using for {type_name} {type(type_name)}" + f"Error when propagating global using for {type_name} {type(type_name)}" ) @property diff --git a/slither/utils/integer_conversion.py b/slither/utils/integer_conversion.py index 8481e8641..f5cf453b5 100644 --- a/slither/utils/integer_conversion.py +++ b/slither/utils/integer_conversion.py @@ -23,6 +23,6 @@ def convert_string_to_int(val: Union[str, int]) -> int: f"{base}e{expo} is too large to fit in any Solidity integer size" ) return 0 - return int(Decimal(base) * Decimal(10**expo)) + return int(Decimal(base) * Decimal(10 ** expo)) return int(Decimal(val)) diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 61c98d65f..1758c83dd 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -43,7 +43,7 @@ class ConstantFolding(ExpressionVisitor): left = get_val(expression.expression_left) right = get_val(expression.expression_right) if expression.type == BinaryOperationType.POWER: - set_val(expression, left**right) + set_val(expression, left ** right) elif expression.type == BinaryOperationType.MULTIPLICATION: set_val(expression, left * right) elif expression.type == BinaryOperationType.DIVISION: From 6571ada9a2f26b4cb1ef3e48196864ff577480b4 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Mon, 3 Oct 2022 10:57:48 +0200 Subject: [PATCH 005/110] run black --- slither/core/solidity_types/elementary_type.py | 6 +++--- .../detectors/naming_convention/naming_convention.py | 12 ++++-------- slither/detectors/statements/type_based_tautology.py | 2 +- slither/slithir/convert.py | 4 ++-- slither/visitors/expression/constants_folding.py | 2 +- 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/slither/core/solidity_types/elementary_type.py b/slither/core/solidity_types/elementary_type.py index c6804f9c1..fc248e946 100644 --- a/slither/core/solidity_types/elementary_type.py +++ b/slither/core/solidity_types/elementary_type.py @@ -43,8 +43,8 @@ Int = [ "int256", ] -Max_Int = {k: 2 ** (8 * i - 1) - 1 if i > 0 else 2 ** 255 - 1 for i, k in enumerate(Int)} -Min_Int = {k: -(2 ** (8 * i - 1)) if i > 0 else -(2 ** 255) for i, k in enumerate(Int)} +Max_Int = {k: 2 ** (8 * i - 1) - 1 if i > 0 else 2**255 - 1 for i, k in enumerate(Int)} +Min_Int = {k: -(2 ** (8 * i - 1)) if i > 0 else -(2**255) for i, k in enumerate(Int)} Uint = [ "uint", @@ -82,7 +82,7 @@ Uint = [ "uint256", ] -Max_Uint = {k: 2 ** (8 * i) - 1 if i > 0 else 2 ** 256 - 1 for i, k in enumerate(Uint)} +Max_Uint = {k: 2 ** (8 * i) - 1 if i > 0 else 2**256 - 1 for i, k in enumerate(Uint)} Min_Uint = {k: 0 for k in Uint} diff --git a/slither/detectors/naming_convention/naming_convention.py b/slither/detectors/naming_convention/naming_convention.py index 2cca9dee9..706f4ae6c 100644 --- a/slither/detectors/naming_convention/naming_convention.py +++ b/slither/detectors/naming_convention/naming_convention.py @@ -89,14 +89,10 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 if func.is_constructor: continue if not self.is_mixed_case(func.name): - if ( - func.visibility - in [ - "internal", - "private", - ] - and self.is_mixed_case_with_underscore(func.name) - ): + if func.visibility in [ + "internal", + "private", + ] and self.is_mixed_case_with_underscore(func.name): continue if func.name.startswith(("echidna_", "crytic_")): continue diff --git a/slither/detectors/statements/type_based_tautology.py b/slither/detectors/statements/type_based_tautology.py index efa814713..0129ad03f 100644 --- a/slither/detectors/statements/type_based_tautology.py +++ b/slither/detectors/statements/type_based_tautology.py @@ -11,7 +11,7 @@ from slither.core.solidity_types.elementary_type import Int, Uint def typeRange(t): bits = int(t.split("int")[1]) if t in Uint: - return 0, (2 ** bits) - 1 + return 0, (2**bits) - 1 if t in Int: v = (2 ** (bits - 1)) - 1 return -v, v diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index e851acfcc..818959afb 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -172,10 +172,10 @@ def _fits_under_integer(val: int, can_be_int: bool, can_be_uint) -> List[str]: assert can_be_int | can_be_uint while n <= 256: if can_be_uint: - if val <= 2 ** n - 1: + if val <= 2**n - 1: ret.append(f"uint{n}") if can_be_int: - if val <= (2 ** n) / 2 - 1: + if val <= (2**n) / 2 - 1: ret.append(f"int{n}") n = n + 8 return ret diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 250104f5e..b324ed842 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -43,7 +43,7 @@ class ConstantFolding(ExpressionVisitor): left = get_val(expression.expression_left) right = get_val(expression.expression_right) if expression.type == BinaryOperationType.POWER: - set_val(expression, left ** right) + set_val(expression, left**right) elif expression.type == BinaryOperationType.MULTIPLICATION: set_val(expression, left * right) elif expression.type == BinaryOperationType.DIVISION: From 3278417af0a8878613818267b7f936097d305ce4 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 3 Oct 2022 13:56:35 +0200 Subject: [PATCH 006/110] Refactor parsing --- slither/solc_parsing/declarations/contract.py | 81 +++++++++---------- .../declarations/using_for_top_level.py | 81 ++++++++++++------- .../slither_compilation_unit_solc.py | 13 ++- 3 files changed, 95 insertions(+), 80 deletions(-) diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py index 32ca0e8ab..c66802844 100644 --- a/slither/solc_parsing/declarations/contract.py +++ b/slither/solc_parsing/declarations/contract.py @@ -5,7 +5,7 @@ from slither.core.declarations import Modifier, Event, EnumContract, StructureCo from slither.core.declarations.contract import Contract from slither.core.declarations.custom_error_contract import CustomErrorContract from slither.core.declarations.function_contract import FunctionContract -from slither.core.solidity_types import ElementaryType, TypeAliasContract +from slither.core.solidity_types import ElementaryType, TypeAliasContract, Type from slither.core.variables.state_variable import StateVariable from slither.solc_parsing.declarations.caller_context import CallerContextExpression from slither.solc_parsing.declarations.custom_error import CustomErrorSolc @@ -574,7 +574,7 @@ class ContractSolc(CallerContextExpression): except (VariableNotFound, KeyError) as e: self.log_incorrect_parsing(f"Missing state variable {e}") - def analyze_using_for(self): + def analyze_using_for(self): # pylint: disable=too-many-branches try: for father in self._contract.inheritance: self._contract.using_for.update(father.using_for) @@ -593,18 +593,7 @@ class ContractSolc(CallerContextExpression): ) else: # We have a list of functions. A function can be topLevel or a library function - # at this point library function are yet to be parsed so we add the function name - # and add the real function later - for f in using_for["functionList"]: - function_name = f["function"]["name"] - if function_name.find(".") != -1: - # Library function - self._contract.using_for[type_name].append(function_name) - else: - # 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) + self._analyze_function_list(using_for["functionList"], type_name) else: for using_for in self._usingForNotParsed: children = using_for[self.get_children()] @@ -622,34 +611,42 @@ class ContractSolc(CallerContextExpression): except (VariableNotFound, KeyError) as e: self.log_incorrect_parsing(f"Missing using for {e}") - def analyze_library_function_using_for(self): - for type_name, full_names in self._contract.using_for.items(): - # If it's a string is a library function e.g. L.a - # We add the actual function and remove the string - for full_name in full_names: - if isinstance(full_name, str): - full_name_split = full_name.split(".") - # TODO this doesn't handle the case if there is an import with an alias - # e.g. MyImport.MyLib.a - if len(full_name_split) == 2: - library_name = full_name_split[0] - function_name = full_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 - self._contract.using_for[type_name].remove(full_name) - else: - self.log_incorrect_parsing( - f"Expected library function instead received {full_name}" - ) + 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: + # 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: + self.log_incorrect_parsing( + f"Expected library function instead received {function_name}" + ) def analyze_enums(self): try: diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py index c3a6cb55e..89d1dc276 100644 --- a/slither/solc_parsing/declarations/using_for_top_level.py +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -2,10 +2,11 @@ Using For Top Level module """ import logging -from typing import TYPE_CHECKING, Dict, Union +from typing import TYPE_CHECKING, Dict, Union, Any 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, @@ -57,26 +58,12 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- if len(full_name_split) == 1: # Top level function function_name = full_name_split[0] - for tl_function in self.compilation_unit.functions_top_level: - if tl_function.name == function_name: - self._using_for.using_for[type_name].append(tl_function) - self._propagate_global(type_name) - break + self._analyze_top_level_function(function_name, type_name) elif len(full_name_split) == 2: # Library function library_name = full_name_split[0] function_name = full_name_split[1] - found = False - for c in self.compilation_unit.contracts: - if found: - break - if c.name == library_name: - for cf in c.functions: - if cf.name == function_name: - self._using_for.using_for[type_name].append(cf) - self._propagate_global(type_name) - found = True - break + self._analyze_library_function(function_name, library_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 @@ -85,6 +72,35 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- ) continue + def _analyze_top_level_function( + self, function_name: str, type_name: Union[TypeAliasTopLevel, UserDefinedType] + ) -> None: + for tl_function in self.compilation_unit.functions_top_level: + if tl_function.name == function_name: + self._using_for.using_for[type_name].append(tl_function) + self._propagate_global(type_name) + break + + def _analyze_library_function( + self, + function_name: str, + library_name: str, + type_name: Union[TypeAliasTopLevel, UserDefinedType], + ) -> None: + found = False + for c in self.compilation_unit.contracts: + if found: + break + if c.name == library_name: + for cf in c.functions: + if cf.name == function_name: + self._using_for.using_for[type_name].append(cf) + self._propagate_global(type_name) + found = True + break + if not found: + LOGGER.warning(f"Library {library_name} - function {function_name} not found") + def _propagate_global(self, type_name: Union[TypeAliasTopLevel, UserDefinedType]) -> None: if self._global: for scope in self.compilation_unit.scopes.values(): @@ -93,24 +109,29 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- if alias == type_name: scope.usingFor.add(self._using_for) elif isinstance(type_name, UserDefinedType): - underlying = type_name.type - if isinstance(underlying, StructureTopLevel): - for struct in scope.structures.values(): - if struct == underlying: - scope.usingFor.add(self._using_for) - elif isinstance(underlying, EnumTopLevel): - for enum in scope.enums.values(): - if enum == underlying: - scope.usingFor.add(self._using_for) - else: - LOGGER.error( - f"Error when propagating global {underlying} {type(underlying)} not a StructTopLevel or EnumTopLevel" - ) + self._propagate_global_UserDefinedType(scope, type_name) else: LOGGER.error( f"Error when propagating global using for {type_name} {type(type_name)}" ) + def _propagate_global_UserDefinedType( + self, scope: Dict[Any, FileScope], type_name: UserDefinedType + ): + underlying = type_name.type + if isinstance(underlying, StructureTopLevel): + for struct in scope.structures.values(): + if struct == underlying: + scope.usingFor.add(self._using_for) + elif isinstance(underlying, EnumTopLevel): + for enum in scope.enums.values(): + if enum == underlying: + scope.usingFor.add(self._using_for) + else: + LOGGER.error( + f"Error when propagating global {underlying} {type(underlying)} not a StructTopLevel or EnumTopLevel" + ) + @property def is_compact_ast(self) -> bool: return self._slither_parser.is_compact_ast diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 828229c0c..f08a71487 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -509,11 +509,7 @@ Please rename it, this name is reserved for Slither's internals""" # Then we analyse state variables, functions and modifiers self._analyze_third_part(contracts_to_be_analyzed, libraries) - self._analyze_top_level_using_for() - - # Convert library function (at the moment are string) in using for that specifies list of functions - # to actual function - self._analyze_library_function_using_for(contracts_to_be_analyzed) + self._analyze_using_for(contracts_to_be_analyzed) self._parsed = True @@ -625,9 +621,11 @@ Please rename it, this name is reserved for Slither's internals""" else: contracts_to_be_analyzed += [contract] - def _analyze_library_function_using_for(self, contracts_to_be_analyzed: List[ContractSolc]): + def _analyze_using_for(self, contracts_to_be_analyzed: List[ContractSolc]): + self._analyze_top_level_using_for() + for c in contracts_to_be_analyzed: - c.analyze_library_function_using_for() + c.analyze_using_for() def _analyze_enums(self, contract: ContractSolc): # Enum must be analyzed first @@ -651,7 +649,6 @@ Please rename it, this name is reserved for Slither's internals""" # Event can refer to struct contract.analyze_events() - contract.analyze_using_for() contract.analyze_custom_errors() contract.set_is_analyzed(True) From 2a6c145c6c334ec5b9d4a3b0db88f516fbcb2efe Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 3 Nov 2022 23:01:23 -0500 Subject: [PATCH 007/110] upgradeability: include inherited private variables, ignore immutables --- .../tools/upgradeability/checks/variable_initialization.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slither/tools/upgradeability/checks/variable_initialization.py b/slither/tools/upgradeability/checks/variable_initialization.py index a2a2edbb2..e8ae9b26c 100644 --- a/slither/tools/upgradeability/checks/variable_initialization.py +++ b/slither/tools/upgradeability/checks/variable_initialization.py @@ -39,8 +39,8 @@ Using initialize functions to write initial values in state variables. def _check(self): results = [] - for s in self.contract.state_variables: - if s.initialized and not s.is_constant: + for s in self.contract.state_variables_ordered: + if s.initialized and not (s.is_constant or s.is_immutable): info = [s, " is a state variable with an initial value.\n"] json = self.generate_result(info) results.append(json) From faed6d7fb2039c231d4631dbed625c7c3d6ae6b5 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Sun, 6 Nov 2022 21:38:45 -0600 Subject: [PATCH 008/110] update constable-states to consider constructor vars which can be immutable --- .../possible_const_state_variables.py | 101 +-- ...es.sol.0.4.25.ConstCandidateStateVars.json | 206 +++--- .../0.5.16/const_state_variables.sol | 1 + ...es.sol.0.5.16.ConstCandidateStateVars.json | 261 ++++--- .../0.6.11/const_state_variables.sol | 8 +- ...es.sol.0.6.11.ConstCandidateStateVars.json | 286 +++++--- .../0.7.6/const_state_variables.sol | 14 +- ...les.sol.0.7.6.ConstCandidateStateVars.json | 480 +++++++++--- .../0.8.0/const_state_variables.sol | 52 ++ ...les.sol.0.8.0.ConstCandidateStateVars.json | 690 ++++++++++++++++++ .../constable-states/0.8.0/immutable.sol | 7 - ...ble.sol.0.8.0.ConstCandidateStateVars.json | 3 - tests/test_detectors.py | 2 +- 13 files changed, 1651 insertions(+), 460 deletions(-) create mode 100644 tests/detectors/constable-states/0.8.0/const_state_variables.sol create mode 100644 tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.ConstCandidateStateVars.json delete mode 100644 tests/detectors/constable-states/0.8.0/immutable.sol delete mode 100644 tests/detectors/constable-states/0.8.0/immutable.sol.0.8.0.ConstCandidateStateVars.json diff --git a/slither/detectors/variables/possible_const_state_variables.py b/slither/detectors/variables/possible_const_state_variables.py index e5b35bb79..4337b3075 100644 --- a/slither/detectors/variables/possible_const_state_variables.py +++ b/slither/detectors/variables/possible_const_state_variables.py @@ -14,6 +14,7 @@ from slither.core.declarations import Contract, Function from slither.core.declarations.solidity_variables import SolidityFunction from slither.core.variables.state_variable import StateVariable from slither.formatters.variables.possible_const_state_variables import custom_format +from slither.core.expressions import CallExpression, NewContract def _is_valid_type(v: StateVariable) -> bool: @@ -44,15 +45,17 @@ class ConstCandidateStateVars(AbstractDetector): """ ARGUMENT = "constable-states" - HELP = "State variables that could be declared constant" + HELP = "State variables that could be declared constant or immutable" IMPACT = DetectorClassification.OPTIMIZATION CONFIDENCE = DetectorClassification.HIGH - WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant" + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant-or-immutable" - WIKI_TITLE = "State variables that could be declared constant" - WIKI_DESCRIPTION = "Constant state variables should be declared constant to save gas." - WIKI_RECOMMENDATION = "Add the `constant` attributes to state variables that never change." + WIKI_TITLE = "State variables that could be declared constant or immutable" + WIKI_DESCRIPTION = "State variables that are not updated following deployment should be declared constant or immutable to save gas." + WIKI_RECOMMENDATION = ( + "Add the `constant` or `immutable` attribute to state variables that never change." + ) # https://solidity.readthedocs.io/en/v0.5.2/contracts.html#constant-state-variables valid_solidity_function = [ @@ -71,54 +74,66 @@ class ConstCandidateStateVars(AbstractDetector): if not v.expression: return True + # B b = new B(); b cannot be constant, so filter out and recommend it be immutable + if isinstance(v.expression, CallExpression) and isinstance( + v.expression.called, NewContract + ): + return False + export = ExportValues(v.expression) values = export.result() if not values: return True - if all((val in self.valid_solidity_function or _is_constant_var(val) for val in values)): - return True - return False + else: + return all( + (val in self.valid_solidity_function or _is_constant_var(val) for val in values) + ) def _detect(self) -> List[Output]: - """Detect state variables that could be const""" - results = [] + """Detect state variables that could be constant or immutable""" + results = {} + + variables = [] + functions = [] + for c in self.compilation_unit.contracts: + variables.append(c.state_variables) + functions.append(c.all_functions_called) - all_variables_l = [c.state_variables for c in self.compilation_unit.contracts] - all_variables: Set[StateVariable] = { - item for sublist in all_variables_l for item in sublist + valid_candidates: Set[StateVariable] = { + item for sublist in variables for item in sublist if _valid_candidate(item) } - all_non_constant_elementary_variables = {v for v in all_variables if _valid_candidate(v)} - - all_functions_nested = [c.all_functions_called for c in self.compilation_unit.contracts] - all_functions = list( - { - item1 - for sublist in all_functions_nested - for item1 in sublist - if isinstance(item1, Function) - } + + all_functions: List[Function] = list( + {item1 for sublist in functions for item1 in sublist if isinstance(item1, Function)} ) - all_variables_written = [ - f.state_variables_written for f in all_functions if not f.is_constructor_variables - ] - all_variables_written = {item for sublist in all_variables_written for item in sublist} - - constable_variables: List[Variable] = [ - v - for v in all_non_constant_elementary_variables - if (v not in all_variables_written) and self._constant_initial_expression(v) - ] - # Order for deterministic results - constable_variables = sorted(constable_variables, key=lambda x: x.canonical_name) - - # Create a result for each finding - for v in constable_variables: - info = [v, " should be constant\n"] - json = self.generate_result(info) - results.append(json) - - return results + variables_written = [] + constructor_variables_written = [] + for f in all_functions: + if f.is_constructor_variables: + constructor_variables_written.append(f.state_variables_written) + else: + variables_written.append(f.state_variables_written) + + variables_written = {item for sublist in variables_written for item in sublist} + constructor_variables_written = { + item for sublist in constructor_variables_written for item in sublist + } + for v in valid_candidates: + if v not in variables_written: + if self._constant_initial_expression(v): + results[v.canonical_name] = self.generate_result([v, " should be constant \n"]) + + # immutable attribute available in Solidity 0.6.5 and above + # https://blog.soliditylang.org/2020/04/06/solidity-0.6.5-release-announcement/ + elif ( + v in constructor_variables_written + and self.compilation_unit.solc_version > "0.6.4" + ): + results[v.canonical_name] = self.generate_result([v, " should be immutable \n"]) + + # Order by canonical name for deterministic results + return [results[k] for k in sorted(results)] @staticmethod def _format(compilation_unit: SlitherCompilationUnit, result: Dict) -> None: diff --git a/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.ConstCandidateStateVars.json index 4ab2cfa83..a46384f06 100644 --- a/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.ConstCandidateStateVars.json @@ -4,19 +4,19 @@ "elements": [ { "type": "variable", - "name": "myFriendsAddress", + "name": "text2", "source_mapping": { - "start": 132, - "length": 76, + "start": 333, + "length": 20, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "is_dependency": false, "lines": [ - 7 + 14 ], "starting_column": 5, - "ending_column": 81 + "ending_column": 25 }, "type_specific_fields": { "parent": { @@ -56,10 +56,10 @@ } } ], - "description": "A.myFriendsAddress (tests/detectors/constable-states/0.4.25/const_state_variables.sol#7) should be constant\n", - "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L7) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L7", - "id": "1454db80653b732bf6acbe54ff0ae4707002207a2a8216708c12d61c88a43e5f", + "description": "A.text2 (tests/detectors/constable-states/0.4.25/const_state_variables.sol#14) should be constant \n", + "markdown": "[A.text2](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L14) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L14", + "id": "2f06e04545cea7e7a8998c65d5419f335bf2579a6ce6a832eac9c87392fd5c1a", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -68,19 +68,79 @@ "elements": [ { "type": "variable", - "name": "test", + "name": "mySistersAddress", "source_mapping": { - "start": 237, - "length": 20, + "start": 496, + "length": 76, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "is_dependency": false, "lines": [ - 10 + 26 ], "starting_column": 5, - "ending_column": 25 + "ending_column": 81 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "B", + "source_mapping": { + "start": 473, + "length": 271, + "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "B.mySistersAddress (tests/detectors/constable-states/0.4.25/const_state_variables.sol#26) should be constant \n", + "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L26) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L26", + "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "myFriendsAddress", + "source_mapping": { + "start": 132, + "length": 76, + "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 7 + ], + "starting_column": 5, + "ending_column": 81 }, "type_specific_fields": { "parent": { @@ -120,10 +180,10 @@ } } ], - "description": "A.test (tests/detectors/constable-states/0.4.25/const_state_variables.sol#10) should be constant\n", - "markdown": "[A.test](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L10) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L10", - "id": "5d9e3fb413322b71a93e90f7e89bd8c83cd4884d577d039598c681fe9db38b1d", + "description": "A.myFriendsAddress (tests/detectors/constable-states/0.4.25/const_state_variables.sol#7) should be constant \n", + "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L7) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L7", + "id": "52fd72f6870c4b504d1bcf9fb44249658e2077474d66208a33a47d2668b8db49", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -132,19 +192,19 @@ "elements": [ { "type": "variable", - "name": "should_be_constant_2", + "name": "should_be_constant", "source_mapping": { - "start": 841, - "length": 33, + "start": 793, + "length": 42, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "is_dependency": false, "lines": [ - 43 + 42 ], "starting_column": 5, - "ending_column": 38 + "ending_column": 47 }, "type_specific_fields": { "parent": { @@ -180,70 +240,10 @@ } } ], - "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.4.25/const_state_variables.sol#43) should be constant\n", - "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L43) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L43", - "id": "9a48a4122de1a6a4774a9f1e0d4917bd0fa08f17b4af41b86ba07689e51bf711", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "mySistersAddress", - "source_mapping": { - "start": 496, - "length": 76, - "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 26 - ], - "starting_column": 5, - "ending_column": 81 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "B", - "source_mapping": { - "start": 473, - "length": 271, - "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "B.mySistersAddress (tests/detectors/constable-states/0.4.25/const_state_variables.sol#26) should be constant\n", - "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L26) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L26", - "id": "bee93a722c8eae4a48aade67d8ef537d84c106f48fc9eb738c795fce10d3bc63", + "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.4.25/const_state_variables.sol#42) should be constant \n", + "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L42) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L42", + "id": "8d08797efc8230b480ec669c7e2bf53c3b3d16bc59bf7770934b34fd892934f8", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -252,19 +252,19 @@ "elements": [ { "type": "variable", - "name": "should_be_constant", + "name": "should_be_constant_2", "source_mapping": { - "start": 793, - "length": 42, + "start": 841, + "length": 33, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "is_dependency": false, "lines": [ - 42 + 43 ], "starting_column": 5, - "ending_column": 47 + "ending_column": 38 }, "type_specific_fields": { "parent": { @@ -300,10 +300,10 @@ } } ], - "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.4.25/const_state_variables.sol#42) should be constant\n", - "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L42) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L42", - "id": "cbcafa2a3efba4d21ac1b51b4b823e5082d556bc3d6cf3fd2ab3188f9f218fc1", + "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.4.25/const_state_variables.sol#43) should be constant \n", + "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L43) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L43", + "id": "d08c6d1e331083b42c45c222691dd1e6d880814c66d114971875337ca61ba9c9", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -312,16 +312,16 @@ "elements": [ { "type": "variable", - "name": "text2", + "name": "test", "source_mapping": { - "start": 333, + "start": 237, "length": 20, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "is_dependency": false, "lines": [ - 14 + 10 ], "starting_column": 5, "ending_column": 25 @@ -364,10 +364,10 @@ } } ], - "description": "A.text2 (tests/detectors/constable-states/0.4.25/const_state_variables.sol#14) should be constant\n", - "markdown": "[A.text2](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L14) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L14", - "id": "df11e6201c4558a8c5cd90b55b134b9ca8f07203b2264d3aa93bd7745e8cb4ba", + "description": "A.test (tests/detectors/constable-states/0.4.25/const_state_variables.sol#10) should be constant \n", + "markdown": "[A.test](tests/detectors/constable-states/0.4.25/const_state_variables.sol#L10) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.4.25/const_state_variables.sol#L10", + "id": "e407a1b57b4d25949ef7c4e6d97197605857099a94774a9c7a848d7dd3463668", "check": "constable-states", "impact": "Optimization", "confidence": "High" diff --git a/tests/detectors/constable-states/0.5.16/const_state_variables.sol b/tests/detectors/constable-states/0.5.16/const_state_variables.sol index aed05d97f..7d018ca2d 100644 --- a/tests/detectors/constable-states/0.5.16/const_state_variables.sol +++ b/tests/detectors/constable-states/0.5.16/const_state_variables.sol @@ -41,6 +41,7 @@ contract MyConc{ uint constant A = 1; bytes32 should_be_constant = sha256('abc'); uint should_be_constant_2 = A + 1; + B should_be_constant_3 = B(address(0)); address not_constant = msg.sender; uint not_constant_2 = getNumber(); uint not_constant_3 = 10 + block.number; diff --git a/tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.ConstCandidateStateVars.json index 9b435a4a8..36de0ff0b 100644 --- a/tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.ConstCandidateStateVars.json @@ -4,50 +4,47 @@ "elements": [ { "type": "variable", - "name": "myFriendsAddress", + "name": "should_be_constant_3", "source_mapping": { - "start": 132, - "length": 76, + "start": 880, + "length": 38, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "is_dependency": false, "lines": [ - 7 + 44 ], "starting_column": 5, - "ending_column": 81 + "ending_column": 43 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "A", + "name": "MyConc", "source_mapping": { - "start": 29, - "length": 441, + "start": 746, + "length": 386, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "is_dependency": false, "lines": [ - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21 + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53 ], "starting_column": 1, "ending_column": 2 @@ -56,10 +53,10 @@ } } ], - "description": "A.myFriendsAddress (tests/detectors/constable-states/0.5.16/const_state_variables.sol#7) should be constant\n", - "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L7) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L7", - "id": "1454db80653b732bf6acbe54ff0ae4707002207a2a8216708c12d61c88a43e5f", + "description": "MyConc.should_be_constant_3 (tests/detectors/constable-states/0.5.16/const_state_variables.sol#44) should be constant \n", + "markdown": "[MyConc.should_be_constant_3](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L44) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L44", + "id": "29247b0a9939e854ad51bf3b2f58705156aa8b7e446e646b1832467d362b5b3e", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -68,16 +65,16 @@ "elements": [ { "type": "variable", - "name": "test", + "name": "text2", "source_mapping": { - "start": 237, + "start": 333, "length": 20, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "is_dependency": false, "lines": [ - 10 + 14 ], "starting_column": 5, "ending_column": 25 @@ -120,10 +117,10 @@ } } ], - "description": "A.test (tests/detectors/constable-states/0.5.16/const_state_variables.sol#10) should be constant\n", - "markdown": "[A.test](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L10) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L10", - "id": "5d9e3fb413322b71a93e90f7e89bd8c83cd4884d577d039598c681fe9db38b1d", + "description": "A.text2 (tests/detectors/constable-states/0.5.16/const_state_variables.sol#14) should be constant \n", + "markdown": "[A.text2](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L14) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L14", + "id": "2f06e04545cea7e7a8998c65d5419f335bf2579a6ce6a832eac9c87392fd5c1a", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -132,46 +129,46 @@ "elements": [ { "type": "variable", - "name": "should_be_constant_2", + "name": "mySistersAddress", "source_mapping": { - "start": 841, - "length": 33, + "start": 496, + "length": 76, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "is_dependency": false, "lines": [ - 43 + 26 ], "starting_column": 5, - "ending_column": 38 + "ending_column": 81 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "B", "source_mapping": { - "start": 746, - "length": 342, + "start": 473, + "length": 271, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "is_dependency": false, "lines": [ - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37 ], "starting_column": 1, "ending_column": 2 @@ -180,10 +177,10 @@ } } ], - "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.5.16/const_state_variables.sol#43) should be constant\n", - "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L43) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L43", - "id": "9a48a4122de1a6a4774a9f1e0d4917bd0fa08f17b4af41b86ba07689e51bf711", + "description": "B.mySistersAddress (tests/detectors/constable-states/0.5.16/const_state_variables.sol#26) should be constant \n", + "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L26) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L26", + "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -192,16 +189,16 @@ "elements": [ { "type": "variable", - "name": "mySistersAddress", + "name": "myFriendsAddress", "source_mapping": { - "start": 496, + "start": 132, "length": 76, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "is_dependency": false, "lines": [ - 26 + 7 ], "starting_column": 5, "ending_column": 81 @@ -209,29 +206,33 @@ "type_specific_fields": { "parent": { "type": "contract", - "name": "B", + "name": "A", "source_mapping": { - "start": 473, - "length": 271, + "start": 29, + "length": 441, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "is_dependency": false, "lines": [ - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37 + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21 ], "starting_column": 1, "ending_column": 2 @@ -240,10 +241,10 @@ } } ], - "description": "B.mySistersAddress (tests/detectors/constable-states/0.5.16/const_state_variables.sol#26) should be constant\n", - "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L26) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L26", - "id": "bee93a722c8eae4a48aade67d8ef537d84c106f48fc9eb738c795fce10d3bc63", + "description": "A.myFriendsAddress (tests/detectors/constable-states/0.5.16/const_state_variables.sol#7) should be constant \n", + "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L7) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L7", + "id": "52fd72f6870c4b504d1bcf9fb44249658e2077474d66208a33a47d2668b8db49", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -272,7 +273,7 @@ "name": "MyConc", "source_mapping": { "start": 746, - "length": 342, + "length": 386, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", @@ -291,7 +292,8 @@ 49, 50, 51, - 52 + 52, + 53 ], "starting_column": 1, "ending_column": 2 @@ -300,10 +302,10 @@ } } ], - "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.5.16/const_state_variables.sol#42) should be constant\n", - "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L42) should be constant\n", + "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.5.16/const_state_variables.sol#42) should be constant \n", + "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L42) should be constant \n", "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L42", - "id": "cbcafa2a3efba4d21ac1b51b4b823e5082d556bc3d6cf3fd2ab3188f9f218fc1", + "id": "8d08797efc8230b480ec669c7e2bf53c3b3d16bc59bf7770934b34fd892934f8", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -312,16 +314,77 @@ "elements": [ { "type": "variable", - "name": "text2", + "name": "should_be_constant_2", "source_mapping": { - "start": 333, + "start": 841, + "length": 33, + "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 43 + ], + "starting_column": 5, + "ending_column": 38 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 746, + "length": 386, + "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.5.16/const_state_variables.sol#43) should be constant \n", + "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L43) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L43", + "id": "d08c6d1e331083b42c45c222691dd1e6d880814c66d114971875337ca61ba9c9", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "test", + "source_mapping": { + "start": 237, "length": 20, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "is_dependency": false, "lines": [ - 14 + 10 ], "starting_column": 5, "ending_column": 25 @@ -364,10 +427,10 @@ } } ], - "description": "A.text2 (tests/detectors/constable-states/0.5.16/const_state_variables.sol#14) should be constant\n", - "markdown": "[A.text2](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L14) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L14", - "id": "df11e6201c4558a8c5cd90b55b134b9ca8f07203b2264d3aa93bd7745e8cb4ba", + "description": "A.test (tests/detectors/constable-states/0.5.16/const_state_variables.sol#10) should be constant \n", + "markdown": "[A.test](tests/detectors/constable-states/0.5.16/const_state_variables.sol#L10) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.5.16/const_state_variables.sol#L10", + "id": "e407a1b57b4d25949ef7c4e6d97197605857099a94774a9c7a848d7dd3463668", "check": "constable-states", "impact": "Optimization", "confidence": "High" diff --git a/tests/detectors/constable-states/0.6.11/const_state_variables.sol b/tests/detectors/constable-states/0.6.11/const_state_variables.sol index 3b0c1a436..66415fd9d 100644 --- a/tests/detectors/constable-states/0.6.11/const_state_variables.sol +++ b/tests/detectors/constable-states/0.6.11/const_state_variables.sol @@ -1,5 +1,3 @@ -//pragma solidity ^0.4.24; - contract A { @@ -36,15 +34,17 @@ contract B is A { } } -contract MyConc{ +contract MyConc { uint constant A = 1; bytes32 should_be_constant = sha256('abc'); uint should_be_constant_2 = A + 1; + B should_be_constant_3 = B(address(0)); address not_constant = msg.sender; uint not_constant_2 = getNumber(); uint not_constant_3 = 10 + block.number; - + B not_constant_4 = new B(); + function getNumber() public returns(uint){ return block.number; } diff --git a/tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.ConstCandidateStateVars.json index 3c7812877..cbb8ecbc1 100644 --- a/tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.ConstCandidateStateVars.json @@ -4,50 +4,48 @@ "elements": [ { "type": "variable", - "name": "myFriendsAddress", + "name": "should_be_constant_3", "source_mapping": { - "start": 132, - "length": 76, + "start": 853, + "length": 38, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 7 + 42 ], "starting_column": 5, - "ending_column": 81 + "ending_column": 43 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "A", + "name": "MyConc", "source_mapping": { - "start": 29, - "length": 441, + "start": 718, + "length": 415, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19, - 20, - 21 + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 ], "starting_column": 1, "ending_column": 2 @@ -56,10 +54,10 @@ } } ], - "description": "A.myFriendsAddress (tests/detectors/constable-states/0.6.11/const_state_variables.sol#7) should be constant\n", - "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L7) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L7", - "id": "1454db80653b732bf6acbe54ff0ae4707002207a2a8216708c12d61c88a43e5f", + "description": "MyConc.should_be_constant_3 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#42) should be constant \n", + "markdown": "[MyConc.should_be_constant_3](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L42) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L42", + "id": "29247b0a9939e854ad51bf3b2f58705156aa8b7e446e646b1832467d362b5b3e", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -68,16 +66,16 @@ "elements": [ { "type": "variable", - "name": "test", + "name": "text2", "source_mapping": { - "start": 237, + "start": 305, "length": 20, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 10 + 12 ], "starting_column": 5, "ending_column": 25 @@ -87,13 +85,15 @@ "type": "contract", "name": "A", "source_mapping": { - "start": 29, + "start": 1, "length": 441, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ + 2, + 3, 4, 5, 6, @@ -109,9 +109,7 @@ 16, 17, 18, - 19, - 20, - 21 + 19 ], "starting_column": 1, "ending_column": 2 @@ -120,10 +118,10 @@ } } ], - "description": "A.test (tests/detectors/constable-states/0.6.11/const_state_variables.sol#10) should be constant\n", - "markdown": "[A.test](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L10) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L10", - "id": "5d9e3fb413322b71a93e90f7e89bd8c83cd4884d577d039598c681fe9db38b1d", + "description": "A.text2 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#12) should be constant \n", + "markdown": "[A.text2](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L12) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L12", + "id": "2f06e04545cea7e7a8998c65d5419f335bf2579a6ce6a832eac9c87392fd5c1a", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -132,46 +130,46 @@ "elements": [ { "type": "variable", - "name": "should_be_constant_2", + "name": "mySistersAddress", "source_mapping": { - "start": 841, - "length": 33, + "start": 468, + "length": 76, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 43 + 24 ], "starting_column": 5, - "ending_column": 38 + "ending_column": 81 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "B", "source_mapping": { - "start": 746, - "length": 342, + "start": 445, + "length": 271, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35 ], "starting_column": 1, "ending_column": 2 @@ -180,10 +178,10 @@ } } ], - "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#43) should be constant\n", - "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L43) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L43", - "id": "9a48a4122de1a6a4774a9f1e0d4917bd0fa08f17b4af41b86ba07689e51bf711", + "description": "B.mySistersAddress (tests/detectors/constable-states/0.6.11/const_state_variables.sol#24) should be constant \n", + "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L24) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L24", + "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -192,16 +190,16 @@ "elements": [ { "type": "variable", - "name": "mySistersAddress", + "name": "myFriendsAddress", "source_mapping": { - "start": 496, + "start": 104, "length": 76, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 26 + 5 ], "starting_column": 5, "ending_column": 81 @@ -209,29 +207,33 @@ "type_specific_fields": { "parent": { "type": "contract", - "name": "B", + "name": "A", "source_mapping": { - "start": 473, - "length": 271, + "start": 1, + "length": 441, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37 + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 ], "starting_column": 1, "ending_column": 2 @@ -240,10 +242,10 @@ } } ], - "description": "B.mySistersAddress (tests/detectors/constable-states/0.6.11/const_state_variables.sol#26) should be constant\n", - "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L26) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L26", - "id": "bee93a722c8eae4a48aade67d8ef537d84c106f48fc9eb738c795fce10d3bc63", + "description": "A.myFriendsAddress (tests/detectors/constable-states/0.6.11/const_state_variables.sol#5) should be constant \n", + "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L5) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L5", + "id": "52fd72f6870c4b504d1bcf9fb44249658e2077474d66208a33a47d2668b8db49", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -254,14 +256,14 @@ "type": "variable", "name": "should_be_constant", "source_mapping": { - "start": 793, + "start": 766, "length": 42, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 42 + 40 ], "starting_column": 5, "ending_column": 47 @@ -271,13 +273,15 @@ "type": "contract", "name": "MyConc", "source_mapping": { - "start": 746, - "length": 342, + "start": 718, + "length": 415, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ + 37, + 38, 39, 40, 41, @@ -300,10 +304,10 @@ } } ], - "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.6.11/const_state_variables.sol#42) should be constant\n", - "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L42) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L42", - "id": "cbcafa2a3efba4d21ac1b51b4b823e5082d556bc3d6cf3fd2ab3188f9f218fc1", + "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.6.11/const_state_variables.sol#40) should be constant \n", + "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L40) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L40", + "id": "8d08797efc8230b480ec669c7e2bf53c3b3d16bc59bf7770934b34fd892934f8", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -312,16 +316,78 @@ "elements": [ { "type": "variable", - "name": "text2", + "name": "should_be_constant_2", + "source_mapping": { + "start": 814, + "length": 33, + "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 41 + ], + "starting_column": 5, + "ending_column": 38 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 415, + "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#41) should be constant \n", + "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L41) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L41", + "id": "d08c6d1e331083b42c45c222691dd1e6d880814c66d114971875337ca61ba9c9", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "test", "source_mapping": { - "start": 333, + "start": 209, "length": 20, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 14 + 8 ], "starting_column": 5, "ending_column": 25 @@ -331,13 +397,15 @@ "type": "contract", "name": "A", "source_mapping": { - "start": 29, + "start": 1, "length": 441, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ + 2, + 3, 4, 5, 6, @@ -353,9 +421,7 @@ 16, 17, 18, - 19, - 20, - 21 + 19 ], "starting_column": 1, "ending_column": 2 @@ -364,10 +430,10 @@ } } ], - "description": "A.text2 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#14) should be constant\n", - "markdown": "[A.text2](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L14) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L14", - "id": "df11e6201c4558a8c5cd90b55b134b9ca8f07203b2264d3aa93bd7745e8cb4ba", + "description": "A.test (tests/detectors/constable-states/0.6.11/const_state_variables.sol#8) should be constant \n", + "markdown": "[A.test](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L8) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L8", + "id": "e407a1b57b4d25949ef7c4e6d97197605857099a94774a9c7a848d7dd3463668", "check": "constable-states", "impact": "Optimization", "confidence": "High" diff --git a/tests/detectors/constable-states/0.7.6/const_state_variables.sol b/tests/detectors/constable-states/0.7.6/const_state_variables.sol index 3b0c1a436..93292dc47 100644 --- a/tests/detectors/constable-states/0.7.6/const_state_variables.sol +++ b/tests/detectors/constable-states/0.7.6/const_state_variables.sol @@ -1,5 +1,3 @@ -//pragma solidity ^0.4.24; - contract A { @@ -36,15 +34,17 @@ contract B is A { } } -contract MyConc{ +contract MyConc { uint constant A = 1; bytes32 should_be_constant = sha256('abc'); uint should_be_constant_2 = A + 1; - address not_constant = msg.sender; - uint not_constant_2 = getNumber(); - uint not_constant_3 = 10 + block.number; - + B should_be_constant_3 = B(address(0)); + address should_be_immutable = msg.sender; + uint should_be_immutable_2 = getNumber(); + uint should_be_immutable_3 = 10 + block.number; + B should_be_immutable_4 = new B(); + function getNumber() public returns(uint){ return block.number; } diff --git a/tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.ConstCandidateStateVars.json index 3cb6d44c4..18c869d56 100644 --- a/tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.ConstCandidateStateVars.json @@ -4,32 +4,96 @@ "elements": [ { "type": "variable", - "name": "myFriendsAddress", + "name": "should_be_constant_3", "source_mapping": { - "start": 132, - "length": 76, + "start": 853, + "length": 38, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 7 + 42 ], "starting_column": 5, - "ending_column": 81 + "ending_column": 43 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_constant_3 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#42) should be constant \n", + "markdown": "[MyConc.should_be_constant_3](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L42) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L42", + "id": "29247b0a9939e854ad51bf3b2f58705156aa8b7e446e646b1832467d362b5b3e", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "text2", + "source_mapping": { + "start": 305, + "length": 20, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 12 + ], + "starting_column": 5, + "ending_column": 25 }, "type_specific_fields": { "parent": { "type": "contract", "name": "A", "source_mapping": { - "start": 29, + "start": 1, "length": 441, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ + 2, + 3, 4, 5, 6, @@ -45,9 +109,7 @@ 16, 17, 18, - 19, - 20, - 21 + 19 ], "starting_column": 1, "ending_column": 2 @@ -56,10 +118,10 @@ } } ], - "description": "A.myFriendsAddress (tests/detectors/constable-states/0.7.6/const_state_variables.sol#7) should be constant\n", - "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L7) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L7", - "id": "1454db80653b732bf6acbe54ff0ae4707002207a2a8216708c12d61c88a43e5f", + "description": "A.text2 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#12) should be constant \n", + "markdown": "[A.text2](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L12) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L12", + "id": "2f06e04545cea7e7a8998c65d5419f335bf2579a6ce6a832eac9c87392fd5c1a", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -68,32 +130,156 @@ "elements": [ { "type": "variable", - "name": "test", + "name": "mySistersAddress", "source_mapping": { - "start": 237, - "length": 20, + "start": 468, + "length": 76, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 10 + 24 ], "starting_column": 5, - "ending_column": 25 + "ending_column": 81 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "B", + "source_mapping": { + "start": 445, + "length": 271, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "B.mySistersAddress (tests/detectors/constable-states/0.7.6/const_state_variables.sol#24) should be constant \n", + "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L24) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L24", + "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable", + "source_mapping": { + "start": 897, + "length": 40, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 43 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_immutable (tests/detectors/constable-states/0.7.6/const_state_variables.sol#43) should be immutable \n", + "markdown": "[MyConc.should_be_immutable](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L43) should be immutable \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L43", + "id": "3cabd54a4d3fa32f960965a41bb09b62052286195b47b2b7db670f87e8df21bf", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "myFriendsAddress", + "source_mapping": { + "start": 104, + "length": 76, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 5 + ], + "starting_column": 5, + "ending_column": 81 }, "type_specific_fields": { "parent": { "type": "contract", "name": "A", "source_mapping": { - "start": 29, + "start": 1, "length": 441, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ + 2, + 3, 4, 5, 6, @@ -109,9 +295,7 @@ 16, 17, 18, - 19, - 20, - 21 + 19 ], "starting_column": 1, "ending_column": 2 @@ -120,10 +304,10 @@ } } ], - "description": "A.test (tests/detectors/constable-states/0.7.6/const_state_variables.sol#10) should be constant\n", - "markdown": "[A.test](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L10) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L10", - "id": "5d9e3fb413322b71a93e90f7e89bd8c83cd4884d577d039598c681fe9db38b1d", + "description": "A.myFriendsAddress (tests/detectors/constable-states/0.7.6/const_state_variables.sol#5) should be constant \n", + "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L5) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L5", + "id": "52fd72f6870c4b504d1bcf9fb44249658e2077474d66208a33a47d2668b8db49", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -132,16 +316,78 @@ "elements": [ { "type": "variable", - "name": "should_be_constant_2", + "name": "should_be_constant", "source_mapping": { - "start": 841, + "start": 766, + "length": 42, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 40 + ], + "starting_column": 5, + "ending_column": 47 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.7.6/const_state_variables.sol#40) should be constant \n", + "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L40) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L40", + "id": "8d08797efc8230b480ec669c7e2bf53c3b3d16bc59bf7770934b34fd892934f8", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_4", + "source_mapping": { + "start": 1041, "length": 33, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 43 + 46 ], "starting_column": 5, "ending_column": 38 @@ -151,13 +397,15 @@ "type": "contract", "name": "MyConc", "source_mapping": { - "start": 746, - "length": 342, + "start": 718, + "length": 443, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ + 37, + 38, 39, 40, 41, @@ -180,10 +428,10 @@ } } ], - "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#43) should be constant\n", - "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L43) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L43", - "id": "9a48a4122de1a6a4774a9f1e0d4917bd0fa08f17b4af41b86ba07689e51bf711", + "description": "MyConc.should_be_immutable_4 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#46) should be immutable \n", + "markdown": "[MyConc.should_be_immutable_4](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L46) should be immutable \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L46", + "id": "a15e34bd516e604d7ba3e0746ad0234d0baea38da2e747648316d5d15ee9b3bc", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -192,46 +440,48 @@ "elements": [ { "type": "variable", - "name": "mySistersAddress", + "name": "should_be_immutable_2", "source_mapping": { - "start": 496, - "length": 76, + "start": 943, + "length": 40, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 26 + 44 ], "starting_column": 5, - "ending_column": 81 + "ending_column": 45 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "B", + "name": "MyConc", "source_mapping": { - "start": 473, - "length": 271, + "start": 718, + "length": 443, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35, - 36, - 37 + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 ], "starting_column": 1, "ending_column": 2 @@ -240,10 +490,10 @@ } } ], - "description": "B.mySistersAddress (tests/detectors/constable-states/0.7.6/const_state_variables.sol#26) should be constant\n", - "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L26) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L26", - "id": "bee93a722c8eae4a48aade67d8ef537d84c106f48fc9eb738c795fce10d3bc63", + "description": "MyConc.should_be_immutable_2 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#44) should be immutable \n", + "markdown": "[MyConc.should_be_immutable_2](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L44) should be immutable \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L44", + "id": "cb6df1f1ce2f32505c81f257863ceef6d5145ee5a2835af1c6719ad695d145e2", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -252,32 +502,34 @@ "elements": [ { "type": "variable", - "name": "should_be_constant", + "name": "should_be_constant_2", "source_mapping": { - "start": 793, - "length": 42, + "start": 814, + "length": 33, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 42 + 41 ], "starting_column": 5, - "ending_column": 47 + "ending_column": 38 }, "type_specific_fields": { "parent": { "type": "contract", "name": "MyConc", "source_mapping": { - "start": 746, - "length": 342, + "start": 718, + "length": 443, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ + 37, + 38, 39, 40, 41, @@ -300,10 +552,10 @@ } } ], - "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.7.6/const_state_variables.sol#42) should be constant\n", - "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L42) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L42", - "id": "cbcafa2a3efba4d21ac1b51b4b823e5082d556bc3d6cf3fd2ab3188f9f218fc1", + "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#41) should be constant \n", + "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L41) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L41", + "id": "d08c6d1e331083b42c45c222691dd1e6d880814c66d114971875337ca61ba9c9", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -312,16 +564,78 @@ "elements": [ { "type": "variable", - "name": "text2", + "name": "should_be_immutable_3", + "source_mapping": { + "start": 989, + "length": 46, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 45 + ], + "starting_column": 5, + "ending_column": 51 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_immutable_3 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#45) should be immutable \n", + "markdown": "[MyConc.should_be_immutable_3](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L45) should be immutable \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L45", + "id": "dc5903ef8f6ec62f53df486fa768a0d817643efe30c90c1308079eee99c316d4", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "test", "source_mapping": { - "start": 333, + "start": 209, "length": 20, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 14 + 8 ], "starting_column": 5, "ending_column": 25 @@ -331,13 +645,15 @@ "type": "contract", "name": "A", "source_mapping": { - "start": 29, + "start": 1, "length": 441, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ + 2, + 3, 4, 5, 6, @@ -353,9 +669,7 @@ 16, 17, 18, - 19, - 20, - 21 + 19 ], "starting_column": 1, "ending_column": 2 @@ -364,10 +678,10 @@ } } ], - "description": "A.text2 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#14) should be constant\n", - "markdown": "[A.text2](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L14) should be constant\n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L14", - "id": "df11e6201c4558a8c5cd90b55b134b9ca8f07203b2264d3aa93bd7745e8cb4ba", + "description": "A.test (tests/detectors/constable-states/0.7.6/const_state_variables.sol#8) should be constant \n", + "markdown": "[A.test](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L8) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L8", + "id": "e407a1b57b4d25949ef7c4e6d97197605857099a94774a9c7a848d7dd3463668", "check": "constable-states", "impact": "Optimization", "confidence": "High" diff --git a/tests/detectors/constable-states/0.8.0/const_state_variables.sol b/tests/detectors/constable-states/0.8.0/const_state_variables.sol new file mode 100644 index 000000000..93292dc47 --- /dev/null +++ b/tests/detectors/constable-states/0.8.0/const_state_variables.sol @@ -0,0 +1,52 @@ + +contract A { + + address constant public MY_ADDRESS = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; + address public myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979; + + uint public used; + uint public test = 5; + + uint constant X = 32**22 + 8; + string constant TEXT1 = "abc"; + string text2 = "xyz"; + + function setUsed() public { + if (msg.sender == MY_ADDRESS) { + used = test; + } + } +} + + +contract B is A { + + address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; + + fallback () external { + used = 0; + } + + function setUsed(uint a) public { + if (msg.sender == MY_ADDRESS) { + used = a; + } + } +} + +contract MyConc { + + uint constant A = 1; + bytes32 should_be_constant = sha256('abc'); + uint should_be_constant_2 = A + 1; + B should_be_constant_3 = B(address(0)); + address should_be_immutable = msg.sender; + uint should_be_immutable_2 = getNumber(); + uint should_be_immutable_3 = 10 + block.number; + B should_be_immutable_4 = new B(); + + function getNumber() public returns(uint){ + return block.number; + } + +} diff --git a/tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.ConstCandidateStateVars.json new file mode 100644 index 000000000..e36a2988d --- /dev/null +++ b/tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.ConstCandidateStateVars.json @@ -0,0 +1,690 @@ +[ + [ + { + "elements": [ + { + "type": "variable", + "name": "should_be_constant_3", + "source_mapping": { + "start": 853, + "length": 38, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 42 + ], + "starting_column": 5, + "ending_column": 43 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_constant_3 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#42) should be constant \n", + "markdown": "[MyConc.should_be_constant_3](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L42) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L42", + "id": "29247b0a9939e854ad51bf3b2f58705156aa8b7e446e646b1832467d362b5b3e", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "text2", + "source_mapping": { + "start": 305, + "length": 20, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 12 + ], + "starting_column": 5, + "ending_column": 25 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "A", + "source_mapping": { + "start": 1, + "length": 441, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "A.text2 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#12) should be constant \n", + "markdown": "[A.text2](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L12) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L12", + "id": "2f06e04545cea7e7a8998c65d5419f335bf2579a6ce6a832eac9c87392fd5c1a", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "mySistersAddress", + "source_mapping": { + "start": 468, + "length": 76, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 24 + ], + "starting_column": 5, + "ending_column": 81 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "B", + "source_mapping": { + "start": 445, + "length": 271, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "B.mySistersAddress (tests/detectors/constable-states/0.8.0/const_state_variables.sol#24) should be constant \n", + "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L24) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L24", + "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable", + "source_mapping": { + "start": 897, + "length": 40, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 43 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_immutable (tests/detectors/constable-states/0.8.0/const_state_variables.sol#43) should be immutable \n", + "markdown": "[MyConc.should_be_immutable](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L43) should be immutable \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L43", + "id": "3cabd54a4d3fa32f960965a41bb09b62052286195b47b2b7db670f87e8df21bf", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "myFriendsAddress", + "source_mapping": { + "start": 104, + "length": 76, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 5 + ], + "starting_column": 5, + "ending_column": 81 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "A", + "source_mapping": { + "start": 1, + "length": 441, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "A.myFriendsAddress (tests/detectors/constable-states/0.8.0/const_state_variables.sol#5) should be constant \n", + "markdown": "[A.myFriendsAddress](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L5) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L5", + "id": "52fd72f6870c4b504d1bcf9fb44249658e2077474d66208a33a47d2668b8db49", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_constant", + "source_mapping": { + "start": 766, + "length": 42, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 40 + ], + "starting_column": 5, + "ending_column": 47 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.8.0/const_state_variables.sol#40) should be constant \n", + "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L40) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L40", + "id": "8d08797efc8230b480ec669c7e2bf53c3b3d16bc59bf7770934b34fd892934f8", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_4", + "source_mapping": { + "start": 1041, + "length": 33, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 46 + ], + "starting_column": 5, + "ending_column": 38 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_immutable_4 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#46) should be immutable \n", + "markdown": "[MyConc.should_be_immutable_4](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L46) should be immutable \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L46", + "id": "a15e34bd516e604d7ba3e0746ad0234d0baea38da2e747648316d5d15ee9b3bc", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_2", + "source_mapping": { + "start": 943, + "length": 40, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 44 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_immutable_2 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#44) should be immutable \n", + "markdown": "[MyConc.should_be_immutable_2](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L44) should be immutable \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L44", + "id": "cb6df1f1ce2f32505c81f257863ceef6d5145ee5a2835af1c6719ad695d145e2", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_constant_2", + "source_mapping": { + "start": 814, + "length": 33, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 41 + ], + "starting_column": 5, + "ending_column": 38 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#41) should be constant \n", + "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L41) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L41", + "id": "d08c6d1e331083b42c45c222691dd1e6d880814c66d114971875337ca61ba9c9", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_3", + "source_mapping": { + "start": 989, + "length": 46, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 45 + ], + "starting_column": 5, + "ending_column": 51 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "MyConc", + "source_mapping": { + "start": 718, + "length": 443, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "MyConc.should_be_immutable_3 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#45) should be immutable \n", + "markdown": "[MyConc.should_be_immutable_3](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L45) should be immutable \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L45", + "id": "dc5903ef8f6ec62f53df486fa768a0d817643efe30c90c1308079eee99c316d4", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "test", + "source_mapping": { + "start": 209, + "length": 20, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 8 + ], + "starting_column": 5, + "ending_column": 25 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "A", + "source_mapping": { + "start": 1, + "length": 441, + "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", + "is_dependency": false, + "lines": [ + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "A.test (tests/detectors/constable-states/0.8.0/const_state_variables.sol#8) should be constant \n", + "markdown": "[A.test](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L8) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L8", + "id": "e407a1b57b4d25949ef7c4e6d97197605857099a94774a9c7a848d7dd3463668", + "check": "constable-states", + "impact": "Optimization", + "confidence": "High" + } + ] +] \ No newline at end of file diff --git a/tests/detectors/constable-states/0.8.0/immutable.sol b/tests/detectors/constable-states/0.8.0/immutable.sol deleted file mode 100644 index aeb9fbfa7..000000000 --- a/tests/detectors/constable-states/0.8.0/immutable.sol +++ /dev/null @@ -1,7 +0,0 @@ -contract C{ - uint immutable v; - - constructor() public{ - v = 0; - } -} diff --git a/tests/detectors/constable-states/0.8.0/immutable.sol.0.8.0.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.8.0/immutable.sol.0.8.0.ConstCandidateStateVars.json deleted file mode 100644 index 5825bcacc..000000000 --- a/tests/detectors/constable-states/0.8.0/immutable.sol.0.8.0.ConstCandidateStateVars.json +++ /dev/null @@ -1,3 +0,0 @@ -[ - [] -] \ No newline at end of file diff --git a/tests/test_detectors.py b/tests/test_detectors.py index 7a27e2d4b..46fff79b0 100644 --- a/tests/test_detectors.py +++ b/tests/test_detectors.py @@ -497,7 +497,7 @@ ALL_TEST_OBJECTS = [ ), Test( all_detectors.ConstCandidateStateVars, - "immutable.sol", + "const_state_variables.sol", "0.8.0", ), Test( From cf5d04f2901c02fc942a978d26373550bd4c8ffb Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 28 Nov 2022 08:33:00 -0600 Subject: [PATCH 009/110] ignore openzeppelin contracts --- .../variables/possible_const_state_variables.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/slither/detectors/variables/possible_const_state_variables.py b/slither/detectors/variables/possible_const_state_variables.py index 4337b3075..60a45dfac 100644 --- a/slither/detectors/variables/possible_const_state_variables.py +++ b/slither/detectors/variables/possible_const_state_variables.py @@ -15,6 +15,7 @@ from slither.core.declarations.solidity_variables import SolidityFunction from slither.core.variables.state_variable import StateVariable from slither.formatters.variables.possible_const_state_variables import custom_format from slither.core.expressions import CallExpression, NewContract +from slither.utils.standard_libraries import is_openzeppelin def _is_valid_type(v: StateVariable) -> bool: @@ -84,10 +85,8 @@ class ConstCandidateStateVars(AbstractDetector): values = export.result() if not values: return True - else: - return all( - (val in self.valid_solidity_function or _is_constant_var(val) for val in values) - ) + + return all((val in self.valid_solidity_function or _is_constant_var(val) for val in values)) def _detect(self) -> List[Output]: """Detect state variables that could be constant or immutable""" @@ -96,6 +95,8 @@ class ConstCandidateStateVars(AbstractDetector): variables = [] functions = [] for c in self.compilation_unit.contracts: + if is_openzeppelin(c): + continue variables.append(c.state_variables) functions.append(c.all_functions_called) From cfb53e8200e6d598ab4e7b8447697f3ef29a1fa5 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Sat, 3 Dec 2022 12:06:37 -0600 Subject: [PATCH 010/110] support ternary in call value --- slither/utils/expression_manipulations.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index 1a300c39b..3e12ae8c1 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -28,15 +28,18 @@ def f_expressions( e._expressions.append(x) -def f_call(e, x): +def f_call(e: CallExpression, x): e._arguments.append(x) +def f_call_value(e: CallExpression, x): + e._value = x + def f_expression(e, x): e._expression = x -def f_called(e, x): +def f_called(e: CallExpression, x): e._called = x @@ -123,6 +126,15 @@ class SplitTernaryExpression: if self.apply_copy(next_expr, true_expression, false_expression, f_called): self.copy_expression(next_expr, true_expression.called, false_expression.called) + next_expr = expression.call_value + # case of (..).func{value: .. ? .. : ..}() + if self.apply_copy(next_expr, true_expression, false_expression, f_call_value): + self.copy_expression( + next_expr, + true_expression.call_value, + false_expression.call_value, + ) + true_expression._arguments = [] false_expression._arguments = [] From e7aa92bbb055068d3c95f2a3eca612d3ec31c64e Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Mon, 5 Dec 2022 17:57:29 +0100 Subject: [PATCH 011/110] Use Codex to generate solidity documentation --- setup.py | 1 + slither/core/declarations/function.py | 3 + slither/solc_parsing/declarations/function.py | 3 + slither/tools/documentation/README.md | 6 + slither/tools/documentation/__init__.py | 0 slither/tools/documentation/__main__.py | 141 ++++++++++++++++++ 6 files changed, 154 insertions(+) create mode 100644 slither/tools/documentation/README.md create mode 100644 slither/tools/documentation/__init__.py create mode 100644 slither/tools/documentation/__main__.py diff --git a/setup.py b/setup.py index 510efd097..81680a39a 100644 --- a/setup.py +++ b/setup.py @@ -45,6 +45,7 @@ setup( "slither-mutate = slither.tools.mutator.__main__:main", "slither-read-storage = slither.tools.read_storage.__main__:main", "slither-doctor = slither.tools.doctor.__main__:main", + "slither-documentation = slither.tools.documentation.__main__:main", ] }, ) diff --git a/slither/core/declarations/function.py b/slither/core/declarations/function.py index a4624feec..2fdea7210 100644 --- a/slither/core/declarations/function.py +++ b/slither/core/declarations/function.py @@ -220,6 +220,9 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu self._id: Optional[str] = None + # To be improved with a parsing of the documentation + self.has_documentation: bool = False + ################################################################################### ################################################################################### # region General properties diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py index 130375211..40ddba07e 100644 --- a/slither/solc_parsing/declarations/function.py +++ b/slither/solc_parsing/declarations/function.py @@ -91,6 +91,9 @@ class FunctionSolc(CallerContextExpression): Union[LocalVariableSolc, LocalVariableInitFromTupleSolc] ] = [] + if "documentation" in function_data: + function.has_documentation = True + @property def underlying_function(self) -> Function: return self._function diff --git a/slither/tools/documentation/README.md b/slither/tools/documentation/README.md new file mode 100644 index 000000000..2ed90692c --- /dev/null +++ b/slither/tools/documentation/README.md @@ -0,0 +1,6 @@ +# Demo + +This directory contains an example of Slither utility. + +See the [utility documentation](https://github.com/crytic/slither/wiki/Adding-a-new-utility) + diff --git a/slither/tools/documentation/__init__.py b/slither/tools/documentation/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/slither/tools/documentation/__main__.py b/slither/tools/documentation/__main__.py new file mode 100644 index 000000000..b01072d1c --- /dev/null +++ b/slither/tools/documentation/__main__.py @@ -0,0 +1,141 @@ +import argparse +import logging +from typing import Optional, Dict +import os +import openai +from crytic_compile import cryticparser +from slither import Slither +from slither.core.compilation_unit import SlitherCompilationUnit + +from slither.formatters.utils.patches import create_patch, apply_patch, create_diff + +logging.basicConfig() +logging.getLogger("Slither").setLevel(logging.INFO) + +logger = logging.getLogger("Slither-demo") + + +def parse_args() -> argparse.Namespace: + """ + Parse the underlying arguments for the program. + :return: Returns the arguments for the program. + """ + parser = argparse.ArgumentParser(description="Demo", usage="slither-documentation filename") + + parser.add_argument("project", help="The target directory/Solidity file.") + + parser.add_argument( + "--overwrite", help="Overwrite the files (be careful).", action="store_true", default=False + ) + + # Add default arguments from crytic-compile + cryticparser.init(parser) + + return parser.parse_args() + + +def _post_processesing(answer: str, starting_column: int) -> Optional[str]: + """ + Clean answers from codex + + Args: + answer: + starting_column: + + Returns: + + """ + if answer.count("/**") != 1 or answer.count("*/") != 1: + return None + if answer.find("/**") > answer.find("*/"): + return None + answer = answer[answer.find("/**") : answer.find("*/") + 2] + answer_lines = answer.splitlines() + # Add indentation to all the lines, aside the first one + if len(answer_lines) > 0: + answer = ( + answer_lines[0] + + "\n" + + "\n".join([" " * (starting_column - 1) + line for line in answer_lines[1:] if line]) + ) + answer += "\n" + " " * (starting_column - 1) + return answer + return answer_lines[0] + + +def _handle_codex(answer: Dict, starting_column: int) -> Optional[str]: + if "choices" in answer: + if answer["choices"]: + if "text" in answer["choices"][0]: + answer_processed = _post_processesing(answer["choices"][0]["text"], starting_column) + if answer_processed is None: + return None + return answer_processed + return None + +# pylint: disable=too-many-locals +def _handle_compilation_unit(compilation_unit: SlitherCompilationUnit, overwrite: bool) -> None: + all_patches: Dict = {} + + for function in compilation_unit.functions: + if function.source_mapping.is_dependency or function.has_documentation: + continue + prompt = "Create a documentation for the solidity code using natspec (use only notice, dev, params, return)\n" + src_mapping = function.source_mapping + content = compilation_unit.core.source_code[src_mapping.filename.absolute] + start = src_mapping.start + end = src_mapping.start + src_mapping.length + prompt += content[start:end] + answer = openai.Completion.create( # type: ignore + model="text-davinci-003", prompt=prompt, temperature=0, max_tokens=200 + ) + + answer_processed = _handle_codex(answer, src_mapping.starting_column) + if answer_processed is None: + print(f"Codex could not generate a well formatted answer for {function.canonical_name}") + print(answer) + continue + + create_patch(all_patches, src_mapping.filename.absolute, start, start, "", answer_processed) + + # cat math.sol + # slither-documentation math.sol --overwrite + # cat math.sol + # exit + for file in all_patches["patches"]: + original_txt = compilation_unit.core.source_code[file].encode("utf8") + patched_txt = original_txt + + patches = all_patches["patches"][file] + offset = 0 + patches.sort(key=lambda x: x["start"]) + + for patch in patches: + patched_txt, offset = apply_patch(patched_txt, patch, offset) + + if overwrite: + with open(file, "w", encoding="utf8") as f: + f.write(patched_txt.decode("utf8")) + else: + diff = create_diff(compilation_unit, original_txt, patched_txt, file) + with open(f"{file}.patch", "w", encoding="utf8") as f: + f.write(diff) + + +def main() -> None: + args = parse_args() + + slither = Slither(args.project, **vars(args)) + + api_key = os.getenv("OPENAI_API_KEY") + if api_key is None: + print("Please provide an Open API Key (https://beta.openai.com/account/api-keys)") + return + openai.api_key = api_key + + for compilation_unit in slither.compilation_units: + _handle_compilation_unit(compilation_unit, args.overwrite) + + +if __name__ == "__main__": + main() From c38c4cb23780eb06e3d49672488057530af40155 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Mon, 5 Dec 2022 18:13:07 +0100 Subject: [PATCH 012/110] Fix CI --- .github/workflows/ci.yml | 2 +- slither/tools/documentation/__main__.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ae5326a8..3c188ce56 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: matrix: os: ["ubuntu-latest", "windows-2022"] type: ["cli", - "dapp", + # "dapp", "data_dependency", "path_filtering", # "embark", diff --git a/slither/tools/documentation/__main__.py b/slither/tools/documentation/__main__.py index b01072d1c..c3979de64 100644 --- a/slither/tools/documentation/__main__.py +++ b/slither/tools/documentation/__main__.py @@ -73,6 +73,7 @@ def _handle_codex(answer: Dict, starting_column: int) -> Optional[str]: return answer_processed return None + # pylint: disable=too-many-locals def _handle_compilation_unit(compilation_unit: SlitherCompilationUnit, overwrite: bool) -> None: all_patches: Dict = {} From b484bde1f39a595f34ffa261b1a494c297099f3f Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 5 Dec 2022 19:33:50 +0100 Subject: [PATCH 013/110] Update ci.yml --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3c188ce56..f25929ea4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,6 @@ jobs: matrix: os: ["ubuntu-latest", "windows-2022"] type: ["cli", - # "dapp", "data_dependency", "path_filtering", # "embark", From 2d64e16fadc2913bfcd3a7b1bc4776c1ad59cd7c Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Tue, 6 Dec 2022 11:04:49 +0100 Subject: [PATCH 014/110] Reenable dapp --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f25929ea4..1ae5326a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,7 @@ jobs: matrix: os: ["ubuntu-latest", "windows-2022"] type: ["cli", + "dapp", "data_dependency", "path_filtering", # "embark", From 3537b95661759721823139369d3d1712faf31361 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Wed, 7 Dec 2022 17:36:07 +0100 Subject: [PATCH 015/110] Improvements --- slither/__main__.py | 44 +---- slither/tools/documentation/__main__.py | 224 ++++++++++++++++++------ slither/utils/codex.py | 60 +++++++ 3 files changed, 229 insertions(+), 99 deletions(-) diff --git a/slither/__main__.py b/slither/__main__.py index 75707af06..d8fce1ce5 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -24,6 +24,7 @@ from slither.detectors.abstract_detector import AbstractDetector, DetectorClassi from slither.printers import all_printers from slither.printers.abstract_printer import AbstractPrinter from slither.slither import Slither +from slither.utils import codex from slither.utils.output import output_to_json, output_to_zip, output_to_sarif, ZIP_TYPES_ACCEPTED from slither.utils.output_capture import StandardOutputCapture from slither.utils.colors import red, set_colorization_enabled @@ -314,7 +315,6 @@ def parse_args( "Checklist (consider using https://github.com/crytic/slither-action)" ) group_misc = parser.add_argument_group("Additional options") - group_codex = parser.add_argument_group("Codex (https://beta.openai.com/docs/guides/code)") group_detector.add_argument( "--detect", @@ -555,47 +555,7 @@ def parse_args( default=False, ) - group_codex.add_argument( - "--codex", - help="Enable codex (require an OpenAI API Key)", - action="store_true", - default=defaults_flag_in_config["codex"], - ) - - group_codex.add_argument( - "--codex-log", - help="Log codex queries (in crytic_export/codex/)", - action="store_true", - default=False, - ) - - group_codex.add_argument( - "--codex-contracts", - help="Comma separated list of contracts to submit to OpenAI Codex", - action="store", - default=defaults_flag_in_config["codex_contracts"], - ) - - group_codex.add_argument( - "--codex-model", - help="Name of the Codex model to use (affects pricing). Defaults to 'text-davinci-003'", - action="store", - default=defaults_flag_in_config["codex_model"], - ) - - group_codex.add_argument( - "--codex-temperature", - help="Temperature to use with Codex. Lower number indicates a more precise answer while higher numbers return more creative answers. Defaults to 0", - action="store", - default=defaults_flag_in_config["codex_temperature"], - ) - - group_codex.add_argument( - "--codex-max-tokens", - help="Maximum amount of tokens to use on the response. This number plus the size of the prompt can be no larger than the limit (4097 for text-davinci-003)", - action="store", - default=defaults_flag_in_config["codex_max_tokens"], - ) + codex.init_parser(parser) # debugger command parser.add_argument("--debug", help=argparse.SUPPRESS, action="store_true", default=False) diff --git a/slither/tools/documentation/__main__.py b/slither/tools/documentation/__main__.py index c3979de64..ea45ed8e1 100644 --- a/slither/tools/documentation/__main__.py +++ b/slither/tools/documentation/__main__.py @@ -1,18 +1,19 @@ import argparse import logging -from typing import Optional, Dict -import os -import openai +import uuid +from typing import Optional, Dict, List from crytic_compile import cryticparser from slither import Slither from slither.core.compilation_unit import SlitherCompilationUnit +from slither.core.declarations import Function from slither.formatters.utils.patches import create_patch, apply_patch, create_diff +from slither.utils import codex logging.basicConfig() logging.getLogger("Slither").setLevel(logging.INFO) -logger = logging.getLogger("Slither-demo") +logger = logging.getLogger("Slither") def parse_args() -> argparse.Namespace: @@ -28,13 +29,43 @@ def parse_args() -> argparse.Namespace: "--overwrite", help="Overwrite the files (be careful).", action="store_true", default=False ) + parser.add_argument( + "--force-answer-parsing", + help="Apply heuristics to better parse codex output (might lead to incorrect results)", + action="store_true", + default=False, + ) + + parser.add_argument("--retry", help="Retry failed query (default 1). Each retry increases the temperature by 0.1", action="store", default=1) + # Add default arguments from crytic-compile cryticparser.init(parser) + codex.init_parser(parser, always_enable_codex=True) + return parser.parse_args() -def _post_processesing(answer: str, starting_column: int) -> Optional[str]: +def _use_tab(char: str) -> Optional[bool]: + """ + Check if the char is a tab + + Args: + char: + + Returns: + + """ + if char == " ": + return False + if char == "\t": + return True + return None + + +def _post_processesing( + answer: str, starting_column: int, use_tab: Optional[bool], force_and_stopped: bool +) -> Optional[str]: """ Clean answers from codex @@ -45,29 +76,46 @@ def _post_processesing(answer: str, starting_column: int) -> Optional[str]: Returns: """ - if answer.count("/**") != 1 or answer.count("*/") != 1: + if answer.count("/**") != 1: return None + # Sometimes codex will miss the */, even if it finished properly the request + # In this case, we allow slither-documentation to force the */ + if answer.count("*/") != 1: + if force_and_stopped: + answer += "*/" + else: + return None if answer.find("/**") > answer.find("*/"): return None answer = answer[answer.find("/**") : answer.find("*/") + 2] answer_lines = answer.splitlines() # Add indentation to all the lines, aside the first one + + space_char = "\t" if use_tab else " " + if len(answer_lines) > 0: answer = ( answer_lines[0] + "\n" - + "\n".join([" " * (starting_column - 1) + line for line in answer_lines[1:] if line]) + + "\n".join( + [space_char * (starting_column - 1) + line for line in answer_lines[1:] if line] + ) ) - answer += "\n" + " " * (starting_column - 1) + answer += "\n" + space_char * (starting_column - 1) return answer return answer_lines[0] -def _handle_codex(answer: Dict, starting_column: int) -> Optional[str]: +def _handle_codex( + answer: Dict, starting_column: int, use_tab: Optional[bool], force: bool +) -> Optional[str]: if "choices" in answer: if answer["choices"]: if "text" in answer["choices"][0]: - answer_processed = _post_processesing(answer["choices"][0]["text"], starting_column) + has_stopped = answer["choices"][0].get("finish_reason", "") == "stop" + answer_processed = _post_processesing( + answer["choices"][0]["text"], starting_column, use_tab, force and has_stopped + ) if answer_processed is None: return None return answer_processed @@ -75,67 +123,129 @@ def _handle_codex(answer: Dict, starting_column: int) -> Optional[str]: # pylint: disable=too-many-locals -def _handle_compilation_unit(compilation_unit: SlitherCompilationUnit, overwrite: bool) -> None: - all_patches: Dict = {} - - for function in compilation_unit.functions: - if function.source_mapping.is_dependency or function.has_documentation: +def _handle_compilation_unit( + slither: Slither, + compilation_unit: SlitherCompilationUnit, + overwrite: bool, + force: bool, + retry: int, +) -> None: + + logging_file = str(uuid.uuid4()) + + for scope in compilation_unit.scopes.values(): + + # TODO remove hardcoded filtering + if ( + ".t.sol" in scope.filename.absolute + or "mock" in scope.filename.absolute.lower() + or "test" in scope.filename.absolute.lower() + ): continue - prompt = "Create a documentation for the solidity code using natspec (use only notice, dev, params, return)\n" - src_mapping = function.source_mapping - content = compilation_unit.core.source_code[src_mapping.filename.absolute] - start = src_mapping.start - end = src_mapping.start + src_mapping.length - prompt += content[start:end] - answer = openai.Completion.create( # type: ignore - model="text-davinci-003", prompt=prompt, temperature=0, max_tokens=200 - ) - answer_processed = _handle_codex(answer, src_mapping.starting_column) - if answer_processed is None: - print(f"Codex could not generate a well formatted answer for {function.canonical_name}") - print(answer) + functions_target: List[Function] = [] + + for contract in scope.contracts.values(): + functions_target += contract.functions_declared + + functions_target += list(scope.functions) + + all_patches: Dict = {} + + for function in functions_target: + + if function.source_mapping.is_dependency or function.has_documentation or function.is_constructor_variables: + continue + prompt = ( + "Create a natpsec documentation for this solidity code with only notice and dev.\n" + ) + src_mapping = function.source_mapping + content = compilation_unit.core.source_code[src_mapping.filename.absolute] + start = src_mapping.start + end = src_mapping.start + src_mapping.length + prompt += content[start:end] + + use_tab = _use_tab(content[start - 1]) + if use_tab is None and src_mapping.starting_column > 1: + logger.info(f"Non standard space indentation found {content[start-1:end]}") + if overwrite: + logger.info("Disable overwrite to avoid mistakes") + overwrite = False + + openai = codex.openai_module() # type: ignore + if openai is None: + return + + if slither.codex_log: + codex.log_codex(logging_file, "Q: " + prompt) + + tentative = 0 + answer_processed: Optional[str] = None + while tentative < retry: + tentative += 1 + + answer = openai.Completion.create( # type: ignore + prompt=prompt, + model=slither.codex_model, + temperature=min(slither.codex_temperature + tentative*0.1, 1), + max_tokens=slither.codex_max_tokens, + ) + + if slither.codex_log: + codex.log_codex(logging_file, "A: " + str(answer)) + + answer_processed = _handle_codex( + answer, src_mapping.starting_column, use_tab, force + ) + if answer_processed: + break + + logger.info( + f"Codex could not generate a well formatted answer for {function.canonical_name}" + ) + logger.info(answer) + + if not answer_processed: + continue + + create_patch( + all_patches, src_mapping.filename.absolute, start, start, "", answer_processed + ) + + # all_patches["patches"] should have only 1 file + if "patches" not in all_patches: continue + for file in all_patches["patches"]: + original_txt = compilation_unit.core.source_code[file].encode("utf8") + patched_txt = original_txt - create_patch(all_patches, src_mapping.filename.absolute, start, start, "", answer_processed) - - # cat math.sol - # slither-documentation math.sol --overwrite - # cat math.sol - # exit - for file in all_patches["patches"]: - original_txt = compilation_unit.core.source_code[file].encode("utf8") - patched_txt = original_txt - - patches = all_patches["patches"][file] - offset = 0 - patches.sort(key=lambda x: x["start"]) + patches = all_patches["patches"][file] + offset = 0 + patches.sort(key=lambda x: x["start"]) - for patch in patches: - patched_txt, offset = apply_patch(patched_txt, patch, offset) + for patch in patches: + patched_txt, offset = apply_patch(patched_txt, patch, offset) - if overwrite: - with open(file, "w", encoding="utf8") as f: - f.write(patched_txt.decode("utf8")) - else: - diff = create_diff(compilation_unit, original_txt, patched_txt, file) - with open(f"{file}.patch", "w", encoding="utf8") as f: - f.write(diff) + if overwrite: + with open(file, "w", encoding="utf8") as f: + f.write(patched_txt.decode("utf8")) + else: + diff = create_diff(compilation_unit, original_txt, patched_txt, file) + with open(f"{file}.patch", "w", encoding="utf8") as f: + f.write(diff) def main() -> None: args = parse_args() + logger.info("This tool is a WIP, use it with cautious") + logger.info("Be aware of OpenAI ToS: https://openai.com/api/policies/terms/") slither = Slither(args.project, **vars(args)) - api_key = os.getenv("OPENAI_API_KEY") - if api_key is None: - print("Please provide an Open API Key (https://beta.openai.com/account/api-keys)") - return - openai.api_key = api_key - for compilation_unit in slither.compilation_units: - _handle_compilation_unit(compilation_unit, args.overwrite) + _handle_compilation_unit( + slither, compilation_unit, args.overwrite, args.force_answer_parsing, int(args.retry) + ) if __name__ == "__main__": diff --git a/slither/utils/codex.py b/slither/utils/codex.py index 0040fb03c..3b06efe6f 100644 --- a/slither/utils/codex.py +++ b/slither/utils/codex.py @@ -1,10 +1,70 @@ import logging import os +from argparse import ArgumentParser from pathlib import Path +from slither.utils.command_line import defaults_flag_in_config + logger = logging.getLogger("Slither") +def init_parser(parser: ArgumentParser, always_enable_codex: bool = False) -> None: + """ + Init the cli arg with codex features + + Args: + parser: + always_enable_codex (Optional(bool)): if true, --codex is not enabled + + Returns: + + """ + group_codex = parser.add_argument_group("Codex (https://beta.openai.com/docs/guides/code)") + + if not always_enable_codex: + group_codex.add_argument( + "--codex", + help="Enable codex (require an OpenAI API Key)", + action="store_true", + default=defaults_flag_in_config["codex"], + ) + + group_codex.add_argument( + "--codex-log", + help="Log codex queries (in crytic_export/codex/)", + action="store_true", + default=False, + ) + + group_codex.add_argument( + "--codex-contracts", + help="Comma separated list of contracts to submit to OpenAI Codex", + action="store", + default=defaults_flag_in_config["codex_contracts"], + ) + + group_codex.add_argument( + "--codex-model", + help="Name of the Codex model to use (affects pricing). Defaults to 'text-davinci-003'", + action="store", + default=defaults_flag_in_config["codex_model"], + ) + + group_codex.add_argument( + "--codex-temperature", + help="Temperature to use with Codex. Lower number indicates a more precise answer while higher numbers return more creative answers. Defaults to 0", + action="store", + default=defaults_flag_in_config["codex_temperature"], + ) + + group_codex.add_argument( + "--codex-max-tokens", + help="Maximum amount of tokens to use on the response. This number plus the size of the prompt can be no larger than the limit (4097 for text-davinci-003)", + action="store", + default=defaults_flag_in_config["codex_max_tokens"], + ) + + # TODO: investigate how to set the correct return type # So that the other modules can work with openai def openai_module(): # type: ignore From eb49e396fd0d60c10e4db1771b443319e1faf55b Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Sat, 10 Dec 2022 15:41:39 -0600 Subject: [PATCH 016/110] support ternaries in both call options, refactor index access --- slither/solc_parsing/declarations/function.py | 4 +- slither/utils/expression_manipulations.py | 116 ++++++++++-------- tests/slithir/ternary_expressions.sol | 11 ++ 3 files changed, 75 insertions(+), 56 deletions(-) diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py index 130375211..269ca580f 100644 --- a/slither/solc_parsing/declarations/function.py +++ b/slither/solc_parsing/declarations/function.py @@ -308,7 +308,7 @@ class FunctionSolc(CallerContextExpression): for node_parser in self._node_to_yulobject.values(): node_parser.analyze_expressions() - self._filter_ternary() + self._rewrite_ternary_as_if_else() self._remove_alone_endif() @@ -1336,7 +1336,7 @@ class FunctionSolc(CallerContextExpression): ################################################################################### ################################################################################### - def _filter_ternary(self) -> bool: + def _rewrite_ternary_as_if_else(self) -> bool: ternary_found = True updated = False while ternary_found: diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index 3e12ae8c1..777c0c2a1 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -3,7 +3,7 @@ as they should be immutable """ import copy -from typing import Union, Callable +from typing import Union, Callable, Tuple, Optional from slither.core.expressions import UnaryOperation from slither.core.expressions.assignment_operation import AssignmentOperation from slither.core.expressions.binary_operation import BinaryOperation @@ -35,6 +35,11 @@ def f_call(e: CallExpression, x): def f_call_value(e: CallExpression, x): e._value = x + +def f_call_gas(e: CallExpression, x): + e._gas = x + + def f_expression(e, x): e._expression = x @@ -56,7 +61,7 @@ class SplitTernaryExpression: self.condition = None self.copy_expression(expression, self.true_expression, self.false_expression) - def apply_copy( + def conditional_not_ahead( self, next_expr: Expression, true_expression: Union[AssignmentOperation, MemberAccess], @@ -94,7 +99,9 @@ class SplitTernaryExpression: # (.. ? .. : ..).add if isinstance(expression, MemberAccess): next_expr = expression.expression - if self.apply_copy(next_expr, true_expression, false_expression, f_expression): + if self.conditional_not_ahead( + next_expr, true_expression, false_expression, f_expression + ): self.copy_expression( next_expr, true_expression.expression, false_expression.expression ) @@ -102,44 +109,75 @@ class SplitTernaryExpression: elif isinstance(expression, (AssignmentOperation, BinaryOperation, TupleExpression)): true_expression._expressions = [] false_expression._expressions = [] - for next_expr in expression.expressions: - if isinstance(next_expr, IndexAccess): - # create an index access for each branch - if isinstance(next_expr.expression_right, ConditionalExpression): - next_expr = _handle_ternary_access( - next_expr, true_expression, false_expression + # TODO: can we get rid of `NoneType` expressions in `TupleExpression`? + if next_expr: + if isinstance(next_expr, IndexAccess): + # create an index access for each branch + # x[if cond ? 1 : 2] -> if cond { x[1] } else { x[2] } + for expr in next_expr.expressions: + if self.conditional_not_ahead( + expr, true_expression, false_expression, f_expressions + ): + self.copy_expression( + expr, + true_expression.expressions[-1], + false_expression.expressions[-1], + ) + + if self.conditional_not_ahead( + next_expr, true_expression, false_expression, f_expressions + ): + # always on last arguments added + self.copy_expression( + next_expr, + true_expression.expressions[-1], + false_expression.expressions[-1], ) - if self.apply_copy(next_expr, true_expression, false_expression, f_expressions): - # always on last arguments added - self.copy_expression( - next_expr, - true_expression.expressions[-1], - false_expression.expressions[-1], - ) elif isinstance(expression, CallExpression): next_expr = expression.called # case of lib # (.. ? .. : ..).add - if self.apply_copy(next_expr, true_expression, false_expression, f_called): + if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_called): self.copy_expression(next_expr, true_expression.called, false_expression.called) - next_expr = expression.call_value - # case of (..).func{value: .. ? .. : ..}() - if self.apply_copy(next_expr, true_expression, false_expression, f_call_value): + # In order to handle ternaries in both call options, gas and value, we return early if the + # conditional is not ahead to rewrite both ternaries (see `_rewrite_ternary_as_if_else`). + if expression.call_gas: + # case of (..).func{gas: .. ? .. : ..}() + next_expr = expression.call_gas + if self.conditional_not_ahead( + next_expr, true_expression, false_expression, f_call_gas + ): + self.copy_expression( + next_expr, + true_expression.call_gas, + false_expression.call_gas, + ) + else: + return + + if expression.call_value: + # case of (..).func{value: .. ? .. : ..}() + next_expr = expression.call_value + if self.conditional_not_ahead( + next_expr, true_expression, false_expression, f_call_value + ): self.copy_expression( next_expr, true_expression.call_value, false_expression.call_value, ) + else: + return true_expression._arguments = [] false_expression._arguments = [] for next_expr in expression.arguments: - if self.apply_copy(next_expr, true_expression, false_expression, f_call): + if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_call): # always on last arguments added self.copy_expression( next_expr, @@ -149,7 +187,9 @@ class SplitTernaryExpression: elif isinstance(expression, (TypeConversion, UnaryOperation)): next_expr = expression.expression - if self.apply_copy(next_expr, true_expression, false_expression, f_expression): + if self.conditional_not_ahead( + next_expr, true_expression, false_expression, f_expression + ): self.copy_expression( expression.expression, true_expression.expression, @@ -160,35 +200,3 @@ class SplitTernaryExpression: raise SlitherException( f"Ternary operation not handled {expression}({type(expression)})" ) - - -def _handle_ternary_access( - next_expr: IndexAccess, - true_expression: AssignmentOperation, - false_expression: AssignmentOperation, -): - """ - Conditional ternary accesses are split into two accesses, one true and one false - E.g. x[if cond ? 1 : 2] -> if cond { x[1] } else { x[2] } - """ - true_index_access = IndexAccess( - next_expr.expression_left, - next_expr.expression_right.then_expression, - next_expr.type, - ) - false_index_access = IndexAccess( - next_expr.expression_left, - next_expr.expression_right.else_expression, - next_expr.type, - ) - - f_expressions( - true_expression, - true_index_access, - ) - f_expressions( - false_expression, - false_index_access, - ) - - return next_expr.expression_right diff --git a/tests/slithir/ternary_expressions.sol b/tests/slithir/ternary_expressions.sol index c2e50b719..7fcc675c1 100644 --- a/tests/slithir/ternary_expressions.sol +++ b/tests/slithir/ternary_expressions.sol @@ -1,3 +1,6 @@ +interface NameReg { + function addressOf() external payable; +} contract C { // TODO // 1) support variable declarations @@ -21,4 +24,12 @@ contract C { function d(bool cond, bytes calldata x) external { bytes1 a = x[cond ? 1 : 2]; } + + function e(address one, address two) public { + return NameReg(one).addressOf{value: msg.sender == two ? 1 : 2, gas: true ? 2 : gasleft()}(); + } + // TODO: nested ternary + // function f(address one, address two) public { + // return NameReg(one).addressOf{value: msg.sender == two ? 1 : 2, gas: true ? (1 == 1 ? 1 : 2) : gasleft()}(); + // } } From a1a0abe17dbc0bc805f5b038fe673376f0d5f14d Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 12 Dec 2022 12:45:31 -0600 Subject: [PATCH 017/110] support parenthetical ternary expr and update tests --- slither/utils/expression_manipulations.py | 7 +++++++ tests/slithir/ternary_expressions.sol | 21 ++++++++++++++------- tests/slithir/test_ternary_expressions.py | 6 +++--- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index 777c0c2a1..9ae01fde7 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -68,6 +68,13 @@ class SplitTernaryExpression: false_expression: Union[AssignmentOperation, MemberAccess], f: Callable, ) -> bool: + # parentetical expression (.. ? .. : ..) + if ( + isinstance(next_expr, TupleExpression) + and len(next_expr.expressions) == 1 + and isinstance(next_expr.expressions[0], ConditionalExpression) + ): + next_expr = next_expr.expressions[0] if isinstance(next_expr, ConditionalExpression): f(true_expression, copy.copy(next_expr.then_expression)) diff --git a/tests/slithir/ternary_expressions.sol b/tests/slithir/ternary_expressions.sol index 7fcc675c1..c6a6d4643 100644 --- a/tests/slithir/ternary_expressions.sol +++ b/tests/slithir/ternary_expressions.sol @@ -1,5 +1,6 @@ -interface NameReg { - function addressOf() external payable; +interface Test { + function test() external payable returns (uint); + function testTuple() external payable returns (uint, uint); } contract C { // TODO @@ -26,10 +27,16 @@ contract C { } function e(address one, address two) public { - return NameReg(one).addressOf{value: msg.sender == two ? 1 : 2, gas: true ? 2 : gasleft()}(); + uint x = Test(one).test{value: msg.sender == two ? 1 : 2, gas: true ? 2 : gasleft()}(); + } + + // Parenthteical expression + function f(address one, address two) public { + uint x = Test(one).test{value: msg.sender == two ? 1 : 2, gas: true ? (1 == 1 ? 1 : 2) : gasleft()}(); + } + + // Unused tuple variable + function g(address one) public { + (, uint x) = Test(one).testTuple(); } - // TODO: nested ternary - // function f(address one, address two) public { - // return NameReg(one).addressOf{value: msg.sender == two ? 1 : 2, gas: true ? (1 == 1 ? 1 : 2) : gasleft()}(); - // } } diff --git a/tests/slithir/test_ternary_expressions.py b/tests/slithir/test_ternary_expressions.py index db5658787..17cac6b2f 100644 --- a/tests/slithir/test_ternary_expressions.py +++ b/tests/slithir/test_ternary_expressions.py @@ -9,10 +9,10 @@ def test_ternary_conversions() -> None: slither = Slither("./tests/slithir/ternary_expressions.sol") for contract in slither.contracts: for function in contract.functions: + vars_declared = 0 + vars_assigned = 0 for node in function.nodes: if node.type in [NodeType.IF, NodeType.IFLOOP]: - vars_declared = 0 - vars_assigned = 0 # Iterate over true and false son for inner_node in node.sons: @@ -31,7 +31,7 @@ def test_ternary_conversions() -> None: if isinstance(ir, Assignment): vars_assigned += 1 - assert vars_declared == vars_assigned + assert vars_declared == vars_assigned if __name__ == "__main__": From a1343a8df596746999e766f8f7c51ed6a8ed93b4 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 12 Dec 2022 12:47:27 -0600 Subject: [PATCH 018/110] update function name --- slither/solc_parsing/declarations/modifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/solc_parsing/declarations/modifier.py b/slither/solc_parsing/declarations/modifier.py index a3f07da7f..e55487612 100644 --- a/slither/solc_parsing/declarations/modifier.py +++ b/slither/solc_parsing/declarations/modifier.py @@ -87,7 +87,7 @@ class ModifierSolc(FunctionSolc): for node in self._node_to_nodesolc.values(): node.analyze_expressions(self) - self._filter_ternary() + self._rewrite_ternary_as_if_else() self._remove_alone_endif() # self._analyze_read_write() From ca252f147293e648d748593c891f1742a9b07db5 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 12 Dec 2022 13:10:25 -0600 Subject: [PATCH 019/110] spelling and linting --- slither/utils/expression_manipulations.py | 6 +++--- tests/slithir/ternary_expressions.sol | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index 9ae01fde7..591fab0ef 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -3,7 +3,7 @@ as they should be immutable """ import copy -from typing import Union, Callable, Tuple, Optional +from typing import Union, Callable from slither.core.expressions import UnaryOperation from slither.core.expressions.assignment_operation import AssignmentOperation from slither.core.expressions.binary_operation import BinaryOperation @@ -68,7 +68,7 @@ class SplitTernaryExpression: false_expression: Union[AssignmentOperation, MemberAccess], f: Callable, ) -> bool: - # parentetical expression (.. ? .. : ..) + # look ahead for parenthetical expression (.. ? .. : ..) if ( isinstance(next_expr, TupleExpression) and len(next_expr.expressions) == 1 @@ -112,7 +112,7 @@ class SplitTernaryExpression: self.copy_expression( next_expr, true_expression.expression, false_expression.expression ) - + # pylint: disable=too-many-nested-blocks elif isinstance(expression, (AssignmentOperation, BinaryOperation, TupleExpression)): true_expression._expressions = [] false_expression._expressions = [] diff --git a/tests/slithir/ternary_expressions.sol b/tests/slithir/ternary_expressions.sol index c6a6d4643..89fdc59d1 100644 --- a/tests/slithir/ternary_expressions.sol +++ b/tests/slithir/ternary_expressions.sol @@ -30,7 +30,7 @@ contract C { uint x = Test(one).test{value: msg.sender == two ? 1 : 2, gas: true ? 2 : gasleft()}(); } - // Parenthteical expression + // Parenthetical expression function f(address one, address two) public { uint x = Test(one).test{value: msg.sender == two ? 1 : 2, gas: true ? (1 == 1 ? 1 : 2) : gasleft()}(); } From 59b9b0392dfb243f73269967d57450f066f7267f Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 13 Dec 2022 13:46:00 -0600 Subject: [PATCH 020/110] analyze all inherited contracts' using for directives first --- .../slither_compilation_unit_solc.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index f08a71487..67c0cb0fc 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -508,6 +508,7 @@ Please rename it, this name is reserved for Slither's internals""" # Then we analyse state variables, functions and modifiers self._analyze_third_part(contracts_to_be_analyzed, libraries) + [c.set_is_analyzed(False) for c in self._underlying_contract_to_parser.values()] self._analyze_using_for(contracts_to_be_analyzed) @@ -624,8 +625,20 @@ Please rename it, this name is reserved for Slither's internals""" def _analyze_using_for(self, contracts_to_be_analyzed: List[ContractSolc]): self._analyze_top_level_using_for() - for c in contracts_to_be_analyzed: - c.analyze_using_for() + while contracts_to_be_analyzed: + contract = contracts_to_be_analyzed[0] + + contracts_to_be_analyzed = contracts_to_be_analyzed[1:] + all_father_analyzed = all( + self._underlying_contract_to_parser[father].is_analyzed + for father in contract.underlying_contract.inheritance + ) + + if not contract.underlying_contract.inheritance or all_father_analyzed: + contract.analyze_using_for() + contract.set_is_analyzed(True) + else: + contracts_to_be_analyzed += [contract] def _analyze_enums(self, contract: ContractSolc): # Enum must be analyzed first @@ -711,6 +724,7 @@ Please rename it, this name is reserved for Slither's internals""" for func in contract.functions + contract.modifiers: try: func.generate_slithir_and_analyze() + except AttributeError as e: # This can happens for example if there is a call to an interface # And the interface is redefined due to contract's name reuse From 2d41b962a9d2441c228b75becc11e5f3ee47781f Mon Sep 17 00:00:00 2001 From: Simone Date: Tue, 13 Dec 2022 22:06:56 +0100 Subject: [PATCH 021/110] rename FileScope.usingFor to using_for_directives --- slither/core/declarations/contract.py | 2 +- slither/core/scope/scope.py | 6 +++--- slither/solc_parsing/declarations/using_for_top_level.py | 6 +++--- slither/solc_parsing/slither_compilation_unit_solc.py | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/slither/core/declarations/contract.py b/slither/core/declarations/contract.py index 1637ea622..1262877f9 100644 --- a/slither/core/declarations/contract.py +++ b/slither/core/declarations/contract.py @@ -281,7 +281,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods if self._using_for_complete is None: result = self.using_for - top_level_using_for = self.file_scope.usingFor + top_level_using_for = self.file_scope.using_for_directives for uftl in top_level_using_for: result = _merge_using_for(result, uftl.using_for) self._using_for_complete = result diff --git a/slither/core/scope/scope.py b/slither/core/scope/scope.py index a27483824..4260e3a5e 100644 --- a/slither/core/scope/scope.py +++ b/slither/core/scope/scope.py @@ -36,7 +36,7 @@ class FileScope: # Because we parse the function signature later on # So we simplify the logic and have the scope fields all populated self.functions: Set[FunctionTopLevel] = set() - self.usingFor: Set[UsingForTopLevel] = set() + self.using_for_directives: Set[UsingForTopLevel] = set() self.imports: Set[Import] = set() self.pragmas: Set[Pragma] = set() self.structures: Dict[str, StructureTopLevel] = {} @@ -74,8 +74,8 @@ class FileScope: if not new_scope.functions.issubset(self.functions): self.functions |= new_scope.functions learn_something = True - if not new_scope.usingFor.issubset(self.usingFor): - self.usingFor |= new_scope.usingFor + if not new_scope.using_for_directives.issubset(self.using_for_directives): + self.using_for_directives |= new_scope.using_for_directives learn_something = True if not new_scope.imports.issubset(self.imports): self.imports |= new_scope.imports diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py index 89d1dc276..85b09130d 100644 --- a/slither/solc_parsing/declarations/using_for_top_level.py +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -107,7 +107,7 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- if isinstance(type_name, TypeAliasTopLevel): for alias in scope.user_defined_types.values(): if alias == type_name: - scope.usingFor.add(self._using_for) + scope.using_for_directives.add(self._using_for) elif isinstance(type_name, UserDefinedType): self._propagate_global_UserDefinedType(scope, type_name) else: @@ -122,11 +122,11 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- if isinstance(underlying, StructureTopLevel): for struct in scope.structures.values(): if struct == underlying: - scope.usingFor.add(self._using_for) + scope.using_for_directives.add(self._using_for) elif isinstance(underlying, EnumTopLevel): for enum in scope.enums.values(): if enum == underlying: - scope.usingFor.add(self._using_for) + scope.using_for_directives.add(self._using_for) else: LOGGER.error( f"Error when propagating global {underlying} {type(underlying)} not a StructTopLevel or EnumTopLevel" diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index b2d76052b..78b6d4733 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -230,7 +230,7 @@ class SlitherCompilationUnitSolc: usingFor = UsingForTopLevel(scope) usingFor_parser = UsingForTopLevelSolc(usingFor, top_level_data, self) usingFor.set_offset(top_level_data["src"], self._compilation_unit) - scope.usingFor.add(usingFor) + scope.using_for_directives.add(usingFor) self._compilation_unit.using_for_top_level.append(usingFor) self._using_for_top_level_parser.append(usingFor_parser) From 74122a6bd68cdef07b178deb6b7624b51cfcb517 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 15 Dec 2022 18:19:04 -0600 Subject: [PATCH 022/110] fold binary expressions with constant operands for fuzzing guidance --- slither/core/expressions/literal.py | 9 ++++++- slither/printers/guidance/echidna.py | 6 +++++ .../visitors/expression/constants_folding.py | 25 ++++++++++++------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/slither/core/expressions/literal.py b/slither/core/expressions/literal.py index 87090b93f..0dc06cb20 100644 --- a/slither/core/expressions/literal.py +++ b/slither/core/expressions/literal.py @@ -20,6 +20,13 @@ class Literal(Expression): def value(self) -> Union[int, str]: return self._value + @property + def converted_value(self) -> int: + """Return the value of the literal, accounting for subdenomination e.g. ether""" + if self.subdenomination: + return convert_subdenomination(self._value, self.subdenomination) + return self._value + @property def type(self) -> "Type": return self._type @@ -30,7 +37,7 @@ class Literal(Expression): def __str__(self): if self.subdenomination: - return str(convert_subdenomination(self._value, self.subdenomination)) + return str(self.converted_value) if self.type in Int + Uint + Fixed + Ufixed + ["address"]: return str(convert_string_to_int(self._value)) diff --git a/slither/printers/guidance/echidna.py b/slither/printers/guidance/echidna.py index dbfa54121..45b3ab332 100644 --- a/slither/printers/guidance/echidna.py +++ b/slither/printers/guidance/echidna.py @@ -30,6 +30,7 @@ from slither.slithir.operations import ( ) from slither.slithir.operations.binary import Binary from slither.slithir.variables import Constant +from slither.visitors.expression.constants_folding import ConstantFolding def _get_name(f: Union[Function, Variable]) -> str: @@ -175,6 +176,11 @@ def _extract_constants_from_irs( # pylint: disable=too-many-branches,too-many-n all_cst_used_in_binary[str(ir.type)].append( ConstantValue(str(r.value), str(r.type)) ) + if isinstance(ir.variable_left, Constant) and isinstance(ir.variable_right, Constant): + if ir.lvalue: + type_ = ir.lvalue.type + cst = ConstantFolding(ir.expression, type_).result() + all_cst_used.append(ConstantValue(str(cst.value), str(type_))) if isinstance(ir, TypeConversion): if isinstance(ir.variable, Constant): all_cst_used.append(ConstantValue(str(ir.variable.value), str(ir.type))) diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index b324ed842..601eebcce 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -1,4 +1,11 @@ -from slither.core.expressions import BinaryOperationType, Literal, UnaryOperationType +from slither.core.expressions import ( + BinaryOperationType, + Literal, + UnaryOperationType, + Identifier, + BinaryOperation, + UnaryOperation, +) from slither.utils.integer_conversion import convert_string_to_fraction, convert_string_to_int from slither.visitors.expression.expression import ExpressionVisitor @@ -29,7 +36,7 @@ class ConstantFolding(ExpressionVisitor): def result(self): return Literal(int(get_val(self._expression)), self._type) - def _post_identifier(self, expression): + def _post_identifier(self, expression: Identifier): if not expression.value.is_constant: raise NotConstant expr = expression.value.expression @@ -37,9 +44,9 @@ class ConstantFolding(ExpressionVisitor): if not isinstance(expr, Literal): cf = ConstantFolding(expr, self._type) expr = cf.result() - set_val(expression, convert_string_to_int(expr.value)) + set_val(expression, convert_string_to_int(expr.converted_value)) - def _post_binary_operation(self, expression): + def _post_binary_operation(self, expression: BinaryOperation): left = get_val(expression.expression_left) right = get_val(expression.expression_right) if expression.type == BinaryOperationType.POWER: @@ -64,7 +71,7 @@ class ConstantFolding(ExpressionVisitor): else: raise NotConstant - def _post_unary_operation(self, expression): + def _post_unary_operation(self, expression: UnaryOperation): # Case of uint a = -7; uint[-a] arr; if expression.type == UnaryOperationType.MINUS_PRE: expr = expression.expression @@ -72,13 +79,13 @@ class ConstantFolding(ExpressionVisitor): cf = ConstantFolding(expr, self._type) expr = cf.result() assert isinstance(expr, Literal) - set_val(expression, -convert_string_to_fraction(expr.value)) + set_val(expression, -convert_string_to_fraction(expr.converted_value)) else: raise NotConstant - def _post_literal(self, expression): + def _post_literal(self, expression: Literal): try: - set_val(expression, convert_string_to_fraction(expression.value)) + set_val(expression, convert_string_to_fraction(expression.converted_value)) except ValueError as e: raise NotConstant from e @@ -115,7 +122,7 @@ class ConstantFolding(ExpressionVisitor): cf = ConstantFolding(expression.expressions[0], self._type) expr = cf.result() assert isinstance(expr, Literal) - set_val(expression, convert_string_to_fraction(expr.value)) + set_val(expression, convert_string_to_fraction(expr.converted_value)) return raise NotConstant From fcd7b68e27ec157fd65d643c774c2b088344163b Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 16 Dec 2022 08:48:59 -0600 Subject: [PATCH 023/110] support bitwise and logical ops in constant folding, add tests --- slither/core/expressions/literal.py | 3 ++ .../visitors/expression/constants_folding.py | 38 +++++++++++---- tests/constant_folding_binop.sol | 13 +++++ tests/test_constant_folding.py | 48 +++++++++++++++++++ 4 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 tests/constant_folding_binop.sol diff --git a/slither/core/expressions/literal.py b/slither/core/expressions/literal.py index 0dc06cb20..7999ccf02 100644 --- a/slither/core/expressions/literal.py +++ b/slither/core/expressions/literal.py @@ -4,6 +4,7 @@ from slither.core.expressions.expression import Expression from slither.core.solidity_types.elementary_type import Fixed, Int, Ufixed, Uint from slither.utils.arithmetic import convert_subdenomination from slither.utils.integer_conversion import convert_string_to_int +from fractions import Fraction if TYPE_CHECKING: from slither.core.solidity_types.type import Type @@ -12,6 +13,8 @@ if TYPE_CHECKING: class Literal(Expression): def __init__(self, value, custom_type, subdenomination=None): super().__init__() + if isinstance(value, Fraction): + value = int(value) self._value: Union[int, str] = value self._type = custom_type self._subdenomination: Optional[str] = subdenomination diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 601eebcce..22691a086 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -34,7 +34,7 @@ class ConstantFolding(ExpressionVisitor): super().__init__(expression) def result(self): - return Literal(int(get_val(self._expression)), self._type) + return Literal(get_val(self._expression), self._type) def _post_identifier(self, expression: Identifier): if not expression.value.is_constant: @@ -60,14 +60,33 @@ class ConstantFolding(ExpressionVisitor): elif expression.type == BinaryOperationType.ADDITION: set_val(expression, left + right) elif expression.type == BinaryOperationType.SUBTRACTION: - if (left - right) < 0: - # Could trigger underflow - raise NotConstant set_val(expression, left - right) elif expression.type == BinaryOperationType.LEFT_SHIFT: set_val(expression, left << right) elif expression.type == BinaryOperationType.RIGHT_SHIFT: set_val(expression, left >> right) + elif expression.type == BinaryOperationType.AND: + set_val(expression, int(left) & int(right)) + elif expression.type == BinaryOperationType.CARET: + set_val(expression, int(left) ^ int(right)) + elif expression.type == BinaryOperationType.OR: + set_val(expression, int(left) | int(right)) + elif expression.type == BinaryOperationType.LESS: + set_val(expression, int(left) < int(right)) + elif expression.type == BinaryOperationType.LESS_EQUAL: + set_val(expression, int(left) <= int(right)) + elif expression.type == BinaryOperationType.GREATER: + set_val(expression, int(left) > int(right)) + elif expression.type == BinaryOperationType.GREATER_EQUAL: + set_val(expression, int(left) >= int(right)) + elif expression.type == BinaryOperationType.EQUAL: + set_val(expression, int(left) == int(right)) + elif expression.type == BinaryOperationType.NOT_EQUAL: + set_val(expression, int(left) != int(right)) + elif expression.type == BinaryOperationType.ANDAND: + set_val(expression, left == "true" and right == "true") + elif expression.type == BinaryOperationType.OROR: + set_val(expression, left == "true" or right == "true") else: raise NotConstant @@ -84,10 +103,13 @@ class ConstantFolding(ExpressionVisitor): raise NotConstant def _post_literal(self, expression: Literal): - try: - set_val(expression, convert_string_to_fraction(expression.converted_value)) - except ValueError as e: - raise NotConstant from e + if expression.converted_value in ["true", "false"]: + set_val(expression, expression.converted_value) + else: + try: + set_val(expression, convert_string_to_fraction(expression.converted_value)) + except ValueError as e: + raise NotConstant from e def _post_assignement_operation(self, expression): raise NotConstant diff --git a/tests/constant_folding_binop.sol b/tests/constant_folding_binop.sol new file mode 100644 index 000000000..baab7147f --- /dev/null +++ b/tests/constant_folding_binop.sol @@ -0,0 +1,13 @@ +contract BinOp { + uint a = 1 & 2; + uint b = 1 ^ 2; + uint c = 1 | 2; + bool d = 2 < 1; + bool e = 1 > 2; + bool f = 1 <= 2; + bool g = 1 >= 2; + bool h = 1 == 2; + bool i = 1 != 2; + bool j = true && false; + bool k = true || false; +} \ No newline at end of file diff --git a/tests/test_constant_folding.py b/tests/test_constant_folding.py index efc3119a8..459e2e3c9 100644 --- a/tests/test_constant_folding.py +++ b/tests/test_constant_folding.py @@ -43,3 +43,51 @@ def test_constant_folding_rational(): variable_g = contract.get_state_variable_from_name("g") assert str(variable_g.type) == "int64" assert str(ConstantFolding(variable_g.expression, "int64").result()) == "-7" + +def test_constant_folding_binary_expressions(): + sl = Slither("./tests/constant_folding_binop.sol") + contract = sl.get_contract_from_name("BinOp")[0] + + variable_a = contract.get_state_variable_from_name("a") + assert str(variable_a.type) == "uint256" + assert str(ConstantFolding(variable_a.expression, "uint256").result()) == "0" + + variable_b = contract.get_state_variable_from_name("b") + assert str(variable_b.type) == "uint256" + assert str(ConstantFolding(variable_b.expression, "uint256").result()) == "3" + + variable_c = contract.get_state_variable_from_name("c") + assert str(variable_c.type) == "uint256" + assert str(ConstantFolding(variable_c.expression, "uint256").result()) == "3" + + variable_d = contract.get_state_variable_from_name("d") + assert str(variable_d.type) == "bool" + assert str(ConstantFolding(variable_d.expression, "bool").result()) == "False" + + variable_e = contract.get_state_variable_from_name("e") + assert str(variable_e.type) == "bool" + assert str(ConstantFolding(variable_e.expression, "bool").result()) == "False" + + variable_f = contract.get_state_variable_from_name("f") + assert str(variable_f.type) == "bool" + assert str(ConstantFolding(variable_f.expression, "bool").result()) == "True" + + variable_g = contract.get_state_variable_from_name("g") + assert str(variable_g.type) == "bool" + assert str(ConstantFolding(variable_g.expression, "bool").result()) == "False" + + variable_h = contract.get_state_variable_from_name("h") + assert str(variable_h.type) == "bool" + assert str(ConstantFolding(variable_h.expression, "bool").result()) == "False" + + variable_i = contract.get_state_variable_from_name("i") + assert str(variable_i.type) == "bool" + assert str(ConstantFolding(variable_i.expression, "bool").result()) == "True" + + variable_j = contract.get_state_variable_from_name("j") + assert str(variable_j.type) == "bool" + assert str(ConstantFolding(variable_j.expression, "bool").result()) == "False" + + variable_k = contract.get_state_variable_from_name("k") + assert str(variable_k.type) == "bool" + assert str(ConstantFolding(variable_k.expression, "bool").result()) == "True" \ No newline at end of file From 887002407a90f596c61ee27357d44f3e0c8d1f6a Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 16 Dec 2022 08:54:20 -0600 Subject: [PATCH 024/110] convert to int for operations not supported by Fraction --- slither/visitors/expression/constants_folding.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 22691a086..e4cd09eb8 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -61,10 +61,11 @@ class ConstantFolding(ExpressionVisitor): set_val(expression, left + right) elif expression.type == BinaryOperationType.SUBTRACTION: set_val(expression, left - right) + # Convert to int for operations not supported by Fraction elif expression.type == BinaryOperationType.LEFT_SHIFT: - set_val(expression, left << right) + set_val(expression, int(left) << int(right)) elif expression.type == BinaryOperationType.RIGHT_SHIFT: - set_val(expression, left >> right) + set_val(expression, int(left) >> int(right)) elif expression.type == BinaryOperationType.AND: set_val(expression, int(left) & int(right)) elif expression.type == BinaryOperationType.CARET: @@ -83,6 +84,7 @@ class ConstantFolding(ExpressionVisitor): set_val(expression, int(left) == int(right)) elif expression.type == BinaryOperationType.NOT_EQUAL: set_val(expression, int(left) != int(right)) + # Convert boolean literals from string to bool elif expression.type == BinaryOperationType.ANDAND: set_val(expression, left == "true" and right == "true") elif expression.type == BinaryOperationType.OROR: From 9d811e4d9ea094b73e52200fd7566bba1734210e Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 16 Dec 2022 09:04:55 -0600 Subject: [PATCH 025/110] format tests --- tests/test_constant_folding.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_constant_folding.py b/tests/test_constant_folding.py index 459e2e3c9..32ecd0bbc 100644 --- a/tests/test_constant_folding.py +++ b/tests/test_constant_folding.py @@ -44,6 +44,7 @@ def test_constant_folding_rational(): assert str(variable_g.type) == "int64" assert str(ConstantFolding(variable_g.expression, "int64").result()) == "-7" + def test_constant_folding_binary_expressions(): sl = Slither("./tests/constant_folding_binop.sol") contract = sl.get_contract_from_name("BinOp")[0] @@ -85,9 +86,9 @@ def test_constant_folding_binary_expressions(): assert str(ConstantFolding(variable_i.expression, "bool").result()) == "True" variable_j = contract.get_state_variable_from_name("j") - assert str(variable_j.type) == "bool" + assert str(variable_j.type) == "bool" assert str(ConstantFolding(variable_j.expression, "bool").result()) == "False" variable_k = contract.get_state_variable_from_name("k") assert str(variable_k.type) == "bool" - assert str(ConstantFolding(variable_k.expression, "bool").result()) == "True" \ No newline at end of file + assert str(ConstantFolding(variable_k.expression, "bool").result()) == "True" From 43aba2a1df25c8d8e0acc3d04f9150316a2f6a1f Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 16 Dec 2022 09:30:41 -0600 Subject: [PATCH 026/110] make pylint happy --- slither/core/expressions/literal.py | 2 +- slither/visitors/expression/constants_folding.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/slither/core/expressions/literal.py b/slither/core/expressions/literal.py index 7999ccf02..1b3d1f7fc 100644 --- a/slither/core/expressions/literal.py +++ b/slither/core/expressions/literal.py @@ -1,10 +1,10 @@ from typing import Optional, Union, TYPE_CHECKING +from fractions import Fraction from slither.core.expressions.expression import Expression from slither.core.solidity_types.elementary_type import Fixed, Int, Ufixed, Uint from slither.utils.arithmetic import convert_subdenomination from slither.utils.integer_conversion import convert_string_to_int -from fractions import Fraction if TYPE_CHECKING: from slither.core.solidity_types.type import Type diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index e4cd09eb8..9f74c7543 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -46,6 +46,7 @@ class ConstantFolding(ExpressionVisitor): expr = cf.result() set_val(expression, convert_string_to_int(expr.converted_value)) + # pylint: disable=too-many-branches def _post_binary_operation(self, expression: BinaryOperation): left = get_val(expression.expression_left) right = get_val(expression.expression_right) From e065fbe8f48d03ab82b29caafe0467ef14557c4a Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 16 Dec 2022 13:07:22 -0600 Subject: [PATCH 027/110] emulate wrapped arithmetic behavior --- slither/core/expressions/literal.py | 3 +++ slither/visitors/expression/constants_folding.py | 6 +++++- tests/constant_folding_binop.sol | 1 + tests/test_constant_folding.py | 7 +++++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/slither/core/expressions/literal.py b/slither/core/expressions/literal.py index 1b3d1f7fc..30b35c11a 100644 --- a/slither/core/expressions/literal.py +++ b/slither/core/expressions/literal.py @@ -15,6 +15,9 @@ class Literal(Expression): super().__init__() if isinstance(value, Fraction): value = int(value) + # emulate 256-bit wrapping + if str(custom_type).startswith("uint"): + value = value & (2**256 - 1) self._value: Union[int, str] = value self._type = custom_type self._subdenomination: Optional[str] = subdenomination diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 9f74c7543..3e934772b 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -152,4 +152,8 @@ class ConstantFolding(ExpressionVisitor): raise NotConstant def _post_type_conversion(self, expression): - raise NotConstant + cf = ConstantFolding(expression.expression, self._type) + expr = cf.result() + assert isinstance(expr, Literal) + set_val(expression, convert_string_to_fraction(expr.converted_value)) + return diff --git a/tests/constant_folding_binop.sol b/tests/constant_folding_binop.sol index baab7147f..923418ce7 100644 --- a/tests/constant_folding_binop.sol +++ b/tests/constant_folding_binop.sol @@ -10,4 +10,5 @@ contract BinOp { bool i = 1 != 2; bool j = true && false; bool k = true || false; + uint l = uint(1) - uint(2); } \ No newline at end of file diff --git a/tests/test_constant_folding.py b/tests/test_constant_folding.py index 32ecd0bbc..21517ddc4 100644 --- a/tests/test_constant_folding.py +++ b/tests/test_constant_folding.py @@ -92,3 +92,10 @@ def test_constant_folding_binary_expressions(): variable_k = contract.get_state_variable_from_name("k") assert str(variable_k.type) == "bool" assert str(ConstantFolding(variable_k.expression, "bool").result()) == "True" + + variable_l = contract.get_state_variable_from_name("l") + assert str(variable_l.type) == "uint256" + assert ( + str(ConstantFolding(variable_l.expression, "uint256").result()) + == "115792089237316195423570985008687907853269984665640564039457584007913129639935" + ) From a59f4f12175e984b3bfc9020dda01f943469ddc9 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 16 Dec 2022 13:19:07 -0600 Subject: [PATCH 028/110] move folding logic out of Literal class --- slither/core/expressions/literal.py | 14 +++++--------- slither/visitors/expression/constants_folding.py | 9 ++++++++- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/slither/core/expressions/literal.py b/slither/core/expressions/literal.py index 30b35c11a..328ec9674 100644 --- a/slither/core/expressions/literal.py +++ b/slither/core/expressions/literal.py @@ -1,5 +1,4 @@ from typing import Optional, Union, TYPE_CHECKING -from fractions import Fraction from slither.core.expressions.expression import Expression from slither.core.solidity_types.elementary_type import Fixed, Int, Ufixed, Uint @@ -11,16 +10,13 @@ if TYPE_CHECKING: class Literal(Expression): - def __init__(self, value, custom_type, subdenomination=None): + def __init__( + self, value: Union[int, str], custom_type: "Type", subdenomination: Optional[str] = None + ): super().__init__() - if isinstance(value, Fraction): - value = int(value) - # emulate 256-bit wrapping - if str(custom_type).startswith("uint"): - value = value & (2**256 - 1) - self._value: Union[int, str] = value + self._value = value self._type = custom_type - self._subdenomination: Optional[str] = subdenomination + self._subdenomination = subdenomination @property def value(self) -> Union[int, str]: diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 3e934772b..547cfe50c 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -1,3 +1,4 @@ +from fractions import Fraction from slither.core.expressions import ( BinaryOperationType, Literal, @@ -34,7 +35,13 @@ class ConstantFolding(ExpressionVisitor): super().__init__(expression) def result(self): - return Literal(get_val(self._expression), self._type) + value = get_val(self._expression) + if isinstance(value, Fraction): + value = int(value) + # emulate 256-bit wrapping + if str(self._type).startswith("uint"): + value = value & (2**256 - 1) + return Literal(value, self._type) def _post_identifier(self, expression: Identifier): if not expression.value.is_constant: From 2684717087b37a097e6e54bf2388c8183f3318a3 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 20 Dec 2022 09:26:11 -0600 Subject: [PATCH 029/110] remove unnecessary return --- slither/visitors/expression/constants_folding.py | 1 - 1 file changed, 1 deletion(-) diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index 547cfe50c..797d1f46e 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -163,4 +163,3 @@ class ConstantFolding(ExpressionVisitor): expr = cf.result() assert isinstance(expr, Literal) set_val(expression, convert_string_to_fraction(expr.converted_value)) - return From f12e367f29acf9a32a6a5d6139b8f5b515a18e8a Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Thu, 22 Dec 2022 17:26:00 +0100 Subject: [PATCH 030/110] Update to the latest crytic-compile source unit API --- setup.py | 4 +- slither/core/scope/scope.py | 116 ++++++++++++++++++++++++- slither/printers/summary/evm.py | 18 +--- slither/slithir/convert.py | 10 ++- tests/source_unit/foundry.toml | 6 ++ tests/source_unit/lib/forge-std | 1 + tests/source_unit/script/Counter.s.sol | 12 +++ tests/source_unit/src/Counter.sol | 14 +++ tests/source_unit/src/Counter2.sol | 5 ++ tests/source_unit/test/Counter.t.sol | 24 +++++ tests/test_source_unit.py | 26 ++++++ 11 files changed, 215 insertions(+), 21 deletions(-) create mode 100644 tests/source_unit/foundry.toml create mode 160000 tests/source_unit/lib/forge-std create mode 100644 tests/source_unit/script/Counter.s.sol create mode 100644 tests/source_unit/src/Counter.sol create mode 100644 tests/source_unit/src/Counter2.sol create mode 100644 tests/source_unit/test/Counter.t.sol create mode 100644 tests/test_source_unit.py diff --git a/setup.py b/setup.py index 03fe64c42..86db4fa9a 100644 --- a/setup.py +++ b/setup.py @@ -14,8 +14,8 @@ setup( install_requires=[ "prettytable>=0.7.2", "pycryptodome>=3.4.6", - "crytic-compile>=0.2.4", - # "crytic-compile@git+https://github.com/crytic/crytic-compile.git@master#egg=crytic-compile", + # "crytic-compile>=0.2.4", + "crytic-compile@git+https://github.com/crytic/crytic-compile.git@dev#egg=crytic-compile", ], extras_require={ "dev": [ diff --git a/slither/core/scope/scope.py b/slither/core/scope/scope.py index c6d18556e..2d1c11491 100644 --- a/slither/core/scope/scope.py +++ b/slither/core/scope/scope.py @@ -1,4 +1,7 @@ -from typing import List, Any, Dict, Optional, Union, Set +from typing import List, Any, Dict, Optional, Union, Set, TypeVar, Callable + +from crytic_compile import CompilationUnit +from crytic_compile.source_unit import SourceUnit from crytic_compile.utils.naming import Filename from slither.core.declarations import Contract, Import, Pragma @@ -98,6 +101,117 @@ class FileScope: return self.contracts.get(name.name, None) return self.contracts.get(name, None) + AbstractReturnType = TypeVar("AbstractReturnType") + + def _generic_source_unit_getter( + self, + crytic_compile_compilation_unit: CompilationUnit, + name: str, + getter: Callable[[SourceUnit], Dict[str, AbstractReturnType]], + ) -> Optional[AbstractReturnType]: + + assert self.filename in crytic_compile_compilation_unit.source_units + + source_unit = crytic_compile_compilation_unit.source_unit(self.filename) + + if name in getter(source_unit): + return getter(source_unit)[name] + + for scope in self.accessible_scopes: + source_unit = crytic_compile_compilation_unit.source_unit(scope.filename) + if name in getter(source_unit): + return getter(source_unit)[name] + + return None + + def bytecode_init( + self, crytic_compile_compilation_unit: CompilationUnit, contract_name: str + ) -> Optional[str]: + """ + Return the init bytecode + + Args: + crytic_compile_compilation_unit: + contract_name: + + Returns: + + """ + getter: Callable[[SourceUnit], Dict[str, str]] = lambda x: x.bytecodes_init + return self._generic_source_unit_getter( + crytic_compile_compilation_unit, contract_name, getter + ) + + def bytecode_runtime( + self, crytic_compile_compilation_unit: CompilationUnit, contract_name: str + ) -> Optional[str]: + """ + Return the runtime bytecode + + Args: + crytic_compile_compilation_unit: + contract_name: + + Returns: + + """ + getter: Callable[[SourceUnit], Dict[str, str]] = lambda x: x.bytecodes_runtime + return self._generic_source_unit_getter( + crytic_compile_compilation_unit, contract_name, getter + ) + + def srcmap_init( + self, crytic_compile_compilation_unit: CompilationUnit, contract_name: str + ) -> Optional[List[str]]: + """ + Return the init scrmap + + Args: + crytic_compile_compilation_unit: + contract_name: + + Returns: + + """ + getter: Callable[[SourceUnit], Dict[str, List[str]]] = lambda x: x.srcmaps_init + return self._generic_source_unit_getter( + crytic_compile_compilation_unit, contract_name, getter + ) + + def srcmap_runtime( + self, crytic_compile_compilation_unit: CompilationUnit, contract_name: str + ) -> Optional[List[str]]: + """ + Return the runtime srcmap + + Args: + crytic_compile_compilation_unit: + contract_name: + + Returns: + + """ + getter: Callable[[SourceUnit], Dict[str, List[str]]] = lambda x: x.srcmaps_runtime + return self._generic_source_unit_getter( + crytic_compile_compilation_unit, contract_name, getter + ) + + def abi(self, crytic_compile_compilation_unit: CompilationUnit, contract_name: str) -> Any: + """ + Return the abi + + Args: + crytic_compile_compilation_unit: + contract_name: + + Returns: + + """ + getter: Callable[[SourceUnit], Dict[str, List[str]]] = lambda x: x.abis + return self._generic_source_unit_getter( + crytic_compile_compilation_unit, contract_name, getter + ) + # region Built in definitions ################################################################################### ################################################################################### diff --git a/slither/printers/summary/evm.py b/slither/printers/summary/evm.py index 8476deaca..660d91204 100644 --- a/slither/printers/summary/evm.py +++ b/slither/printers/summary/evm.py @@ -21,14 +21,8 @@ def _extract_evm_info(slither): CFG = load_evm_cfg_builder() for contract in slither.contracts_derived: - contract_bytecode_runtime = ( - contract.compilation_unit.crytic_compile_compilation_unit.bytecode_runtime( - contract.name - ) - ) - contract_srcmap_runtime = ( - contract.compilation_unit.crytic_compile_compilation_unit.srcmap_runtime(contract.name) - ) + contract_bytecode_runtime = contract.scope.bytecode_runtime(contract.name) + contract_srcmap_runtime = contract.scope.srcmap_runtime(contract.name) cfg = CFG(contract_bytecode_runtime) evm_info["cfg", contract.name] = cfg evm_info["mapping", contract.name] = generate_source_to_evm_ins_mapping( @@ -38,12 +32,8 @@ def _extract_evm_info(slither): contract.source_mapping.filename.absolute, ) - contract_bytecode_init = ( - contract.compilation_unit.crytic_compile_compilation_unit.bytecode_init(contract.name) - ) - contract_srcmap_init = ( - contract.compilation_unit.crytic_compile_compilation_unit.srcmap_init(contract.name) - ) + contract_bytecode_init = contract.scope.bytecode_init(contract.name) + contract_srcmap_init = contract.scope.srcmap_init(contract.name) cfg_init = CFG(contract_bytecode_init) evm_info["cfg_init", contract.name] = cfg_init diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index c5817f4cd..bb679ac6b 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -450,19 +450,21 @@ def propagate_type_and_convert_call(result, node): return result -def _convert_type_contract(ir, compilation_unit: "SlitherCompilationUnit"): +def _convert_type_contract(ir: Member) -> Assignment: assert isinstance(ir.variable_left.type, TypeInformation) contract = ir.variable_left.type.type + scope = ir.node.scope + if ir.variable_right == "creationCode": - bytecode = compilation_unit.crytic_compile_compilation_unit.bytecode_init(contract.name) + bytecode = scope.bytecode_init(contract.name) assignment = Assignment(ir.lvalue, Constant(str(bytecode)), ElementaryType("bytes")) assignment.set_expression(ir.expression) assignment.set_node(ir.node) assignment.lvalue.set_type(ElementaryType("bytes")) return assignment if ir.variable_right == "runtimeCode": - bytecode = compilation_unit.crytic_compile_compilation_unit.bytecode_runtime(contract.name) + bytecode = scope.bytecode_runtime(contract.name) assignment = Assignment(ir.lvalue, Constant(str(bytecode)), ElementaryType("bytes")) assignment.set_expression(ir.expression) assignment.set_node(ir.node) @@ -673,7 +675,7 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals if isinstance(ir.variable_left, TemporaryVariable) and isinstance( ir.variable_left.type, TypeInformation ): - return _convert_type_contract(ir, node.function.compilation_unit) + return _convert_type_contract(ir) left = ir.variable_left t = None ir_func = ir.function diff --git a/tests/source_unit/foundry.toml b/tests/source_unit/foundry.toml new file mode 100644 index 000000000..e6810b2b5 --- /dev/null +++ b/tests/source_unit/foundry.toml @@ -0,0 +1,6 @@ +[profile.default] +src = 'src' +out = 'out' +libs = ['lib'] + +# See more config options https://github.com/foundry-rs/foundry/tree/master/config \ No newline at end of file diff --git a/tests/source_unit/lib/forge-std b/tests/source_unit/lib/forge-std new file mode 160000 index 000000000..eb980e1d4 --- /dev/null +++ b/tests/source_unit/lib/forge-std @@ -0,0 +1 @@ +Subproject commit eb980e1d4f0e8173ec27da77297ae411840c8ccb diff --git a/tests/source_unit/script/Counter.s.sol b/tests/source_unit/script/Counter.s.sol new file mode 100644 index 000000000..0e546aba3 --- /dev/null +++ b/tests/source_unit/script/Counter.s.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Script.sol"; + +contract CounterScript is Script { + function setUp() public {} + + function run() public { + vm.broadcast(); + } +} diff --git a/tests/source_unit/src/Counter.sol b/tests/source_unit/src/Counter.sol new file mode 100644 index 000000000..aded7997b --- /dev/null +++ b/tests/source_unit/src/Counter.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +contract Counter { + uint256 public number; + + function setNumber(uint256 newNumber) public { + number = newNumber; + } + + function increment() public { + number++; + } +} diff --git a/tests/source_unit/src/Counter2.sol b/tests/source_unit/src/Counter2.sol new file mode 100644 index 000000000..fa830a446 --- /dev/null +++ b/tests/source_unit/src/Counter2.sol @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +contract Counter { +} diff --git a/tests/source_unit/test/Counter.t.sol b/tests/source_unit/test/Counter.t.sol new file mode 100644 index 000000000..30235e8a8 --- /dev/null +++ b/tests/source_unit/test/Counter.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.13; + +import "forge-std/Test.sol"; +import "../src/Counter.sol"; + +contract CounterTest is Test { + Counter public counter; + + function setUp() public { + counter = new Counter(); + counter.setNumber(0); + } + + function testIncrement() public { + counter.increment(); + assertEq(counter.number(), 1); + } + + function testSetNumber(uint256 x) public { + counter.setNumber(x); + assertEq(counter.number(), x); + } +} diff --git a/tests/test_source_unit.py b/tests/test_source_unit.py new file mode 100644 index 000000000..a76109201 --- /dev/null +++ b/tests/test_source_unit.py @@ -0,0 +1,26 @@ +import inspect + +from crytic_compile import CryticCompile +from crytic_compile.platform.solc_standard_json import SolcStandardJson +from solc_select import solc_select + +from slither import Slither +from slither.detectors import all_detectors +from slither.detectors.abstract_detector import AbstractDetector + + +def test_contract_info(): + slither = Slither("./tests/source_unit") + + assert len(slither.compilation_units) == 1 + compilation_unit = slither.compilation_units[0] + + for source_unit in compilation_unit.crytic_compile_compilation_unit.source_units.values(): + source_unit.remove_metadata() + + counter_sol = compilation_unit.crytic_compile.filename_lookup("tests/source_unit/src/Counter.sol") + assert compilation_unit.scopes[counter_sol].bytecode_init(compilation_unit.crytic_compile_compilation_unit, "Counter") == "608060405234801561001057600080fd5b5060f78061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fe" + + counter2_sol = compilation_unit.crytic_compile.filename_lookup("tests/source_unit/src/Counter2.sol") + assert compilation_unit.scopes[counter2_sol].bytecode_init(compilation_unit.crytic_compile_compilation_unit, "Counter") == "6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfe" + From 9c339a69299bbcb4becadf8fb84f27f3c275e1f8 Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 23 Dec 2022 13:28:40 -0600 Subject: [PATCH 031/110] Implement `--detect` and `--exclude` for slither-check-upgradeability --- slither/tools/upgradeability/__main__.py | 61 ++++++++++++++++++++---- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/slither/tools/upgradeability/__main__.py b/slither/tools/upgradeability/__main__.py index 414a4c175..bafe3fa9e 100644 --- a/slither/tools/upgradeability/__main__.py +++ b/slither/tools/upgradeability/__main__.py @@ -27,7 +27,9 @@ logger: logging.Logger = logging.getLogger("Slither") logger.setLevel(logging.INFO) -def parse_args() -> argparse.Namespace: +def parse_args( + check_classes: List[Type[AbstractCheck]] +) -> argparse.Namespace: parser = argparse.ArgumentParser( description="Slither Upgradeability Checks. For usage information see https://github.com/crytic/slither/wiki/Upgradeability-Checks.", usage="slither-check-upgradeability contract.sol ContractName", @@ -51,6 +53,23 @@ def parse_args() -> argparse.Namespace: default=False, ) + parser.add_argument( + "--detect", + help="Comma-separated list of detectors, defaults to all, " + f"available detectors: {', '.join(d.ARGUMENT for d in check_classes)}", + action="store", + dest="detectors_to_run", + default="all", + ) + + parser.add_argument( + "--exclude", + help="Comma-separated list of detectors that should be excluded", + action="store", + dest="detectors_to_exclude", + default=None, + ) + parser.add_argument( "--list-detectors", help="List available detectors", @@ -104,6 +123,30 @@ def _get_checks() -> List[Type[AbstractCheck]]: return detectors +def choose_checks( + args: argparse.Namespace, all_check_classes: List[Type[AbstractCheck]] +) -> List[Type[AbstractCheck]]: + detectors_to_run = [] + detectors = {d.ARGUMENT: d for d in all_check_classes} + + if args.detectors_to_run == "all": + detectors_to_run = all_check_classes + if args.detectors_to_exclude: + detectors_excluded = args.detectors_to_exclude.split(",") + for detector in detectors: + if detector in detectors_excluded: + detectors_to_run.remove(detectors[detector]) + else: + for detector in args.detectors_to_run.split(","): + if detector in detectors: + detectors_to_run.append(detectors[detector]) + else: + raise Exception(f"Error: {detector} is not a detector") + detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) + return detectors_to_run + return detectors_to_run + + class ListDetectors(argparse.Action): # pylint: disable=too-few-public-methods def __call__( self, parser: Any, *args: Any, **kwargs: Any @@ -200,11 +243,11 @@ def main() -> None: "detectors": [], } - args = parse_args() - + detectors = _get_checks() + args = parse_args(detectors) + detectors_to_run = choose_checks(args, detectors) v1_filename = vars(args)["contract.sol"] number_detectors_run = 0 - detectors = _get_checks() try: variable1 = Slither(v1_filename, **vars(args)) @@ -219,7 +262,7 @@ def main() -> None: return v1_contract = v1_contracts[0] - detectors_results, number_detectors = _checks_on_contract(detectors, v1_contract) + detectors_results, number_detectors = _checks_on_contract(detectors_to_run, v1_contract) json_results["detectors"] += detectors_results number_detectors_run += number_detectors @@ -242,7 +285,7 @@ def main() -> None: json_results["proxy-present"] = True detectors_results, number_detectors = _checks_on_contract_and_proxy( - detectors, v1_contract, proxy_contract + detectors_to_run, v1_contract, proxy_contract ) json_results["detectors"] += detectors_results number_detectors_run += number_detectors @@ -267,19 +310,19 @@ def main() -> None: if proxy_contract: detectors_results, _ = _checks_on_contract_and_proxy( - detectors, v2_contract, proxy_contract + detectors_to_run, v2_contract, proxy_contract ) json_results["detectors"] += detectors_results detectors_results, number_detectors = _checks_on_contract_update( - detectors, v1_contract, v2_contract + detectors_to_run, v1_contract, v2_contract ) json_results["detectors"] += detectors_results number_detectors_run += number_detectors # If there is a V2, we run the contract-only check on the V2 - detectors_results, number_detectors = _checks_on_contract(detectors, v2_contract) + detectors_results, number_detectors = _checks_on_contract(detectors_to_run, v2_contract) json_results["detectors"] += detectors_results number_detectors_run += number_detectors From 194b1bd90563092dbf97d254dda4ad253cda91fe Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 23 Dec 2022 13:41:37 -0600 Subject: [PATCH 032/110] Implement `--exclude-` for slither-check-upgradeability --- slither/tools/upgradeability/__main__.py | 63 +++++++++++++++++++++--- 1 file changed, 56 insertions(+), 7 deletions(-) diff --git a/slither/tools/upgradeability/__main__.py b/slither/tools/upgradeability/__main__.py index bafe3fa9e..f71ed1e5b 100644 --- a/slither/tools/upgradeability/__main__.py +++ b/slither/tools/upgradeability/__main__.py @@ -35,6 +35,8 @@ def parse_args( usage="slither-check-upgradeability contract.sol ContractName", ) + group_checks = parser.add_argument_group("Checks") + parser.add_argument("contract.sol", help="Codebase to analyze") parser.add_argument("ContractName", help="Contract name (logic contract)") @@ -53,7 +55,7 @@ def parse_args( default=False, ) - parser.add_argument( + group_checks.add_argument( "--detect", help="Comma-separated list of detectors, defaults to all, " f"available detectors: {', '.join(d.ARGUMENT for d in check_classes)}", @@ -62,7 +64,15 @@ def parse_args( default="all", ) - parser.add_argument( + group_checks.add_argument( + "--list-detectors", + help="List available detectors", + action=ListDetectors, + nargs=0, + default=False, + ) + + group_checks.add_argument( "--exclude", help="Comma-separated list of detectors that should be excluded", action="store", @@ -70,11 +80,31 @@ def parse_args( default=None, ) - parser.add_argument( - "--list-detectors", - help="List available detectors", - action=ListDetectors, - nargs=0, + group_checks.add_argument( + "--exclude-informational", + help="Exclude informational impact analyses", + action="store_true", + default=False, + ) + + group_checks.add_argument( + "--exclude-low", + help="Exclude low impact analyses", + action="store_true", + default=False, + ) + + group_checks.add_argument( + "--exclude-medium", + help="Exclude medium impact analyses", + action="store_true", + default=False, + ) + + group_checks.add_argument( + "--exclude-high", + help="Exclude high impact analyses", + action="store_true", default=False, ) @@ -144,6 +174,25 @@ def choose_checks( raise Exception(f"Error: {detector} is not a detector") detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) return detectors_to_run + + if args.exclude_informational: + detectors_to_run = [ + d for d in detectors_to_run if d.IMPACT != DetectorClassification.INFORMATIONAL + ] + if args.exclude_low: + detectors_to_run = [ + d for d in detectors_to_run if d.IMPACT != DetectorClassification.LOW + ] + if args.exclude_medium: + detectors_to_run = [ + d for d in detectors_to_run if d.IMPACT != DetectorClassification.MEDIUM + ] + if args.exclude_high: + detectors_to_run = [ + d for d in detectors_to_run if d.IMPACT != DetectorClassification.HIGH + ] + + detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) return detectors_to_run From c66f2dca4069b5e83b5e8e6f6820cf35db96f56e Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 23 Dec 2022 13:51:04 -0600 Subject: [PATCH 033/110] Import `CheckClassification` and fix references --- slither/tools/upgradeability/__main__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/slither/tools/upgradeability/__main__.py b/slither/tools/upgradeability/__main__.py index f71ed1e5b..7a5beacf5 100644 --- a/slither/tools/upgradeability/__main__.py +++ b/slither/tools/upgradeability/__main__.py @@ -14,7 +14,10 @@ from slither.exceptions import SlitherException from slither.utils.colors import red from slither.utils.output import output_to_json from slither.tools.upgradeability.checks import all_checks -from slither.tools.upgradeability.checks.abstract_checks import AbstractCheck +from slither.tools.upgradeability.checks.abstract_checks import ( + AbstractCheck, + CheckClassification, +) from slither.tools.upgradeability.utils.command_line import ( output_detectors_json, output_wiki, @@ -177,19 +180,19 @@ def choose_checks( if args.exclude_informational: detectors_to_run = [ - d for d in detectors_to_run if d.IMPACT != DetectorClassification.INFORMATIONAL + d for d in detectors_to_run if d.IMPACT != CheckClassification.INFORMATIONAL ] if args.exclude_low: detectors_to_run = [ - d for d in detectors_to_run if d.IMPACT != DetectorClassification.LOW + d for d in detectors_to_run if d.IMPACT != CheckClassification.LOW ] if args.exclude_medium: detectors_to_run = [ - d for d in detectors_to_run if d.IMPACT != DetectorClassification.MEDIUM + d for d in detectors_to_run if d.IMPACT != CheckClassification.MEDIUM ] if args.exclude_high: detectors_to_run = [ - d for d in detectors_to_run if d.IMPACT != DetectorClassification.HIGH + d for d in detectors_to_run if d.IMPACT != CheckClassification.HIGH ] detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) From 1965d262b1f9255a9bb17e4546d74b0af19d572b Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 23 Dec 2022 13:52:22 -0600 Subject: [PATCH 034/110] Black --- slither/tools/upgradeability/__main__.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/slither/tools/upgradeability/__main__.py b/slither/tools/upgradeability/__main__.py index 7a5beacf5..ceb9ce421 100644 --- a/slither/tools/upgradeability/__main__.py +++ b/slither/tools/upgradeability/__main__.py @@ -30,9 +30,7 @@ logger: logging.Logger = logging.getLogger("Slither") logger.setLevel(logging.INFO) -def parse_args( - check_classes: List[Type[AbstractCheck]] -) -> argparse.Namespace: +def parse_args(check_classes: List[Type[AbstractCheck]]) -> argparse.Namespace: parser = argparse.ArgumentParser( description="Slither Upgradeability Checks. For usage information see https://github.com/crytic/slither/wiki/Upgradeability-Checks.", usage="slither-check-upgradeability contract.sol ContractName", @@ -183,17 +181,11 @@ def choose_checks( d for d in detectors_to_run if d.IMPACT != CheckClassification.INFORMATIONAL ] if args.exclude_low: - detectors_to_run = [ - d for d in detectors_to_run if d.IMPACT != CheckClassification.LOW - ] + detectors_to_run = [d for d in detectors_to_run if d.IMPACT != CheckClassification.LOW] if args.exclude_medium: - detectors_to_run = [ - d for d in detectors_to_run if d.IMPACT != CheckClassification.MEDIUM - ] + detectors_to_run = [d for d in detectors_to_run if d.IMPACT != CheckClassification.MEDIUM] if args.exclude_high: - detectors_to_run = [ - d for d in detectors_to_run if d.IMPACT != CheckClassification.HIGH - ] + detectors_to_run = [d for d in detectors_to_run if d.IMPACT != CheckClassification.HIGH] detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) return detectors_to_run From cd8c6388e7e2e1865a590caae9707f39ec9b0eae Mon Sep 17 00:00:00 2001 From: webthethird Date: Fri, 23 Dec 2022 13:58:55 -0600 Subject: [PATCH 035/110] Don't sort checks by impact which caused CI test to fail --- slither/tools/upgradeability/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/tools/upgradeability/__main__.py b/slither/tools/upgradeability/__main__.py index ceb9ce421..56b838b9c 100644 --- a/slither/tools/upgradeability/__main__.py +++ b/slither/tools/upgradeability/__main__.py @@ -187,7 +187,7 @@ def choose_checks( if args.exclude_high: detectors_to_run = [d for d in detectors_to_run if d.IMPACT != CheckClassification.HIGH] - detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) + # detectors_to_run = sorted(detectors_to_run, key=lambda x: x.IMPACT) return detectors_to_run From d9ea635a836d6e70367d73d9b67875efa9a42904 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Tue, 3 Jan 2023 13:35:11 +0100 Subject: [PATCH 036/110] Additional updates --- slither/detectors/attributes/constant_pragma.py | 2 +- slither/slithir/convert.py | 10 +++++++--- tests/test_source_unit.py | 10 +--------- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/slither/detectors/attributes/constant_pragma.py b/slither/detectors/attributes/constant_pragma.py index fe68051c2..0c77b69ca 100644 --- a/slither/detectors/attributes/constant_pragma.py +++ b/slither/detectors/attributes/constant_pragma.py @@ -32,7 +32,7 @@ class ConstantPragma(AbstractDetector): info = ["Different versions of Solidity are used:\n"] info += [f"\t- Version used: {[str(v) for v in versions]}\n"] - for p in pragma: + for p in sorted(pragma, key=lambda x: x.version): info += ["\t- ", p, "\n"] res = self.generate_result(info) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index bb679ac6b..0b43184bd 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -454,17 +454,21 @@ def _convert_type_contract(ir: Member) -> Assignment: assert isinstance(ir.variable_left.type, TypeInformation) contract = ir.variable_left.type.type - scope = ir.node.scope + scope = ir.node.file_scope if ir.variable_right == "creationCode": - bytecode = scope.bytecode_init(contract.name) + bytecode = scope.bytecode_init( + ir.node.compilation_unit.crytic_compile_compilation_unit, contract.name + ) assignment = Assignment(ir.lvalue, Constant(str(bytecode)), ElementaryType("bytes")) assignment.set_expression(ir.expression) assignment.set_node(ir.node) assignment.lvalue.set_type(ElementaryType("bytes")) return assignment if ir.variable_right == "runtimeCode": - bytecode = scope.bytecode_runtime(contract.name) + bytecode = scope.bytecode_runtime( + ir.node.compilation_unit.crytic_compile_compilation_unit, contract.name + ) assignment = Assignment(ir.lvalue, Constant(str(bytecode)), ElementaryType("bytes")) assignment.set_expression(ir.expression) assignment.set_node(ir.node) diff --git a/tests/test_source_unit.py b/tests/test_source_unit.py index a76109201..a94cd3557 100644 --- a/tests/test_source_unit.py +++ b/tests/test_source_unit.py @@ -1,15 +1,7 @@ -import inspect - -from crytic_compile import CryticCompile -from crytic_compile.platform.solc_standard_json import SolcStandardJson -from solc_select import solc_select - from slither import Slither -from slither.detectors import all_detectors -from slither.detectors.abstract_detector import AbstractDetector -def test_contract_info(): +def test_contract_info() -> None: slither = Slither("./tests/source_unit") assert len(slither.compilation_units) == 1 From feafd9bbc65e57e2b4c08518de2b9b89870caf5b Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Tue, 3 Jan 2023 14:20:21 +0100 Subject: [PATCH 037/110] Improvements --- slither/tools/documentation/__main__.py | 158 ++++++++++++++---------- 1 file changed, 93 insertions(+), 65 deletions(-) diff --git a/slither/tools/documentation/__main__.py b/slither/tools/documentation/__main__.py index ea45ed8e1..1f2280de7 100644 --- a/slither/tools/documentation/__main__.py +++ b/slither/tools/documentation/__main__.py @@ -36,7 +36,12 @@ def parse_args() -> argparse.Namespace: default=False, ) - parser.add_argument("--retry", help="Retry failed query (default 1). Each retry increases the temperature by 0.1", action="store", default=1) + parser.add_argument( + "--retry", + help="Retry failed query (default 1). Each retry increases the temperature by 0.1", + action="store", + default=1, + ) # Add default arguments from crytic-compile cryticparser.init(parser) @@ -122,7 +127,75 @@ def _handle_codex( return None -# pylint: disable=too-many-locals +# pylint: disable=too-many-locals,too-many-arguments +def _handle_function( + function: Function, + overwrite: bool, + all_patches: Dict, + logging_file: Optional[str], + slither: Slither, + retry: int, + force: bool, +) -> bool: + if ( + function.source_mapping.is_dependency + or function.has_documentation + or function.is_constructor_variables + ): + return overwrite + prompt = "Create a natpsec documentation for this solidity code with only notice and dev.\n" + src_mapping = function.source_mapping + content = function.compilation_unit.core.source_code[src_mapping.filename.absolute] + start = src_mapping.start + end = src_mapping.start + src_mapping.length + prompt += content[start:end] + + use_tab = _use_tab(content[start - 1]) + if use_tab is None and src_mapping.starting_column > 1: + logger.info(f"Non standard space indentation found {content[start - 1:end]}") + if overwrite: + logger.info("Disable overwrite to avoid mistakes") + overwrite = False + + openai = codex.openai_module() # type: ignore + if openai is None: + raise ImportError + + if logging_file: + codex.log_codex(logging_file, "Q: " + prompt) + + tentative = 0 + answer_processed: Optional[str] = None + while tentative < retry: + tentative += 1 + + answer = openai.Completion.create( # type: ignore + prompt=prompt, + model=slither.codex_model, + temperature=min(slither.codex_temperature + tentative * 0.1, 1), + max_tokens=slither.codex_max_tokens, + ) + + if logging_file: + codex.log_codex(logging_file, "A: " + str(answer)) + + answer_processed = _handle_codex(answer, src_mapping.starting_column, use_tab, force) + if answer_processed: + break + + logger.info( + f"Codex could not generate a well formatted answer for {function.canonical_name}" + ) + logger.info(answer) + + if not answer_processed: + return overwrite + + create_patch(all_patches, src_mapping.filename.absolute, start, start, "", answer_processed) + + return overwrite + + def _handle_compilation_unit( slither: Slither, compilation_unit: SlitherCompilationUnit, @@ -130,8 +203,11 @@ def _handle_compilation_unit( force: bool, retry: int, ) -> None: - - logging_file = str(uuid.uuid4()) + logging_file: Optional[str] + if slither.codex_log: + logging_file = str(uuid.uuid4()) + else: + logging_file = None for scope in compilation_unit.scopes.values(): @@ -153,63 +229,8 @@ def _handle_compilation_unit( all_patches: Dict = {} for function in functions_target: - - if function.source_mapping.is_dependency or function.has_documentation or function.is_constructor_variables: - continue - prompt = ( - "Create a natpsec documentation for this solidity code with only notice and dev.\n" - ) - src_mapping = function.source_mapping - content = compilation_unit.core.source_code[src_mapping.filename.absolute] - start = src_mapping.start - end = src_mapping.start + src_mapping.length - prompt += content[start:end] - - use_tab = _use_tab(content[start - 1]) - if use_tab is None and src_mapping.starting_column > 1: - logger.info(f"Non standard space indentation found {content[start-1:end]}") - if overwrite: - logger.info("Disable overwrite to avoid mistakes") - overwrite = False - - openai = codex.openai_module() # type: ignore - if openai is None: - return - - if slither.codex_log: - codex.log_codex(logging_file, "Q: " + prompt) - - tentative = 0 - answer_processed: Optional[str] = None - while tentative < retry: - tentative += 1 - - answer = openai.Completion.create( # type: ignore - prompt=prompt, - model=slither.codex_model, - temperature=min(slither.codex_temperature + tentative*0.1, 1), - max_tokens=slither.codex_max_tokens, - ) - - if slither.codex_log: - codex.log_codex(logging_file, "A: " + str(answer)) - - answer_processed = _handle_codex( - answer, src_mapping.starting_column, use_tab, force - ) - if answer_processed: - break - - logger.info( - f"Codex could not generate a well formatted answer for {function.canonical_name}" - ) - logger.info(answer) - - if not answer_processed: - continue - - create_patch( - all_patches, src_mapping.filename.absolute, start, start, "", answer_processed + overwrite = _handle_function( + function, overwrite, all_patches, logging_file, slither, retry, force ) # all_patches["patches"] should have only 1 file @@ -242,10 +263,17 @@ def main() -> None: logger.info("Be aware of OpenAI ToS: https://openai.com/api/policies/terms/") slither = Slither(args.project, **vars(args)) - for compilation_unit in slither.compilation_units: - _handle_compilation_unit( - slither, compilation_unit, args.overwrite, args.force_answer_parsing, int(args.retry) - ) + try: + for compilation_unit in slither.compilation_units: + _handle_compilation_unit( + slither, + compilation_unit, + args.overwrite, + args.force_answer_parsing, + int(args.retry), + ) + except ImportError: + pass if __name__ == "__main__": From 518137aba546227793cdf873bf58340c64032179 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Tue, 3 Jan 2023 14:29:37 +0100 Subject: [PATCH 038/110] Use latest setuptools in CI Tentative to fix https://github.com/crytic/slither/issues/1538 --- .github/workflows/pip-audit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pip-audit.yml b/.github/workflows/pip-audit.yml index d0fcb419c..636093071 100644 --- a/.github/workflows/pip-audit.yml +++ b/.github/workflows/pip-audit.yml @@ -26,7 +26,7 @@ jobs: python -m venv /tmp/pip-audit-env source /tmp/pip-audit-env/bin/activate - python -m pip install --upgrade pip + python -m pip install --upgrade pip setuptools wheel python -m pip install . - name: Run pip-audit From 217970fb914842f4585ea8481190e8787b301a41 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Tue, 3 Jan 2023 14:32:15 +0100 Subject: [PATCH 039/110] Black --- tests/test_source_unit.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/tests/test_source_unit.py b/tests/test_source_unit.py index a94cd3557..7b653599e 100644 --- a/tests/test_source_unit.py +++ b/tests/test_source_unit.py @@ -10,9 +10,22 @@ def test_contract_info() -> None: for source_unit in compilation_unit.crytic_compile_compilation_unit.source_units.values(): source_unit.remove_metadata() - counter_sol = compilation_unit.crytic_compile.filename_lookup("tests/source_unit/src/Counter.sol") - assert compilation_unit.scopes[counter_sol].bytecode_init(compilation_unit.crytic_compile_compilation_unit, "Counter") == "608060405234801561001057600080fd5b5060f78061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fe" - - counter2_sol = compilation_unit.crytic_compile.filename_lookup("tests/source_unit/src/Counter2.sol") - assert compilation_unit.scopes[counter2_sol].bytecode_init(compilation_unit.crytic_compile_compilation_unit, "Counter") == "6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfe" + counter_sol = compilation_unit.crytic_compile.filename_lookup( + "tests/source_unit/src/Counter.sol" + ) + assert ( + compilation_unit.scopes[counter_sol].bytecode_init( + compilation_unit.crytic_compile_compilation_unit, "Counter" + ) + == "608060405234801561001057600080fd5b5060f78061001f6000396000f3fe6080604052348015600f57600080fd5b5060043610603c5760003560e01c80633fb5c1cb1460415780638381f58a146053578063d09de08a14606d575b600080fd5b6051604c3660046083565b600055565b005b605b60005481565b60405190815260200160405180910390f35b6051600080549080607c83609b565b9190505550565b600060208284031215609457600080fd5b5035919050565b60006001820160ba57634e487b7160e01b600052601160045260246000fd5b506001019056fe" + ) + counter2_sol = compilation_unit.crytic_compile.filename_lookup( + "tests/source_unit/src/Counter2.sol" + ) + assert ( + compilation_unit.scopes[counter2_sol].bytecode_init( + compilation_unit.crytic_compile_compilation_unit, "Counter" + ) + == "6080604052348015600f57600080fd5b50603f80601d6000396000f3fe6080604052600080fdfe" + ) From 45e90dc4c10120ac0f52b1490e62167870277c97 Mon Sep 17 00:00:00 2001 From: Simone Date: Tue, 3 Jan 2023 15:13:14 +0100 Subject: [PATCH 040/110] Fix top level struct parsing --- slither/solc_parsing/slither_compilation_unit_solc.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index d12bda1b4..6dce9b005 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -24,6 +24,7 @@ from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc from slither.solc_parsing.exceptions import VariableNotFound from slither.solc_parsing.variables.top_level_variable import TopLevelVariableSolc +from slither.solc_parsing.declarations.caller_context import CallerContextExpression logging.basicConfig() logger = logging.getLogger("SlitherSolcParsing") @@ -57,7 +58,7 @@ def _handle_import_aliases( scope.renaming[local_name] = original_name -class SlitherCompilationUnitSolc: +class SlitherCompilationUnitSolc(CallerContextExpression): # pylint: disable=no-self-use,too-many-instance-attributes def __init__(self, compilation_unit: SlitherCompilationUnit): super().__init__() @@ -95,6 +96,10 @@ class SlitherCompilationUnitSolc: def underlying_contract_to_parser(self) -> Dict[Contract, ContractSolc]: return self._underlying_contract_to_parser + @property + def slither_parser(self) -> "SlitherCompilationUnitSolc": + return self + ################################################################################### ################################################################################### # region AST From 680c914ded73e5b221f9df903da8050ed4756ce7 Mon Sep 17 00:00:00 2001 From: Simone Date: Tue, 3 Jan 2023 15:29:20 +0100 Subject: [PATCH 041/110] Add test --- ...p-level-struct-0.8.0.sol-0.8.0-compact.zip | Bin 0 -> 2027 bytes ...-level-struct-0.8.0.sol-0.8.0-compact.json | 3 +++ tests/ast-parsing/top-level-struct-0.8.0.sol | 18 ++++++++++++++++++ tests/test_ast_parsing.py | 1 + 4 files changed, 22 insertions(+) create mode 100644 tests/ast-parsing/compile/top-level-struct-0.8.0.sol-0.8.0-compact.zip create mode 100644 tests/ast-parsing/expected/top-level-struct-0.8.0.sol-0.8.0-compact.json create mode 100644 tests/ast-parsing/top-level-struct-0.8.0.sol diff --git a/tests/ast-parsing/compile/top-level-struct-0.8.0.sol-0.8.0-compact.zip b/tests/ast-parsing/compile/top-level-struct-0.8.0.sol-0.8.0-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..7cb2fb659609b654a99a51480f172e7555306ef0 GIT binary patch literal 2027 zcmb8wX&}>$0|)TmOq&+TP087uZRT+;(#n)GH1bq)#GH%Sm>IciEFO|0w~0i}BM~i+ z5|X2sBg7OUDrb(c9RHsG`~Qpo_xs}e>ihcRU;`G!00O{4AR~ z005{#WJG{B%{u@QLJbZjP!T938i_)N1O>Qz)5$@>RCkYHf}cOl8%YcaBJCI42e<-2 zEC84?nZA14dX#(pJ@qCc1#KjMc#{Gn1$X$A;&8|dY29_~sZ`z(53#8)oRtI4MYq>2 z53g41;1+YTEz1v$yr)tMNkWb9u$51%tmmZPmi(CbvDy*U;=X`4g>g*HFQ!P>F$C}} z4wvS9({^#fNLRHNdF?mr(!ztp2Su!Sz3vlPj-3-%Z^9%z0X7U{vU)iQ^1BD6Kt;yaqh?RTYzFae;%GnYvxX8eOb6W0#j^oXNfb?OX7+8d|ed1N-B z-0BW|icHqLExr(z{k5EzB`|%Yz+CL+OX#y%gT3)rT=Brq+;6%fJqm-FgYhHFL-Fw0 zM_@U$|A*uUWA)8#ABNkLpktOys1l=IZvIol2{#0aWSbPFt?_pgyXKU?QGU zw|ciCJNKd6^eVG0Hu(xY?e{A9Z$j&Ck-BbP&q3y#AZ zEHuA#oeJA4Dr(iWwOq@m9q%W-wIwvB59Z4WuSy&R*LQ09*yD~R!gxD%^9#LHRA~3v zptY+*q(4EC+7Se|zs}z=tzSf^JzQ({yuE)S^@)KOpA}s=G5O%AYTEe|Nnh6-&m z#c1Y9eDix&4K2#U9`@bQ(*ZX0;9IaoJFHxIZK{Cv`}Q>*TZ}2~amOmm6fuBZsN(MG z+zQ|0@?m3nfl69}_BglaYNy*xvL?2FIbkKT-tbSoEL)B-Fd%B|kL{l_R$BfQ`{{cr zUuIg|r}to3bqIX)*WJ1YVSzd!DvMcvKZtm-yf-{p-jYR%+JpoiAmWdWnDe&bX9z}7 zT#V}VC>}@`5+k*|+F$Jyu1*^t>YDLGy@WC$yZ8M>jIOMu0K02sC-0XGA)xk9J^F+I zcsR18=RD1EtN99=(=CI`(2Ne>8~u6Gjh^|~Mr^UmA50sU=`0O>A^t3Z4>;HI@{ z1*A)IuB0oIXPsGY(=cRr^l6wdEV*@1CtDbSkqX_=jNvD1!EseMyrpa!MBA8wt^OW;F45L#Q|HJ zT{5%NC|#p$_twRpPuY`$c))Coclw-KSsBeQj76kaKB0Z<>;3m3FJnQL?iTFj@7#3szYSzmtA#%^x1R1!rC`7jzNRW<$;#+sL*Q z9*%iT&j?gK7qQlE$bY`nW-gBh*b_ZdJ)VKAVAn4By{qw;>CCReKa=fw=o*#0kI^Ci zN#!F9Llw3e!JW@1xVN3tOI!zU<3~l~L<2nqEtDwgUa#!QGqJi;=})b93`F9fO~NI;X5&ELI4UToDpZjmk0;Ol^%KN}}U}5i`2|qb6Px;g2tLD%bRZ zdKZdwyd74DshduessvR9PV5dvs(j9feS8Tna>EJ%@0!2JZGVA)0JEabjL|&&-j7Ev pYYsLb0Sx$m)B9WB|0Wjn@BDudJJ{@l{QCm^uFLNY|4ljo{09_{xwZfR literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/expected/top-level-struct-0.8.0.sol-0.8.0-compact.json b/tests/ast-parsing/expected/top-level-struct-0.8.0.sol-0.8.0-compact.json new file mode 100644 index 000000000..65dfd3b51 --- /dev/null +++ b/tests/ast-parsing/expected/top-level-struct-0.8.0.sol-0.8.0-compact.json @@ -0,0 +1,3 @@ +{ + "BaseContract": {} +} \ No newline at end of file diff --git a/tests/ast-parsing/top-level-struct-0.8.0.sol b/tests/ast-parsing/top-level-struct-0.8.0.sol new file mode 100644 index 000000000..8a335680c --- /dev/null +++ b/tests/ast-parsing/top-level-struct-0.8.0.sol @@ -0,0 +1,18 @@ +struct my_struct { + uint[][] a; // works fine + uint[][3] b; // works fine + uint[3][] c; // fails + uint[3][3] d; // fails + uint[2**20] e; // works fine +} +contract BaseContract{ + struct my_struct_2 { + uint[][] f; // works fine + uint[][3] g; // works fine + uint[3][] h; // works fine + uint[3][3] i; // works fine + uint[2**20] j; // works fine + } + + uint[3][] k; // works fine +} diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index e96a129b8..47f230534 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -425,6 +425,7 @@ ALL_TESTS = [ Test("free_functions/library_constant_function_collision.sol", ["0.8.12"]), Test("ternary-with-max.sol", ["0.8.15"]), Test("library_event-0.8.16.sol", ["0.8.16"]), + Test("top-level-struct-0.8.0.sol", ["0.8.0"]), ] # create the output folder if needed try: From 04949548e9b05535a76f740e0099d4667fee2dec Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Tue, 3 Jan 2023 16:02:54 +0100 Subject: [PATCH 042/110] Minor --- slither/tools/documentation/README.md | 6 +++--- slither/tools/documentation/__main__.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/slither/tools/documentation/README.md b/slither/tools/documentation/README.md index 2ed90692c..5e70b3a49 100644 --- a/slither/tools/documentation/README.md +++ b/slither/tools/documentation/README.md @@ -1,6 +1,6 @@ -# Demo +# slither-documentation -This directory contains an example of Slither utility. +`slither-documentation` uses [codex](https://beta.openai.com) to generate natspec documenation. -See the [utility documentation](https://github.com/crytic/slither/wiki/Adding-a-new-utility) +This tool is experimental. See https://github.com/montyly/solmate/pull/1 for an example of usage. diff --git a/slither/tools/documentation/__main__.py b/slither/tools/documentation/__main__.py index 1f2280de7..8e545fb09 100644 --- a/slither/tools/documentation/__main__.py +++ b/slither/tools/documentation/__main__.py @@ -211,7 +211,7 @@ def _handle_compilation_unit( for scope in compilation_unit.scopes.values(): - # TODO remove hardcoded filtering + # Dont send tests file if ( ".t.sol" in scope.filename.absolute or "mock" in scope.filename.absolute.lower() From 656f2145ae7fc268a54da5098bbed0179cab5aff Mon Sep 17 00:00:00 2001 From: pavan-nambi Date: Tue, 3 Jan 2023 21:02:49 +0530 Subject: [PATCH 043/110] chore(CI):removing solc-select install all lines --- .github/workflows/IR.yml | 1 - .github/workflows/ci.yml | 1 - .github/workflows/detectors.yml | 1 - .github/workflows/features.yml | 1 - 4 files changed, 4 deletions(-) diff --git a/.github/workflows/IR.yml b/.github/workflows/IR.yml index 434cef75b..b1d11478f 100644 --- a/.github/workflows/IR.yml +++ b/.github/workflows/IR.yml @@ -34,7 +34,6 @@ jobs: - name: Install dependencies run: | pip install ".[dev]" - solc-select install all solc-select use 0.8.11 - name: Test with pytest diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ae5326a8..7338d248c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,6 @@ jobs: - name: Install dependencies run: | pip install ".[dev]" - solc-select install all solc-select use 0.5.1 pip install typing_extensions==4.1.1 pip install importlib_metadata==4.8.3 diff --git a/.github/workflows/detectors.yml b/.github/workflows/detectors.yml index 8f3b45d15..c85e8d26b 100644 --- a/.github/workflows/detectors.yml +++ b/.github/workflows/detectors.yml @@ -35,7 +35,6 @@ jobs: run: | pip install ".[dev]" - solc-select install all solc-select use 0.7.3 - name: Test with pytest run: | diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 49db14793..14150388a 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -35,7 +35,6 @@ jobs: run: | pip install ".[dev]" - solc-select install all solc-select use 0.8.0 cd tests/test_node_modules/ From df896e80f2814befab085a34072374dc6ebe9ebf Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 3 Jan 2023 09:40:26 -0600 Subject: [PATCH 044/110] better error handling of malformed symbol alias AST node for solc <0.6.0 --- .../slither_compilation_unit_solc.py | 27 +++++++++++-------- .../import_aliases_issue_1319/import.sol | 1 + .../import_aliases_issue_1319/test.sol | 9 +++++++ .../import_aliases_issue_1319/test_fail.sol | 9 +++++++ 4 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 tests/ast-parsing/complex_imports/import_aliases_issue_1319/import.sol create mode 100644 tests/ast-parsing/complex_imports/import_aliases_issue_1319/test.sol create mode 100644 tests/ast-parsing/complex_imports/import_aliases_issue_1319/test_fail.sol diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index d12bda1b4..5c93d5f1d 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -45,16 +45,22 @@ def _handle_import_aliases( """ for symbol_alias in symbol_aliases: - if ( - "foreign" in symbol_alias - and "name" in symbol_alias["foreign"] - and "local" in symbol_alias - ): - original_name = symbol_alias["foreign"]["name"] - local_name = symbol_alias["local"] - import_directive.renaming[local_name] = original_name - # Assuming that two imports cannot collide in renaming - scope.renaming[local_name] = original_name + if "foreign" in symbol_alias and "local" in symbol_alias: + if isinstance(symbol_alias["foreign"], dict) and "name" in symbol_alias["foreign"]: + + original_name = symbol_alias["foreign"]["name"] + local_name = symbol_alias["local"] + import_directive.renaming[local_name] = original_name + # Assuming that two imports cannot collide in renaming + scope.renaming[local_name] = original_name + + # This path should only be hit for the malformed AST of solc 0.5.12 where + # the foreign identifier cannot be found but is required to resolve the alias. + # see https://github.com/crytic/slither/issues/1319 + if symbol_alias["local"]: + raise SlitherException( + "Cannot resolve local alias for import directive due to malformed AST. Please upgrade to solc 0.6.0 or higher." + ) class SlitherCompilationUnitSolc: @@ -389,7 +395,6 @@ Please rename it, this name is reserved for Slither's internals""" ) self._contracts_by_id[contract.id] = contract self._compilation_unit.contracts.append(contract) - # Update of the inheritance for contract_parser in self._underlying_contract_to_parser.values(): # remove the first elem in linearizedBaseContracts as it is the contract itself diff --git a/tests/ast-parsing/complex_imports/import_aliases_issue_1319/import.sol b/tests/ast-parsing/complex_imports/import_aliases_issue_1319/import.sol new file mode 100644 index 000000000..7cfff4bfa --- /dev/null +++ b/tests/ast-parsing/complex_imports/import_aliases_issue_1319/import.sol @@ -0,0 +1 @@ +contract A {} \ No newline at end of file diff --git a/tests/ast-parsing/complex_imports/import_aliases_issue_1319/test.sol b/tests/ast-parsing/complex_imports/import_aliases_issue_1319/test.sol new file mode 100644 index 000000000..7c5bf1eee --- /dev/null +++ b/tests/ast-parsing/complex_imports/import_aliases_issue_1319/test.sol @@ -0,0 +1,9 @@ +pragma solidity 0.5.12; + +import {A} from "./import.sol"; + +contract Z is A { + function test() public pure returns (uint) { + return 1; + } +} \ No newline at end of file diff --git a/tests/ast-parsing/complex_imports/import_aliases_issue_1319/test_fail.sol b/tests/ast-parsing/complex_imports/import_aliases_issue_1319/test_fail.sol new file mode 100644 index 000000000..eb2ab8af0 --- /dev/null +++ b/tests/ast-parsing/complex_imports/import_aliases_issue_1319/test_fail.sol @@ -0,0 +1,9 @@ +pragma solidity 0.5.12; + +import {A as X, A as Y} from "./import.sol"; + +contract Z is X { + function test() public pure returns (uint) { + return 1; + } +} \ No newline at end of file From f92cb37a400f9ddf72f4d48ebfc5a786de5236fc Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 3 Jan 2023 09:49:50 -0600 Subject: [PATCH 045/110] only check for local alias if foreign isn't dict --- slither/solc_parsing/slither_compilation_unit_solc.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 5c93d5f1d..05dc4113b 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -57,7 +57,7 @@ def _handle_import_aliases( # This path should only be hit for the malformed AST of solc 0.5.12 where # the foreign identifier cannot be found but is required to resolve the alias. # see https://github.com/crytic/slither/issues/1319 - if symbol_alias["local"]: + elif symbol_alias["local"]: raise SlitherException( "Cannot resolve local alias for import directive due to malformed AST. Please upgrade to solc 0.6.0 or higher." ) @@ -395,6 +395,7 @@ Please rename it, this name is reserved for Slither's internals""" ) self._contracts_by_id[contract.id] = contract self._compilation_unit.contracts.append(contract) + # Update of the inheritance for contract_parser in self._underlying_contract_to_parser.values(): # remove the first elem in linearizedBaseContracts as it is the contract itself From 1b6acfa9a40f712d6d2cda44496c13c858968370 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 3 Jan 2023 09:50:30 -0600 Subject: [PATCH 046/110] format --- slither/solc_parsing/slither_compilation_unit_solc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 05dc4113b..930f60ff9 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -395,7 +395,7 @@ Please rename it, this name is reserved for Slither's internals""" ) self._contracts_by_id[contract.id] = contract self._compilation_unit.contracts.append(contract) - + # Update of the inheritance for contract_parser in self._underlying_contract_to_parser.values(): # remove the first elem in linearizedBaseContracts as it is the contract itself From 3e67fff11768e6c39f8f82cc65ef1c0f883723ff Mon Sep 17 00:00:00 2001 From: pavan-nambi Date: Tue, 3 Jan 2023 21:21:03 +0530 Subject: [PATCH 047/110] update(#1546) --- .github/workflows/IR.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/detectors.yml | 2 +- .github/workflows/features.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/IR.yml b/.github/workflows/IR.yml index b1d11478f..29e6ba2a0 100644 --- a/.github/workflows/IR.yml +++ b/.github/workflows/IR.yml @@ -34,7 +34,7 @@ jobs: - name: Install dependencies run: | pip install ".[dev]" - solc-select use 0.8.11 + solc-select use 0.8.11--always-install - name: Test with pytest run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7338d248c..ff038574a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - name: Install dependencies run: | pip install ".[dev]" - solc-select use 0.5.1 + solc-select use 0.5.1--always-install pip install typing_extensions==4.1.1 pip install importlib_metadata==4.8.3 diff --git a/.github/workflows/detectors.yml b/.github/workflows/detectors.yml index c85e8d26b..ff568a046 100644 --- a/.github/workflows/detectors.yml +++ b/.github/workflows/detectors.yml @@ -35,7 +35,7 @@ jobs: run: | pip install ".[dev]" - solc-select use 0.7.3 + solc-select use 0.7.3--always-install - name: Test with pytest run: | pytest tests/test_detectors.py diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index 14150388a..dada1e141 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -35,7 +35,7 @@ jobs: run: | pip install ".[dev]" - solc-select use 0.8.0 + solc-select use 0.8.0--always-install cd tests/test_node_modules/ npm install hardhat From 41806075a6d258fdfedae91f8263bf27c6231aa7 Mon Sep 17 00:00:00 2001 From: pavan-nambi Date: Tue, 3 Jan 2023 21:42:30 +0530 Subject: [PATCH 048/110] update2(#1546) --- .github/workflows/IR.yml | 2 +- .github/workflows/ci.yml | 2 +- .github/workflows/detectors.yml | 2 +- .github/workflows/features.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/IR.yml b/.github/workflows/IR.yml index 29e6ba2a0..c5187da65 100644 --- a/.github/workflows/IR.yml +++ b/.github/workflows/IR.yml @@ -34,7 +34,7 @@ jobs: - name: Install dependencies run: | pip install ".[dev]" - solc-select use 0.8.11--always-install + solc-select use 0.8.11 --always-install - name: Test with pytest run: | diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff038574a..3378cd420 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: - name: Install dependencies run: | pip install ".[dev]" - solc-select use 0.5.1--always-install + solc-select use 0.5.1 --always-install pip install typing_extensions==4.1.1 pip install importlib_metadata==4.8.3 diff --git a/.github/workflows/detectors.yml b/.github/workflows/detectors.yml index ff568a046..15aa8a5dd 100644 --- a/.github/workflows/detectors.yml +++ b/.github/workflows/detectors.yml @@ -35,7 +35,7 @@ jobs: run: | pip install ".[dev]" - solc-select use 0.7.3--always-install + solc-select use 0.7.3 --always-install - name: Test with pytest run: | pytest tests/test_detectors.py diff --git a/.github/workflows/features.yml b/.github/workflows/features.yml index dada1e141..5007fd7bf 100644 --- a/.github/workflows/features.yml +++ b/.github/workflows/features.yml @@ -35,7 +35,7 @@ jobs: run: | pip install ".[dev]" - solc-select use 0.8.0--always-install + solc-select use 0.8.0 --always-install cd tests/test_node_modules/ npm install hardhat From baf4143345059339719a12960283eed6e6490f6c Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 3 Jan 2023 12:03:29 -0600 Subject: [PATCH 049/110] move nested logic into functions --- slither/utils/expression_manipulations.py | 178 +++++++++++----------- 1 file changed, 92 insertions(+), 86 deletions(-) diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index 591fab0ef..974c6f68b 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -23,7 +23,8 @@ from slither.all_exceptions import SlitherException # pylint: disable=protected-access def f_expressions( - e: AssignmentOperation, x: Union[Identifier, Literal, MemberAccess, IndexAccess] + e: Union[AssignmentOperation, BinaryOperation, TupleExpression], + x: Union[Identifier, Literal, MemberAccess, IndexAccess], ) -> None: e._expressions.append(x) @@ -40,7 +41,7 @@ def f_call_gas(e: CallExpression, x): e._gas = x -def f_expression(e, x): +def f_expression(e: Union[TypeConversion, UnaryOperation, MemberAccess], x): e._expression = x @@ -86,7 +87,6 @@ class SplitTernaryExpression: f(false_expression, copy.copy(next_expr)) return True - # pylint: disable=too-many-branches def copy_expression( self, expression: Expression, true_expression: Expression, false_expression: Expression ) -> None: @@ -102,108 +102,114 @@ class SplitTernaryExpression: ): return - # case of lib - # (.. ? .. : ..).add - if isinstance(expression, MemberAccess): - next_expr = expression.expression - if self.conditional_not_ahead( - next_expr, true_expression, false_expression, f_expression - ): - self.copy_expression( - next_expr, true_expression.expression, false_expression.expression - ) - # pylint: disable=too-many-nested-blocks elif isinstance(expression, (AssignmentOperation, BinaryOperation, TupleExpression)): true_expression._expressions = [] false_expression._expressions = [] - for next_expr in expression.expressions: - # TODO: can we get rid of `NoneType` expressions in `TupleExpression`? - if next_expr: - if isinstance(next_expr, IndexAccess): - # create an index access for each branch - # x[if cond ? 1 : 2] -> if cond { x[1] } else { x[2] } - for expr in next_expr.expressions: - if self.conditional_not_ahead( - expr, true_expression, false_expression, f_expressions - ): - self.copy_expression( - expr, - true_expression.expressions[-1], - false_expression.expressions[-1], - ) - - if self.conditional_not_ahead( - next_expr, true_expression, false_expression, f_expressions - ): - # always on last arguments added - self.copy_expression( - next_expr, - true_expression.expressions[-1], - false_expression.expressions[-1], - ) + self.convert_expressions(expression, true_expression, false_expression) elif isinstance(expression, CallExpression): next_expr = expression.called + self.convert_call_expression(expression, next_expr, true_expression, false_expression) + + elif isinstance(expression, (TypeConversion, UnaryOperation, MemberAccess)): + next_expr = expression.expression + if self.conditional_not_ahead( + next_expr, true_expression, false_expression, f_expression + ): + self.copy_expression( + expression.expression, + true_expression.expression, + false_expression.expression, + ) - # case of lib - # (.. ? .. : ..).add - if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_called): - self.copy_expression(next_expr, true_expression.called, false_expression.called) + else: + raise SlitherException( + f"Ternary operation not handled {expression}({type(expression)})" + ) - # In order to handle ternaries in both call options, gas and value, we return early if the - # conditional is not ahead to rewrite both ternaries (see `_rewrite_ternary_as_if_else`). - if expression.call_gas: - # case of (..).func{gas: .. ? .. : ..}() - next_expr = expression.call_gas - if self.conditional_not_ahead( - next_expr, true_expression, false_expression, f_call_gas - ): - self.copy_expression( - next_expr, - true_expression.call_gas, - false_expression.call_gas, - ) - else: - return + def convert_expressions( + self, + expression: Union[AssignmentOperation, BinaryOperation, TupleExpression], + true_expression: Expression, + false_expression: Expression, + ) -> None: + for next_expr in expression.expressions: + # TODO: can we get rid of `NoneType` expressions in `TupleExpression`? + if next_expr: + if isinstance(next_expr, IndexAccess): + self.convert_index_access(next_expr, true_expression, false_expression) - if expression.call_value: - # case of (..).func{value: .. ? .. : ..}() - next_expr = expression.call_value if self.conditional_not_ahead( - next_expr, true_expression, false_expression, f_call_value + next_expr, true_expression, false_expression, f_expressions ): + # always on last arguments added self.copy_expression( next_expr, - true_expression.call_value, - false_expression.call_value, + true_expression.expressions[-1], + false_expression.expressions[-1], ) - else: - return - true_expression._arguments = [] - false_expression._arguments = [] + def convert_index_access( + self, next_expr: IndexAccess, true_expression: Expression, false_expression: Expression + ) -> None: + # create an index access for each branch + # x[if cond ? 1 : 2] -> if cond { x[1] } else { x[2] } + for expr in next_expr.expressions: + if self.conditional_not_ahead(expr, true_expression, false_expression, f_expressions): + self.copy_expression( + expr, + true_expression.expressions[-1], + false_expression.expressions[-1], + ) - for next_expr in expression.arguments: - if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_call): - # always on last arguments added - self.copy_expression( - next_expr, - true_expression.arguments[-1], - false_expression.arguments[-1], - ) + def convert_call_expression( + self, + expression: CallExpression, + next_expr: Expression, + true_expression: Expression, + false_expression: Expression, + ) -> None: + # case of lib + # (.. ? .. : ..).add + if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_called): + self.copy_expression(next_expr, true_expression.called, false_expression.called) + + # In order to handle ternaries in both call options, gas and value, we return early if the + # conditional is not ahead to rewrite both ternaries (see `_rewrite_ternary_as_if_else`). + if expression.call_gas: + # case of (..).func{gas: .. ? .. : ..}() + next_expr = expression.call_gas + if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_call_gas): + self.copy_expression( + next_expr, + true_expression.call_gas, + false_expression.call_gas, + ) + else: + return - elif isinstance(expression, (TypeConversion, UnaryOperation)): - next_expr = expression.expression + if expression.call_value: + # case of (..).func{value: .. ? .. : ..}() + next_expr = expression.call_value if self.conditional_not_ahead( - next_expr, true_expression, false_expression, f_expression + next_expr, true_expression, false_expression, f_call_value ): self.copy_expression( - expression.expression, - true_expression.expression, - false_expression.expression, + next_expr, + true_expression.call_value, + false_expression.call_value, ) + else: + return - else: - raise SlitherException( - f"Ternary operation not handled {expression}({type(expression)})" - ) + true_expression._arguments = [] + false_expression._arguments = [] + + for expr in expression.arguments: + if self.conditional_not_ahead(expr, true_expression, false_expression, f_call): + # always on last arguments added + self.copy_expression( + expr, + true_expression.arguments[-1], + false_expression.arguments[-1], + ) From b68f4c17a7aedfe0382828b85e2ecd95dca4fb38 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Tue, 3 Jan 2023 12:31:47 -0600 Subject: [PATCH 050/110] pylint --- slither/utils/expression_manipulations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index 974c6f68b..bc2a1556e 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -102,7 +102,7 @@ class SplitTernaryExpression: ): return - elif isinstance(expression, (AssignmentOperation, BinaryOperation, TupleExpression)): + if isinstance(expression, (AssignmentOperation, BinaryOperation, TupleExpression)): true_expression._expressions = [] false_expression._expressions = [] self.convert_expressions(expression, true_expression, false_expression) From bd3e4504b8233bf2cfda0e3daca07d71a445b1e9 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Wed, 4 Jan 2023 12:13:33 +0100 Subject: [PATCH 051/110] Fix markdown@ --- slither/tools/documentation/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/slither/tools/documentation/README.md b/slither/tools/documentation/README.md index 5e70b3a49..b4b3e6a76 100644 --- a/slither/tools/documentation/README.md +++ b/slither/tools/documentation/README.md @@ -2,5 +2,4 @@ `slither-documentation` uses [codex](https://beta.openai.com) to generate natspec documenation. -This tool is experimental. See https://github.com/montyly/solmate/pull/1 for an example of usage. - +This tool is experimental. See [solmate documentation](https://github.com/montyly/solmate/pull/1) for an example of usage. From 23d77e23fd0b7d89504d0b6ff291a0b50f370101 Mon Sep 17 00:00:00 2001 From: pavan-nambi Date: Wed, 4 Jan 2023 19:07:55 +0530 Subject: [PATCH 052/110] refractor(ver-in-path_filterin) --- scripts/ci_test_path_filtering.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci_test_path_filtering.sh b/scripts/ci_test_path_filtering.sh index fb2a18842..838ecfa1d 100644 --- a/scripts/ci_test_path_filtering.sh +++ b/scripts/ci_test_path_filtering.sh @@ -2,7 +2,7 @@ ### Test path filtering across POSIX and Windows -solc-select use 0.8.0 +solc-select use 0.5.0 slither "tests/test_path_filtering/test_path_filtering.sol" --config "tests/test_path_filtering/slither.config.json" > "output.txt" 2>&1 if ! grep -q "0 result(s) found" "output.txt" From 8388597e77708e200ba3916db6feb668ad823212 Mon Sep 17 00:00:00 2001 From: pavan-nambi Date: Wed, 4 Jan 2023 19:30:26 +0530 Subject: [PATCH 053/110] Revert "refractor(ver-in-path_filterin)" This reverts commit 23d77e23fd0b7d89504d0b6ff291a0b50f370101. --- scripts/ci_test_path_filtering.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci_test_path_filtering.sh b/scripts/ci_test_path_filtering.sh index 838ecfa1d..fb2a18842 100644 --- a/scripts/ci_test_path_filtering.sh +++ b/scripts/ci_test_path_filtering.sh @@ -2,7 +2,7 @@ ### Test path filtering across POSIX and Windows -solc-select use 0.5.0 +solc-select use 0.8.0 slither "tests/test_path_filtering/test_path_filtering.sol" --config "tests/test_path_filtering/slither.config.json" > "output.txt" 2>&1 if ! grep -q "0 result(s) found" "output.txt" From 9015e739c2e60b5c4df8889b7fb13970ff77e2c1 Mon Sep 17 00:00:00 2001 From: pavan-nambi Date: Wed, 4 Jan 2023 20:05:16 +0530 Subject: [PATCH 054/110] update(adding-more-installations) --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3378cd420..73cba44b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,6 +55,8 @@ jobs: - name: Install dependencies run: | pip install ".[dev]" + solc-select use 0.4.25 --always-install + solc-select use 0.8.0 --always-install solc-select use 0.5.1 --always-install pip install typing_extensions==4.1.1 pip install importlib_metadata==4.8.3 From 020d8638dab92b6fd952e988296e4d6b2478fdd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 17:08:49 -0300 Subject: [PATCH 055/110] slither-doctor: remove LegacyVersion import, add `packaging` dependency This was used just for typing, and it was removed in a recent `packaging` version, so remove the LegacyVersion import. Also declare the missing `packaging` dependency in setup.py --- setup.py | 1 + slither/tools/doctor/checks/versions.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 86db4fa9a..9cfbb29e4 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ setup( packages=find_packages(), python_requires=">=3.8", install_requires=[ + "packaging", "prettytable>=0.7.2", "pycryptodome>=3.4.6", # "crytic-compile>=0.2.4", diff --git a/slither/tools/doctor/checks/versions.py b/slither/tools/doctor/checks/versions.py index 909bccf55..90a478a1e 100644 --- a/slither/tools/doctor/checks/versions.py +++ b/slither/tools/doctor/checks/versions.py @@ -3,19 +3,19 @@ import json from typing import Optional import urllib -from packaging.version import parse, LegacyVersion, Version +from packaging.version import parse, Version from slither.utils.colors import yellow, green -def get_installed_version(name: str) -> Optional[LegacyVersion | Version]: +def get_installed_version(name: str) -> Optional[Version]: try: return parse(metadata.version(name)) except metadata.PackageNotFoundError: return None -def get_github_version(name: str) -> Optional[LegacyVersion | Version]: +def get_github_version(name: str) -> Optional[Version]: try: with urllib.request.urlopen( f"https://api.github.com/repos/crytic/{name}/releases/latest" From 4c759ca6a4d0c0b6577a0a8e23ad80f948447865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 17:29:24 -0300 Subject: [PATCH 056/110] slither-doctor: add new PATH checks This ensures PATH is correctly configured, and hints the user about what they might need to do to configure it correctly. --- slither/tools/doctor/checks/__init__.py | 2 + slither/tools/doctor/checks/paths.py | 56 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 slither/tools/doctor/checks/paths.py diff --git a/slither/tools/doctor/checks/__init__.py b/slither/tools/doctor/checks/__init__.py index 762c60b5d..8a0741940 100644 --- a/slither/tools/doctor/checks/__init__.py +++ b/slither/tools/doctor/checks/__init__.py @@ -1,6 +1,7 @@ from typing import Callable, List from dataclasses import dataclass +from slither.tools.doctor.checks.paths import check_slither_path from slither.tools.doctor.checks.platform import compile_project, detect_platform from slither.tools.doctor.checks.versions import show_versions @@ -12,6 +13,7 @@ class Check: ALL_CHECKS: List[Check] = [ + Check("PATH configuration", check_slither_path), Check("Software versions", show_versions), Check("Project platform", detect_platform), Check("Project compilation", compile_project), diff --git a/slither/tools/doctor/checks/paths.py b/slither/tools/doctor/checks/paths.py new file mode 100644 index 000000000..53fae78ad --- /dev/null +++ b/slither/tools/doctor/checks/paths.py @@ -0,0 +1,56 @@ +from pathlib import Path +from typing import List, Optional, Tuple +import shutil +import sysconfig + +from slither.utils.colors import yellow, green, red + + +def check_path_config(name: str) -> Tuple[bool, Optional[Path], List[Path]]: + binary_path = shutil.which(name) + possible_paths = [] + + for scheme in sysconfig.get_scheme_names(): + script_path = Path(sysconfig.get_path("scripts", scheme)) + purelib_path = Path(sysconfig.get_path("purelib", scheme)) + script_binary_path = shutil.which(name, path=script_path) + if script_binary_path is not None: + possible_paths.append((script_path, purelib_path)) + + binary_here = False + if binary_path is not None: + binary_path = Path(binary_path) + this_code = Path(__file__) + this_binary = list(filter(lambda x: this_code.is_relative_to(x[1]), possible_paths)) + binary_here = len(this_binary) > 0 and all( + binary_path.is_relative_to(script) for script, _ in this_binary + ) + + return binary_here, binary_path, list(set(script for script, _ in possible_paths)) + + +def check_slither_path(**_kwargs) -> None: + binary_here, binary_path, possible_paths = check_path_config("slither") + show_paths = False + + if binary_path: + print(green(f"`slither` found in PATH at `{binary_path}`.")) + if binary_here: + print(green("Its location matches this slither-doctor installation.")) + else: + print( + yellow( + f"This path does not correspond to this slither-doctor installation.\n" + + "Double-check the order of directories in PATH if you have several slither installations." + ) + ) + show_paths = True + else: + print(red("`slither` was not found in PATH.")) + show_paths = True + + if show_paths: + print() + print("Consider adding one of the following directories to PATH:") + for path in possible_paths: + print(f" * {path}") From c531681a8a7ec52e4b724336929d9d7377b21927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 17:31:01 -0300 Subject: [PATCH 057/110] ci: slither-doctor: add workflow --- .github/workflows/doctor.yml | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 .github/workflows/doctor.yml diff --git a/.github/workflows/doctor.yml b/.github/workflows/doctor.yml new file mode 100644 index 000000000..3d1150eef --- /dev/null +++ b/.github/workflows/doctor.yml @@ -0,0 +1,74 @@ +--- +name: CI (slither-doctor) + +defaults: + run: + shell: bash + +on: + push: + branches: + - master + - dev + pull_request: + paths: + - 'slither/tools/doctor/**' + - '.github/workflows/doctor.yml' + +jobs: + doctor: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: ["ubuntu-latest", "windows-2022"] + python: ["3.8", "3.9", "3.10", "3.11"] + steps: + - uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + + - name: Try system-wide Slither + run: | + pip3 install . + + # escape cwd so python doesn't pick up local module + cd / + + echo "Via module" + python3 -m slither.tools.doctor . + + echo "Via binary" + slither-doctor . + + - name: Try user Slither + run: | + pip3 install --user . + + # escape cwd so python doesn't pick up local module + cd / + + echo "Via module" + python3 -m slither.tools.doctor . + + echo "Via binary" + slither-doctor . + + - name: Try venv Slither + run: | + python3 -m venv venv + source venv/bin/activate + hash -r + pip3 install . + + # escape cwd so python doesn't pick up local module + cd / + + echo "Via module" + python3 -m slither.tools.doctor . + + echo "Via binary" + slither-doctor . From b2ce73108adb4ef50e65c079f51305d9dd20d917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 17:53:48 -0300 Subject: [PATCH 058/110] slither-doctor: fix "unsupported format string passed to Version.__format__" --- slither/tools/doctor/checks/versions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/slither/tools/doctor/checks/versions.py b/slither/tools/doctor/checks/versions.py index 90a478a1e..ec7ef1d1f 100644 --- a/slither/tools/doctor/checks/versions.py +++ b/slither/tools/doctor/checks/versions.py @@ -45,7 +45,9 @@ def show_versions(**_kwargs) -> None: for name, (installed, latest) in versions.items(): color = yellow if name in outdated else green - print(f"{name + ':':<16}{color(installed or 'N/A'):<16} (latest is {latest or 'Unknown'})") + print( + f"{name + ':':<16}{color(str(installed) or 'N/A'):<16} (latest is {str(latest) or 'Unknown'})" + ) if len(outdated) > 0: print() From 21daf7348997273424d8445998aab93c105e083f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 17:55:27 -0300 Subject: [PATCH 059/110] slither-doctor: log on stdout This avoids mixed output in e.g. CI outputs --- slither/tools/doctor/__main__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/slither/tools/doctor/__main__.py b/slither/tools/doctor/__main__.py index 94ae865ec..b9b4c5497 100644 --- a/slither/tools/doctor/__main__.py +++ b/slither/tools/doctor/__main__.py @@ -1,4 +1,6 @@ import argparse +import logging +import sys from crytic_compile import cryticparser @@ -25,6 +27,9 @@ def parse_args() -> argparse.Namespace: def main(): + # log on stdout to keep output in order + logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, force=True) + args = parse_args() kwargs = vars(args) From 20198b9618d21e394d0b1599adefe46ec1c03102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 17:57:28 -0300 Subject: [PATCH 060/110] slither-doctor: fix `is_relative_to` on Python 3.8 --- slither/tools/doctor/checks/paths.py | 33 ++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/slither/tools/doctor/checks/paths.py b/slither/tools/doctor/checks/paths.py index 53fae78ad..4adf3b159 100644 --- a/slither/tools/doctor/checks/paths.py +++ b/slither/tools/doctor/checks/paths.py @@ -1,12 +1,41 @@ from pathlib import Path from typing import List, Optional, Tuple import shutil +import sys import sysconfig from slither.utils.colors import yellow, green, red +def path_is_relative_to(path: Path, relative_to: Path) -> bool: + """ + Check if a path is relative to another one. + + Compatibility wrapper for Path.is_relative_to + """ + if sys.version_info >= (3, 9, 0): + return path.is_relative_to(relative_to) + + path_parts = path.resolve().parts + relative_to_parts = relative_to.resolve().parts + + if len(path_parts) < len(relative_to_parts): + return False + + for (a, b) in zip(path_parts, relative_to_parts): + if a != b: + return False + + return True + + def check_path_config(name: str) -> Tuple[bool, Optional[Path], List[Path]]: + """ + Check if a given Python binary/script is in PATH. + :return: Returns if the binary on PATH corresponds to this installation, + its path (if present), and a list of possible paths where this + binary might be found. + """ binary_path = shutil.which(name) possible_paths = [] @@ -21,9 +50,9 @@ def check_path_config(name: str) -> Tuple[bool, Optional[Path], List[Path]]: if binary_path is not None: binary_path = Path(binary_path) this_code = Path(__file__) - this_binary = list(filter(lambda x: this_code.is_relative_to(x[1]), possible_paths)) + this_binary = list(filter(lambda x: path_is_relative_to(this_code, x[1]), possible_paths)) binary_here = len(this_binary) > 0 and all( - binary_path.is_relative_to(script) for script, _ in this_binary + path_is_relative_to(binary_path, script) for script, _ in this_binary ) return binary_here, binary_path, list(set(script for script, _ in possible_paths)) From e65031ebd55e08da23f97919a3f7ecc49981177d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 17:59:03 -0300 Subject: [PATCH 061/110] ci: slither-doctor: fix Windows venv execution --- .github/workflows/doctor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/doctor.yml b/.github/workflows/doctor.yml index 3d1150eef..612374bc2 100644 --- a/.github/workflows/doctor.yml +++ b/.github/workflows/doctor.yml @@ -60,7 +60,7 @@ jobs: - name: Try venv Slither run: | python3 -m venv venv - source venv/bin/activate + source venv/bin/activate || source venv/Scripts/activate hash -r pip3 install . From 21967c2525c4dcf6bc40aa487e1eb08e46c4156f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 19:18:45 -0300 Subject: [PATCH 062/110] ci: slither-doctor: group output --- .github/workflows/doctor.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/doctor.yml b/.github/workflows/doctor.yml index 612374bc2..582e0dc87 100644 --- a/.github/workflows/doctor.yml +++ b/.github/workflows/doctor.yml @@ -33,42 +33,54 @@ jobs: - name: Try system-wide Slither run: | + echo "::group::Install slither" pip3 install . + echo "::endgroup::" # escape cwd so python doesn't pick up local module cd / - echo "Via module" + echo "::group::Via module" python3 -m slither.tools.doctor . + echo "::endgroup::" - echo "Via binary" + echo "::group::Via binary" slither-doctor . + echo "::endgroup::" - name: Try user Slither run: | + echo "::group::Install slither" pip3 install --user . + echo "::endgroup::" # escape cwd so python doesn't pick up local module cd / - echo "Via module" + echo "::group::Via module" python3 -m slither.tools.doctor . + echo "::endgroup::" - echo "Via binary" + echo "::group::Via binary" slither-doctor . + echo "::endgroup::" - name: Try venv Slither run: | + echo "::group::Install slither" python3 -m venv venv source venv/bin/activate || source venv/Scripts/activate hash -r pip3 install . + echo "::endgroup::" # escape cwd so python doesn't pick up local module cd / - echo "Via module" + echo "::group::Via module" python3 -m slither.tools.doctor . + echo "::endgroup::" - echo "Via binary" + echo "::group::Via binary" slither-doctor . + echo "::endgroup::" From d7538795a50eea61633daf54c86ae25ce2109e67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 20:06:47 -0300 Subject: [PATCH 063/110] ci: slither-doctor: disable on branches, add dispatch --- .github/workflows/doctor.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/doctor.yml b/.github/workflows/doctor.yml index 582e0dc87..811680db4 100644 --- a/.github/workflows/doctor.yml +++ b/.github/workflows/doctor.yml @@ -1,22 +1,19 @@ --- -name: CI (slither-doctor) +name: CI defaults: run: shell: bash on: - push: - branches: - - master - - dev + workflow_dispatch: pull_request: paths: - 'slither/tools/doctor/**' - '.github/workflows/doctor.yml' jobs: - doctor: + slither-doctor: runs-on: ${{ matrix.os }} strategy: fail-fast: false From b01ba03fa8da270f51151926b789448928301afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 20:08:14 -0300 Subject: [PATCH 064/110] ci: slither-doctor: disable Windows with Python 3.8 --- .github/workflows/doctor.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/doctor.yml b/.github/workflows/doctor.yml index 811680db4..b6124216a 100644 --- a/.github/workflows/doctor.yml +++ b/.github/workflows/doctor.yml @@ -20,6 +20,10 @@ jobs: matrix: os: ["ubuntu-latest", "windows-2022"] python: ["3.8", "3.9", "3.10", "3.11"] + exclude: + # strange failure + - os: windows-2022 + python: 3.8 steps: - uses: actions/checkout@v3 From 407d35cbd8bb21c34e9731ddaf77751ff496a840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Wed, 4 Jan 2023 20:31:09 -0300 Subject: [PATCH 065/110] slither-doctor: fix lint error --- slither/tools/doctor/checks/paths.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slither/tools/doctor/checks/paths.py b/slither/tools/doctor/checks/paths.py index 4adf3b159..d388847ef 100644 --- a/slither/tools/doctor/checks/paths.py +++ b/slither/tools/doctor/checks/paths.py @@ -69,8 +69,8 @@ def check_slither_path(**_kwargs) -> None: else: print( yellow( - f"This path does not correspond to this slither-doctor installation.\n" - + "Double-check the order of directories in PATH if you have several slither installations." + "This path does not correspond to this slither-doctor installation.\n" + + "Double-check the order of directories in PATH if you have several Slither installations." ) ) show_paths = True From 254f02b374d906df619edebe099af8f61eaef6e0 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Thu, 5 Jan 2023 11:02:43 +0100 Subject: [PATCH 066/110] Update expression_manipulations.py --- slither/utils/expression_manipulations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index bc2a1556e..a63db9829 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -135,6 +135,7 @@ class SplitTernaryExpression: ) -> None: for next_expr in expression.expressions: # TODO: can we get rid of `NoneType` expressions in `TupleExpression`? + # montyly: this might happen with unnamed tuple (ex: (,,,) = f()), but it needs to be checked if next_expr: if isinstance(next_expr, IndexAccess): self.convert_index_access(next_expr, true_expression, false_expression) From 75ee80c3880082bbe32d6f9363bae837144a709c Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 5 Jan 2023 13:43:39 +0100 Subject: [PATCH 067/110] Fix edge case + code quality --- slither/slithir/convert.py | 47 ++++++++++--------- .../declarations/using_for_top_level.py | 7 +-- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 82b659981..445fc7a8e 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -201,18 +201,19 @@ def _fits_under_byte(val: Union[int, str]) -> List[str]: return [f"bytes{f}" for f in range(length, 33)] + ["bytes"] -def _find_function_from_parameter(ir: Call, candidates: List[Function]) -> Optional[Function]: +def _find_function_from_parameter( + arguments: List[Variable], candidates: List[Function] +) -> Optional[Function]: """ - Look for a function in candidates that can be the target of the ir's call + Look for a function in candidates that can be the target based on the ir's call arguments Try the implicit type conversion for uint/int/bytes. Constant values can be both uint/int While variables stick to their base type, but can changed the size - :param ir: + :param arguments: :param candidates: :return: """ - arguments = ir.arguments type_args: List[str] for idx, arg in enumerate(arguments): if isinstance(arg, (list,)): @@ -1335,20 +1336,24 @@ def convert_to_pop(ir, node): def look_for_library_or_top_level(contract, ir, using_for, t): for destination in using_for[t]: if isinstance(destination, FunctionTopLevel) and destination.name == ir.function_name: - internalcall = InternalCall(destination, ir.nbr_arguments, ir.lvalue, ir.type_call) - internalcall.set_expression(ir.expression) - internalcall.set_node(ir.node) - internalcall.call_gas = ir.call_gas - internalcall.arguments = [ir.destination] + ir.arguments - return_type = internalcall.function.return_type - if return_type: - if len(return_type) == 1: - internalcall.lvalue.set_type(return_type[0]) - elif len(return_type) > 1: - internalcall.lvalue.set_type(return_type) - else: - internalcall.lvalue = None - return internalcall + arguments = [ir.destination] + ir.arguments + if ( + len(destination.parameters) == len(arguments) + and _find_function_from_parameter(arguments, [destination]) is not None + ): + internalcall = InternalCall(destination, ir.nbr_arguments, ir.lvalue, ir.type_call) + internalcall.set_expression(ir.expression) + internalcall.set_node(ir.node) + internalcall.arguments = [ir.destination] + ir.arguments + return_type = internalcall.function.return_type + if return_type: + if len(return_type) == 1: + internalcall.lvalue.set_type(return_type[0]) + elif len(return_type) > 1: + internalcall.lvalue.set_type(return_type) + else: + internalcall.lvalue = None + return internalcall if isinstance(destination, FunctionContract) and destination.contract.is_library: lib_contract = destination.contract @@ -1431,7 +1436,7 @@ def convert_type_library_call(ir: HighLevelCall, lib_contract: Contract): # TODO: handle collision with multiple state variables/functions func = lib_contract.get_state_variable_from_name(ir.function_name) if func is None and candidates: - func = _find_function_from_parameter(ir, candidates) + func = _find_function_from_parameter(ir.arguments, candidates) # In case of multiple binding to the same type # TODO: this part might not be needed with _find_function_from_parameter @@ -1527,7 +1532,7 @@ def convert_type_of_high_and_internal_level_call(ir: Operation, contract: Option if f.name == ir.function_name and len(f.parameters) == len(ir.arguments) ] - func = _find_function_from_parameter(ir, candidates) + func = _find_function_from_parameter(ir.arguments, candidates) if not func: assert contract @@ -1550,7 +1555,7 @@ def convert_type_of_high_and_internal_level_call(ir: Operation, contract: Option # TODO: handle collision with multiple state variables/functions func = contract.get_state_variable_from_name(ir.function_name) if func is None and candidates: - func = _find_function_from_parameter(ir, candidates) + func = _find_function_from_parameter(ir.arguments, candidates) # lowlelvel lookup needs to be done at last step if not func: diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py index 85b09130d..3ec191d46 100644 --- a/slither/solc_parsing/declarations/using_for_top_level.py +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -27,12 +27,12 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- UsingFor class """ - def __init__( # pylint: disable=too-many-arguments + def __init__( self, uftl: UsingForTopLevel, top_level_data: Dict, slither_parser: "SlitherCompilationUnitSolc", - ): + ) -> None: self._type_name = top_level_data["typeName"] self._global = top_level_data["global"] @@ -40,6 +40,7 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- self._library_name = top_level_data["libraryName"] else: self._functions = top_level_data["functionList"] + self._library_name = None self._using_for = uftl self._slither_parser = slither_parser @@ -48,7 +49,7 @@ class UsingForTopLevelSolc(CallerContextExpression): # pylint: disable=too-few- type_name = parse_type(self._type_name, self) self._using_for.using_for[type_name] = [] - if hasattr(self, "_library_name"): + if self._library_name is not None: library_name = parse_type(self._library_name, self) self._using_for.using_for[type_name].append(library_name) self._propagate_global(type_name) From 7798f473d204200fb7a98df10585c6ac067d20f9 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 5 Jan 2023 07:03:37 -0600 Subject: [PATCH 068/110] make it easier to run specific tests and document --- CONTRIBUTING.md | 9 ++++++++- tests/test_ast_parsing.py | 30 +++++++++++++++--------------- tests/test_detectors.py | 2 +- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a30595ec..3cfdb7d3f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,7 +64,10 @@ For each new detector, at least one regression tests must be present. - If updating an existing detector, identify the respective json artifacts and then delete them, or run `python ./tests/test_detectors.py --overwrite` instead. - Run `pytest ./tests/test_detectors.py` and check that everything worked. -To see the tests coverage, run `pytest tests/test_detectors.py --cov=slither/detectors --cov-branch --cov-report html` +To see the tests coverage, run `pytest tests/test_detectors.py --cov=slither/detectors --cov-branch --cov-report html`. +To run tests for a specific detector, run `pytest tests/test_detectors.py -k ReentrancyReadBeforeWritten` (the detector's class name is the argument). +To run tests for a specific version, run `pytest tests/test_detectors.py -k 0.7.6`. +The id's of tests can be inspected using ``pytest tests/test_detectors.py --collect-only`. ### Parser tests - Create a test in `tests/ast-parsing` @@ -73,6 +76,10 @@ To see the tests coverage, run `pytest tests/test_detectors.py --cov=slither/d - Run `pytest ./tests/test_ast_parsing.py` and check that everything worked. To see the tests coverage, run `pytest tests/test_ast_parsing.py --cov=slither/solc_parsing --cov-branch --cov-report html` +To run tests for a specific test case, run `pytest tests/test_ast_parsing.py -k user_defined_value_type` (the file name is the argument). +To run tests for a specific version, run `pytest tests/test_ast_parsing.py -k 0.8.12`. +To run tests for a specific compiler json format, run `pytest tests/test_ast_parsing.py -k legacy` (can be legacy or compact). +The id's of tests can be inspected using ``pytest tests/test_ast_parsing.py --collect-only`. ### Synchronization with crytic-compile By default, `slither` follows either the latest version of crytic-compile in pip, or `crytic-compile@master` (look for dependencies in [`setup.py`](./setup.py). If crytic-compile development comes with breaking changes, the process to update `slither` is: diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index e96a129b8..23783137b 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -433,18 +433,19 @@ except OSError: pass -@pytest.mark.parametrize("test_item", ALL_TESTS, ids=lambda x: x.test_file) -def test_parsing(test_item: Test): - flavors = ["compact"] - if not test_item.disable_legacy: - flavors += ["legacy"] - for version, flavor in test_item.versions_with_flavors: - test_file = os.path.join( - TEST_ROOT, "compile", f"{test_item.test_file}-{version}-{flavor}.zip" - ) - expected_file = os.path.join( - TEST_ROOT, "expected", f"{test_item.test_file}-{version}-{flavor}.json" - ) +def pytest_generate_tests(metafunc): + test_cases = [] + for test_item in ALL_TESTS: + for version, flavor in test_item.versions_with_flavors: + test_cases.append((test_item.test_file, version, flavor)) + metafunc.parametrize("test_file, version, flavor", test_cases) + + +class TestASTParsing: + # pylint: disable=no-self-use + def test_parsing(self, test_file, version, flavor): + test_file = os.path.join(TEST_ROOT, "compile", f"{test_file}-{version}-{flavor}.zip") + expected_file = os.path.join(TEST_ROOT, "expected", f"{test_file}-{version}-{flavor}.json") cc = load_from_zip(test_file)[0] @@ -465,19 +466,18 @@ def test_parsing(test_item: Test): raise diff = DeepDiff(expected, actual, ignore_order=True, verbose_level=2, view="tree") - if diff: for change in diff.get("values_changed", []): path_list = re.findall(r"\['(.*?)'\]", change.path()) path = "_".join(path_list) with open( - f"test_artifacts/{test_item.test_file}_{path}_expected.dot", + f"test_artifacts/{test_file}_{path}_expected.dot", "w", encoding="utf8", ) as f: f.write(change.t1) with open( - f"test_artifacts/{test_item.test_file}_{version}_{flavor}_{path}_actual.dot", + f"test_artifacts/{test_file}_{version}_{flavor}_{path}_actual.dot", "w", encoding="utf8", ) as f: diff --git a/tests/test_detectors.py b/tests/test_detectors.py index a5ecaae2a..a45369fcd 100644 --- a/tests/test_detectors.py +++ b/tests/test_detectors.py @@ -52,7 +52,7 @@ def set_solc(test_item: Test): # pylint: disable=too-many-lines def id_test(test_item: Test): - return f"{test_item.detector}: {test_item.solc_ver}/{test_item.test_file}" + return f"{test_item.detector.__name__}-{test_item.solc_ver}-{test_item.test_file}" ALL_TEST_OBJECTS = [ From e524b7299335236024da95a848ae5c53cab3c110 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 5 Jan 2023 07:06:21 -0600 Subject: [PATCH 069/110] typo --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3cfdb7d3f..cf86a516d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,7 @@ For each new detector, at least one regression tests must be present. To see the tests coverage, run `pytest tests/test_detectors.py --cov=slither/detectors --cov-branch --cov-report html`. To run tests for a specific detector, run `pytest tests/test_detectors.py -k ReentrancyReadBeforeWritten` (the detector's class name is the argument). To run tests for a specific version, run `pytest tests/test_detectors.py -k 0.7.6`. -The id's of tests can be inspected using ``pytest tests/test_detectors.py --collect-only`. +The id's of tests can be inspected using `pytest tests/test_detectors.py --collect-only`. ### Parser tests - Create a test in `tests/ast-parsing` From 10085c1c1228e4eefc22b2a8c3f1df4194131ca4 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 5 Jan 2023 07:21:54 -0600 Subject: [PATCH 070/110] add tests --- .../test.sol-0.5.12-compact.zip | Bin 0 -> 1931 bytes .../test.sol-0.5.12-legacy.zip | Bin 0 -> 1857 bytes .../test.sol-0.5.12-compact.json | 6 ++++++ .../test.sol-0.5.12-legacy.json | 6 ++++++ tests/test_ast_parsing.py | 1 + 5 files changed, 13 insertions(+) create mode 100644 tests/ast-parsing/compile/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-compact.zip create mode 100644 tests/ast-parsing/compile/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-legacy.zip create mode 100644 tests/ast-parsing/expected/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-compact.json create mode 100644 tests/ast-parsing/expected/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-legacy.json diff --git a/tests/ast-parsing/compile/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-compact.zip b/tests/ast-parsing/compile/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..f1b13305654d3104c79b9fbcebc2e89f2ae02147 GIT binary patch literal 1931 zcmaLY`#;l*0|xMqWpc}9xh1z^O=YaZv@vpRB6C+%7NQL`GY7Rqt!X$eaY~yc8cSIv z)IyOMri;w2%fw2}Wi%l~PUrjk_dL%J&+GXM-o9SzpL0`Ql9ASl3~^96_>*f3{n9N@{G2mSmSxcm=n#0K4DPOeh%vv z22*~ojmUakw`-rr#Fie-O0$aZ5@jOEzELZVZn^q)baS>53#lIT6^}4<$bKsKiLnI`5Nc`#iN{~y^uP|`(Cy6Y1H*! zLa`z{oLS}EV_AmDJodUZ>gD9hrIc`l20U&QeMPvW+ENw_R|!*aqPcEpQgW$!o^>rB zI?+-MXa~2_ILCHh3^pFUqZG75m-;x^=-h|KXb7zt2@-~SKvGE_e<~L8JAceO??>We zOxoKtauX`;+c%Ooy$xN!cp@fS@uA%9eUIJigOUyYDh=h<*P{e6yTb&y$B!h5pQb9W z8_SCHGUiNpN79XMus&`=MbP|$B(uH&h!y(Zt7+77YZ(LpMVg+yoR> zlaY|aLzS1IL6O9HpUT7W;#ld8t0tN4IAM*lDr9>UQ*P z@Ro}O%tb~@!}7_2Sx}EO0>y+HHnYx$rul+EVZw1HbWz^XBzXDoSaT-U?gIby zEzn9rLl0V@RTJ>XYU1*Z3nVhZpo>dc-;FpiKWng57c|GY@@4qmyAnZMHwjtt>v?x? zy)5O%UicjRd1=2@t&`s$(GB0Y-v>WWHo*EiRV-0JG>#YG2E(|2XI>JT3fk0GYa?y) z!Ed0W_-9jU%m|)IM!L5(n#V-yVZpa^MZBg?H)+dF$qRGc_aXcoxit{iXTX79ei7yA z;lDVgvoRbxI~Mq1z+vf!NS4=-(%FPj@u%)&Io0?v1og(#p`i!+UbL zliOLKg}kem`S0aoN8nG^dlf{u1~ehky>>qKLIwrm=5CIZF67SdAAn|h3lHBOPK zeS=CH1|p;{S6)d#{M*va)mFvxaf{LQ-z&7$k*cVJYXqBHb|H_nWMFfFonl9OEXK6N z{!MrBX~J^&!1&YJhs$x#*6j1f#pUNjky#FT9wBpNJ^GfQLq_nJB~Yq`^X!fM)R-)} z@f_>5sBSis8XaI+IC{ZG527|HI+WJ-(;l(oTEEkB9uDy$^piQyyZ@;7;PN~EA(~yhJpy~ z*#%8O@^iG1Rkfe0N6|Vbq{N8_euk~S*qAoWi?33Y`rTMYB^DTJPt<4Ln5M4Nwp6Or z)IjpSw3R>AiR#t!)aFHh6m3$(I0r?$`Q9fg#tNO5BA!Iv2aO44b=z z+1wnSJz9&(o8`jGd$OBXE>W&0$iF^3HvdK^^~`js zx2VTe6<{r@kL%3cX$@~CXX$UuI{vojPw^!y_a;Pw?a=l_t3`KjSmVqqU2=;;X@Nu3 zuX7dBKzFt$Fvi)1yd56@QQZHfRbxI^A5^D1QxO{Ov_!a@>W+2Ydb{5){`^ojt*F>E zZI;j&T3TZ2>aNE^h@do*ktj_sp`@kHTcp$%+?5RFa}lXH#|3;u+HT%ZG`Sy=aFWvfj5-$9?OfY}vU+rkal5c!m@ED0GAhq9B8s2vvD^M)!E) zt+MR2(yB}_N&;0#B+6lIk=wFy=*3>rjBuEfzoX(q>k_~>hY{UWXezmkJ0o7PY$@ai z%*Hy~<*W#NilbWCb3&Eb6CwWmi&f;{>m>);v+n<6`P<9?C0*{{`7b(sy}-Yb1pv9< M_58g%*Z=$e0jWoo0ssI2 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-legacy.zip b/tests/ast-parsing/compile/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-legacy.zip new file mode 100644 index 0000000000000000000000000000000000000000..3f457a34d429fcb217e4c6f8d6d4fe219e25014d GIT binary patch literal 1857 zcmaLY_dnYS0|)T0*gI{xRt2#VL}OG-#U|7$>a5x{_6}+m7c17GCqmRyYWEWJ;jw~H zT6I<(S5c!zt=Otnj1t2jh88vuxi0RRL5 zfN%^p9ElAMaK%K01c!yYx`%oC_(o!oe%Rn3P8L?c82}OiKr=nv`}W!G(6Y(VRupf^ z>mXn09?_KShc~svX0Y8qDeW8ar&JcW*v-TO;Lu&cbrQJ0a#aVXlClYT{yNFXzy;1l z7gWp`Yf&=3zbQU`rAn&uaGlFH7}Y5dkb*q_ur$9rv>_i^JEhrtGRx0Zjw0LIp|XfuZMJD4 ze(lItVaJM1=9T!j9kYw8`n_q&JCtXH{Ipyr+FXNfgPOvj=)6|D_@c4Ht0KlVOr4>P zW-?wtdBUq4{hDPtuQKyJGD_&Ot#=uLa>YsZq#8gv1xl^DJ&N9JJtCMlK64|gU}-K1 z6NlztYxj(-j)9IK)*z0xZw*tNpIm)4?sW!U!TgS4tCae;t`4uzF~0k{T0?KJ;`E8J z9*4g99+Ol!PeU#W%n|i&ZK@BZ>PsfNo8)!HwezmI&xEL&I+S+J5xk1+m4ksZl@-!9 zPKV9bSu*ujP_u(&wGwhNhO|3o=1oU>T_DyYY-s&2l;oxc%nrU}Z|M%wHmi=n(ds$v zn&b^HP@o=uO*8WbP{vUs4~Un(G_whb#>JM@i}>0feCYQU#O%GCJ^leQ#(V~53^lcQaDjM4{DY*xnDD1o{=5vgLZ`LZ)WSpjWTNI! zsp@gwHw`~7&K*j#ESJpsp;{dfwla~;t}$X|9o`>K^<^s8EI-ItlIR1TF z$uz3<`(s_*$t4>EsCVsNQP$=Mkp z91DG{;@;O2ns+r1ZS5E>ZD~*;dzwsc(g~qLBU)Z`bjmN8D29;eI&a_6Us*f773beu zdjxYzbj1w1HuIZBLp};ze!g2_5DlF4Sk|2LoR36?WbM^&i28lGRR1)t@arjI9brz| zfZOIa%}4o4c`1K~7=*~C@4 z1UM}CXw~7C491Iczk`UYX1xV01XtLYdA0;a!+Xo{W()Rf=pDPix&o1UXezzz%QeOY zL!kOUYG!BE8$+9y9{0T%Ym&rF|AepSWuSaG(oE^?bLzQdK5WuNlg%Rd>*(5I7lfpw{o$_9 zEu&6Xas-&1`1HK%FUMVG5_t!$;mWi-%-=Y-DaP7#sR26m0OrF{%t%fgKiRyse)}06 zO5Tqsv%WzxTg|WabRnsSVReepQZc#jk0tEdQ|!ahhPC4Ix?%2Ox-%8u+=ZhI{To%@XjhMJq$OmL2Qc~6g3b?{qef#ZZD?~?k_wFY zMilEaY$1`Z_h1XX@A24&;)3uCXc}tjJioFibH>QGI9*^p2uo#D?HKnCr9dGdN4t`u z2rbgRwU6o7tGFlXII0IhJW=9 zg4jD8-tB(YJ?&jV literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/expected/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-compact.json b/tests/ast-parsing/expected/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-compact.json new file mode 100644 index 000000000..4132f73d9 --- /dev/null +++ b/tests/ast-parsing/expected/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-compact.json @@ -0,0 +1,6 @@ +{ + "A": {}, + "Z": { + "test()": "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/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-legacy.json b/tests/ast-parsing/expected/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-legacy.json new file mode 100644 index 000000000..4132f73d9 --- /dev/null +++ b/tests/ast-parsing/expected/complex_imports/import_aliases_issue_1319/test.sol-0.5.12-legacy.json @@ -0,0 +1,6 @@ +{ + "A": {}, + "Z": { + "test()": "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/test_ast_parsing.py b/tests/test_ast_parsing.py index e96a129b8..5f1f6f58c 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -425,6 +425,7 @@ ALL_TESTS = [ Test("free_functions/library_constant_function_collision.sol", ["0.8.12"]), Test("ternary-with-max.sol", ["0.8.15"]), Test("library_event-0.8.16.sol", ["0.8.16"]), + Test("complex_imports/import_aliases_issue_1319/test.sol", ["0.5.12"]), ] # create the output folder if needed try: From 92bad4c5c69cadd53bee0082885e640b070e7544 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 5 Jan 2023 07:28:04 -0600 Subject: [PATCH 071/110] add missing check in other places --- .../upgradeability/checks/variables_order.py | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/slither/tools/upgradeability/checks/variables_order.py b/slither/tools/upgradeability/checks/variables_order.py index 8e30d3c3f..66a44b89b 100644 --- a/slither/tools/upgradeability/checks/variables_order.py +++ b/slither/tools/upgradeability/checks/variables_order.py @@ -48,8 +48,16 @@ Do not change the order of the state variables in the updated contract. def _check(self): contract1 = self.contract contract2 = self.contract_v2 - order1 = [variable for variable in contract1.state_variables if not variable.is_constant] - order2 = [variable for variable in contract2.state_variables if not variable.is_constant] + order1 = [ + variable + for variable in contract1.state_variables_ordered + if not (variable.is_constant or variable.is_immutable) + ] + order2 = [ + variable + for variable in contract2.state_variables_ordered + if not (variable.is_constant or variable.is_immutable) + ] results = [] for idx, _ in enumerate(order1): @@ -109,8 +117,16 @@ Avoid variables in the proxy. If a variable is in the proxy, ensure it has the s def _check(self): contract1 = self._contract1() contract2 = self._contract2() - order1 = [variable for variable in contract1.state_variables if not variable.is_constant] - order2 = [variable for variable in contract2.state_variables if not variable.is_constant] + order1 = [ + variable + for variable in contract1.state_variables_ordered + if not (variable.is_constant or variable.is_immutable) + ] + order2 = [ + variable + for variable in contract2.state_variables_ordered + if not (variable.is_constant or variable.is_immutable) + ] results = [] for idx, _ in enumerate(order1): @@ -228,8 +244,16 @@ Avoid variables in the proxy. If a variable is in the proxy, ensure it has the s def _check(self): contract1 = self._contract1() contract2 = self._contract2() - order1 = [variable for variable in contract1.state_variables if not variable.is_constant] - order2 = [variable for variable in contract2.state_variables if not variable.is_constant] + order1 = [ + variable + for variable in contract1.state_variables_ordered + if not (variable.is_constant or variable.is_immutable) + ] + order2 = [ + variable + for variable in contract2.state_variables_ordered + if not (variable.is_constant or variable.is_immutable) + ] results = [] From 8d3aa94450a9c1bb675e570634cd4628ddaa1533 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Thu, 5 Jan 2023 10:31:30 -0300 Subject: [PATCH 072/110] ci: etherscan: add output grouping --- scripts/ci_test_etherscan.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/ci_test_etherscan.sh b/scripts/ci_test_etherscan.sh index c8e69958c..77457dc43 100755 --- a/scripts/ci_test_etherscan.sh +++ b/scripts/ci_test_etherscan.sh @@ -5,15 +5,19 @@ mkdir etherscan cd etherscan || exit 255 +echo "::group::Etherscan mainnet" if ! slither 0x7F37f78cBD74481E593F9C737776F7113d76B315 --etherscan-apikey "$GITHUB_ETHERSCAN"; then - echo "Etherscan test failed" + echo "Etherscan mainnet test failed" exit 1 fi +echo "::endgroup::" +echo "::group::Etherscan rinkeby" if ! slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --etherscan-apikey "$GITHUB_ETHERSCAN"; then - echo "Etherscan test failed" + echo "Etherscan rinkeby test failed" exit 1 fi +echo "::endgroup::" exit 0 From 52daecec188a16a79c8d21de1b0f0ef639464f39 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 5 Jan 2023 08:06:35 -0600 Subject: [PATCH 073/110] lint --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cf86a516d..8568ef709 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,7 @@ For each new detector, at least one regression tests must be present. To see the tests coverage, run `pytest tests/test_detectors.py --cov=slither/detectors --cov-branch --cov-report html`. To run tests for a specific detector, run `pytest tests/test_detectors.py -k ReentrancyReadBeforeWritten` (the detector's class name is the argument). To run tests for a specific version, run `pytest tests/test_detectors.py -k 0.7.6`. -The id's of tests can be inspected using `pytest tests/test_detectors.py --collect-only`. +The IDs of tests can be inspected using `pytest tests/test_detectors.py --collect-only`. ### Parser tests - Create a test in `tests/ast-parsing` @@ -76,10 +76,10 @@ The id's of tests can be inspected using `pytest tests/test_detectors.py --colle - Run `pytest ./tests/test_ast_parsing.py` and check that everything worked. To see the tests coverage, run `pytest tests/test_ast_parsing.py --cov=slither/solc_parsing --cov-branch --cov-report html` -To run tests for a specific test case, run `pytest tests/test_ast_parsing.py -k user_defined_value_type` (the file name is the argument). +To run tests for a specific test case, run `pytest tests/test_ast_parsing.py -k user_defined_value_type` (the filename is the argument). To run tests for a specific version, run `pytest tests/test_ast_parsing.py -k 0.8.12`. To run tests for a specific compiler json format, run `pytest tests/test_ast_parsing.py -k legacy` (can be legacy or compact). -The id's of tests can be inspected using ``pytest tests/test_ast_parsing.py --collect-only`. +The IDs of tests can be inspected using ``pytest tests/test_ast_parsing.py --collect-only`. ### Synchronization with crytic-compile By default, `slither` follows either the latest version of crytic-compile in pip, or `crytic-compile@master` (look for dependencies in [`setup.py`](./setup.py). If crytic-compile development comes with breaking changes, the process to update `slither` is: From d72302f94c033c5d2739af71672d467796b8807f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Thu, 5 Jan 2023 10:31:49 -0300 Subject: [PATCH 074/110] ci: etherscan: sleep briefly when the API key is not available Etherscan performs a 1/5s rate limit when using no API key, so this adds a small random sleep to avoid the second test failing if it executes fast enough. --- scripts/ci_test_etherscan.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/ci_test_etherscan.sh b/scripts/ci_test_etherscan.sh index 77457dc43..2f17d3f5d 100755 --- a/scripts/ci_test_etherscan.sh +++ b/scripts/ci_test_etherscan.sh @@ -12,6 +12,11 @@ if ! slither 0x7F37f78cBD74481E593F9C737776F7113d76B315 --etherscan-apikey "$GIT fi echo "::endgroup::" +# Perform a small sleep when API key is not available (e.g. on PR CI from external contributor) +if [ "$GITHUB_ETHERSCAN" = "" ]; then + sleep $(( ( RANDOM % 5 ) + 1 ))s +fi + echo "::group::Etherscan rinkeby" if ! slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --etherscan-apikey "$GITHUB_ETHERSCAN"; then echo "Etherscan rinkeby test failed" From 2109b5fad980b98315348bf4f47c01e2077e5b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Thu, 5 Jan 2023 11:11:07 -0300 Subject: [PATCH 075/110] ci: etherscan: fix test check --- scripts/ci_test_etherscan.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/ci_test_etherscan.sh b/scripts/ci_test_etherscan.sh index 2f17d3f5d..694690691 100755 --- a/scripts/ci_test_etherscan.sh +++ b/scripts/ci_test_etherscan.sh @@ -6,7 +6,7 @@ mkdir etherscan cd etherscan || exit 255 echo "::group::Etherscan mainnet" -if ! slither 0x7F37f78cBD74481E593F9C737776F7113d76B315 --etherscan-apikey "$GITHUB_ETHERSCAN"; then +if ! slither 0x7F37f78cBD74481E593F9C737776F7113d76B315 --etherscan-apikey "$GITHUB_ETHERSCAN" --no-fail-pedantic; then echo "Etherscan mainnet test failed" exit 1 fi @@ -18,7 +18,7 @@ if [ "$GITHUB_ETHERSCAN" = "" ]; then fi echo "::group::Etherscan rinkeby" -if ! slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --etherscan-apikey "$GITHUB_ETHERSCAN"; then +if ! slither rinkeby:0xFe05820C5A92D9bc906D4A46F662dbeba794d3b7 --etherscan-apikey "$GITHUB_ETHERSCAN" --no-fail-pedantic; then echo "Etherscan rinkeby test failed" exit 1 fi From ac624bfcefb52468ff05b1e114a5b47057108559 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Thu, 5 Jan 2023 11:09:45 -0300 Subject: [PATCH 076/110] ci: etherscan: re-enable test --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1ae5326a8..6503d2b62 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: # "embark", "erc", # "etherlime", - # "etherscan" + "etherscan", "find_paths", "flat", "kspec", From 1c869df9e91f65143d4201511143c6f582b697f8 Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 5 Jan 2023 16:41:51 +0100 Subject: [PATCH 077/110] Fix implicit conversion --- slither/slithir/convert.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 445fc7a8e..1918d8cd2 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -202,16 +202,19 @@ def _fits_under_byte(val: Union[int, str]) -> List[str]: def _find_function_from_parameter( - arguments: List[Variable], candidates: List[Function] + arguments: List[Variable], candidates: List[Function], full_comparison: bool ) -> Optional[Function]: """ Look for a function in candidates that can be the target based on the ir's call arguments Try the implicit type conversion for uint/int/bytes. Constant values can be both uint/int - While variables stick to their base type, but can changed the size + While variables stick to their base type, but can changed the size. + If full_comparison is True it will do a comparison of all the arguments regardless if + the candidate remained is one. :param arguments: :param candidates: + :param full_comparison: :return: """ type_args: List[str] @@ -261,7 +264,7 @@ def _find_function_from_parameter( not_found = False candidates_kept.append(candidate) - if len(candidates_kept) == 1: + if len(candidates_kept) == 1 and not full_comparison: return candidates_kept[0] candidates = candidates_kept if len(candidates) == 1: @@ -1339,7 +1342,7 @@ def look_for_library_or_top_level(contract, ir, using_for, t): arguments = [ir.destination] + ir.arguments if ( len(destination.parameters) == len(arguments) - and _find_function_from_parameter(arguments, [destination]) is not None + and _find_function_from_parameter(arguments, [destination], True) is not None ): internalcall = InternalCall(destination, ir.nbr_arguments, ir.lvalue, ir.type_call) internalcall.set_expression(ir.expression) @@ -1436,7 +1439,7 @@ def convert_type_library_call(ir: HighLevelCall, lib_contract: Contract): # TODO: handle collision with multiple state variables/functions func = lib_contract.get_state_variable_from_name(ir.function_name) if func is None and candidates: - func = _find_function_from_parameter(ir.arguments, candidates) + func = _find_function_from_parameter(ir.arguments, candidates, False) # In case of multiple binding to the same type # TODO: this part might not be needed with _find_function_from_parameter @@ -1532,7 +1535,7 @@ def convert_type_of_high_and_internal_level_call(ir: Operation, contract: Option if f.name == ir.function_name and len(f.parameters) == len(ir.arguments) ] - func = _find_function_from_parameter(ir.arguments, candidates) + func = _find_function_from_parameter(ir.arguments, candidates, False) if not func: assert contract @@ -1555,7 +1558,7 @@ def convert_type_of_high_and_internal_level_call(ir: Operation, contract: Option # TODO: handle collision with multiple state variables/functions func = contract.get_state_variable_from_name(ir.function_name) if func is None and candidates: - func = _find_function_from_parameter(ir.arguments, candidates) + func = _find_function_from_parameter(ir.arguments, candidates, False) # lowlelvel lookup needs to be done at last step if not func: From 2ee6d0a4c8f31d27588738fdc9addb64b4b0854c Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 5 Jan 2023 16:44:30 +0100 Subject: [PATCH 078/110] Add tests --- .../using-for-3-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 4063 bytes .../using-for-4-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 4106 bytes .../using-for-3-0.8.0.sol-0.8.15-compact.json | 8 ++++++ .../using-for-4-0.8.0.sol-0.8.15-compact.json | 8 ++++++ tests/ast-parsing/using-for-3-0.8.0.sol | 27 ++++++++++++++++++ tests/ast-parsing/using-for-4-0.8.0.sol | 25 ++++++++++++++++ tests/test_ast_parsing.py | 2 ++ tests/test_features.py | 21 ++++++++++++++ 8 files changed, 91 insertions(+) create mode 100644 tests/ast-parsing/compile/using-for-3-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/using-for-4-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/expected/using-for-3-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/using-for-4-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/using-for-3-0.8.0.sol create mode 100644 tests/ast-parsing/using-for-4-0.8.0.sol diff --git a/tests/ast-parsing/compile/using-for-3-0.8.0.sol-0.8.15-compact.zip b/tests/ast-parsing/compile/using-for-3-0.8.0.sol-0.8.15-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..e51c777db47f414eb433760536fa95b590cf3960 GIT binary patch literal 4063 zcma*q{beed`C zJolUr=hOKEemd$v3>g4AfB-NM!v5xqKY1|^Apmfr4*+lh003WaM>l)0ox2wp0v6yC z=M&)bc6YI`4e)UH^0Bb;dgtKiXUpg0?e2z)feA1J0N?zrO65it;XxPqvBT`C{0QZkxXt^ycnJy9LFAhq*=H} zhufl`KPG)L1r-Mtk>TmwEu!TUDe66q*PY?p)LmQp)HR7tymD&(o=9hY;P@iABk+m# zu(;?mb29}P0~Q+`B19ngy1Mvx+=KgdIuXI{&Jz!A7&_-crm@U!?tHom?d!0S^ap4q z{Q@07{|5i8EmUW}4Ey9;_^L5IN>Wiwx0*NE{Q0&)4BGqlu;4%xWPflgqxQJ`nPmG0 zCS~7!U4rDFzLdnhttnXcnIlycCz&iHPa9;H2kx}*^G>73EVblWAGJ{rtUL34#JbPd zCDUIJ@ol6u5{y424qm8btLFmJ-VeRGz^Wj)=i3!@(raDnB{{ofJdNl&uYi;JHs);( zRF1cJV2XD^f`@u)=y6UrJ|(Y0zJNNE^`n2)kqD@Q4FHTQhjvg*uj zR%4!U_-U7oF@O+`fMlaZE7fYL_gW{6!kg@rQa3Xg&#JH05(k?adgL*G-(ALn~>TMRBtS5%g`aN`F=0 z9zba&j+Ayr;Tw_Vgxg&VwFCa@`qx|1u9dnaPfwy;3Zv$V*UL=49;s0+OTTAvE3f>WA!fGZ{m-2} znOY4#D1O7cz5pErBpX)=aP5UWZ8`y1lQuspwV0btUw>p<8>;!*cP)x@Z}KO&4OEu# zv>qU-05#brfa~(p)$m|GG_ynfRxB&pq-1BBEiK8T4t>3;1K3|_c1QKc8-;>|_YOj4 z{2xG4d}SE5aAi*y_*w1YNn+p}rAe$aDXlUOBexJ%4R&^E_<7ea%aG9c4!`b;=|8rC z1}BJB?a^r*KDbiE){Sg=Io~!u$72fcNE`uL`oWYHg<7U5){J|XLo)VLyE4-Blu z)~NW`9P)P8v63AEY0bSgR#hOCh|=<{-Hj}EWPgqPr2X3OZWk^ywcm=DFbmqZ+LhQw zn8kSqZxLY`WO1DMaoRE#!Hpu^*7&-33WqDljs7*2lR?O@?tg-)VznLA*TdHK1x0`8 zs%0z+U)l!h$ucuj5#iwQ%>Eu26KmqVaR?Pce zld_Oa>Y}HGj*4|(Mv)a*zJr#90$qPaiEl$LEc7l!2_$o$-k?;~OS9$sYl9oU?}UBU zXSDhQ?1quA|A1Zb;aO$9+9@Z!BE=+wMJI=p?O~+Z-lRywy|Oh@V1g{JFt4S_VyFO;G8;+gNN>eqaFdlM6&TLvN8$K`9^{ zioXUrWE@cG3Lc21pGWh0P^}@o`W=7sH}$jJaB}@%ddu7Fs~hj7 zR;`YRqOd=Kjr|r%cY8{f6bpX2l@CrL*J<(CHK+c}pY3bvHxFh$A~M0bQ==@vME?nH zGFBCt{8M4+>yeF}VMIfV$69y93Ja4)noC8T4fDvGR5RktC9&F*wnmO_&L(vu6&7jvs~&-scm1F+d>_qtHzz0pc^L(b4BUF`A_ z@+?i99PCP#*-~0HLSq)pVL7m1e=#3)S0nNuAb=Oz+ely(E8j#}gvP;0+p_9VbJqE= zu4Pz3D_@&j^5Rfgab<9*RYBpTaMQRT0gEyAPPhKvH>$Twd-CVYL`RZ-+mdw8YK@Vi zEiMjBhQccM;)3u+!n*KOSK2b znqS*8JSZy}47|1>Voer5)O~KVn)-Npsh^VSl3TTUI6^3+9`AqR9YV8M9v3le42h-k z3(;b{AFw9G7|Lo4h>~(UpRU`mB%9!jFq{Y=K3p2;SlTPbogxZRlb~}i?jMagTMBSv zEs4~1r|F^gJuZ3&dQIGg5i9|>x^rETN9_Jc&Gs3IREgZCc869Lgg-*1bTrSS*!W{# zi++I6bNRTruhutNSEtGU!siXSk#gD4>UUW5v%{jj@SYggWJwoa4Ib=NTk17b0LxC* zt^G80*UoZozDA#gNX6F=U>9$^pyTnBe&3wr#H7AL8DSM8G}fm2z)Uh9#*Ey+HQX9x z?)>IK-_L<)2E2foS<%02pdE^JR`Rd=yQGN?0KI*89Zvhy_B!+KK$@5&yU`x2K`V(S zc~*%Sa7rR~%d7aREx6uf9`tl<9o2sukrmg&hH_(62&HZ|nA`3%ngX&d%1ht356`9! zOf|W+U2!oQ^h8;l5}%Xj(|P4RY!FvHz}nGo(j~-1hEMqogXafbxcEoEZX?~Q^bjGz z`aBDk!d;K@b5Jz;z5bb+YT}Bf4_!oI1(+ewEFOsBJYkh=3pE~ zGZkwVC-xRRz_F2#%PiYJdNQs%*7J34nF%(*`R}OCp3GuKl(@fOE}R)&?fNVE$FCM2 zAlEdgL2$j10*AjPt+sow@TvLA57?%$cCMTzoRbkl*?iCSzLr>E$+MFr`%QqcSS6RLM_?Wm#5W!n@p9L*-F?(s`u z1g8~W+$NJR57j3pn3k(z)!QzT5ysoLo*F+co$*dLJeB@(<8*I_tV2H6VaD_S)GH(U z!IH1o&wohdPbrnuBwL)S?LL6&k;dt+5RBykiHwI@pW?T-@X6*^w45WO&Cig^$jj?M z;8_K!Ug(FX*?#sq^p#Ha7qjGd30>2yTz%?hj6_!AT1!OB&)(i6){I2E$yB}I= zN|B@X-L%W@#aNweUSepfOCLrQ`%nm{*hg56HSBvi;ummMtaOv6^GsKsQ^S(6!c;nu x^LguAfr*Yf8oCVd|2Fr3*!{nOqy2aO-vZZB$He;Y0qs9E{Lgy*hw%Ww{{Tv}rv?B3 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/using-for-4-0.8.0.sol-0.8.15-compact.zip b/tests/ast-parsing/compile/using-for-4-0.8.0.sol-0.8.15-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..12452d862d63429261cc2fb14c95004cf6299003 GIT binary patch literal 4106 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 p(a_~y{CA%JEA;af5y7DIwsbC4ru?@@ZZh1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "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/expected/using-for-4-0.8.0.sol-0.8.15-compact.json b/tests/ast-parsing/expected/using-for-4-0.8.0.sol-0.8.15-compact.json new file mode 100644 index 000000000..6ff9c9780 --- /dev/null +++ b/tests/ast-parsing/expected/using-for-4-0.8.0.sol-0.8.15-compact.json @@ -0,0 +1,8 @@ +{ + "Lib": { + "f(St,uint256)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "C": { + "libCall(uint16)": "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/using-for-3-0.8.0.sol b/tests/ast-parsing/using-for-3-0.8.0.sol new file mode 100644 index 000000000..1da4f3dc6 --- /dev/null +++ b/tests/ast-parsing/using-for-3-0.8.0.sol @@ -0,0 +1,27 @@ +using {a} for Data; + +struct Data { mapping(uint => bool) flags; } + +function a(Data storage self, uint value, uint value2) returns(bool){ + return false; +} + +library Lib { + function a(Data storage self, uint value) public + view + returns (bool) + { + return true; + } + +} + +contract C { + using Lib for Data; + Data knownValues; + + function libCall(uint value) public { + require(knownValues.a(value)); + } + +} \ No newline at end of file diff --git a/tests/ast-parsing/using-for-4-0.8.0.sol b/tests/ast-parsing/using-for-4-0.8.0.sol new file mode 100644 index 000000000..d50e107a4 --- /dev/null +++ b/tests/ast-parsing/using-for-4-0.8.0.sol @@ -0,0 +1,25 @@ +using {f} for St; +struct St { uint field; } + + +function f(St storage self, uint8 v) view returns(uint){ + return 0; +} + + +library Lib { + function f(St storage self, uint256 v) public view returns (uint) { + return 1; + } + +} + +contract C { + using Lib for St; + St st; + + function libCall(uint16 v) public view returns(uint){ + return st.f(v); // return 1 + } + +} \ No newline at end of file diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 9d5662b91..92fd93a17 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -426,6 +426,8 @@ ALL_TESTS = [ Test("ternary-with-max.sol", ["0.8.15"]), Test("using-for-1-0.8.0.sol", ["0.8.15"]), 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-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 c06ee96ce..1bf7ba4ff 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -7,6 +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 def _run_all_detectors(slither: Slither): @@ -50,3 +51,23 @@ def test_funcion_id_rec_structure(): for compilation_unit in slither.compilation_units: for function in compilation_unit.functions: assert function.solidity_signature + + +def test_using_for_top_level_same_name() -> None: + slither = Slither("./tests/ast-parsing/using-for-3-0.8.0.sol") + contract_c = slither.get_contract_from_name("C")[0] + libCall = contract_c.get_function_from_full_name("libCall(uint256)") + for ir in libCall.all_slithir_operations(): + if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "a": + return + assert False + + +def test_using_for_top_level_implicit_conversion() -> None: + slither = Slither("./tests/ast-parsing/using-for-4-0.8.0.sol") + contract_c = slither.get_contract_from_name("C")[0] + libCall = contract_c.get_function_from_full_name("libCall(uint16)") + for ir in libCall.all_slithir_operations(): + if isinstance(ir, LibraryCall) and ir.destination == "Lib" and ir.function_name == "f": + return + assert False From ea681f9399e6060232844305c5bb9337e42fa0cb Mon Sep 17 00:00:00 2001 From: Simone Date: Thu, 5 Jan 2023 16:57:19 +0100 Subject: [PATCH 079/110] Fix testing feature --- tests/test_features.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_features.py b/tests/test_features.py index 48d65dde8..e6e781881 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -73,6 +73,7 @@ def test_upgradeable_comments() -> None: def test_using_for_top_level_same_name() -> None: + solc_select.switch_global_version("0.8.15", always_install=True) slither = Slither("./tests/ast-parsing/using-for-3-0.8.0.sol") contract_c = slither.get_contract_from_name("C")[0] libCall = contract_c.get_function_from_full_name("libCall(uint256)") @@ -83,6 +84,7 @@ def test_using_for_top_level_same_name() -> None: def test_using_for_top_level_implicit_conversion() -> None: + solc_select.switch_global_version("0.8.15", always_install=True) slither = Slither("./tests/ast-parsing/using-for-4-0.8.0.sol") contract_c = slither.get_contract_from_name("C")[0] libCall = contract_c.get_function_from_full_name("libCall(uint16)") From d4fd85adea64b46cadee71cbf88ece867eac6683 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Thu, 5 Jan 2023 11:40:39 -0600 Subject: [PATCH 080/110] fix overwriting test_file --- tests/test_ast_parsing.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 23783137b..bcd0fe3f7 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -444,10 +444,10 @@ def pytest_generate_tests(metafunc): class TestASTParsing: # pylint: disable=no-self-use def test_parsing(self, test_file, version, flavor): - test_file = os.path.join(TEST_ROOT, "compile", f"{test_file}-{version}-{flavor}.zip") - expected_file = os.path.join(TEST_ROOT, "expected", f"{test_file}-{version}-{flavor}.json") + actual = os.path.join(TEST_ROOT, "compile", f"{test_file}-{version}-{flavor}.zip") + expected = os.path.join(TEST_ROOT, "expected", f"{test_file}-{version}-{flavor}.json") - cc = load_from_zip(test_file)[0] + cc = load_from_zip(actual)[0] sl = Slither( cc, @@ -459,7 +459,7 @@ class TestASTParsing: actual = generate_output(sl) try: - with open(expected_file, "r", encoding="utf8") as f: + with open(expected, "r", encoding="utf8") as f: expected = json.load(f) except OSError: pytest.xfail("the file for this test was not generated") From c7154637d64de45b9be849b60003c016189f4da1 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Thu, 5 Jan 2023 19:33:14 +0100 Subject: [PATCH 081/110] WIP fix yul parsing --- slither/core/children/child_function.py | 4 +- slither/core/expressions/identifier.py | 4 +- slither/core/variables/local_variable.py | 4 +- slither/slithir/convert.py | 1 + slither/solc_parsing/declarations/function.py | 1 - slither/solc_parsing/yul/evm_functions.py | 4 +- slither/solc_parsing/yul/parse_yul.py | 86 +++++++++++-------- slither/tools/documentation/__main__.py | 0 tests/ast-parsing/yul-top-level-0.8.0.sol | 16 ++++ tests/test_ast_parsing.py | 1 + 10 files changed, 76 insertions(+), 45 deletions(-) create mode 100644 slither/tools/documentation/__main__.py create mode 100644 tests/ast-parsing/yul-top-level-0.8.0.sol diff --git a/slither/core/children/child_function.py b/slither/core/children/child_function.py index cb4f0109f..5367320ca 100644 --- a/slither/core/children/child_function.py +++ b/slither/core/children/child_function.py @@ -5,11 +5,11 @@ if TYPE_CHECKING: class ChildFunction: - def __init__(self): + def __init__(self) -> None: super().__init__() self._function = None - def set_function(self, function: "Function"): + def set_function(self, function: "Function") -> None: self._function = function @property diff --git a/slither/core/expressions/identifier.py b/slither/core/expressions/identifier.py index ab40472a4..0b10c5615 100644 --- a/slither/core/expressions/identifier.py +++ b/slither/core/expressions/identifier.py @@ -7,7 +7,7 @@ if TYPE_CHECKING: class Identifier(ExpressionTyped): - def __init__(self, value): + def __init__(self, value) -> None: super().__init__() self._value: "Variable" = value @@ -15,5 +15,5 @@ class Identifier(ExpressionTyped): def value(self) -> "Variable": return self._value - def __str__(self): + def __str__(self) -> str: return str(self._value) diff --git a/slither/core/variables/local_variable.py b/slither/core/variables/local_variable.py index 5eb641fb4..7b7b4f8bc 100644 --- a/slither/core/variables/local_variable.py +++ b/slither/core/variables/local_variable.py @@ -11,11 +11,11 @@ from slither.core.declarations.structure import Structure class LocalVariable(ChildFunction, Variable): - def __init__(self): + def __init__(self) -> None: super().__init__() self._location: Optional[str] = None - def set_location(self, loc: str): + def set_location(self, loc: str) -> None: self._location = loc @property diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 0d2ef1b74..a93f42136 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -1630,6 +1630,7 @@ def find_references_origin(irs): """ for ir in irs: if isinstance(ir, (Index, Member)): + print(ir.node.source_mapping) ir.lvalue.points_to = ir.variable_left diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py index 269ca580f..150840b49 100644 --- a/slither/solc_parsing/declarations/function.py +++ b/slither/solc_parsing/declarations/function.py @@ -340,7 +340,6 @@ class FunctionSolc(CallerContextExpression): node, [self._function.name, f"asm_{len(self._node_to_yulobject)}"], scope, - parent_func=self._function, ) self._node_to_yulobject[node] = yul_object return yul_object diff --git a/slither/solc_parsing/yul/evm_functions.py b/slither/solc_parsing/yul/evm_functions.py index 0276d4bf7..41c150765 100644 --- a/slither/solc_parsing/yul/evm_functions.py +++ b/slither/solc_parsing/yul/evm_functions.py @@ -264,9 +264,9 @@ binary_ops = { class YulBuiltin: # pylint: disable=too-few-public-methods - def __init__(self, name): + def __init__(self, name: str) -> None: self._name = name @property - def name(self): + def name(self) -> str: return self._name diff --git a/slither/solc_parsing/yul/parse_yul.py b/slither/solc_parsing/yul/parse_yul.py index 8c9ee427e..f7c9938fc 100644 --- a/slither/solc_parsing/yul/parse_yul.py +++ b/slither/solc_parsing/yul/parse_yul.py @@ -24,6 +24,7 @@ from slither.core.expressions import ( UnaryOperation, ) from slither.core.expressions.expression import Expression +from slither.core.scope.scope import FileScope from slither.core.solidity_types import ElementaryType from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.variables.local_variable import LocalVariable @@ -51,30 +52,35 @@ class YulNode: def underlying_node(self) -> Node: return self._node - def add_unparsed_expression(self, expression: Dict): + def add_unparsed_expression(self, expression: Dict) -> None: assert self._unparsed_expression is None self._unparsed_expression = expression - def analyze_expressions(self): + def analyze_expressions(self) -> None: if self._node.type == NodeType.VARIABLE and not self._node.expression: - self._node.add_expression(self._node.variable_declaration.expression) + expression = self._node.variable_declaration.expression + if expression: + self._node.add_expression(expression) if self._unparsed_expression: expression = parse_yul(self._scope, self, self._unparsed_expression) - self._node.add_expression(expression) + if expression: + self._node.add_expression(expression) if self._node.expression: if self._node.type == NodeType.VARIABLE: # Update the expression to be an assignement to the variable - _expression = AssignmentOperation( - Identifier(self._node.variable_declaration), - self._node.expression, - AssignmentOperationType.ASSIGN, - self._node.variable_declaration.type, - ) - _expression.set_offset( - self._node.expression.source_mapping, self._node.compilation_unit - ) - self._node.add_expression(_expression, bypass_verif_empty=True) + variable_declaration = self._node.variable_declaration + if variable_declaration: + _expression = AssignmentOperation( + Identifier(self._node.variable_declaration), + self._node.expression, + AssignmentOperationType.ASSIGN, + variable_declaration.type, + ) + _expression.set_offset( + self._node.expression.source_mapping, self._node.compilation_unit + ) + self._node.add_expression(_expression, bypass_verif_empty=True) expression = self._node.expression read_var = ReadVar(expression) @@ -122,13 +128,13 @@ class YulScope(metaclass=abc.ABCMeta): ] def __init__( - self, contract: Optional[Contract], yul_id: List[str], parent_func: Function = None - ): + self, contract: Optional[Contract], yul_id: List[str], parent_func: Function + ) -> None: self._contract = contract self._id: List[str] = yul_id self._yul_local_variables: List[YulLocalVariable] = [] self._yul_local_functions: List[YulFunction] = [] - self._parent_func = parent_func + self._parent_func: Function = parent_func @property def id(self) -> List[str]: @@ -155,10 +161,14 @@ class YulScope(metaclass=abc.ABCMeta): def new_node(self, node_type: NodeType, src: Union[str, Dict]) -> YulNode: pass - def add_yul_local_variable(self, var): + @property + def file_scope(self) -> FileScope: + return self._parent_func.file_scope + + def add_yul_local_variable(self, var: "YulLocalVariable") -> None: self._yul_local_variables.append(var) - def get_yul_local_variable_from_name(self, variable_name): + def get_yul_local_variable_from_name(self, variable_name: str) -> Optional["YulLocalVariable"]: return next( ( v @@ -168,10 +178,10 @@ class YulScope(metaclass=abc.ABCMeta): None, ) - def add_yul_local_function(self, func): + def add_yul_local_function(self, func: "YulFunction") -> None: self._yul_local_functions.append(func) - def get_yul_local_function_from_name(self, func_name): + def get_yul_local_function_from_name(self, func_name: str) -> Optional["YulLocalVariable"]: return next( (v for v in self._yul_local_functions if v.underlying.name == func_name), None, @@ -242,7 +252,7 @@ class YulFunction(YulScope): def function(self) -> Function: return self._function - def convert_body(self): + def convert_body(self) -> None: node = self.new_node(NodeType.ENTRYPOINT, self._ast["src"]) link_underlying_nodes(self._entrypoint, node) @@ -258,7 +268,7 @@ class YulFunction(YulScope): convert_yul(self, node, self._ast["body"], self.node_scope) - def parse_body(self): + def parse_body(self) -> None: for node in self._nodes: node.analyze_expressions() @@ -289,9 +299,8 @@ class YulBlock(YulScope): entrypoint: Node, yul_id: List[str], node_scope: Union[Scope, Function], - **kwargs, ): - super().__init__(contract, yul_id, **kwargs) + super().__init__(contract, yul_id, entrypoint.function) self._entrypoint: YulNode = YulNode(entrypoint, self) self._nodes: List[YulNode] = [] @@ -318,7 +327,7 @@ class YulBlock(YulScope): def convert(self, ast: Dict) -> YulNode: return convert_yul(self, self._entrypoint, ast, self.node_scope) - def analyze_expressions(self): + def analyze_expressions(self) -> None: for node in self._nodes: node.analyze_expressions() @@ -361,18 +370,22 @@ def convert_yul_function_definition( while not isinstance(top_node_scope, Function): top_node_scope = top_node_scope.father + func: Union[FunctionTopLevel, FunctionContract] if isinstance(top_node_scope, FunctionTopLevel): - scope = root.contract.file_scope + scope = root.file_scope func = FunctionTopLevel(root.compilation_unit, scope) # Note: we do not add the function in the scope # While its a top level function, it is not accessible outside of the function definition # In practice we should probably have a specific function type for function defined within a function else: func = FunctionContract(root.compilation_unit) + func.function_language = FunctionLanguage.Yul yul_function = YulFunction(func, root, ast, node_scope) - root.contract.add_function(func) + if root.contract: + root.contract.add_function(func) + root.compilation_unit.add_function(func) root.add_yul_local_function(yul_function) @@ -774,14 +787,15 @@ def parse_yul_identifier(root: YulScope, _node: YulNode, ast: Dict) -> Optional[ # check function-scoped variables parent_func = root.parent_func if parent_func: - variable = parent_func.get_local_variable_from_name(name) - if variable: - return Identifier(variable) + local_variable = parent_func.get_local_variable_from_name(name) + if local_variable: + return Identifier(local_variable) if isinstance(parent_func, FunctionContract): - variable = parent_func.contract.get_state_variable_from_name(name) - if variable: - return Identifier(variable) + assert parent_func.contract + state_variable = parent_func.contract.get_state_variable_from_name(name) + if state_variable: + return Identifier(state_variable) # check yul-scoped variable variable = root.get_yul_local_variable_from_name(name) @@ -798,7 +812,7 @@ def parse_yul_identifier(root: YulScope, _node: YulNode, ast: Dict) -> Optional[ if magic_suffix: return magic_suffix - ret, _ = find_top_level(name, root.contract.file_scope) + ret, _ = find_top_level(name, root.file_scope) if ret: return Identifier(ret) @@ -840,7 +854,7 @@ def parse_yul_unsupported(_root: YulScope, _node: YulNode, ast: Dict) -> Optiona def parse_yul(root: YulScope, node: YulNode, ast: Dict) -> Optional[Expression]: - op = parsers.get(ast["nodeType"], parse_yul_unsupported)(root, node, ast) + op: Expression = parsers.get(ast["nodeType"], parse_yul_unsupported)(root, node, ast) if op: op.set_offset(ast["src"], root.compilation_unit) return op diff --git a/slither/tools/documentation/__main__.py b/slither/tools/documentation/__main__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/ast-parsing/yul-top-level-0.8.0.sol b/tests/ast-parsing/yul-top-level-0.8.0.sol new file mode 100644 index 000000000..214db9cb4 --- /dev/null +++ b/tests/ast-parsing/yul-top-level-0.8.0.sol @@ -0,0 +1,16 @@ +function top_level_yul(int256 c) pure returns (uint result) { + assembly { + function internal_yul(a) -> b { + b := a + } + + result := internal_yul(c) + } +} + + +contract Test { + function test() public{ + top_level_yul(10); + } +} \ No newline at end of file diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 96aad1a63..e6764ba0c 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -435,6 +435,7 @@ ALL_TESTS = [ Test("using-for-global-0.8.0.sol", ["0.8.15"]), Test("library_event-0.8.16.sol", ["0.8.16"]), Test("top-level-struct-0.8.0.sol", ["0.8.0"]), + Test("yul-top-level-0.8.0.sol", ["0.8.0"]), ] # create the output folder if needed try: From 0b99b348fb8ccc702a6b0c18ba92bd623e8725a5 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Thu, 5 Jan 2023 19:42:19 +0100 Subject: [PATCH 082/110] minor --- slither/slithir/convert.py | 1 - 1 file changed, 1 deletion(-) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index a93f42136..0d2ef1b74 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -1630,7 +1630,6 @@ def find_references_origin(irs): """ for ir in irs: if isinstance(ir, (Index, Member)): - print(ir.node.source_mapping) ir.lvalue.points_to = ir.variable_left From d1b875d85e7e3660bd5fcc2d90ed68c6f1c8f479 Mon Sep 17 00:00:00 2001 From: pavan-nambi Date: Fri, 6 Jan 2023 02:25:17 +0530 Subject: [PATCH 083/110] update --- .github/workflows/IR.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/IR.yml b/.github/workflows/IR.yml index c5187da65..891de2bfb 100644 --- a/.github/workflows/IR.yml +++ b/.github/workflows/IR.yml @@ -34,8 +34,14 @@ jobs: - name: Install dependencies run: | pip install ".[dev]" + solc-select install 0.5.0 solc-select use 0.8.11 --always-install + - name: Install old solc + if: matrix.os == 'ubuntu-latest' + run: solc-select install 0.4.0 + + - name: Test with pytest run: | - pytest tests/test_ssa_generation.py + pytest tests/test_ssa_generation.py \ No newline at end of file From cbc3077a65e6cefc21537aeb59ef57f1963212ba Mon Sep 17 00:00:00 2001 From: Simone Date: Fri, 6 Jan 2023 01:18:41 +0100 Subject: [PATCH 084/110] 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 b595d8f946b9172d26a0eb6e1e125c1cd8a54d51 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Fri, 6 Jan 2023 10:02:12 +0100 Subject: [PATCH 085/110] Create CODEOWNERS --- CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..e76e5a2bb --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,4 @@ +* @montyly @0xalpharush @smonicas +/slither/tools/read_storage @0xalpharush +/slither/slithir/ @montyly +/slither/analyses/ @montyly From 794b3b9aa4c2fb28f6b54d7472f13d21c40e1067 Mon Sep 17 00:00:00 2001 From: Simone Date: Fri, 6 Jan 2023 13:07:26 +0100 Subject: [PATCH 086/110] 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 53eea1d21640e19bd703d2a7e7e7db68f76b4a2a Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Fri, 6 Jan 2023 13:40:32 +0100 Subject: [PATCH 087/110] Add missing file --- .../yul-top-level-0.8.0.sol-0.8.0-compact.zip | Bin 0 -> 2061 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/ast-parsing/compile/yul-top-level-0.8.0.sol-0.8.0-compact.zip diff --git a/tests/ast-parsing/compile/yul-top-level-0.8.0.sol-0.8.0-compact.zip b/tests/ast-parsing/compile/yul-top-level-0.8.0.sol-0.8.0-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..ce81a5c37e9972e41c7cc13f57469de6b38aa11c GIT binary patch literal 2061 zcmb8wX&}>$0|)TmWTJme%JDen4zam&A2}lybL4T(nIn@q=bi~I_c7$0Bv+TH5QefW z&sgQoy(mZK>dF1|{NMjy{J-B9-&fz)ADe5ZSPcLcfD33Um3Ca1o3V8`4FG;303Z(l z05;+lEIi~k?3Qn&?=6@TTobMY4-2{F;TwHB1QYJziShOii1dXAhJ~OxSiyiB03-o` zUV8dX)kD=#(ns1$9nP|M=m6<%=$%ZYpuXr>SSO$I_Da7w*{SFq@Mmkr2C8{Gpj5}W!Ye#Dg=n*{o1cP+%1xr zlUhqkz9t03i~Ixs>{El?+IEE)-@ZM6cU_FcHe?cmgN zLS3DqnryzYnKO+xAVq1YOo@tG2eH4eN7zgh?kRZDIGP`tttzJEdxV;xM&{)Fd&Gu% z?+spc=H_@KSH92CC|S7JoGTQ!t+{Y8Fu8Va2)9`5mMa^s#$ebPNbKK1y7o%j$yGDb z3U>1}cU%JICm)Uv8#rDB`^xwe+>|4r>fcy%^ktr!CjV&A%AzrU2H=qqYP#`>E^X&L z>loIT1Vf(r#VfS%-Jj}cRX(4PHtcRJ7BnoCDvxuD^i&YCa)vzW35z- zm@*&Lj&?0~%dnhds%-K@+j<6C;E+g(q%Y$O5c;L0N|hgf&s42}doz@a_sv|CPa?R4T(r)JULDI^)d+4p zAD*JQr3e~fI$?9yA|eXo>WPcw?Tq53cN}luHxkMZbqY?N4_mYeuKm2| zb-$#}{*>&tJi1lp?&?py(8_kKThPesb%K zhx%iNsz)CNMSwOi_VYV ziY3P`CO99dog#PE6-{Z3R2yGuZSOEabI3dN$m(vCwKU76qt^H!W7bl!Jkc?;Jr1Z7 zyme{|zJa{lPg9RWInl4Y?|WHPsw=FL)w=?pb(YuL>s;k24E3}0JFu>d>S(z0(Mb*k z)k`)2a}P(jP42}u0*Ya-h-|Y8-V16@_!fTtt!fDgy+O)iQ@>%P9TP(%>~d8~3^laW zOw?qM_h_Ku>0vZ!1=g=$PO^N2V|7BS>PwaruMThyN^xh4CGwi;I(vfY^n$NTD?(6* zE(lq)QsnZT^oZ5tx0?n&Qa)XVNqS_$>faJ9XrUa;QhBwA_XLR|u3p46K|ln=wZl#r zHAaMb1p#a?X<+CrwhTRkrE5G8A3`j!If)|iHd1|sSFBN7Hdf3CE@ z>+PS-1;t7eA-QrcQ|E9Ile-8j3*i|SrP7MP=U*CXn`9iD2~+g_>#JKA<_CCjKnLmR zbkZCfZX?E`=Oa}4KysB3tyP2YF{+t2PmHh-$!t0N4*cS2qX5o=Psi>t1&^4UZc`!! z#|Pu-NWU?3LSSVYv`-eLunceaUZi^-K4?M6ENOo#y?R8bFkLo14quV|AWH(VPVbp@81k+qzu!EgQEH8=*?e#pCC#)zrpns# z`x7W!seD?=jIhJqv~Ip?%Y7KlG1$*PvI!LT%jY6)U0d>u&ci_rHM?`z*VybB^_Zy3 zM8|xc{c4+a6s;=yr{3nv8*fwlZ9phaoSg!v>Ju_+3cho^RY<*|wEqqG(I%$pGlXGv zsn^&i$W%7(vKdrlJWn5vHj=aIbWh-HAhB(~SGhbo9i7VSIPOyt)uA0AS|;0>zUw}q zF=4TBWJwb!n|;~dx@)V90DpylUetS1t(e6PM5n0PdC7 Date: Fri, 6 Jan 2023 14:03:33 +0100 Subject: [PATCH 088/110] Add --no-fail mode --- slither/__main__.py | 7 ++++ slither/core/slither_core.py | 4 +++ slither/printers/guidance/echidna.py | 47 +++++++++++++++------------ slither/slither.py | 48 +++++++++++----------------- slither/utils/command_line.py | 1 + 5 files changed, 56 insertions(+), 51 deletions(-) diff --git a/slither/__main__.py b/slither/__main__.py index 75707af06..dddf973c0 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -555,6 +555,13 @@ def parse_args( default=False, ) + group_misc.add_argument( + "--no-fail", + help="Do not fail in case of parsing (echidna mode only)", + action="store_true", + default=defaults_flag_in_config["no_fail"], + ) + group_codex.add_argument( "--codex", help="Enable codex (require an OpenAI API Key)", diff --git a/slither/core/slither_core.py b/slither/core/slither_core.py index 691699067..66b8fc430 100644 --- a/slither/core/slither_core.py +++ b/slither/core/slither_core.py @@ -92,6 +92,10 @@ class SlitherCore(Context): # But we allow to alter this (ex: file.sol:1) for vscode integration self.line_prefix: str = "#" + # Use by the echidna printer + # If true, partial analysis is allowed + self.no_fail = False + @property def compilation_units(self) -> List[SlitherCompilationUnit]: return list(self._compilation_units) diff --git a/slither/printers/guidance/echidna.py b/slither/printers/guidance/echidna.py index dbfa54121..ec200d5e1 100644 --- a/slither/printers/guidance/echidna.py +++ b/slither/printers/guidance/echidna.py @@ -323,27 +323,32 @@ def _call_a_parameter(slither: SlitherCore) -> Dict[str, List[Dict]]: ret: Dict[str, List[Dict]] = defaultdict(list) for contract in slither.contracts: # pylint: disable=too-many-nested-blocks for function in contract.functions_entry_points: - for ir in function.all_slithir_operations(): - if isinstance(ir, HighLevelCall): - for idx, parameter in enumerate(function.parameters): - if is_dependent(ir.destination, parameter, function): - ret[contract.name].append( - { - "function": _get_name(function), - "parameter_idx": idx, - "signature": _get_name(ir.function), - } - ) - if isinstance(ir, LowLevelCall): - for idx, parameter in enumerate(function.parameters): - if is_dependent(ir.destination, parameter, function): - ret[contract.name].append( - { - "function": _get_name(function), - "parameter_idx": idx, - "signature": None, - } - ) + try: + for ir in function.all_slithir_operations(): + if isinstance(ir, HighLevelCall): + for idx, parameter in enumerate(function.parameters): + if is_dependent(ir.destination, parameter, function): + ret[contract.name].append( + { + "function": _get_name(function), + "parameter_idx": idx, + "signature": _get_name(ir.function), + } + ) + if isinstance(ir, LowLevelCall): + for idx, parameter in enumerate(function.parameters): + if is_dependent(ir.destination, parameter, function): + ret[contract.name].append( + { + "function": _get_name(function), + "parameter_idx": idx, + "signature": None, + } + ) + except Exception as e: + if slither.no_fail: + continue + raise e return ret diff --git a/slither/slither.py b/slither/slither.py index 81e920d01..45d99906f 100644 --- a/slither/slither.py +++ b/slither/slither.py @@ -91,6 +91,8 @@ class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes self.codex_max_tokens = kwargs.get("codex_max_tokens", 300) self.codex_log = kwargs.get("codex_log", False) + self.no_fail = kwargs.get("no_fail", False) + self._parsers: List[SlitherCompilationUnitSolc] = [] try: if isinstance(target, CryticCompile): @@ -128,41 +130,27 @@ class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes triage_mode = kwargs.get("triage_mode", False) self._triage_mode = triage_mode + self._init_parsing_and_analyses(kwargs.get("skip_analyze", False)) + + def _init_parsing_and_analyses(self, skip_analyze: bool) -> None: for parser in self._parsers: - parser.parse_contracts() + try: + parser.parse_contracts() + except Exception as e: + if self.no_fail: + continue + raise e # skip_analyze is only used for testing - if not kwargs.get("skip_analyze", False): + if not skip_analyze: for parser in self._parsers: - parser.analyze_contracts() - - # def _init_from_raw_json(self, filename): - # if not os.path.isfile(filename): - # raise SlitherError( - # "{} does not exist (are you in the correct directory?)".format(filename) - # ) - # assert filename.endswith("json") - # with open(filename, encoding="utf8") as astFile: - # stdout = astFile.read() - # if not stdout: - # to_log = f"Empty AST file: {filename}" - # raise SlitherError(to_log) - # contracts_json = stdout.split("\n=") - # - # self._parser = SlitherCompilationUnitSolc(filename, self) - # - # for c in contracts_json: - # self._parser.parse_top_level_from_json(c) - - # def _init_from_list(self, contract): - # self._parser = SlitherCompilationUnitSolc("", self) - # for c in contract: - # if "absolutePath" in c: - # path = c["absolutePath"] - # else: - # path = c["attributes"]["absolutePath"] - # self._parser.parse_top_level_from_loaded_json(c, path) + try: + parser.analyze_contracts() + except Exception as e: + if self.no_fail: + continue + raise e @property def detectors(self): diff --git a/slither/utils/command_line.py b/slither/utils/command_line.py index 71305c56e..174c2a4b6 100644 --- a/slither/utils/command_line.py +++ b/slither/utils/command_line.py @@ -60,6 +60,7 @@ defaults_flag_in_config = { "zip": None, "zip_type": "lzma", "show_ignored_findings": False, + "no_fail": False, **DEFAULTS_FLAG_IN_CONFIG_CRYTIC_COMPILE, } From ed9cbf8320b38b6e1f4eebb46d28288f5c063906 Mon Sep 17 00:00:00 2001 From: Josselin Feist Date: Fri, 6 Jan 2023 14:13:19 +0100 Subject: [PATCH 089/110] 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 090/110] 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 From 1c12f2a7fcf9bf809b4be7a3b60917ee422730af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 6 Jan 2023 11:08:24 -0300 Subject: [PATCH 091/110] tests: source_unit: add missing foundry submodule --- .gitmodules | 4 ++++ 1 file changed, 4 insertions(+) create mode 100755 .gitmodules diff --git a/.gitmodules b/.gitmodules new file mode 100755 index 000000000..f2ce479c6 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "tests/source_unit/lib/forge-std"] + path = tests/source_unit/lib/forge-std + url = https://github.com/foundry-rs/forge-std + branch = v1.2.0 From d875eff4153d6249189f4e31ee46af3f5ff23bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 6 Jan 2023 12:34:15 -0300 Subject: [PATCH 092/110] Revert "tests: source_unit: add missing foundry submodule" This reverts commit 1c12f2a7fcf9bf809b4be7a3b60917ee422730af. --- .gitmodules | 4 ---- 1 file changed, 4 deletions(-) delete mode 100755 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100755 index f2ce479c6..000000000 --- a/.gitmodules +++ /dev/null @@ -1,4 +0,0 @@ -[submodule "tests/source_unit/lib/forge-std"] - path = tests/source_unit/lib/forge-std - url = https://github.com/foundry-rs/forge-std - branch = v1.2.0 From afb73426194840e78af83a8b00bbb7befe04f912 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 6 Jan 2023 10:11:43 -0600 Subject: [PATCH 093/110] fix constructor var not detected as candidate, separate detectors --- slither/detectors/all_detectors.py | 3 +- .../detectors/variables/could_be_constant.py | 45 ++ .../detectors/variables/could_be_immutable.py | 44 ++ .../possible_const_state_variables.py | 141 ------ .../variables/unchanged_state_variables.py | 123 ++++++ ...iables.py => unchanged_state_variables.py} | 6 +- .../tools/slither_format/slither_format.py | 6 +- .../0.4.25/const_state_variables.sol | 5 + ...variables.sol.0.4.25.CouldBeConstant.json} | 18 +- .../0.5.16/const_state_variables.sol | 5 + ...variables.sol.0.5.16.CouldBeConstant.json} | 27 +- .../0.6.11/const_state_variables.sol | 37 +- ...variables.sol.0.6.11.CouldBeConstant.json} | 169 ++++---- .../0.7.6/const_state_variables.sol | 28 +- ..._variables.sol.0.7.6.CouldBeConstant.json} | 406 ++++-------------- .../0.8.0/const_state_variables.sol | 30 +- ..._variables.sol.0.8.0.CouldBeConstant.json} | 406 ++++-------------- .../0.4.25/immut_state_variables.sol | 57 +++ ...variables.sol.0.4.25.CouldBeImmutable.json | 3 + .../0.5.16/immut_state_variables.sol | 58 +++ ...variables.sol.0.5.16.CouldBeImmutable.json | 3 + .../0.6.11/immut_state_variables.sol | 79 ++++ ...variables.sol.0.6.11.CouldBeImmutable.json | 3 + .../0.7.6/immut_state_variables.sol | 78 ++++ ..._variables.sol.0.7.6.CouldBeImmutable.json | 334 ++++++++++++++ .../0.8.0/immut_state_variables.sol | 78 ++++ ..._variables.sol.0.8.0.CouldBeImmutable.json | 268 ++++++++++++ tests/test_detectors.py | 35 +- 28 files changed, 1606 insertions(+), 889 deletions(-) create mode 100644 slither/detectors/variables/could_be_constant.py create mode 100644 slither/detectors/variables/could_be_immutable.py delete mode 100644 slither/detectors/variables/possible_const_state_variables.py create mode 100644 slither/detectors/variables/unchanged_state_variables.py rename slither/formatters/variables/{possible_const_state_variables.py => unchanged_state_variables.py} (94%) rename tests/detectors/constable-states/0.4.25/{const_state_variables.sol.0.4.25.ConstCandidateStateVars.json => const_state_variables.sol.0.4.25.CouldBeConstant.json} (96%) rename tests/detectors/constable-states/0.5.16/{const_state_variables.sol.0.5.16.ConstCandidateStateVars.json => const_state_variables.sol.0.5.16.CouldBeConstant.json} (96%) rename tests/detectors/constable-states/0.6.11/{const_state_variables.sol.0.6.11.ConstCandidateStateVars.json => const_state_variables.sol.0.6.11.CouldBeConstant.json} (89%) rename tests/detectors/constable-states/0.7.6/{const_state_variables.sol.0.7.6.ConstCandidateStateVars.json => const_state_variables.sol.0.7.6.CouldBeConstant.json} (58%) rename tests/detectors/constable-states/0.8.0/{const_state_variables.sol.0.8.0.ConstCandidateStateVars.json => const_state_variables.sol.0.8.0.CouldBeConstant.json} (58%) create mode 100644 tests/detectors/immutable-states/0.4.25/immut_state_variables.sol create mode 100644 tests/detectors/immutable-states/0.4.25/immut_state_variables.sol.0.4.25.CouldBeImmutable.json create mode 100644 tests/detectors/immutable-states/0.5.16/immut_state_variables.sol create mode 100644 tests/detectors/immutable-states/0.5.16/immut_state_variables.sol.0.5.16.CouldBeImmutable.json create mode 100644 tests/detectors/immutable-states/0.6.11/immut_state_variables.sol create mode 100644 tests/detectors/immutable-states/0.6.11/immut_state_variables.sol.0.6.11.CouldBeImmutable.json create mode 100644 tests/detectors/immutable-states/0.7.6/immut_state_variables.sol create mode 100644 tests/detectors/immutable-states/0.7.6/immut_state_variables.sol.0.7.6.CouldBeImmutable.json create mode 100644 tests/detectors/immutable-states/0.8.0/immut_state_variables.sol create mode 100644 tests/detectors/immutable-states/0.8.0/immut_state_variables.sol.0.8.0.CouldBeImmutable.json diff --git a/slither/detectors/all_detectors.py b/slither/detectors/all_detectors.py index fb2e3c731..1cab317ad 100644 --- a/slither/detectors/all_detectors.py +++ b/slither/detectors/all_detectors.py @@ -19,7 +19,8 @@ from .reentrancy.reentrancy_eth import ReentrancyEth from .reentrancy.reentrancy_no_gas import ReentrancyNoGas from .reentrancy.reentrancy_events import ReentrancyEvent from .variables.unused_state_variables import UnusedStateVars -from .variables.possible_const_state_variables import ConstCandidateStateVars +from .variables.could_be_constant import CouldBeConstant +from .variables.could_be_immutable import CouldBeImmutable from .statements.tx_origin import TxOrigin from .statements.assembly import Assembly from .operations.low_level_calls import LowLevelCalls diff --git a/slither/detectors/variables/could_be_constant.py b/slither/detectors/variables/could_be_constant.py new file mode 100644 index 000000000..0a294dd8d --- /dev/null +++ b/slither/detectors/variables/could_be_constant.py @@ -0,0 +1,45 @@ +from typing import List, Dict +from slither.utils.output import Output +from slither.core.compilation_unit import SlitherCompilationUnit +from slither.formatters.variables.unchanged_state_variables import custom_format +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from .unchanged_state_variables import UnchangedStateVariables + + +class CouldBeConstant(AbstractDetector): + """ + State variables that could be declared as constant. + Not all types for constants are implemented in Solidity as of 0.4.25. + The only supported types are value types and strings (ElementaryType). + Reference: https://solidity.readthedocs.io/en/latest/contracts.html#constant-state-variables + """ + + ARGUMENT = "constable-states" + HELP = "State variables that could be declared constant" + IMPACT = DetectorClassification.OPTIMIZATION + CONFIDENCE = DetectorClassification.HIGH + + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant" + + WIKI_TITLE = "State variables that could be declared constant" + WIKI_DESCRIPTION = "State variables that are not updated following deployment should be declared constant to save gas." + WIKI_RECOMMENDATION = "Add the `constant` attribute to state variables that never change." + + def _detect(self) -> List[Output]: + """Detect state variables that could be constant""" + results = {} + + unchanged_state_variables = UnchangedStateVariables(self.compilation_unit) + unchanged_state_variables.detect() + + for variable in unchanged_state_variables.constant_candidates: + results[variable.canonical_name] = self.generate_result( + [variable, " should be constant \n"] + ) + + # Order by canonical name for deterministic results + return [results[k] for k in sorted(results)] + + @staticmethod + def _format(compilation_unit: SlitherCompilationUnit, result: Dict) -> None: + custom_format(compilation_unit, result, "constant") diff --git a/slither/detectors/variables/could_be_immutable.py b/slither/detectors/variables/could_be_immutable.py new file mode 100644 index 000000000..a9ecb60cd --- /dev/null +++ b/slither/detectors/variables/could_be_immutable.py @@ -0,0 +1,44 @@ +from typing import List, Dict +from slither.utils.output import Output +from slither.core.compilation_unit import SlitherCompilationUnit +from slither.formatters.variables.unchanged_state_variables import custom_format +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from .unchanged_state_variables import UnchangedStateVariables + + +class CouldBeImmutable(AbstractDetector): + """ + State variables that could be declared immutable. + # Immutable attribute available in Solidity 0.6.5 and above + # https://blog.soliditylang.org/2020/04/06/solidity-0.6.5-release-announcement/ + """ + + # VULNERABLE_SOLC_VERSIONS = + ARGUMENT = "immutable-states" + HELP = "State variables that could be declared immutable" + IMPACT = DetectorClassification.OPTIMIZATION + CONFIDENCE = DetectorClassification.HIGH + + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-immutable" + + WIKI_TITLE = "State variables that could be declared immutable" + WIKI_DESCRIPTION = "State variables that are not updated following deployment should be declared immutable to save gas." + WIKI_RECOMMENDATION = "Add the `immutable` attribute to state variables that never change or are set only in the constructor." + + def _detect(self) -> List[Output]: + """Detect state variables that could be immutable""" + results = {} + unchanged_state_variables = UnchangedStateVariables(self.compilation_unit) + unchanged_state_variables.detect() + + for variable in unchanged_state_variables.immutable_candidates: + results[variable.canonical_name] = self.generate_result( + [variable, " should be immutable \n"] + ) + + # Order by canonical name for deterministic results + return [results[k] for k in sorted(results)] + + @staticmethod + def _format(compilation_unit: SlitherCompilationUnit, result: Dict) -> None: + custom_format(compilation_unit, result, "immutable") diff --git a/slither/detectors/variables/possible_const_state_variables.py b/slither/detectors/variables/possible_const_state_variables.py deleted file mode 100644 index 60a45dfac..000000000 --- a/slither/detectors/variables/possible_const_state_variables.py +++ /dev/null @@ -1,141 +0,0 @@ -""" -Module detecting state variables that could be declared as constant -""" -from typing import Set, List, Dict - -from slither.core.compilation_unit import SlitherCompilationUnit -from slither.core.solidity_types.elementary_type import ElementaryType -from slither.core.solidity_types.user_defined_type import UserDefinedType -from slither.core.variables.variable import Variable -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification -from slither.utils.output import Output -from slither.visitors.expression.export_values import ExportValues -from slither.core.declarations import Contract, Function -from slither.core.declarations.solidity_variables import SolidityFunction -from slither.core.variables.state_variable import StateVariable -from slither.formatters.variables.possible_const_state_variables import custom_format -from slither.core.expressions import CallExpression, NewContract -from slither.utils.standard_libraries import is_openzeppelin - - -def _is_valid_type(v: StateVariable) -> bool: - t = v.type - if isinstance(t, ElementaryType): - return True - if isinstance(t, UserDefinedType) and isinstance(t.type, Contract): - return True - return False - - -def _valid_candidate(v: StateVariable) -> bool: - return _is_valid_type(v) and not (v.is_constant or v.is_immutable) - - -def _is_constant_var(v: Variable) -> bool: - if isinstance(v, StateVariable): - return v.is_constant - return False - - -class ConstCandidateStateVars(AbstractDetector): - """ - State variables that could be declared as constant detector. - Not all types for constants are implemented in Solidity as of 0.4.25. - The only supported types are value types and strings (ElementaryType). - Reference: https://solidity.readthedocs.io/en/latest/contracts.html#constant-state-variables - """ - - ARGUMENT = "constable-states" - HELP = "State variables that could be declared constant or immutable" - IMPACT = DetectorClassification.OPTIMIZATION - CONFIDENCE = DetectorClassification.HIGH - - WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#state-variables-that-could-be-declared-constant-or-immutable" - - WIKI_TITLE = "State variables that could be declared constant or immutable" - WIKI_DESCRIPTION = "State variables that are not updated following deployment should be declared constant or immutable to save gas." - WIKI_RECOMMENDATION = ( - "Add the `constant` or `immutable` attribute to state variables that never change." - ) - - # https://solidity.readthedocs.io/en/v0.5.2/contracts.html#constant-state-variables - valid_solidity_function = [ - SolidityFunction("keccak256()"), - SolidityFunction("keccak256(bytes)"), - SolidityFunction("sha256()"), - SolidityFunction("sha256(bytes)"), - SolidityFunction("ripemd160()"), - SolidityFunction("ripemd160(bytes)"), - SolidityFunction("ecrecover(bytes32,uint8,bytes32,bytes32)"), - SolidityFunction("addmod(uint256,uint256,uint256)"), - SolidityFunction("mulmod(uint256,uint256,uint256)"), - ] - - def _constant_initial_expression(self, v: Variable) -> bool: - if not v.expression: - return True - - # B b = new B(); b cannot be constant, so filter out and recommend it be immutable - if isinstance(v.expression, CallExpression) and isinstance( - v.expression.called, NewContract - ): - return False - - export = ExportValues(v.expression) - values = export.result() - if not values: - return True - - return all((val in self.valid_solidity_function or _is_constant_var(val) for val in values)) - - def _detect(self) -> List[Output]: - """Detect state variables that could be constant or immutable""" - results = {} - - variables = [] - functions = [] - for c in self.compilation_unit.contracts: - if is_openzeppelin(c): - continue - variables.append(c.state_variables) - functions.append(c.all_functions_called) - - valid_candidates: Set[StateVariable] = { - item for sublist in variables for item in sublist if _valid_candidate(item) - } - - all_functions: List[Function] = list( - {item1 for sublist in functions for item1 in sublist if isinstance(item1, Function)} - ) - - variables_written = [] - constructor_variables_written = [] - for f in all_functions: - if f.is_constructor_variables: - constructor_variables_written.append(f.state_variables_written) - else: - variables_written.append(f.state_variables_written) - - variables_written = {item for sublist in variables_written for item in sublist} - constructor_variables_written = { - item for sublist in constructor_variables_written for item in sublist - } - for v in valid_candidates: - if v not in variables_written: - if self._constant_initial_expression(v): - results[v.canonical_name] = self.generate_result([v, " should be constant \n"]) - - # immutable attribute available in Solidity 0.6.5 and above - # https://blog.soliditylang.org/2020/04/06/solidity-0.6.5-release-announcement/ - elif ( - v in constructor_variables_written - and self.compilation_unit.solc_version > "0.6.4" - ): - results[v.canonical_name] = self.generate_result([v, " should be immutable \n"]) - - # Order by canonical name for deterministic results - return [results[k] for k in sorted(results)] - - @staticmethod - def _format(compilation_unit: SlitherCompilationUnit, result: Dict) -> None: - custom_format(compilation_unit, result) diff --git a/slither/detectors/variables/unchanged_state_variables.py b/slither/detectors/variables/unchanged_state_variables.py new file mode 100644 index 000000000..62fc61f43 --- /dev/null +++ b/slither/detectors/variables/unchanged_state_variables.py @@ -0,0 +1,123 @@ +""" +Module detecting state variables that could be declared as constant +""" +from typing import Set, List + +from slither.core.compilation_unit import SlitherCompilationUnit +from slither.core.solidity_types.elementary_type import ElementaryType +from slither.core.solidity_types.user_defined_type import UserDefinedType +from slither.core.variables.variable import Variable + +from slither.visitors.expression.export_values import ExportValues +from slither.core.declarations import Contract, Function +from slither.core.declarations.solidity_variables import SolidityFunction +from slither.core.variables.state_variable import StateVariable +from slither.core.expressions import CallExpression, NewContract + + +def _is_valid_type(v: StateVariable) -> bool: + t = v.type + if isinstance(t, ElementaryType): + return True + if isinstance(t, UserDefinedType) and isinstance(t.type, Contract): + return True + return False + + +def _valid_candidate(v: StateVariable) -> bool: + return _is_valid_type(v) and not (v.is_constant or v.is_immutable) + + +def _is_constant_var(v: Variable) -> bool: + if isinstance(v, StateVariable): + return v.is_constant + return False + + +# https://solidity.readthedocs.io/en/v0.5.2/contracts.html#constant-state-variables +valid_solidity_function = [ + SolidityFunction("keccak256()"), + SolidityFunction("keccak256(bytes)"), + SolidityFunction("sha256()"), + SolidityFunction("sha256(bytes)"), + SolidityFunction("ripemd160()"), + SolidityFunction("ripemd160(bytes)"), + SolidityFunction("ecrecover(bytes32,uint8,bytes32,bytes32)"), + SolidityFunction("addmod(uint256,uint256,uint256)"), + SolidityFunction("mulmod(uint256,uint256,uint256)"), +] + + +def _constant_initial_expression(v: Variable) -> bool: + if not v.expression: + return True + + # B b = new B(); b cannot be constant, so filter out and recommend it be immutable + if isinstance(v.expression, CallExpression) and isinstance(v.expression.called, NewContract): + return False + + export = ExportValues(v.expression) + values = export.result() + if not values: + return True + + return all((val in valid_solidity_function or _is_constant_var(val) for val in values)) + + +class UnchangedStateVariables: + """ + Find state variables that could be declared as constant or immutable (not written after deployment). + """ + + def __init__(self, compilation_unit: SlitherCompilationUnit): + self.compilation_unit = compilation_unit + self._constant_candidates: List[StateVariable] = [] + self._immutable_candidates: List[StateVariable] = [] + + @property + def immutable_candidates(self) -> List[StateVariable]: + """Return the immutable candidates""" + return self._immutable_candidates + + @property + def constant_candidates(self) -> List[StateVariable]: + """Return the constant candidates""" + return self._constant_candidates + + def detect(self): + """Detect state variables that could be constant or immutable""" + for c in self.compilation_unit.contracts_derived: + variables = [] + functions = [] + + variables.append(c.state_variables) + functions.append(c.all_functions_called) + + valid_candidates: Set[StateVariable] = { + item for sublist in variables for item in sublist if _valid_candidate(item) + } + + all_functions: List[Function] = list( + {item1 for sublist in functions for item1 in sublist if isinstance(item1, Function)} + ) + + variables_written = [] + constructor_variables_written = [] + variables_initialized = [] + for f in all_functions: + if f.is_constructor_variables: + variables_initialized.extend(f.state_variables_written) + elif f.is_constructor: + constructor_variables_written.extend(f.state_variables_written) + else: + variables_written.extend(f.state_variables_written) + + for v in valid_candidates: + if v not in variables_written: + if _constant_initial_expression(v) and v not in constructor_variables_written: + self.constant_candidates.append(v) + + elif ( + v in constructor_variables_written or v in variables_initialized + ) and self.compilation_unit.solc_version >= "0.6.5": + self.immutable_candidates.append(v) diff --git a/slither/formatters/variables/possible_const_state_variables.py b/slither/formatters/variables/unchanged_state_variables.py similarity index 94% rename from slither/formatters/variables/possible_const_state_variables.py rename to slither/formatters/variables/unchanged_state_variables.py index 88f92b841..c7c8bf003 100644 --- a/slither/formatters/variables/possible_const_state_variables.py +++ b/slither/formatters/variables/unchanged_state_variables.py @@ -5,7 +5,7 @@ from slither.formatters.exceptions import FormatError, FormatImpossible from slither.formatters.utils.patches import create_patch -def custom_format(compilation_unit: SlitherCompilationUnit, result): +def custom_format(compilation_unit: SlitherCompilationUnit, result, attribute: str) -> None: elements = result["elements"] for element in elements: @@ -15,14 +15,14 @@ def custom_format(compilation_unit: SlitherCompilationUnit, result): contract = scope.get_contract_from_name(contract_name) var = contract.get_state_variable_from_name(element["name"]) if not var.expression: - raise FormatImpossible(f"{var.name} is uninitialized and cannot become constant.") + raise FormatImpossible(f"{var.name} is uninitialized and cannot become {attribute}.") _patch( compilation_unit, result, element["source_mapping"]["filename_absolute"], element["name"], - "constant " + element["name"], + f"{attribute} " + element["name"], element["source_mapping"]["start"], element["source_mapping"]["start"] + element["source_mapping"]["length"], ) diff --git a/slither/tools/slither_format/slither_format.py b/slither/tools/slither_format/slither_format.py index c165b3fbb..3c37313fd 100644 --- a/slither/tools/slither_format/slither_format.py +++ b/slither/tools/slither_format/slither_format.py @@ -9,7 +9,8 @@ from slither.detectors.attributes.incorrect_solc import IncorrectSolc from slither.detectors.attributes.constant_pragma import ConstantPragma from slither.detectors.naming_convention.naming_convention import NamingConvention from slither.detectors.functions.external_function import ExternalFunction -from slither.detectors.variables.possible_const_state_variables import ConstCandidateStateVars +from slither.detectors.variables.could_be_constant import CouldBeConstant +from slither.detectors.variables.could_be_immutable import CouldBeImmutable from slither.detectors.attributes.const_functions_asm import ConstantFunctionsAsm from slither.detectors.attributes.const_functions_state import ConstantFunctionsState from slither.utils.colors import yellow @@ -23,7 +24,8 @@ all_detectors: Dict[str, Type[AbstractDetector]] = { "pragma": ConstantPragma, "naming-convention": NamingConvention, "external-function": ExternalFunction, - "constable-states": ConstCandidateStateVars, + "constable-states": CouldBeConstant, + "immutable-states": CouldBeImmutable, "constant-function-asm": ConstantFunctionsAsm, "constant-functions-state": ConstantFunctionsState, } diff --git a/tests/detectors/constable-states/0.4.25/const_state_variables.sol b/tests/detectors/constable-states/0.4.25/const_state_variables.sol index aed05d97f..45f8cc87a 100644 --- a/tests/detectors/constable-states/0.4.25/const_state_variables.sol +++ b/tests/detectors/constable-states/0.4.25/const_state_variables.sol @@ -44,7 +44,12 @@ contract MyConc{ address not_constant = msg.sender; uint not_constant_2 = getNumber(); uint not_constant_3 = 10 + block.number; + uint not_constant_5; + constructor(uint b) public { + not_constant_5 = b; + } + function getNumber() public returns(uint){ return block.number; } diff --git a/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.CouldBeConstant.json similarity index 96% rename from tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.ConstCandidateStateVars.json rename to tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.CouldBeConstant.json index a46384f06..c7e1f5b43 100644 --- a/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.CouldBeConstant.json @@ -212,7 +212,7 @@ "name": "MyConc", "source_mapping": { "start": 746, - "length": 342, + "length": 416, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", @@ -231,7 +231,12 @@ 49, 50, 51, - 52 + 52, + 53, + 54, + 55, + 56, + 57 ], "starting_column": 1, "ending_column": 2 @@ -272,7 +277,7 @@ "name": "MyConc", "source_mapping": { "start": 746, - "length": 342, + "length": 416, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", @@ -291,7 +296,12 @@ 49, 50, 51, - 52 + 52, + 53, + 54, + 55, + 56, + 57 ], "starting_column": 1, "ending_column": 2 diff --git a/tests/detectors/constable-states/0.5.16/const_state_variables.sol b/tests/detectors/constable-states/0.5.16/const_state_variables.sol index 7d018ca2d..8fd1ca808 100644 --- a/tests/detectors/constable-states/0.5.16/const_state_variables.sol +++ b/tests/detectors/constable-states/0.5.16/const_state_variables.sol @@ -45,7 +45,12 @@ contract MyConc{ address not_constant = msg.sender; uint not_constant_2 = getNumber(); uint not_constant_3 = 10 + block.number; + uint not_constant_5; + constructor(uint b) public { + not_constant_5 = b; + } + function getNumber() public returns(uint){ return block.number; } diff --git a/tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.CouldBeConstant.json similarity index 96% rename from tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.ConstCandidateStateVars.json rename to tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.CouldBeConstant.json index 36de0ff0b..f9ed17eb1 100644 --- a/tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.5.16/const_state_variables.sol.0.5.16.CouldBeConstant.json @@ -24,7 +24,7 @@ "name": "MyConc", "source_mapping": { "start": 746, - "length": 386, + "length": 467, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", @@ -44,7 +44,12 @@ 50, 51, 52, - 53 + 53, + 54, + 55, + 56, + 57, + 58 ], "starting_column": 1, "ending_column": 2 @@ -273,7 +278,7 @@ "name": "MyConc", "source_mapping": { "start": 746, - "length": 386, + "length": 467, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", @@ -293,7 +298,12 @@ 50, 51, 52, - 53 + 53, + 54, + 55, + 56, + 57, + 58 ], "starting_column": 1, "ending_column": 2 @@ -334,7 +344,7 @@ "name": "MyConc", "source_mapping": { "start": 746, - "length": 386, + "length": 467, "filename_relative": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.5.16/const_state_variables.sol", @@ -354,7 +364,12 @@ 50, 51, 52, - 53 + 53, + 54, + 55, + 56, + 57, + 58 ], "starting_column": 1, "ending_column": 2 diff --git a/tests/detectors/constable-states/0.6.11/const_state_variables.sol b/tests/detectors/constable-states/0.6.11/const_state_variables.sol index 66415fd9d..17548f46f 100644 --- a/tests/detectors/constable-states/0.6.11/const_state_variables.sol +++ b/tests/detectors/constable-states/0.6.11/const_state_variables.sol @@ -34,19 +34,46 @@ contract B is A { } } -contract MyConc { +contract Bad { uint constant A = 1; bytes32 should_be_constant = sha256('abc'); uint should_be_constant_2 = A + 1; B should_be_constant_3 = B(address(0)); - address not_constant = msg.sender; - uint not_constant_2 = getNumber(); - uint not_constant_3 = 10 + block.number; - B not_constant_4 = new B(); + address should_be_immutable = msg.sender; + uint should_be_immutable_2 = getNumber(); + uint should_be_immutable_3 = 10 + block.number; + B should_be_immutable_4 = new B(); + uint should_be_immutable_5; + + constructor(uint b) public { + should_be_immutable_5 = b; + } function getNumber() public returns(uint){ return block.number; } } + +contract Good { + + uint constant A = 1; + bytes32 constant should_be_constant = sha256('abc'); + uint constant should_be_constant_2 = A + 1; + B constant should_be_constant_3 = B(address(0)); + address immutable should_be_immutable = msg.sender; + uint immutable should_be_immutable_2 = getNumber(); + uint immutable should_be_immutable_3 = 10 + block.number; + B immutable should_be_immutable_4 = new B(); + uint immutable should_be_immutable_5; + + constructor(uint b) public { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} \ No newline at end of file diff --git a/tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.CouldBeConstant.json similarity index 89% rename from tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.ConstCandidateStateVars.json rename to tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.CouldBeConstant.json index cbb8ecbc1..ac3608f81 100644 --- a/tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.6.11/const_state_variables.sol.0.6.11.CouldBeConstant.json @@ -4,48 +4,50 @@ "elements": [ { "type": "variable", - "name": "should_be_constant_3", + "name": "text2", "source_mapping": { - "start": 853, - "length": 38, + "start": 305, + "length": 20, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 42 + 12 ], "starting_column": 5, - "ending_column": 43 + "ending_column": 25 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "A", "source_mapping": { - "start": 718, - "length": 415, + "start": 1, + "length": 441, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19 ], "starting_column": 1, "ending_column": 2 @@ -54,10 +56,10 @@ } } ], - "description": "MyConc.should_be_constant_3 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#42) should be constant \n", - "markdown": "[MyConc.should_be_constant_3](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L42) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L42", - "id": "29247b0a9939e854ad51bf3b2f58705156aa8b7e446e646b1832467d362b5b3e", + "description": "A.text2 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#12) should be constant \n", + "markdown": "[A.text2](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L12) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L12", + "id": "2f06e04545cea7e7a8998c65d5419f335bf2579a6ce6a832eac9c87392fd5c1a", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -66,50 +68,53 @@ "elements": [ { "type": "variable", - "name": "text2", + "name": "should_be_constant_2", "source_mapping": { - "start": 305, - "length": 20, + "start": 811, + "length": 33, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 12 + 41 ], "starting_column": 5, - "ending_column": 25 + "ending_column": 38 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "A", + "name": "Bad", "source_mapping": { - "start": 1, - "length": 441, + "start": 718, + "length": 539, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12, - 13, - 14, - 15, - 16, - 17, - 18, - 19 + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 ], "starting_column": 1, "ending_column": 2 @@ -118,10 +123,10 @@ } } ], - "description": "A.text2 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#12) should be constant \n", - "markdown": "[A.text2](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L12) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L12", - "id": "2f06e04545cea7e7a8998c65d5419f335bf2579a6ce6a832eac9c87392fd5c1a", + "description": "Bad.should_be_constant_2 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#41) should be constant \n", + "markdown": "[Bad.should_be_constant_2](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L41) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L41", + "id": "3a8b682f7960750cd8228d6cd3d0bb5d7d6f9faaf1a044de2fa7069d8e475af2", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -256,7 +261,7 @@ "type": "variable", "name": "should_be_constant", "source_mapping": { - "start": 766, + "start": 763, "length": 42, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", @@ -271,10 +276,10 @@ "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "Bad", "source_mapping": { "start": 718, - "length": 415, + "length": 539, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", @@ -295,7 +300,12 @@ 49, 50, 51, - 52 + 52, + 53, + 54, + 55, + 56, + 57 ], "starting_column": 1, "ending_column": 2 @@ -304,10 +314,10 @@ } } ], - "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.6.11/const_state_variables.sol#40) should be constant \n", - "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L40) should be constant \n", + "description": "Bad.should_be_constant (tests/detectors/constable-states/0.6.11/const_state_variables.sol#40) should be constant \n", + "markdown": "[Bad.should_be_constant](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L40) should be constant \n", "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L40", - "id": "8d08797efc8230b480ec669c7e2bf53c3b3d16bc59bf7770934b34fd892934f8", + "id": "87097c03d57b72ad7c15336eb44e5a30054c50f8daff32e08bc4fbd97852961c", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -316,27 +326,27 @@ "elements": [ { "type": "variable", - "name": "should_be_constant_2", + "name": "should_be_constant_3", "source_mapping": { - "start": 814, - "length": 33, + "start": 850, + "length": 38, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "is_dependency": false, "lines": [ - 41 + 42 ], "starting_column": 5, - "ending_column": 38 + "ending_column": 43 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "Bad", "source_mapping": { "start": 718, - "length": 415, + "length": 539, "filename_relative": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.6.11/const_state_variables.sol", @@ -357,7 +367,12 @@ 49, 50, 51, - 52 + 52, + 53, + 54, + 55, + 56, + 57 ], "starting_column": 1, "ending_column": 2 @@ -366,10 +381,10 @@ } } ], - "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#41) should be constant \n", - "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L41) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L41", - "id": "d08c6d1e331083b42c45c222691dd1e6d880814c66d114971875337ca61ba9c9", + "description": "Bad.should_be_constant_3 (tests/detectors/constable-states/0.6.11/const_state_variables.sol#42) should be constant \n", + "markdown": "[Bad.should_be_constant_3](tests/detectors/constable-states/0.6.11/const_state_variables.sol#L42) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.6.11/const_state_variables.sol#L42", + "id": "8e991c1370b1adb10f01f2d7e48f341dee92a98b91b56ccb291d9149d2da97d0", "check": "constable-states", "impact": "Optimization", "confidence": "High" diff --git a/tests/detectors/constable-states/0.7.6/const_state_variables.sol b/tests/detectors/constable-states/0.7.6/const_state_variables.sol index 93292dc47..297dd6294 100644 --- a/tests/detectors/constable-states/0.7.6/const_state_variables.sol +++ b/tests/detectors/constable-states/0.7.6/const_state_variables.sol @@ -34,7 +34,7 @@ contract B is A { } } -contract MyConc { +contract Bad { uint constant A = 1; bytes32 should_be_constant = sha256('abc'); @@ -44,6 +44,32 @@ contract MyConc { uint should_be_immutable_2 = getNumber(); uint should_be_immutable_3 = 10 + block.number; B should_be_immutable_4 = new B(); + uint should_be_immutable_5; + + constructor(uint b) { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } +} + +contract Good { + + uint constant A = 1; + bytes32 constant should_be_constant = sha256('abc'); + uint constant should_be_constant_2 = A + 1; + B constant should_be_constant_3 = B(address(0)); + address immutable should_be_immutable = msg.sender; + uint immutable should_be_immutable_2 = getNumber(); + uint immutable should_be_immutable_3 = 10 + block.number; + B immutable should_be_immutable_4 = new B(); + uint immutable should_be_immutable_5; + + constructor(uint b) { + should_be_immutable_5 = b; + } function getNumber() public returns(uint){ return block.number; diff --git a/tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.CouldBeConstant.json similarity index 58% rename from tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.ConstCandidateStateVars.json rename to tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.CouldBeConstant.json index 18c869d56..d54beb405 100644 --- a/tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.7.6/const_state_variables.sol.0.7.6.CouldBeConstant.json @@ -1,67 +1,5 @@ [ [ - { - "elements": [ - { - "type": "variable", - "name": "should_be_constant_3", - "source_mapping": { - "start": 853, - "length": 38, - "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 42 - ], - "starting_column": 5, - "ending_column": 43 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "MyConc", - "source_mapping": { - "start": 718, - "length": 443, - "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "MyConc.should_be_constant_3 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#42) should be constant \n", - "markdown": "[MyConc.should_be_constant_3](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L42) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L42", - "id": "29247b0a9939e854ad51bf3b2f58705156aa8b7e446e646b1832467d362b5b3e", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, { "elements": [ { @@ -130,46 +68,52 @@ "elements": [ { "type": "variable", - "name": "mySistersAddress", + "name": "should_be_constant_2", "source_mapping": { - "start": 468, - "length": 76, + "start": 811, + "length": 33, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 24 + 41 ], "starting_column": 5, - "ending_column": 81 + "ending_column": 38 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "B", + "name": "Bad", "source_mapping": { - "start": 445, - "length": 271, + "start": 718, + "length": 531, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35 + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 ], "starting_column": 1, "ending_column": 2 @@ -178,10 +122,10 @@ } } ], - "description": "B.mySistersAddress (tests/detectors/constable-states/0.7.6/const_state_variables.sol#24) should be constant \n", - "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L24) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L24", - "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", + "description": "Bad.should_be_constant_2 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#41) should be constant \n", + "markdown": "[Bad.should_be_constant_2](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L41) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L41", + "id": "3a8b682f7960750cd8228d6cd3d0bb5d7d6f9faaf1a044de2fa7069d8e475af2", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -190,48 +134,46 @@ "elements": [ { "type": "variable", - "name": "should_be_immutable", + "name": "mySistersAddress", "source_mapping": { - "start": 897, - "length": 40, + "start": 468, + "length": 76, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 43 + 24 ], "starting_column": 5, - "ending_column": 45 + "ending_column": 81 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "B", "source_mapping": { - "start": 718, - "length": 443, + "start": 445, + "length": 271, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35 ], "starting_column": 1, "ending_column": 2 @@ -240,10 +182,10 @@ } } ], - "description": "MyConc.should_be_immutable (tests/detectors/constable-states/0.7.6/const_state_variables.sol#43) should be immutable \n", - "markdown": "[MyConc.should_be_immutable](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L43) should be immutable \n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L43", - "id": "3cabd54a4d3fa32f960965a41bb09b62052286195b47b2b7db670f87e8df21bf", + "description": "B.mySistersAddress (tests/detectors/constable-states/0.7.6/const_state_variables.sol#24) should be constant \n", + "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L24) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L24", + "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -318,7 +260,7 @@ "type": "variable", "name": "should_be_constant", "source_mapping": { - "start": 766, + "start": 763, "length": 42, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", @@ -333,10 +275,10 @@ "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "Bad", "source_mapping": { "start": 718, - "length": 443, + "length": 531, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", @@ -357,7 +299,11 @@ 49, 50, 51, - 52 + 52, + 53, + 54, + 55, + 56 ], "starting_column": 1, "ending_column": 2 @@ -366,72 +312,10 @@ } } ], - "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.7.6/const_state_variables.sol#40) should be constant \n", - "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L40) should be constant \n", + "description": "Bad.should_be_constant (tests/detectors/constable-states/0.7.6/const_state_variables.sol#40) should be constant \n", + "markdown": "[Bad.should_be_constant](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L40) should be constant \n", "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L40", - "id": "8d08797efc8230b480ec669c7e2bf53c3b3d16bc59bf7770934b34fd892934f8", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "should_be_immutable_4", - "source_mapping": { - "start": 1041, - "length": 33, - "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 46 - ], - "starting_column": 5, - "ending_column": 38 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "MyConc", - "source_mapping": { - "start": 718, - "length": 443, - "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "MyConc.should_be_immutable_4 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#46) should be immutable \n", - "markdown": "[MyConc.should_be_immutable_4](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L46) should be immutable \n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L46", - "id": "a15e34bd516e604d7ba3e0746ad0234d0baea38da2e747648316d5d15ee9b3bc", + "id": "87097c03d57b72ad7c15336eb44e5a30054c50f8daff32e08bc4fbd97852961c", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -440,151 +324,27 @@ "elements": [ { "type": "variable", - "name": "should_be_immutable_2", - "source_mapping": { - "start": 943, - "length": 40, - "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 44 - ], - "starting_column": 5, - "ending_column": 45 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "MyConc", - "source_mapping": { - "start": 718, - "length": 443, - "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "MyConc.should_be_immutable_2 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#44) should be immutable \n", - "markdown": "[MyConc.should_be_immutable_2](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L44) should be immutable \n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L44", - "id": "cb6df1f1ce2f32505c81f257863ceef6d5145ee5a2835af1c6719ad695d145e2", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "should_be_constant_2", - "source_mapping": { - "start": 814, - "length": 33, - "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 41 - ], - "starting_column": 5, - "ending_column": 38 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "MyConc", - "source_mapping": { - "start": 718, - "length": 443, - "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#41) should be constant \n", - "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L41) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L41", - "id": "d08c6d1e331083b42c45c222691dd1e6d880814c66d114971875337ca61ba9c9", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "should_be_immutable_3", + "name": "should_be_constant_3", "source_mapping": { - "start": 989, - "length": 46, + "start": 850, + "length": 38, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "is_dependency": false, "lines": [ - 45 + 42 ], "starting_column": 5, - "ending_column": 51 + "ending_column": 43 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "Bad", "source_mapping": { "start": 718, - "length": 443, + "length": 531, "filename_relative": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.7.6/const_state_variables.sol", @@ -605,7 +365,11 @@ 49, 50, 51, - 52 + 52, + 53, + 54, + 55, + 56 ], "starting_column": 1, "ending_column": 2 @@ -614,10 +378,10 @@ } } ], - "description": "MyConc.should_be_immutable_3 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#45) should be immutable \n", - "markdown": "[MyConc.should_be_immutable_3](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L45) should be immutable \n", - "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L45", - "id": "dc5903ef8f6ec62f53df486fa768a0d817643efe30c90c1308079eee99c316d4", + "description": "Bad.should_be_constant_3 (tests/detectors/constable-states/0.7.6/const_state_variables.sol#42) should be constant \n", + "markdown": "[Bad.should_be_constant_3](tests/detectors/constable-states/0.7.6/const_state_variables.sol#L42) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.7.6/const_state_variables.sol#L42", + "id": "8e991c1370b1adb10f01f2d7e48f341dee92a98b91b56ccb291d9149d2da97d0", "check": "constable-states", "impact": "Optimization", "confidence": "High" diff --git a/tests/detectors/constable-states/0.8.0/const_state_variables.sol b/tests/detectors/constable-states/0.8.0/const_state_variables.sol index 93292dc47..f405a1587 100644 --- a/tests/detectors/constable-states/0.8.0/const_state_variables.sol +++ b/tests/detectors/constable-states/0.8.0/const_state_variables.sol @@ -34,7 +34,7 @@ contract B is A { } } -contract MyConc { +contract Bad { uint constant A = 1; bytes32 should_be_constant = sha256('abc'); @@ -43,10 +43,36 @@ contract MyConc { address should_be_immutable = msg.sender; uint should_be_immutable_2 = getNumber(); uint should_be_immutable_3 = 10 + block.number; - B should_be_immutable_4 = new B(); + uint should_be_immutable_5; + + constructor(uint b) { + should_be_immutable_5 = b; + } function getNumber() public returns(uint){ return block.number; } } + +contract Good { + + uint constant A = 1; + bytes32 constant should_be_constant = sha256('abc'); + uint constant should_be_constant_2 = A + 1; + B constant should_be_constant_3 = B(address(0)); + address immutable should_be_immutable = msg.sender; + uint immutable should_be_immutable_2 = getNumber(); + uint immutable should_be_immutable_3 = 10 + block.number; + B immutable should_be_immutable_4 = new B(); + uint immutable should_be_immutable_5; + + constructor(uint b) { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} \ No newline at end of file diff --git a/tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.ConstCandidateStateVars.json b/tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.CouldBeConstant.json similarity index 58% rename from tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.ConstCandidateStateVars.json rename to tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.CouldBeConstant.json index e36a2988d..7febfd637 100644 --- a/tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.ConstCandidateStateVars.json +++ b/tests/detectors/constable-states/0.8.0/const_state_variables.sol.0.8.0.CouldBeConstant.json @@ -1,67 +1,5 @@ [ [ - { - "elements": [ - { - "type": "variable", - "name": "should_be_constant_3", - "source_mapping": { - "start": 853, - "length": 38, - "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 42 - ], - "starting_column": 5, - "ending_column": 43 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "MyConc", - "source_mapping": { - "start": 718, - "length": 443, - "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "MyConc.should_be_constant_3 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#42) should be constant \n", - "markdown": "[MyConc.should_be_constant_3](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L42) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L42", - "id": "29247b0a9939e854ad51bf3b2f58705156aa8b7e446e646b1832467d362b5b3e", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, { "elements": [ { @@ -130,46 +68,52 @@ "elements": [ { "type": "variable", - "name": "mySistersAddress", + "name": "should_be_constant_2", "source_mapping": { - "start": 468, - "length": 76, + "start": 811, + "length": 33, "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "is_dependency": false, "lines": [ - 24 + 41 ], "starting_column": 5, - "ending_column": 81 + "ending_column": 38 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "B", + "name": "Bad", "source_mapping": { - "start": 445, - "length": 271, + "start": 718, + "length": 493, "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "is_dependency": false, "lines": [ - 22, - 23, - 24, - 25, - 26, - 27, - 28, - 29, - 30, - 31, - 32, - 33, - 34, - 35 + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 ], "starting_column": 1, "ending_column": 2 @@ -178,10 +122,10 @@ } } ], - "description": "B.mySistersAddress (tests/detectors/constable-states/0.8.0/const_state_variables.sol#24) should be constant \n", - "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L24) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L24", - "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", + "description": "Bad.should_be_constant_2 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#41) should be constant \n", + "markdown": "[Bad.should_be_constant_2](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L41) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L41", + "id": "3a8b682f7960750cd8228d6cd3d0bb5d7d6f9faaf1a044de2fa7069d8e475af2", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -190,48 +134,46 @@ "elements": [ { "type": "variable", - "name": "should_be_immutable", + "name": "mySistersAddress", "source_mapping": { - "start": 897, - "length": 40, + "start": 468, + "length": 76, "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "is_dependency": false, "lines": [ - 43 + 24 ], "starting_column": 5, - "ending_column": 45 + "ending_column": 81 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "B", "source_mapping": { - "start": 718, - "length": 443, + "start": 445, + "length": 271, "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "is_dependency": false, "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35 ], "starting_column": 1, "ending_column": 2 @@ -240,10 +182,10 @@ } } ], - "description": "MyConc.should_be_immutable (tests/detectors/constable-states/0.8.0/const_state_variables.sol#43) should be immutable \n", - "markdown": "[MyConc.should_be_immutable](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L43) should be immutable \n", - "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L43", - "id": "3cabd54a4d3fa32f960965a41bb09b62052286195b47b2b7db670f87e8df21bf", + "description": "B.mySistersAddress (tests/detectors/constable-states/0.8.0/const_state_variables.sol#24) should be constant \n", + "markdown": "[B.mySistersAddress](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L24) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L24", + "id": "3b5bff93954a48a79387e7981e8c45d78edc575a0988a10f1c7f439b9f930539", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -318,7 +260,7 @@ "type": "variable", "name": "should_be_constant", "source_mapping": { - "start": 766, + "start": 763, "length": 42, "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", @@ -333,10 +275,10 @@ "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "Bad", "source_mapping": { "start": 718, - "length": 443, + "length": 493, "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", @@ -357,7 +299,11 @@ 49, 50, 51, - 52 + 52, + 53, + 54, + 55, + 56 ], "starting_column": 1, "ending_column": 2 @@ -366,72 +312,10 @@ } } ], - "description": "MyConc.should_be_constant (tests/detectors/constable-states/0.8.0/const_state_variables.sol#40) should be constant \n", - "markdown": "[MyConc.should_be_constant](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L40) should be constant \n", + "description": "Bad.should_be_constant (tests/detectors/constable-states/0.8.0/const_state_variables.sol#40) should be constant \n", + "markdown": "[Bad.should_be_constant](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L40) should be constant \n", "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L40", - "id": "8d08797efc8230b480ec669c7e2bf53c3b3d16bc59bf7770934b34fd892934f8", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "should_be_immutable_4", - "source_mapping": { - "start": 1041, - "length": 33, - "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 46 - ], - "starting_column": 5, - "ending_column": 38 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "MyConc", - "source_mapping": { - "start": 718, - "length": 443, - "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "MyConc.should_be_immutable_4 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#46) should be immutable \n", - "markdown": "[MyConc.should_be_immutable_4](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L46) should be immutable \n", - "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L46", - "id": "a15e34bd516e604d7ba3e0746ad0234d0baea38da2e747648316d5d15ee9b3bc", + "id": "87097c03d57b72ad7c15336eb44e5a30054c50f8daff32e08bc4fbd97852961c", "check": "constable-states", "impact": "Optimization", "confidence": "High" @@ -440,151 +324,27 @@ "elements": [ { "type": "variable", - "name": "should_be_immutable_2", - "source_mapping": { - "start": 943, - "length": 40, - "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 44 - ], - "starting_column": 5, - "ending_column": 45 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "MyConc", - "source_mapping": { - "start": 718, - "length": 443, - "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "MyConc.should_be_immutable_2 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#44) should be immutable \n", - "markdown": "[MyConc.should_be_immutable_2](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L44) should be immutable \n", - "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L44", - "id": "cb6df1f1ce2f32505c81f257863ceef6d5145ee5a2835af1c6719ad695d145e2", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "should_be_constant_2", - "source_mapping": { - "start": 814, - "length": 33, - "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 41 - ], - "starting_column": 5, - "ending_column": 38 - }, - "type_specific_fields": { - "parent": { - "type": "contract", - "name": "MyConc", - "source_mapping": { - "start": 718, - "length": 443, - "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "filename_absolute": "/GENERIC_PATH", - "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", - "is_dependency": false, - "lines": [ - 37, - 38, - 39, - 40, - 41, - 42, - 43, - 44, - 45, - 46, - 47, - 48, - 49, - 50, - 51, - 52 - ], - "starting_column": 1, - "ending_column": 2 - } - } - } - } - ], - "description": "MyConc.should_be_constant_2 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#41) should be constant \n", - "markdown": "[MyConc.should_be_constant_2](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L41) should be constant \n", - "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L41", - "id": "d08c6d1e331083b42c45c222691dd1e6d880814c66d114971875337ca61ba9c9", - "check": "constable-states", - "impact": "Optimization", - "confidence": "High" - }, - { - "elements": [ - { - "type": "variable", - "name": "should_be_immutable_3", + "name": "should_be_constant_3", "source_mapping": { - "start": 989, - "length": 46, + "start": 850, + "length": 38, "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "is_dependency": false, "lines": [ - 45 + 42 ], "starting_column": 5, - "ending_column": 51 + "ending_column": 43 }, "type_specific_fields": { "parent": { "type": "contract", - "name": "MyConc", + "name": "Bad", "source_mapping": { "start": 718, - "length": 443, + "length": 493, "filename_relative": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.8.0/const_state_variables.sol", @@ -605,7 +365,11 @@ 49, 50, 51, - 52 + 52, + 53, + 54, + 55, + 56 ], "starting_column": 1, "ending_column": 2 @@ -614,10 +378,10 @@ } } ], - "description": "MyConc.should_be_immutable_3 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#45) should be immutable \n", - "markdown": "[MyConc.should_be_immutable_3](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L45) should be immutable \n", - "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L45", - "id": "dc5903ef8f6ec62f53df486fa768a0d817643efe30c90c1308079eee99c316d4", + "description": "Bad.should_be_constant_3 (tests/detectors/constable-states/0.8.0/const_state_variables.sol#42) should be constant \n", + "markdown": "[Bad.should_be_constant_3](tests/detectors/constable-states/0.8.0/const_state_variables.sol#L42) should be constant \n", + "first_markdown_element": "tests/detectors/constable-states/0.8.0/const_state_variables.sol#L42", + "id": "8e991c1370b1adb10f01f2d7e48f341dee92a98b91b56ccb291d9149d2da97d0", "check": "constable-states", "impact": "Optimization", "confidence": "High" diff --git a/tests/detectors/immutable-states/0.4.25/immut_state_variables.sol b/tests/detectors/immutable-states/0.4.25/immut_state_variables.sol new file mode 100644 index 000000000..45f8cc87a --- /dev/null +++ b/tests/detectors/immutable-states/0.4.25/immut_state_variables.sol @@ -0,0 +1,57 @@ +//pragma solidity ^0.4.24; + + +contract A { + + address constant public MY_ADDRESS = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; + address public myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979; + + uint public used; + uint public test = 5; + + uint constant X = 32**22 + 8; + string constant TEXT1 = "abc"; + string text2 = "xyz"; + + function setUsed() public { + if (msg.sender == MY_ADDRESS) { + used = test; + } + } +} + + +contract B is A { + + address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; + + function () external { + used = 0; + } + + function setUsed(uint a) public { + if (msg.sender == MY_ADDRESS) { + used = a; + } + } +} + +contract MyConc{ + + uint constant A = 1; + bytes32 should_be_constant = sha256('abc'); + uint should_be_constant_2 = A + 1; + address not_constant = msg.sender; + uint not_constant_2 = getNumber(); + uint not_constant_3 = 10 + block.number; + uint not_constant_5; + + constructor(uint b) public { + not_constant_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} diff --git a/tests/detectors/immutable-states/0.4.25/immut_state_variables.sol.0.4.25.CouldBeImmutable.json b/tests/detectors/immutable-states/0.4.25/immut_state_variables.sol.0.4.25.CouldBeImmutable.json new file mode 100644 index 000000000..5825bcacc --- /dev/null +++ b/tests/detectors/immutable-states/0.4.25/immut_state_variables.sol.0.4.25.CouldBeImmutable.json @@ -0,0 +1,3 @@ +[ + [] +] \ No newline at end of file diff --git a/tests/detectors/immutable-states/0.5.16/immut_state_variables.sol b/tests/detectors/immutable-states/0.5.16/immut_state_variables.sol new file mode 100644 index 000000000..8fd1ca808 --- /dev/null +++ b/tests/detectors/immutable-states/0.5.16/immut_state_variables.sol @@ -0,0 +1,58 @@ +//pragma solidity ^0.4.24; + + +contract A { + + address constant public MY_ADDRESS = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; + address public myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979; + + uint public used; + uint public test = 5; + + uint constant X = 32**22 + 8; + string constant TEXT1 = "abc"; + string text2 = "xyz"; + + function setUsed() public { + if (msg.sender == MY_ADDRESS) { + used = test; + } + } +} + + +contract B is A { + + address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; + + function () external { + used = 0; + } + + function setUsed(uint a) public { + if (msg.sender == MY_ADDRESS) { + used = a; + } + } +} + +contract MyConc{ + + uint constant A = 1; + bytes32 should_be_constant = sha256('abc'); + uint should_be_constant_2 = A + 1; + B should_be_constant_3 = B(address(0)); + address not_constant = msg.sender; + uint not_constant_2 = getNumber(); + uint not_constant_3 = 10 + block.number; + uint not_constant_5; + + constructor(uint b) public { + not_constant_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} diff --git a/tests/detectors/immutable-states/0.5.16/immut_state_variables.sol.0.5.16.CouldBeImmutable.json b/tests/detectors/immutable-states/0.5.16/immut_state_variables.sol.0.5.16.CouldBeImmutable.json new file mode 100644 index 000000000..5825bcacc --- /dev/null +++ b/tests/detectors/immutable-states/0.5.16/immut_state_variables.sol.0.5.16.CouldBeImmutable.json @@ -0,0 +1,3 @@ +[ + [] +] \ No newline at end of file diff --git a/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol b/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol new file mode 100644 index 000000000..17548f46f --- /dev/null +++ b/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol @@ -0,0 +1,79 @@ + +contract A { + + address constant public MY_ADDRESS = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; + address public myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979; + + uint public used; + uint public test = 5; + + uint constant X = 32**22 + 8; + string constant TEXT1 = "abc"; + string text2 = "xyz"; + + function setUsed() public { + if (msg.sender == MY_ADDRESS) { + used = test; + } + } +} + + +contract B is A { + + address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; + + fallback () external { + used = 0; + } + + function setUsed(uint a) public { + if (msg.sender == MY_ADDRESS) { + used = a; + } + } +} + +contract Bad { + + uint constant A = 1; + bytes32 should_be_constant = sha256('abc'); + uint should_be_constant_2 = A + 1; + B should_be_constant_3 = B(address(0)); + address should_be_immutable = msg.sender; + uint should_be_immutable_2 = getNumber(); + uint should_be_immutable_3 = 10 + block.number; + B should_be_immutable_4 = new B(); + uint should_be_immutable_5; + + constructor(uint b) public { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} + +contract Good { + + uint constant A = 1; + bytes32 constant should_be_constant = sha256('abc'); + uint constant should_be_constant_2 = A + 1; + B constant should_be_constant_3 = B(address(0)); + address immutable should_be_immutable = msg.sender; + uint immutable should_be_immutable_2 = getNumber(); + uint immutable should_be_immutable_3 = 10 + block.number; + B immutable should_be_immutable_4 = new B(); + uint immutable should_be_immutable_5; + + constructor(uint b) public { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} \ No newline at end of file diff --git a/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol.0.6.11.CouldBeImmutable.json b/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol.0.6.11.CouldBeImmutable.json new file mode 100644 index 000000000..5825bcacc --- /dev/null +++ b/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol.0.6.11.CouldBeImmutable.json @@ -0,0 +1,3 @@ +[ + [] +] \ No newline at end of file diff --git a/tests/detectors/immutable-states/0.7.6/immut_state_variables.sol b/tests/detectors/immutable-states/0.7.6/immut_state_variables.sol new file mode 100644 index 000000000..297dd6294 --- /dev/null +++ b/tests/detectors/immutable-states/0.7.6/immut_state_variables.sol @@ -0,0 +1,78 @@ + +contract A { + + address constant public MY_ADDRESS = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; + address public myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979; + + uint public used; + uint public test = 5; + + uint constant X = 32**22 + 8; + string constant TEXT1 = "abc"; + string text2 = "xyz"; + + function setUsed() public { + if (msg.sender == MY_ADDRESS) { + used = test; + } + } +} + + +contract B is A { + + address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; + + fallback () external { + used = 0; + } + + function setUsed(uint a) public { + if (msg.sender == MY_ADDRESS) { + used = a; + } + } +} + +contract Bad { + + uint constant A = 1; + bytes32 should_be_constant = sha256('abc'); + uint should_be_constant_2 = A + 1; + B should_be_constant_3 = B(address(0)); + address should_be_immutable = msg.sender; + uint should_be_immutable_2 = getNumber(); + uint should_be_immutable_3 = 10 + block.number; + B should_be_immutable_4 = new B(); + uint should_be_immutable_5; + + constructor(uint b) { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } +} + +contract Good { + + uint constant A = 1; + bytes32 constant should_be_constant = sha256('abc'); + uint constant should_be_constant_2 = A + 1; + B constant should_be_constant_3 = B(address(0)); + address immutable should_be_immutable = msg.sender; + uint immutable should_be_immutable_2 = getNumber(); + uint immutable should_be_immutable_3 = 10 + block.number; + B immutable should_be_immutable_4 = new B(); + uint immutable should_be_immutable_5; + + constructor(uint b) { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} diff --git a/tests/detectors/immutable-states/0.7.6/immut_state_variables.sol.0.7.6.CouldBeImmutable.json b/tests/detectors/immutable-states/0.7.6/immut_state_variables.sol.0.7.6.CouldBeImmutable.json new file mode 100644 index 000000000..40c8b1368 --- /dev/null +++ b/tests/detectors/immutable-states/0.7.6/immut_state_variables.sol.0.7.6.CouldBeImmutable.json @@ -0,0 +1,334 @@ +[ + [ + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_5", + "source_mapping": { + "start": 1077, + "length": 26, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 47 + ], + "starting_column": 5, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 531, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_5 (tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#47) should be immutable \n", + "markdown": "[Bad.should_be_immutable_5](tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L47) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L47", + "id": "42d50245236163ceca90dea732165e65c2155934b149a5a1a5c51bddc0b5b02a", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_2", + "source_mapping": { + "start": 940, + "length": 40, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 44 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 531, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_2 (tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#44) should be immutable \n", + "markdown": "[Bad.should_be_immutable_2](tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L44) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L44", + "id": "70d57aa51dda92c28444a466db8567fa783c85d484259aa5eee2ebc63f97a200", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_4", + "source_mapping": { + "start": 1038, + "length": 33, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 46 + ], + "starting_column": 5, + "ending_column": 38 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 531, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_4 (tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#46) should be immutable \n", + "markdown": "[Bad.should_be_immutable_4](tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L46) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L46", + "id": "a26d6df4087ac010928bc4bd18aa70ac58a28e584b1288e348d9c255473c300d", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable", + "source_mapping": { + "start": 894, + "length": 40, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 43 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 531, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable (tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#43) should be immutable \n", + "markdown": "[Bad.should_be_immutable](tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L43) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L43", + "id": "b163d277f544f7f05ed4bcddda61e444be893e65ba0469688abd7b401a1db222", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_3", + "source_mapping": { + "start": 986, + "length": 46, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 45 + ], + "starting_column": 5, + "ending_column": 51 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 531, + "filename_relative": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_3 (tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#45) should be immutable \n", + "markdown": "[Bad.should_be_immutable_3](tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L45) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.7.6/immut_state_variables.sol#L45", + "id": "f19f7a22a6f17ffd8b5c29021226388aab7548f996b686a8e0b2bc861f72d447", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + } + ] +] \ No newline at end of file diff --git a/tests/detectors/immutable-states/0.8.0/immut_state_variables.sol b/tests/detectors/immutable-states/0.8.0/immut_state_variables.sol new file mode 100644 index 000000000..f405a1587 --- /dev/null +++ b/tests/detectors/immutable-states/0.8.0/immut_state_variables.sol @@ -0,0 +1,78 @@ + +contract A { + + address constant public MY_ADDRESS = 0xE0f5206BBD039e7b0592d8918820024e2a7437b9; + address public myFriendsAddress = 0xc0ffee254729296a45a3885639AC7E10F9d54979; + + uint public used; + uint public test = 5; + + uint constant X = 32**22 + 8; + string constant TEXT1 = "abc"; + string text2 = "xyz"; + + function setUsed() public { + if (msg.sender == MY_ADDRESS) { + used = test; + } + } +} + + +contract B is A { + + address public mySistersAddress = 0x999999cf1046e68e36E1aA2E0E07105eDDD1f08E; + + fallback () external { + used = 0; + } + + function setUsed(uint a) public { + if (msg.sender == MY_ADDRESS) { + used = a; + } + } +} + +contract Bad { + + uint constant A = 1; + bytes32 should_be_constant = sha256('abc'); + uint should_be_constant_2 = A + 1; + B should_be_constant_3 = B(address(0)); + address should_be_immutable = msg.sender; + uint should_be_immutable_2 = getNumber(); + uint should_be_immutable_3 = 10 + block.number; + uint should_be_immutable_5; + + constructor(uint b) { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} + +contract Good { + + uint constant A = 1; + bytes32 constant should_be_constant = sha256('abc'); + uint constant should_be_constant_2 = A + 1; + B constant should_be_constant_3 = B(address(0)); + address immutable should_be_immutable = msg.sender; + uint immutable should_be_immutable_2 = getNumber(); + uint immutable should_be_immutable_3 = 10 + block.number; + B immutable should_be_immutable_4 = new B(); + uint immutable should_be_immutable_5; + + constructor(uint b) { + should_be_immutable_5 = b; + } + + function getNumber() public returns(uint){ + return block.number; + } + +} \ No newline at end of file diff --git a/tests/detectors/immutable-states/0.8.0/immut_state_variables.sol.0.8.0.CouldBeImmutable.json b/tests/detectors/immutable-states/0.8.0/immut_state_variables.sol.0.8.0.CouldBeImmutable.json new file mode 100644 index 000000000..afa2e3bb2 --- /dev/null +++ b/tests/detectors/immutable-states/0.8.0/immut_state_variables.sol.0.8.0.CouldBeImmutable.json @@ -0,0 +1,268 @@ +[ + [ + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_5", + "source_mapping": { + "start": 1038, + "length": 26, + "filename_relative": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 46 + ], + "starting_column": 5, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 493, + "filename_relative": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_5 (tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#46) should be immutable \n", + "markdown": "[Bad.should_be_immutable_5](tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#L46) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#L46", + "id": "42d50245236163ceca90dea732165e65c2155934b149a5a1a5c51bddc0b5b02a", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_2", + "source_mapping": { + "start": 940, + "length": 40, + "filename_relative": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 44 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 493, + "filename_relative": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_2 (tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#44) should be immutable \n", + "markdown": "[Bad.should_be_immutable_2](tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#L44) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#L44", + "id": "70d57aa51dda92c28444a466db8567fa783c85d484259aa5eee2ebc63f97a200", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable", + "source_mapping": { + "start": 894, + "length": 40, + "filename_relative": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 43 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 493, + "filename_relative": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable (tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#43) should be immutable \n", + "markdown": "[Bad.should_be_immutable](tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#L43) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#L43", + "id": "b163d277f544f7f05ed4bcddda61e444be893e65ba0469688abd7b401a1db222", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_3", + "source_mapping": { + "start": 986, + "length": 46, + "filename_relative": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 45 + ], + "starting_column": 5, + "ending_column": 51 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 493, + "filename_relative": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_3 (tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#45) should be immutable \n", + "markdown": "[Bad.should_be_immutable_3](tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#L45) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.8.0/immut_state_variables.sol#L45", + "id": "f19f7a22a6f17ffd8b5c29021226388aab7548f996b686a8e0b2bc861f72d447", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + } + ] +] \ No newline at end of file diff --git a/tests/test_detectors.py b/tests/test_detectors.py index 744f75b6c..18f406bf4 100644 --- a/tests/test_detectors.py +++ b/tests/test_detectors.py @@ -480,30 +480,55 @@ ALL_TEST_OBJECTS = [ "0.7.6", ), Test( - all_detectors.ConstCandidateStateVars, + all_detectors.CouldBeConstant, "const_state_variables.sol", "0.4.25", ), Test( - all_detectors.ConstCandidateStateVars, + all_detectors.CouldBeConstant, "const_state_variables.sol", "0.5.16", ), Test( - all_detectors.ConstCandidateStateVars, + all_detectors.CouldBeConstant, "const_state_variables.sol", "0.6.11", ), Test( - all_detectors.ConstCandidateStateVars, + all_detectors.CouldBeConstant, "const_state_variables.sol", "0.7.6", ), Test( - all_detectors.ConstCandidateStateVars, + all_detectors.CouldBeConstant, "const_state_variables.sol", "0.8.0", ), + Test( + all_detectors.CouldBeImmutable, + "immut_state_variables.sol", + "0.4.25", + ), + Test( + all_detectors.CouldBeImmutable, + "immut_state_variables.sol", + "0.5.16", + ), + Test( + all_detectors.CouldBeImmutable, + "immut_state_variables.sol", + "0.6.11", + ), + Test( + all_detectors.CouldBeImmutable, + "immut_state_variables.sol", + "0.7.6", + ), + Test( + all_detectors.CouldBeImmutable, + "immut_state_variables.sol", + "0.8.0", + ), Test( all_detectors.ExternalFunction, "external_function.sol", From 4685eac44f4105ff4d06a42a008dea8548e24704 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 6 Jan 2023 10:32:21 -0600 Subject: [PATCH 094/110] parse semver --- setup.py | 1 + .../variables/unchanged_state_variables.py | 6 +- ...variables.sol.0.6.11.CouldBeImmutable.json | 338 +++++++++++++++++- 3 files changed, 342 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 86db4fa9a..9cfbb29e4 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,7 @@ setup( packages=find_packages(), python_requires=">=3.8", install_requires=[ + "packaging", "prettytable>=0.7.2", "pycryptodome>=3.4.6", # "crytic-compile>=0.2.4", diff --git a/slither/detectors/variables/unchanged_state_variables.py b/slither/detectors/variables/unchanged_state_variables.py index 62fc61f43..0dccb6d1c 100644 --- a/slither/detectors/variables/unchanged_state_variables.py +++ b/slither/detectors/variables/unchanged_state_variables.py @@ -2,7 +2,7 @@ Module detecting state variables that could be declared as constant """ from typing import Set, List - +from packaging import version from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.solidity_types.elementary_type import ElementaryType from slither.core.solidity_types.user_defined_type import UserDefinedType @@ -119,5 +119,7 @@ class UnchangedStateVariables: elif ( v in constructor_variables_written or v in variables_initialized - ) and self.compilation_unit.solc_version >= "0.6.5": + ) and version.parse(self.compilation_unit.solc_version) >= version.parse( + "0.6.5" + ): self.immutable_candidates.append(v) diff --git a/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol.0.6.11.CouldBeImmutable.json b/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol.0.6.11.CouldBeImmutable.json index 5825bcacc..15064ca99 100644 --- a/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol.0.6.11.CouldBeImmutable.json +++ b/tests/detectors/immutable-states/0.6.11/immut_state_variables.sol.0.6.11.CouldBeImmutable.json @@ -1,3 +1,339 @@ [ - [] + [ + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_5", + "source_mapping": { + "start": 1077, + "length": 26, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 47 + ], + "starting_column": 5, + "ending_column": 31 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 539, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_5 (tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#47) should be immutable \n", + "markdown": "[Bad.should_be_immutable_5](tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L47) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L47", + "id": "42d50245236163ceca90dea732165e65c2155934b149a5a1a5c51bddc0b5b02a", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_2", + "source_mapping": { + "start": 940, + "length": 40, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 44 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 539, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_2 (tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#44) should be immutable \n", + "markdown": "[Bad.should_be_immutable_2](tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L44) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L44", + "id": "70d57aa51dda92c28444a466db8567fa783c85d484259aa5eee2ebc63f97a200", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_4", + "source_mapping": { + "start": 1038, + "length": 33, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 46 + ], + "starting_column": 5, + "ending_column": 38 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 539, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_4 (tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#46) should be immutable \n", + "markdown": "[Bad.should_be_immutable_4](tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L46) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L46", + "id": "a26d6df4087ac010928bc4bd18aa70ac58a28e584b1288e348d9c255473c300d", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable", + "source_mapping": { + "start": 894, + "length": 40, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 43 + ], + "starting_column": 5, + "ending_column": 45 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 539, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable (tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#43) should be immutable \n", + "markdown": "[Bad.should_be_immutable](tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L43) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L43", + "id": "b163d277f544f7f05ed4bcddda61e444be893e65ba0469688abd7b401a1db222", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + }, + { + "elements": [ + { + "type": "variable", + "name": "should_be_immutable_3", + "source_mapping": { + "start": 986, + "length": 46, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 45 + ], + "starting_column": 5, + "ending_column": 51 + }, + "type_specific_fields": { + "parent": { + "type": "contract", + "name": "Bad", + "source_mapping": { + "start": 718, + "length": 539, + "filename_relative": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "filename_absolute": "/GENERIC_PATH", + "filename_short": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol", + "is_dependency": false, + "lines": [ + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57 + ], + "starting_column": 1, + "ending_column": 2 + } + } + } + } + ], + "description": "Bad.should_be_immutable_3 (tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#45) should be immutable \n", + "markdown": "[Bad.should_be_immutable_3](tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L45) should be immutable \n", + "first_markdown_element": "tests/detectors/immutable-states/0.6.11/immut_state_variables.sol#L45", + "id": "f19f7a22a6f17ffd8b5c29021226388aab7548f996b686a8e0b2bc861f72d447", + "check": "immutable-states", + "impact": "Optimization", + "confidence": "High" + } + ] ] \ No newline at end of file From cfb5c4eedb6c452625507e383ede3d1c315a889a Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Fri, 6 Jan 2023 10:41:29 -0600 Subject: [PATCH 095/110] fix artifact --- .../const_state_variables.sol.0.4.25.CouldBeConstant.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.CouldBeConstant.json b/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.CouldBeConstant.json index c7e1f5b43..51a485f5b 100644 --- a/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.CouldBeConstant.json +++ b/tests/detectors/constable-states/0.4.25/const_state_variables.sol.0.4.25.CouldBeConstant.json @@ -212,7 +212,7 @@ "name": "MyConc", "source_mapping": { "start": 746, - "length": 416, + "length": 423, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", @@ -277,7 +277,7 @@ "name": "MyConc", "source_mapping": { "start": 746, - "length": 416, + "length": 423, "filename_relative": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", "filename_absolute": "/GENERIC_PATH", "filename_short": "tests/detectors/constable-states/0.4.25/const_state_variables.sol", From 55c24280cf6ee2c881dbeb06a726e3a8dfa772ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 6 Jan 2023 12:36:57 -0300 Subject: [PATCH 096/110] tests: source_unit: remove submodule --- tests/source_unit/README.md | 3 +++ tests/source_unit/lib/forge-std | 1 - tests/test_source_unit.py | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 tests/source_unit/README.md delete mode 160000 tests/source_unit/lib/forge-std diff --git a/tests/source_unit/README.md b/tests/source_unit/README.md new file mode 100644 index 000000000..9cf3657e0 --- /dev/null +++ b/tests/source_unit/README.md @@ -0,0 +1,3 @@ +# README + +Before using this project, run `forge init --no-git --no-commit --force` to initialize submodules diff --git a/tests/source_unit/lib/forge-std b/tests/source_unit/lib/forge-std deleted file mode 160000 index eb980e1d4..000000000 --- a/tests/source_unit/lib/forge-std +++ /dev/null @@ -1 +0,0 @@ -Subproject commit eb980e1d4f0e8173ec27da77297ae411840c8ccb diff --git a/tests/test_source_unit.py b/tests/test_source_unit.py index 7b653599e..f979a41ec 100644 --- a/tests/test_source_unit.py +++ b/tests/test_source_unit.py @@ -1,5 +1,7 @@ from slither import Slither +# NB: read tests/source_unit/README.md before using this test + def test_contract_info() -> None: slither = Slither("./tests/source_unit") From 024729aa2f54a12ea09b0ff8d1bb137da2de1646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 6 Jan 2023 15:20:21 -0300 Subject: [PATCH 097/110] ci: fix Docker build This fixes some issues with the Docker build process * missing `git` in wheel build process - pip requires Git to pull dependencies expressed as `foo @ git+https://...`. * pip upgrade before building - it was disabled with an extra `echo` Thanks to @ahpaleus for reporting this! * final image installation - pip insists on rebuilding git-referenced dependencies, so this installs the wheels directly with `--no-deps` to get the desired behavior. --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 71bb9f57f..d0a7d67be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,7 @@ FROM ubuntu:jammy AS python-wheels RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ gcc \ + git \ python3-dev \ python3-pip \ && rm -rf /var/lib/apt/lists/* @@ -9,7 +10,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins COPY . /slither RUN cd /slither && \ - echo pip3 install --no-cache-dir --upgrade pip && \ + pip3 install --no-cache-dir --upgrade pip && \ pip3 wheel -w /wheels . solc-select pip setuptools wheel @@ -44,7 +45,7 @@ ENV PATH="/home/slither/.local/bin:${PATH}" # no-index ensures we install the freshly-built wheels RUN --mount=type=bind,target=/mnt,source=/wheels,from=python-wheels \ - pip3 install --user --no-cache-dir --upgrade --no-index --find-links /mnt pip slither-analyzer solc-select + pip3 install --user --no-cache-dir --upgrade --no-index --find-links /mnt --no-deps /mnt/*.whl RUN solc-select install 0.4.25 && solc-select use 0.4.25 From 48c75485dce51a84a319a9595129f77b2eeafb3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20L=C3=B3pez?= Date: Fri, 6 Jan 2023 15:33:48 -0300 Subject: [PATCH 098/110] tests: source_unit: add skipif for requirements --- tests/test_source_unit.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/test_source_unit.py b/tests/test_source_unit.py index f979a41ec..73c165016 100644 --- a/tests/test_source_unit.py +++ b/tests/test_source_unit.py @@ -1,8 +1,18 @@ +from pathlib import Path +import shutil + +import pytest from slither import Slither -# NB: read tests/source_unit/README.md before using this test +# NB: read tests/source_unit/README.md for setup before using this test + +foundry_available = shutil.which("forge") is not None +project_ready = Path("./tests/source_unit/lib/forge-std").exists() +@pytest.mark.skipif( + not foundry_available or not project_ready, reason="requires Foundry and project setup" +) def test_contract_info() -> None: slither = Slither("./tests/source_unit") From c548dfdcc78116dd879182c1aef99972d9d6c059 Mon Sep 17 00:00:00 2001 From: Simone Date: Sat, 7 Jan 2023 19:51:16 +0100 Subject: [PATCH 099/110] Fix analyze library using for directives --- .../slither_compilation_unit_solc.py | 7 +++++-- ...g-for-in-library-0.8.0.sol-0.8.15-compact.zip | Bin 0 -> 2831 bytes ...-for-in-library-0.8.0.sol-0.8.15-compact.json | 8 ++++++++ tests/ast-parsing/using-for-in-library-0.8.0.sol | 14 ++++++++++++++ tests/test_ast_parsing.py | 1 + tests/test_features.py | 11 +++++++++++ 6 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/ast-parsing/compile/using-for-in-library-0.8.0.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/expected/using-for-in-library-0.8.0.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/using-for-in-library-0.8.0.sol diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 7bae88c5c..3d636d339 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -512,7 +512,7 @@ Please rename it, this name is reserved for Slither's internals""" self._analyze_third_part(contracts_to_be_analyzed, libraries) [c.set_is_analyzed(False) for c in self._underlying_contract_to_parser.values()] - self._analyze_using_for(contracts_to_be_analyzed) + self._analyze_using_for(contracts_to_be_analyzed, libraries) self._parsed = True @@ -624,9 +624,12 @@ Please rename it, this name is reserved for Slither's internals""" else: contracts_to_be_analyzed += [contract] - def _analyze_using_for(self, contracts_to_be_analyzed: List[ContractSolc]): + def _analyze_using_for(self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc]): self._analyze_top_level_using_for() + for lib in libraries: + lib.analyze_using_for() + while contracts_to_be_analyzed: contract = contracts_to_be_analyzed[0] diff --git a/tests/ast-parsing/compile/using-for-in-library-0.8.0.sol-0.8.15-compact.zip b/tests/ast-parsing/compile/using-for-in-library-0.8.0.sol-0.8.15-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..ca32c7583bce8f8c3e6e94dd274a36cab9fdef09 GIT binary patch literal 2831 zcmb8xXCM@e0|xNR=B(@;Sy^XiyEEcABmVxpJoxoSY+^hC1`OYU1VO0q{JF3mYweh|qHOg%1w`^3V*OV@6etug$;mj253iwfZ|{R8009Sjjdby>p7Q&~Kpo zs^}8<`ed_7{dtAg(3lR!=kSd773E^Yh!RhdrMWje{35l_D`62b(*E>!rEbUWx3pcY ziY;CY9nhQY7!AMoQrB+}PdY^!{htib-ly zC)S?4xyFWwPb@hTy1`i%dF)%Vf{EBfdJ_R@^INKu2&92X(#>FzOlyl;ZuVwf0X`P` zrSW{?Kv>K!H2X@vg0kClSMgUK;Jt^85#x%y)~~XKwhbA;v?Q@k6ARoi1aL>oJZMGk zS=`J&hJlpach0lY4_ND~VX0{+dzPVP%@xjD@I!MC!KsWWx}=QTtW9@BqN?g8G>r${ zISYO#<3pIVr?YEj9+$*AD24Mh{o1V%;Et}r-zY?wdwmVjYD>AoPuu&e!OX3Q|6Gs6 zyNl1Ci36{k*Vu zIqM|ZR>oQg$1gb}-MHGmija}~5)+p8*$^5QM6S<;*YpWzU2k-)4Y-*pe!zr)rWo6|Iu5+Yx4bdN33=q=;?KS)33)gjwI z;S?oghuP(!P*r%fy1T$dJyRfWgwgl5d`B)*U<*ye9AOT=OdHb1W{d zuXwxd+0GfNh=VvtSOFGcTH4>|;9z!PVQ*5)q?Sd@C@3d5*MTgpV?Zv#Dtf%ahm`Iw zRmr{Lz3e0NIjnT{?0eQq3=O8ZYsef&Gd9JRs_}Uz`RfEiaVa^KCjxJ?HWx9Y#PWN3 zTj;LkTn78|)yWGpSOXDw`|c**1liZ-4C10vvt}yt6c4uazdc$7AY9$IfxhC zEs~5U{+bL=^w+chzQDBxkpDIO8Z{r>cYcOq47%6sb;NY|<8aOF%i4rV`^bo<^H|O^ z33wUAol^3ywgVcAO*5Cvo1W^+Evt{KilCX|>I}fi3>Hfg6-k1pq0 z9h0t9fOl0Mf2UyE(WkofDR2_m(3%Zz5@MOSztP3|NXRYN#m`VmkuvPTP|EMsJ#I7q zlfM?i;F!jZTY@p)$escR+?dm^oqiua{QQ}tOG ze&$|@a0#uw{cV~18kVFc+k-I;tpY3b{NXH~6p4(Ay-)xV50YXN1wpeti_3}oww^G9 zGSdQRp@fTeaJ>OZdQd<1sv7*s>!e(F3z>-M3itq+82HGlsL(mIz=l<@ncoPjDlCOD z(jOO#nvvr;`MRUr+*2GvX)fF72V#1SSM?mfJSyO`X;a9^%XVISJryNl@2A!@@LJet zVF~&VALcsYBO$;<%)}O;-Z~a?{ACoJk73=yd(RgM8kn+q98I) zgJ6|tj1ULGbvlAc1i5JdMTZ9r!rMK)RFbkvL7we}NNMq$IfWy+0Wv}C zzS|=v8T6U zdV*(Tvjb*ecF?d+%1sPvxv62&;u$=j78Kg^<}n;Twgs=;+CLHz;Q7&wU5_&pVRtEEo%W+PK1;k#6(KK zZ=v2jDSdb=P~)mBBwO0@DC?b|WIXKo`DzPz)byVeolxsbwUb#tHGVm#gYtAL;4ow8#1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "B": { + "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/using-for-in-library-0.8.0.sol b/tests/ast-parsing/using-for-in-library-0.8.0.sol new file mode 100644 index 000000000..0e8f6a6b9 --- /dev/null +++ b/tests/ast-parsing/using-for-in-library-0.8.0.sol @@ -0,0 +1,14 @@ + +library A { + using B for uint256; + + function a(uint256 v) public view returns (uint) { + return v.b(); + } +} + +library B { + function b(uint256 v) public view returns (uint) { + return 1; + } +} diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 0d6118601..7e22ea186 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -428,6 +428,7 @@ 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-in-library-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"]), diff --git a/tests/test_features.py b/tests/test_features.py index a5541b589..924e0b154 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -128,3 +128,14 @@ def test_using_for_alias_contract() -> None: if isinstance(ir, InternalCall) and ir.function_name == "a": return assert False + + +def test_using_for_in_library() -> None: + solc_select.switch_global_version("0.8.15", always_install=True) + slither = Slither("./tests/ast-parsing/using-for-in-library-0.8.0.sol") + contract_c = slither.get_contract_from_name("A")[0] + libCall = contract_c.get_function_from_full_name("a(uint256)") + for ir in libCall.all_slithir_operations(): + if isinstance(ir, LibraryCall) and ir.destination == "B" and ir.function_name == "b": + return + assert False From f47f6820409822d8ccac2dd94f1e152ef466fa54 Mon Sep 17 00:00:00 2001 From: Simone Date: Sat, 7 Jan 2023 19:56:49 +0100 Subject: [PATCH 100/110] Run black --- slither/solc_parsing/slither_compilation_unit_solc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 3d636d339..c8b69d4b2 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -624,7 +624,9 @@ Please rename it, this name is reserved for Slither's internals""" else: contracts_to_be_analyzed += [contract] - def _analyze_using_for(self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc]): + def _analyze_using_for( + self, contracts_to_be_analyzed: List[ContractSolc], libraries: List[ContractSolc] + ): self._analyze_top_level_using_for() for lib in libraries: From 22635452e362f5bd46acd04300e4a2f5c0b46952 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 9 Jan 2023 14:23:04 +0100 Subject: [PATCH 101/110] Update CODEOWNERS --- CODEOWNERS | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index e76e5a2bb..41954591d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,5 @@ -* @montyly @0xalpharush @smonicas -/slither/tools/read_storage @0xalpharush -/slither/slithir/ @montyly -/slither/analyses/ @montyly +* @montyly @0xalpharush @smonicas +/slither/tools/read_storage/ @0xalpharush +/slither/tools/doctor/ @elopez +/slither/slithir/ @montyly +/slither/analyses/ @montyly From c5299d6bc8808b67605f78039e8e795a2cd506dd Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 9 Jan 2023 14:30:13 +0100 Subject: [PATCH 102/110] Update CODEOWNERS --- CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/CODEOWNERS b/CODEOWNERS index 41954591d..c92f0d79d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -3,3 +3,4 @@ /slither/tools/doctor/ @elopez /slither/slithir/ @montyly /slither/analyses/ @montyly +/.github/workflows/ @elopez From 811dd78b482d037e34044fa9d68a6ddb5202f962 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Mon, 9 Jan 2023 14:40:44 +0100 Subject: [PATCH 103/110] Update literal.py --- slither/core/expressions/literal.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/slither/core/expressions/literal.py b/slither/core/expressions/literal.py index 328ec9674..2eaeb715d 100644 --- a/slither/core/expressions/literal.py +++ b/slither/core/expressions/literal.py @@ -23,7 +23,7 @@ class Literal(Expression): return self._value @property - def converted_value(self) -> int: + def converted_value(self) -> Union[int, str]: """Return the value of the literal, accounting for subdenomination e.g. ether""" if self.subdenomination: return convert_subdenomination(self._value, self.subdenomination) @@ -37,7 +37,7 @@ class Literal(Expression): def subdenomination(self) -> Optional[str]: return self._subdenomination - def __str__(self): + def __str__(self) -> str: if self.subdenomination: return str(self.converted_value) @@ -47,7 +47,7 @@ class Literal(Expression): # be sure to handle any character return str(self._value) - def __eq__(self, other): + def __eq__(self, other) -> bool: if not isinstance(other, Literal): return False return (self.value, self.subdenomination) == (other.value, other.subdenomination) From 7569131faa6b5103b7a5d2c2c4e7b98a7b8daf1b Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 9 Jan 2023 14:23:37 -0600 Subject: [PATCH 104/110] fix type conversion of alias so library function can be found --- .../visitors/slithir/expression_to_slithir.py | 9 +++++-- .../using-for-0.8.8.sol-0.8.10-compact.zip | Bin 0 -> 3526 bytes .../using-for-0.8.8.sol-0.8.11-compact.zip | Bin 0 -> 3522 bytes .../using-for-0.8.8.sol-0.8.12-compact.zip | Bin 0 -> 3526 bytes .../using-for-0.8.8.sol-0.8.13-compact.zip | Bin 0 -> 3523 bytes .../using-for-0.8.8.sol-0.8.14-compact.zip | Bin 0 -> 3521 bytes .../using-for-0.8.8.sol-0.8.15-compact.zip | Bin 0 -> 3522 bytes .../using-for-0.8.8.sol-0.8.8-compact.zip | Bin 0 -> 3501 bytes .../using-for-0.8.8.sol-0.8.10-compact.json | 11 +++++++++ .../using-for-0.8.8.sol-0.8.11-compact.json | 11 +++++++++ .../using-for-0.8.8.sol-0.8.12-compact.json | 11 +++++++++ .../using-for-0.8.8.sol-0.8.13-compact.json | 11 +++++++++ .../using-for-0.8.8.sol-0.8.14-compact.json | 11 +++++++++ .../using-for-0.8.8.sol-0.8.15-compact.json | 11 +++++++++ .../using-for-0.8.8.sol-0.8.8-compact.json | 11 +++++++++ .../using-for-0.8.8.sol | 22 ++++++++++++++++++ tests/test_ast_parsing.py | 1 + 17 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.10-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.11-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.12-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.13-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.14-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.8-compact.zip create mode 100644 tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.10-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.11-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.12-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.13-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.14-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.8-compact.json create mode 100644 tests/ast-parsing/user_defined_value_type/using-for-0.8.8.sol diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index 3c4595b92..66aa43ee6 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -282,10 +282,15 @@ class ExpressionToSlithIR(ExpressionVisitor): and expression_called.member_name in ["wrap", "unwrap"] and len(args) == 1 ): + # wrap: underlying_type -> alias + # unwrap: alias -> underlying_type + dest_type = ( + called if expression_called.member_name == "wrap" else called.underlying_type + ) val = TemporaryVariable(self._node) - var = TypeConversion(val, args[0], called) + var = TypeConversion(val, args[0], dest_type) var.set_expression(expression) - val.set_type(called) + val.set_type(dest_type) self._result.append(var) set_val(expression, val) diff --git a/tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.10-compact.zip b/tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.10-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..2dedfd0a66c31fed984fda23bfe51fc62c5c0a4b GIT binary patch literal 3526 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.12-compact.zip b/tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.12-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..573f4efc0c8f049284aecb80e7ad10cc286f81e3 GIT binary patch literal 3526 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.14-compact.zip b/tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.14-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..db90bfcab2734551019cd1eab69f56c3a191db1c GIT binary patch literal 3521 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.8-compact.zip b/tests/ast-parsing/compile/user_defined_value_type/using-for-0.8.8.sol-0.8.8-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..89d650f85e835f65ed927413f91318fb0066435a GIT binary patch literal 3501 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\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n" + }, + "A": { + "b(MyType)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "B": { + "c(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/user_defined_value_type/using-for-0.8.8.sol-0.8.11-compact.json b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.11-compact.json new file mode 100644 index 000000000..58fb20ce1 --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.11-compact.json @@ -0,0 +1,11 @@ +{ + "MyLib": { + "a()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n" + }, + "A": { + "b(MyType)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "B": { + "c(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/user_defined_value_type/using-for-0.8.8.sol-0.8.12-compact.json b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.12-compact.json new file mode 100644 index 000000000..58fb20ce1 --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.12-compact.json @@ -0,0 +1,11 @@ +{ + "MyLib": { + "a()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n" + }, + "A": { + "b(MyType)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "B": { + "c(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/user_defined_value_type/using-for-0.8.8.sol-0.8.13-compact.json b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.13-compact.json new file mode 100644 index 000000000..58fb20ce1 --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.13-compact.json @@ -0,0 +1,11 @@ +{ + "MyLib": { + "a()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n" + }, + "A": { + "b(MyType)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "B": { + "c(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/user_defined_value_type/using-for-0.8.8.sol-0.8.14-compact.json b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.14-compact.json new file mode 100644 index 000000000..58fb20ce1 --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.14-compact.json @@ -0,0 +1,11 @@ +{ + "MyLib": { + "a()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n" + }, + "A": { + "b(MyType)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "B": { + "c(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/user_defined_value_type/using-for-0.8.8.sol-0.8.15-compact.json b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.15-compact.json new file mode 100644 index 000000000..58fb20ce1 --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.15-compact.json @@ -0,0 +1,11 @@ +{ + "MyLib": { + "a()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n" + }, + "A": { + "b(MyType)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "B": { + "c(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/user_defined_value_type/using-for-0.8.8.sol-0.8.8-compact.json b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.8-compact.json new file mode 100644 index 000000000..58fb20ce1 --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_value_type/using-for-0.8.8.sol-0.8.8-compact.json @@ -0,0 +1,11 @@ +{ + "MyLib": { + "a()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: RETURN 2\n\"];\n}\n" + }, + "A": { + "b(MyType)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + }, + "B": { + "c(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/user_defined_value_type/using-for-0.8.8.sol b/tests/ast-parsing/user_defined_value_type/using-for-0.8.8.sol new file mode 100644 index 000000000..bc65038ab --- /dev/null +++ b/tests/ast-parsing/user_defined_value_type/using-for-0.8.8.sol @@ -0,0 +1,22 @@ +type MyType is uint256; + +library MyLib { + using A for MyType; + using B for uint; + function a() internal returns(uint){ + MyType myvar = MyType.wrap(4); + return MyType.unwrap(myvar.b()).c(); + } +} + +library A { + function b(MyType e) public returns(MyType){ + return MyType.wrap(3); + } + +} +library B { + function c(uint e) public returns(uint){ + return 345; + } +} \ No newline at end of file diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 2f0e9b12c..38c12e5d8 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -418,6 +418,7 @@ ALL_TESTS = [ Test("user_defined_value_type/constant-0.8.8.sol", ["0.8.8"] + make_version(8, 10, 15)), Test("user_defined_value_type/erc20-0.8.8.sol", ["0.8.8"] + make_version(8, 10, 15)), Test("user_defined_value_type/in_parenthesis-0.8.8.sol", ["0.8.8"] + make_version(8, 10, 15)), + Test("user_defined_value_type/using-for-0.8.8.sol", ["0.8.8"] + make_version(8, 10, 15)), Test("bytes_call.sol", ["0.8.12"]), Test("modifier_identifier_path.sol", VERSIONS_08), Test("free_functions/libraries_from_free.sol", ["0.8.12"]), From b1899516170987fbcf91d4b4d3f25edc02b49759 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 9 Jan 2023 15:22:51 -0600 Subject: [PATCH 105/110] resolve error referenced as member of contract --- .../custom-error-selector.sol-0.8.10-compact.zip | Bin 0 -> 2802 bytes .../custom-error-selector.sol-0.8.11-compact.zip | Bin 0 -> 2802 bytes .../custom-error-selector.sol-0.8.12-compact.zip | Bin 0 -> 2802 bytes .../custom-error-selector.sol-0.8.13-compact.zip | Bin 0 -> 2813 bytes .../custom-error-selector.sol-0.8.14-compact.zip | Bin 0 -> 2810 bytes .../custom-error-selector.sol-0.8.15-compact.zip | Bin 0 -> 2814 bytes .../custom-error-selector.sol-0.8.4-compact.zip | Bin 0 -> 2767 bytes .../custom-error-selector.sol-0.8.5-compact.zip | Bin 0 -> 2790 bytes .../custom-error-selector.sol-0.8.6-compact.zip | Bin 0 -> 2789 bytes .../custom-error-selector.sol-0.8.7-compact.zip | Bin 0 -> 2781 bytes .../custom-error-selector.sol-0.8.8-compact.zip | Bin 0 -> 2788 bytes .../custom-error-selector.sol-0.8.9-compact.zip | Bin 0 -> 2800 bytes tests/ast-parsing/custom-error-selector.sol | 13 +++++++++++++ ...custom-error-selector.sol-0.8.10-compact.json | 10 ++++++++++ ...custom-error-selector.sol-0.8.11-compact.json | 10 ++++++++++ ...custom-error-selector.sol-0.8.12-compact.json | 10 ++++++++++ ...custom-error-selector.sol-0.8.13-compact.json | 10 ++++++++++ ...custom-error-selector.sol-0.8.14-compact.json | 10 ++++++++++ ...custom-error-selector.sol-0.8.15-compact.json | 10 ++++++++++ .../custom-error-selector.sol-0.8.4-compact.json | 10 ++++++++++ .../custom-error-selector.sol-0.8.5-compact.json | 10 ++++++++++ .../custom-error-selector.sol-0.8.6-compact.json | 10 ++++++++++ .../custom-error-selector.sol-0.8.7-compact.json | 10 ++++++++++ .../custom-error-selector.sol-0.8.8-compact.json | 10 ++++++++++ .../custom-error-selector.sol-0.8.9-compact.json | 10 ++++++++++ 25 files changed, 133 insertions(+) create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.10-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.11-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.12-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.13-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.14-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.15-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.4-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.5-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.6-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.7-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.8-compact.zip create mode 100644 tests/ast-parsing/compile/custom-error-selector.sol-0.8.9-compact.zip create mode 100644 tests/ast-parsing/custom-error-selector.sol create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.10-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.11-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.12-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.13-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.14-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.15-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.4-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.5-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.6-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.7-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.8-compact.json create mode 100644 tests/ast-parsing/expected/custom-error-selector.sol-0.8.9-compact.json diff --git a/tests/ast-parsing/compile/custom-error-selector.sol-0.8.10-compact.zip b/tests/ast-parsing/compile/custom-error-selector.sol-0.8.10-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..0d7f3ac0f8b3788f226520e3db4ca8cc9725727d GIT binary patch literal 2802 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/custom-error-selector.sol-0.8.11-compact.zip b/tests/ast-parsing/compile/custom-error-selector.sol-0.8.11-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..193a3c93105974f4ac5511c47995ba117df9d22c GIT binary patch literal 2802 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/custom-error-selector.sol-0.8.13-compact.zip b/tests/ast-parsing/compile/custom-error-selector.sol-0.8.13-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..6225bd2c26d2e2632f5eb9d8acd19d72a3c31bcf GIT binary patch literal 2813 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/custom-error-selector.sol-0.8.14-compact.zip b/tests/ast-parsing/compile/custom-error-selector.sol-0.8.14-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..6c13dbacce34c35076051b2f475d40b383a280af GIT binary patch literal 2810 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/custom-error-selector.sol-0.8.5-compact.zip b/tests/ast-parsing/compile/custom-error-selector.sol-0.8.5-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..3c91ae99a593b982e81fe5764c99968b8e502df1 GIT binary patch literal 2790 zcmb8xX&@7f0|xLhcSdtx(IIk7IVWe!(ah@>851!=j7^RSLyj1WjCftK5ScT#$QjZc zAy>KYBfM_$@BM%OfA~Mohv(Dt{bye!i&>E(@#aEWVxzbwKKbo?oRM$I_SU08fQvp`yvu)IYNU~HIiWabo-V=hMx~{8zNACi>~KF?fqQ>eX_v%j z%`G97&k$Fdm{G&efEu#^>cJ zyB}N3w`+S2NDH#;&E(SYl&XYM-%2yzgub4wh)0P9n?ffXeu*Pq$xzmp+d?T2JCxtp z`{r2tckhqS!#Ph`7;D7ic0T{29Q00bA=hNVYj4^Xb-qeVCf;h9#?~dka zAeHaVg@ax;Q>`9Fw&vBWdm)v}M(d7V=PO%5{qXM)-XNl>K$@=j{+ zm<#TY7=3X?4Di%(p2&`khpXGXDvD2KBs9G8{P7QJmaEiPxUIn$XUnuzkW)TjQZ6#d z2wxYfkQz^vm`$@Q(hXQDl64YRDVkzSrs}N&b3Fg zp%h-<2_-JR)zxVov4sxWjPf|)*I+JOQ88pDr(VKhKy9y~Vl&sigpKzMzqh)C4(hmE=|c<@7i^I^Pb((t(ZUHRh@`gl?Q*Wq?+W{ zR#KWZ#5IsFf#>|#&0GnycytoddUSDqmO-n-p-nS+p7^z5nLKgZeOBpZu~Ay5cI#5_ zGE2lXVWP>&3++8V_4re~pWMyEk%!q*PWs;^jD_fO0~XZ{ zV)7`k3#IkS5zj?M_ntAokY!|csKDP|mn&Tj@EYpBEi5gR4}!ofTz-yx>woS4fckv~ z8b%a5o>TugHj&?76M5rGmj^4<(0cu#ChWw*S;b*4Kp#+W^OF38ade54BXF#C{;KAu zLeFli4$Ek*bNY9v&DH%Q2LI&043`jPcsOnEq-+9*MELo;_6cIig&rD8 zrgD=M2^@puQsZ5Vlk`TEWe)?In>JIbVZ!{=XA9o&pWQ8eEZE5f(X^Bwhb#OCipeST%M{jQMoec$&Wsp2ub+}PP^0eL z=>f&VK*LpsFf&JiW15x8hu4elLCCE5#C<7(>16XQkxBPsZA8=u$9Lw{EfLSmGiJCX zD*RtH7??CjVQ#M6D&xquMF;}Y5QTf*b<$}1r$kLcvmUcDiHnIHTMSokh#o1Ly3`WL zU(5bp{3tq1NR_XrgVdwJW)5Y@^TTNc6`SdlIJte>FjR8#>pn~<&_hU&N>?ibSKr^| zQZ~9D)u@oY`vS<2VcYFIwcdySARtK)bSA(OTEq1NZ9fwuj%YxUxBh%*)lDgrIln6Y zdb-dd!g>GeUW}j$fa1Q>0sI&4FAKE-DVq&Y?*!AhaItqyI3Vk9|2^+4y z)_3zTD6?!Rje+@_xXYU_4^VIeCunFnBGBYlmV>8Z^`#!H?608;zIMzBb)VTqpXXQb zqYy)3U%x6pEubjw{YR_W-;@BDNv_w3Mlx-MwB`+oKP=v29+VDI=BM0C8acZdz_8FF zD2u=79-Cg=N`0e>xxuC{!dOoHR8yjmRU%Su&zdNU5>@Joj%$hZ-%_y@Qn9);q#%zV zX4_n6^cz-~X$VH&x(W}VRtZi|fcUdN0_b(idN(y?3<|+H#?QbNj4|FY(0nn4l&g1n$n~tg(!s9|0S2h6Gqidg<5cLTj zZx;j!RNdHFx!I$}Q{2Xd-49WXNXcjgUX4FU-p|z?mCD;%i;Y1WgmxaYa~0CrTc2`C zIhT(O-#dA^I1_|4_0n2Ru-sY~(7w>b-84@fwNn#t#}}=P#e-_U4v(n8tFi)<`!XgF zRP}Inq@F|G+=eg#EMNVT>lRO6cAD_>a7Z0*I=*I`KE~5L!^7gMM5~w2>n4j5m4dwTWA+@+z|8GFhcFB0C5Z z_YZd(xEYKqP0?1J`Dz89avmdc2c&oRRL0Ak9}FT0riOI%+Q9$K&Oh?}ZwPe%&i{o_ VQ$t3ke@}FOYWruO{?RM|@E^?cGQb008gM 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 X7eO7YIe`D3Sbo?2_hNoq76AAUh4VBH literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/custom-error-selector.sol-0.8.9-compact.zip b/tests/ast-parsing/compile/custom-error-selector.sol-0.8.9-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..eae6bf9c155f54636987c1dd5e18ae8387fb8b09 GIT binary patch literal 2800 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/custom-error-selector.sol b/tests/ast-parsing/custom-error-selector.sol new file mode 100644 index 000000000..05fe75f99 --- /dev/null +++ b/tests/ast-parsing/custom-error-selector.sol @@ -0,0 +1,13 @@ + contract Test { + error myError(); +} + +interface VM { + function expectRevert(bytes4) external; + function expectRevert(bytes calldata) external; +} +contract A { + function b(address c) public { + VM(c).expectRevert(Test.myError.selector); + } +} diff --git a/tests/ast-parsing/expected/custom-error-selector.sol-0.8.10-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.10-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.10-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.11-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.11-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.11-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.12-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.12-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.12-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.13-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.13-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.13-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.14-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.14-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.14-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.15-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.15-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.15-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.4-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.4-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.4-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.5-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.5-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.5-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.6-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.6-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.6-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.7-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.7-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.7-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.8-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.8-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.8-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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/expected/custom-error-selector.sol-0.8.9-compact.json b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.9-compact.json new file mode 100644 index 000000000..d35b14059 --- /dev/null +++ b/tests/ast-parsing/expected/custom-error-selector.sol-0.8.9-compact.json @@ -0,0 +1,10 @@ +{ + "Test": {}, + "VM": { + "expectRevert(bytes4)": "digraph{\n}\n", + "expectRevert(bytes)": "digraph{\n}\n" + }, + "A": { + "b(address)": "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 From cf7c62bad138d1728c3961eb72bf42be539d4591 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 9 Jan 2023 15:25:05 -0600 Subject: [PATCH 106/110] add changes --- slither/slithir/convert.py | 25 ++++++++++++++++--- .../visitors/slithir/expression_to_slithir.py | 12 ++++++--- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 0d2ef1b74..7b9e286fa 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -379,7 +379,7 @@ def integrate_value_gas(result): ################################################################################### -def propagate_type_and_convert_call(result, node): +def propagate_type_and_convert_call(result: List[Operation], node: "Node") -> List[Operation]: """ Propagate the types variables and convert tmp call to real call operation """ @@ -664,7 +664,24 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals if ir.variable_right == "selector" and isinstance(ir.variable_left, (CustomError)): assignment = Assignment( ir.lvalue, - Constant(str(get_function_id(ir.variable_left.solidity_signature))), + Constant( + str(get_function_id(ir.variable_left.solidity_signature)), + ElementaryType("bytes4"), + ), + ElementaryType("bytes4"), + ) + assignment.set_expression(ir.expression) + assignment.set_node(ir.node) + assignment.lvalue.set_type(ElementaryType("bytes4")) + return assignment + + if isinstance(ir.variable_right, (CustomError)): + assignment = Assignment( + ir.lvalue, + Constant( + str(get_function_id(ir.variable_left.solidity_signature)), + ElementaryType("bytes4"), + ), ElementaryType("bytes4"), ) assignment.set_expression(ir.expression) @@ -736,7 +753,7 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals if f: ir.lvalue.set_type(f) else: - # Allow propgation for variable access through contract's nale + # Allow propgation for variable access through contract's name # like Base_contract.my_variable v = next( ( @@ -1819,7 +1836,7 @@ def _find_source_mapping_references(irs: List[Operation]): ################################################################################### -def apply_ir_heuristics(irs, node): +def apply_ir_heuristics(irs: List[Operation], node: "Node"): """ Apply a set of heuristic to improve slithIR """ diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index 3c4595b92..d59fc1a0e 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -455,14 +455,18 @@ class ExpressionToSlithIR(ExpressionVisitor): set_val(expression, expr) return - # Early lookup to detect user defined types from other contracts definitions - # contract A { type MyInt is int} - # contract B { function f() public{ A.MyInt test = A.MyInt.wrap(1);}} - # The logic is handled by _post_call_expression if isinstance(expr, Contract): + # Early lookup to detect user defined types from other contracts definitions + # contract A { type MyInt is int} + # contract B { function f() public{ A.MyInt test = A.MyInt.wrap(1);}} + # The logic is handled by _post_call_expression if expression.member_name in expr.file_scope.user_defined_types: set_val(expression, expr.file_scope.user_defined_types[expression.member_name]) return + # Lookup errors referred to as member of contract e.g. Test.myError.selector + if expression.member_name in expr.custom_errors_as_dict: + set_val(expression, expr.custom_errors_as_dict[expression.member_name]) + return val = ReferenceVariable(self._node) member = Member(expr, Constant(expression.member_name), val) From e21d6eb17b4441b12ede8a53a63e1c9d5868c5b5 Mon Sep 17 00:00:00 2001 From: alpharush <0xalpharush@protonmail.com> Date: Mon, 9 Jan 2023 15:31:12 -0600 Subject: [PATCH 107/110] add ast test --- tests/test_ast_parsing.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 2f0e9b12c..ff96df929 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -328,6 +328,7 @@ ALL_TESTS = [ ALL_VERSIONS, ), Test("custom_error-0.8.4.sol", make_version(8, 4, 15)), + Test("custom-error-selector.sol", make_version(8, 4, 15)), Test( "top-level-0.4.0.sol", VERSIONS_04 + VERSIONS_05 + VERSIONS_06 + ["0.7.0"], From 4ed2a6adf9b57482b2b9a47f2c89ac68869647a5 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Tue, 10 Jan 2023 13:11:57 +0100 Subject: [PATCH 108/110] Improve lookup for state variables --- tests/lookup/private_variable.sol | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/lookup/private_variable.sol diff --git a/tests/lookup/private_variable.sol b/tests/lookup/private_variable.sol new file mode 100644 index 000000000..e69de29bb From 33c1fd2c8fe9d62f93047362ec350356a4ca1a0c Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Tue, 10 Jan 2023 13:12:34 +0100 Subject: [PATCH 109/110] Add files --- slither/core/declarations/contract.py | 9 ++++++++- slither/slithir/convert.py | 2 -- slither/solc_parsing/declarations/contract.py | 12 +++++++++--- .../solc_parsing/slither_compilation_unit_solc.py | 2 +- tests/lookup/private_variable.sol | 13 +++++++++++++ tests/test_features.py | 11 +++++++++++ 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/slither/core/declarations/contract.py b/slither/core/declarations/contract.py index e0191ac2e..d1feebb05 100644 --- a/slither/core/declarations/contract.py +++ b/slither/core/declarations/contract.py @@ -70,6 +70,8 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods self._enums: Dict[str, "EnumContract"] = {} self._structures: Dict[str, "StructureContract"] = {} self._events: Dict[str, "Event"] = {} + # map accessible variable from name -> variable + # do not contain private variables inherited from contract self._variables: Dict[str, "StateVariable"] = {} self._variables_ordered: List["StateVariable"] = [] self._modifiers: Dict[str, "Modifier"] = {} @@ -330,7 +332,9 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods @property def variables(self) -> List["StateVariable"]: """ - list(StateVariable): List of the state variables. Alias to self.state_variables + Returns all the accessible variables (do not include private variable from inherited contract) + + list(StateVariable): List of the state variables. Alias to self.state_variables. """ return list(self.state_variables) @@ -341,6 +345,9 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods @property def state_variables(self) -> List["StateVariable"]: """ + Returns all the accessible variables (do not include private variable from inherited contract). + Use state_variables_ordered for all the variables following the storage order + list(StateVariable): List of the state variables. """ return list(self._variables.values()) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 0d2ef1b74..18aa12273 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -1546,7 +1546,6 @@ def convert_type_of_high_and_internal_level_call(ir: Operation, contract: Option else: assert isinstance(ir, HighLevelCall) assert contract - candidates = [ f for f in contract.functions @@ -1554,7 +1553,6 @@ def convert_type_of_high_and_internal_level_call(ir: Operation, contract: Option and not f.is_shadowed and len(f.parameters) == len(ir.arguments) ] - if len(candidates) == 1: func = candidates[0] if func is None: diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py index a93914449..0ffd24131 100644 --- a/slither/solc_parsing/declarations/contract.py +++ b/slither/solc_parsing/declarations/contract.py @@ -326,7 +326,13 @@ class ContractSolc(CallerContextExpression): def parse_state_variables(self): for father in self._contract.inheritance_reverse: - self._contract.variables_as_dict.update(father.variables_as_dict) + self._contract.variables_as_dict.update( + { + name: v + for name, v in father.variables_as_dict.items() + if v.visibility != "private" + } + ) self._contract.add_variables_ordered( [ var @@ -391,11 +397,11 @@ class ContractSolc(CallerContextExpression): ################################################################################### ################################################################################### - def log_incorrect_parsing(self, error): + def log_incorrect_parsing(self, error: str) -> None: if self._contract.compilation_unit.core.disallow_partial: raise ParsingError(error) LOGGER.error(error) - self._contract.is_incorrectly_parsed = True + self._contract.is_incorrectly_constructed = True def analyze_content_modifiers(self): try: diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 296ac8238..4f6f9ac5c 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -743,7 +743,7 @@ Please rename it, this name is reserved for Slither's internals""" # And the interface is redefined due to contract's name reuse # But the available version misses some functions self._underlying_contract_to_parser[contract].log_incorrect_parsing( - f"Impossible to generate IR for {contract.name}.{func.name}:\n {e}" + f"Impossible to generate IR for {contract.name}.{func.name} ({func.source_mapping}):\n {e}" ) contract.convert_expression_to_slithir_ssa() diff --git a/tests/lookup/private_variable.sol b/tests/lookup/private_variable.sol index e69de29bb..93f4d3dda 100644 --- a/tests/lookup/private_variable.sol +++ b/tests/lookup/private_variable.sol @@ -0,0 +1,13 @@ +contract A{ + uint private v = 10; +} + +contract B{ + uint v = 20; +} + +contract C is B, A{ + function f() public view returns(uint) { + return v; + } +} \ No newline at end of file diff --git a/tests/test_features.py b/tests/test_features.py index 924e0b154..0303a5760 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -5,6 +5,7 @@ from crytic_compile.platform.solc_standard_json import SolcStandardJson from solc_select import solc_select from slither import Slither +from slither.core.variables.state_variable import StateVariable from slither.detectors import all_detectors from slither.detectors.abstract_detector import AbstractDetector from slither.slithir.operations import LibraryCall, InternalCall @@ -139,3 +140,13 @@ def test_using_for_in_library() -> None: if isinstance(ir, LibraryCall) and ir.destination == "B" and ir.function_name == "b": return assert False + + +def test_private_variable() -> None: + solc_select.switch_global_version("0.8.15", always_install=True) + slither = Slither("./tests/lookup/private_variable.sol") + contract_c = slither.get_contract_from_name("C")[0] + f = contract_c.functions[0] + var_read = f.variables_read[0] + assert isinstance(var_read, StateVariable) + assert str(var_read.contract) == "B" From 20206a86aa2313fb69d80e5b7483ed2b52ec6c46 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Tue, 10 Jan 2023 13:49:35 +0100 Subject: [PATCH 110/110] Improve convert_type_of_high_and_internal_level_call --- slither/slithir/convert.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 0d2ef1b74..6cdc6b12c 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -547,8 +547,8 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals # UserdefinedType t_type = t.type if isinstance(t_type, Contract): - contract = node.file_scope.get_contract_from_name(t_type.name) - return convert_type_of_high_and_internal_level_call(ir, contract) + # the target contract of the IR is the t_type (the destination of the call) + return convert_type_of_high_and_internal_level_call(ir, t_type) # Convert HighLevelCall to LowLevelCall if (isinstance(t, ElementaryType) and t.name == "address") or ( @@ -557,6 +557,7 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals # Cannot be a top level function with this. assert isinstance(node_function, FunctionContract) if ir.destination.name == "this": + # the target contract is the contract itself return convert_type_of_high_and_internal_level_call( ir, node_function.contract ) @@ -591,6 +592,7 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals function_contract = ( func.contract if isinstance(func, FunctionContract) else None ) + # the target contract might be None if its a top level function convert_type_of_high_and_internal_level_call(ir, function_contract) return_type = ir.function.return_type if return_type: @@ -1512,7 +1514,19 @@ def _convert_to_structure_to_list(return_type: Type) -> List[Type]: return [return_type.type] -def convert_type_of_high_and_internal_level_call(ir: Operation, contract: Optional[Contract]): +def convert_type_of_high_and_internal_level_call( + ir: Operation, contract: Optional[Contract] +) -> Optional[Operation]: + """ + Convert the IR type based on heuristic + + Args: + ir: target + contract: optional contract. This should be the target of the IR. It will be used to look up potential functions + + Returns: + Potential new IR + """ func = None if isinstance(ir, InternalCall): candidates: List[Function]