From 8b6ac7590520931d7297a222ff69835044744a94 Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Wed, 15 Feb 2023 12:08:33 +0100 Subject: [PATCH] Improve types in detectors --- .../assembly/shift_parameter_mixup.py | 6 +-- .../detectors/attributes/constant_pragma.py | 5 ++- .../detectors/attributes/incorrect_solc.py | 6 +-- slither/detectors/attributes/locked_ether.py | 7 ++-- .../attributes/unimplemented_interface.py | 10 ++--- .../compiler_bugs/array_by_reference.py | 5 +-- .../compiler_bugs/enum_conversion.py | 9 +++- .../multiple_constructor_schemes.py | 5 ++- .../storage_signed_integer_array.py | 4 +- .../erc/erc20/incorrect_erc20_interface.py | 13 +++--- .../erc/incorrect_erc721_interface.py | 2 +- .../erc/unindexed_event_parameters.py | 2 +- slither/detectors/examples/backdoor.py | 5 ++- slither/detectors/functions/dead_code.py | 4 +- slither/detectors/functions/modifier.py | 4 +- .../permit_domain_signature_collision.py | 4 +- .../detectors/functions/protected_variable.py | 4 +- slither/detectors/functions/suicidal.py | 8 ++-- slither/detectors/functions/unimplemented.py | 4 +- .../naming_convention/naming_convention.py | 6 +-- .../detectors/operations/block_timestamp.py | 4 +- .../detectors/operations/low_level_calls.py | 6 +-- .../missing_events_access_control.py | 13 +++--- .../operations/missing_events_arithmetic.py | 17 ++++---- .../missing_zero_address_validation.py | 19 +++++---- .../operations/unused_return_values.py | 13 +++--- .../detectors/operations/void_constructor.py | 5 ++- .../detectors/reentrancy/reentrancy_benign.py | 4 +- .../detectors/reentrancy/reentrancy_events.py | 6 +-- .../detectors/reentrancy/reentrancy_no_gas.py | 13 +++--- slither/detectors/reentrancy/token.py | 3 +- .../detectors/shadowing/builtin_symbols.py | 19 +++++---- slither/detectors/shadowing/local.py | 17 +++++--- slither/detectors/shadowing/state.py | 8 ++-- slither/detectors/slither/name_reused.py | 7 ++-- slither/detectors/source/rtlo.py | 5 ++- slither/detectors/statements/assembly.py | 11 +++-- .../statements/assert_state_change.py | 11 ++--- .../statements/boolean_constant_equality.py | 15 +++---- .../statements/boolean_constant_misuse.py | 15 ++++--- .../statements/controlled_delegatecall.py | 11 ++--- .../detectors/statements/deprecated_calls.py | 42 ++++++++++--------- .../statements/divide_before_multiply.py | 29 ++++++------- .../statements/incorrect_strict_equality.py | 2 +- .../detectors/statements/mapping_deletion.py | 16 +++---- .../statements/redundant_statements.py | 11 ++--- .../detectors/statements/too_many_digits.py | 12 +++--- slither/detectors/statements/tx_origin.py | 11 +++-- .../statements/type_based_tautology.py | 19 ++++----- slither/detectors/statements/unary.py | 11 ++--- .../statements/unprotected_upgradeable.py | 4 +- .../detectors/statements/write_after_write.py | 4 +- .../function_init_state_variables.py | 13 +++--- .../variables/predeclaration_usage_local.py | 17 ++++---- .../detectors/variables/similar_variables.py | 7 ++-- .../uninitialized_local_variables.py | 8 ++-- .../uninitialized_state_variables.py | 34 ++++++++------- .../uninitialized_storage_variables.py | 9 ++-- .../variables/unused_state_variables.py | 11 ++--- .../variables/var_read_using_this.py | 4 +- 60 files changed, 315 insertions(+), 284 deletions(-) diff --git a/slither/detectors/assembly/shift_parameter_mixup.py b/slither/detectors/assembly/shift_parameter_mixup.py index 410f99715..31dad2371 100644 --- a/slither/detectors/assembly/shift_parameter_mixup.py +++ b/slither/detectors/assembly/shift_parameter_mixup.py @@ -1,4 +1,4 @@ -from typing import Any, List, Union +from typing import List from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import Binary, BinaryType from slither.slithir.variables import Constant @@ -39,7 +39,7 @@ The shift statement will right-shift the constant 8 by `a` bits""" WIKI_RECOMMENDATION = "Swap the order of parameters." - def _check_function(self, f: FunctionContract) -> List[Union[Output, Any]]: + def _check_function(self, f: FunctionContract) -> List[Output]: results = [] for node in f.nodes: @@ -55,7 +55,7 @@ The shift statement will right-shift the constant 8 by `a` bits""" results.append(json) return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: results = [] for c in self.contracts: for f in c.functions: diff --git a/slither/detectors/attributes/constant_pragma.py b/slither/detectors/attributes/constant_pragma.py index 69915ba42..2164a78e8 100644 --- a/slither/detectors/attributes/constant_pragma.py +++ b/slither/detectors/attributes/constant_pragma.py @@ -1,7 +1,8 @@ """ Check that the same pragma is used in all the files """ -from typing import Any, List, Union +from typing import List + from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.formatters.attributes.constant_pragma import custom_format from slither.utils.output import Output @@ -23,7 +24,7 @@ class ConstantPragma(AbstractDetector): WIKI_DESCRIPTION = "Detect whether different Solidity versions are used." WIKI_RECOMMENDATION = "Use one Solidity version." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: results = [] pragma = self.compilation_unit.pragma_directives versions = [p.version for p in pragma if p.is_solidity_version] diff --git a/slither/detectors/attributes/incorrect_solc.py b/slither/detectors/attributes/incorrect_solc.py index fdc10ab70..fa9ffd88d 100644 --- a/slither/detectors/attributes/incorrect_solc.py +++ b/slither/detectors/attributes/incorrect_solc.py @@ -3,12 +3,12 @@ """ import re -from typing import Any, List, Optional, Tuple, Union +from typing import List, Optional, Tuple + from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.formatters.attributes.incorrect_solc import custom_format from slither.utils.output import Output - # group: # 0: ^ > >= < <= (optional) # 1: ' ' (optional) @@ -120,7 +120,7 @@ Consider using the latest version of Solidity for testing.""" return self._check_version(version_left) return self.COMPLEX_PRAGMA_TXT - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detects pragma statements that allow for outdated solc versions. :return: Returns the relevant JSON data for the findings. diff --git a/slither/detectors/attributes/locked_ether.py b/slither/detectors/attributes/locked_ether.py index ae40c5f55..2fdabaea6 100644 --- a/slither/detectors/attributes/locked_ether.py +++ b/slither/detectors/attributes/locked_ether.py @@ -1,7 +1,9 @@ """ Check if ethers are locked in the contract """ -from typing import Any, List, Union +from typing import List + +from slither.core.declarations.contract import Contract from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import ( HighLevelCall, @@ -12,7 +14,6 @@ from slither.slithir.operations import ( LibraryCall, InternalCall, ) -from slither.core.declarations.contract import Contract from slither.utils.output import Output @@ -75,7 +76,7 @@ Every Ether sent to `Locked` will be lost.""" return True - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: results = [] for contract in self.compilation_unit.contracts_derived: diff --git a/slither/detectors/attributes/unimplemented_interface.py b/slither/detectors/attributes/unimplemented_interface.py index 1ebc48396..ff0889d11 100644 --- a/slither/detectors/attributes/unimplemented_interface.py +++ b/slither/detectors/attributes/unimplemented_interface.py @@ -4,7 +4,7 @@ Module detecting unimplemented interfaces Collect all the interfaces Check for contracts which implement all interface functions but do not explicitly derive from those interfaces. """ -from typing import Any, List, Union +from typing import List from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.core.declarations.contract import Contract from slither.utils.output import Output @@ -45,8 +45,8 @@ contract Something { @staticmethod def detect_unimplemented_interface( - contract: Contract, interfaces: List[Union[Any, Contract]] - ) -> List[Union[Any, Contract]]: + contract: Contract, interfaces: List[Contract] + ) -> List[Contract]: """ Detects if contract intends to implement one of the interfaces but does not explicitly do so by deriving from it :param contract: The contract to check @@ -54,7 +54,7 @@ contract Something { :return: Interfaces likely intended to implement by the contract """ - intended_interfaces = [] + intended_interfaces: List[Contract] = [] sigs_contract = {f.full_name for f in contract.functions_entry_points} if not sigs_contract: @@ -115,7 +115,7 @@ contract Something { return intended_interfaces - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect unimplemented interfaces Returns: list: {'contract'} diff --git a/slither/detectors/compiler_bugs/array_by_reference.py b/slither/detectors/compiler_bugs/array_by_reference.py index 2dbc44c3d..83ed69b9b 100644 --- a/slither/detectors/compiler_bugs/array_by_reference.py +++ b/slither/detectors/compiler_bugs/array_by_reference.py @@ -1,7 +1,7 @@ """ Detects the passing of arrays located in memory to functions which expect to modify arrays via storage reference. """ -from typing import Any, List, Set, Tuple, Union +from typing import List, Set, Tuple, Union from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.core.solidity_types.array_type import ArrayType from slither.core.variables.state_variable import StateVariable @@ -93,7 +93,6 @@ As a result, Bob's usage of the contract is incorrect.""" Union[ Tuple[Node, StateVariable, FunctionContract], Tuple[Node, LocalVariable, FunctionContract], - Any, ] ]: """ @@ -146,7 +145,7 @@ As a result, Bob's usage of the contract is incorrect.""" results.append((node, arg, ir.function)) return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detects passing of arrays located in memory to functions which expect to modify arrays via storage reference. :return: The JSON results of the detector, which contains the calling_node, affected_argument_variable and diff --git a/slither/detectors/compiler_bugs/enum_conversion.py b/slither/detectors/compiler_bugs/enum_conversion.py index 477188fe0..671b8d699 100644 --- a/slither/detectors/compiler_bugs/enum_conversion.py +++ b/slither/detectors/compiler_bugs/enum_conversion.py @@ -1,7 +1,11 @@ """ Module detecting dangerous conversion to enum """ +from typing import List, Tuple +from slither.core.cfg.node import Node +from slither.core.declarations import Contract +from slither.core.source_mapping.source_mapping import SourceMapping from slither.detectors.abstract_detector import ( AbstractDetector, DetectorClassification, @@ -9,9 +13,10 @@ from slither.detectors.abstract_detector import ( ) from slither.slithir.operations import TypeConversion from slither.core.declarations.enum import Enum +from slither.utils.output import Output -def _detect_dangerous_enum_conversions(contract): +def _detect_dangerous_enum_conversions(contract: Contract) -> List[Tuple[Node, SourceMapping]]: """Detect dangerous conversion to enum by checking IR Args: contract (Contract) @@ -61,7 +66,7 @@ Attackers can trigger unexpected behaviour by calling `bug(1)`.""" VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 0, 4) - def _detect(self): + def _detect(self) -> List[Output]: """Detect dangerous conversion to enum""" results = [] diff --git a/slither/detectors/compiler_bugs/multiple_constructor_schemes.py b/slither/detectors/compiler_bugs/multiple_constructor_schemes.py index f07bfc8ce..3486cc41b 100644 --- a/slither/detectors/compiler_bugs/multiple_constructor_schemes.py +++ b/slither/detectors/compiler_bugs/multiple_constructor_schemes.py @@ -1,4 +1,5 @@ -from typing import Any, List, Union +from typing import List + from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -45,7 +46,7 @@ In Solidity [0.4.22](https://github.com/ethereum/solidity/releases/tag/v0.4.23), WIKI_RECOMMENDATION = "Only declare one constructor, preferably using the new scheme `constructor(...)` instead of `function (...)`." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detect multiple constructor schemes in the same contract :return: Returns a list of contract JSON result, where each result contains all constructor definitions. diff --git a/slither/detectors/compiler_bugs/storage_signed_integer_array.py b/slither/detectors/compiler_bugs/storage_signed_integer_array.py index 419c71c87..736f66789 100644 --- a/slither/detectors/compiler_bugs/storage_signed_integer_array.py +++ b/slither/detectors/compiler_bugs/storage_signed_integer_array.py @@ -1,6 +1,7 @@ """ Module detecting storage signed integer array bug """ +from typing import List from slither.detectors.abstract_detector import ( AbstractDetector, @@ -14,6 +15,7 @@ from slither.core.variables.local_variable import LocalVariable from slither.core.variables.state_variable import StateVariable from slither.slithir.operations.assignment import Assignment from slither.slithir.operations.init_array import InitArray +from slither.utils.output import Output class StorageSignedIntegerArray(AbstractDetector): @@ -108,7 +110,7 @@ contract A { # Return the resulting set of tuples return results - def _detect(self): + def _detect(self) -> List[Output]: """ Detect storage signed integer array init/assignment """ diff --git a/slither/detectors/erc/erc20/incorrect_erc20_interface.py b/slither/detectors/erc/erc20/incorrect_erc20_interface.py index e45432157..4da6ab5ae 100644 --- a/slither/detectors/erc/erc20/incorrect_erc20_interface.py +++ b/slither/detectors/erc/erc20/incorrect_erc20_interface.py @@ -2,10 +2,11 @@ Detect incorrect erc20 interface. Some contracts do not return a bool on transfer/transferFrom/approve, which may lead to preventing the contract to be used with contracts compiled with recent solc (>0.4.22) """ -from typing import Any, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Tuple + from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -40,9 +41,7 @@ contract Token{ ) @staticmethod - def incorrect_erc20_interface( - signature: Union[Tuple[str, List[str], List[Any]], Tuple[str, List[Any], List[Any]]] - ) -> bool: + def incorrect_erc20_interface(signature: Tuple[str, List[str], List[str]]) -> bool: (name, parameters, returnVars) = signature if name == "transfer" and parameters == ["address", "uint256"] and returnVars != ["bool"]: @@ -74,7 +73,7 @@ contract Token{ return False @staticmethod - def detect_incorrect_erc20_interface(contract: Contract) -> List[Union[FunctionContract, Any]]: + def detect_incorrect_erc20_interface(contract: Contract) -> List[FunctionContract]: """Detect incorrect ERC20 interface Returns: @@ -99,7 +98,7 @@ contract Token{ return functions - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect incorrect erc20 interface Returns: diff --git a/slither/detectors/erc/incorrect_erc721_interface.py b/slither/detectors/erc/incorrect_erc721_interface.py index 984323211..8327e8b2e 100644 --- a/slither/detectors/erc/incorrect_erc721_interface.py +++ b/slither/detectors/erc/incorrect_erc721_interface.py @@ -108,7 +108,7 @@ contract Token{ ] return functions - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect incorrect erc721 interface Returns: diff --git a/slither/detectors/erc/unindexed_event_parameters.py b/slither/detectors/erc/unindexed_event_parameters.py index 5f394b036..6e91b0fb3 100644 --- a/slither/detectors/erc/unindexed_event_parameters.py +++ b/slither/detectors/erc/unindexed_event_parameters.py @@ -75,7 +75,7 @@ Failure to include these keywords will exclude the parameter data in the transac # Return the results. return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detect un-indexed ERC20 event parameters in all contracts. """ diff --git a/slither/detectors/examples/backdoor.py b/slither/detectors/examples/backdoor.py index 1adc3ae1b..0e8e9ad81 100644 --- a/slither/detectors/examples/backdoor.py +++ b/slither/detectors/examples/backdoor.py @@ -1,4 +1,5 @@ -from typing import Any, List, Union +from typing import List + from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -19,7 +20,7 @@ class Backdoor(AbstractDetector): WIKI_EXPLOIT_SCENARIO = ".." WIKI_RECOMMENDATION = ".." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: results = [] for contract in self.compilation_unit.contracts_derived: diff --git a/slither/detectors/functions/dead_code.py b/slither/detectors/functions/dead_code.py index 2033984fa..1a25c5776 100644 --- a/slither/detectors/functions/dead_code.py +++ b/slither/detectors/functions/dead_code.py @@ -1,7 +1,7 @@ """ Module detecting dead code """ -from typing import Any, Union, List, Tuple +from typing import List, Tuple from slither.core.declarations import Function, FunctionContract, Contract from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification @@ -35,7 +35,7 @@ contract Contract{ WIKI_RECOMMENDATION = "Remove unused functions." - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: results = [] diff --git a/slither/detectors/functions/modifier.py b/slither/detectors/functions/modifier.py index 6a4203619..271d8e6cb 100644 --- a/slither/detectors/functions/modifier.py +++ b/slither/detectors/functions/modifier.py @@ -5,7 +5,7 @@ Note that require()/assert() are not considered here. Even if they are in the outermost scope, they do not guarantee a revert, so a default value can still be returned. """ -from typing import Any, List, Union +from typing import List from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.core.cfg.node import Node, NodeType from slither.utils.output import Output @@ -61,7 +61,7 @@ If the condition in `myModif` is false, the execution of `get()` will return 0." WIKI_RECOMMENDATION = "All the paths in a modifier must execute `_` or revert." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: results = [] for c in self.contracts: for mod in c.modifiers: diff --git a/slither/detectors/functions/permit_domain_signature_collision.py b/slither/detectors/functions/permit_domain_signature_collision.py index ae3e1c597..de64ec52e 100644 --- a/slither/detectors/functions/permit_domain_signature_collision.py +++ b/slither/detectors/functions/permit_domain_signature_collision.py @@ -1,7 +1,7 @@ """ Module detecting EIP-2612 domain separator collision """ -from typing import Any, Union, List +from typing import Union, List from slither.core.declarations import Function from slither.core.solidity_types.elementary_type import ElementaryType @@ -40,7 +40,7 @@ contract Contract{ WIKI_RECOMMENDATION = "Remove or rename the function that collides with DOMAIN_SEPARATOR()." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: domain_sig = get_function_id("DOMAIN_SEPARATOR()") for contract in self.compilation_unit.contracts_derived: if contract.is_erc20(): diff --git a/slither/detectors/functions/protected_variable.py b/slither/detectors/functions/protected_variable.py index 5dbd68957..68ed098c7 100644 --- a/slither/detectors/functions/protected_variable.py +++ b/slither/detectors/functions/protected_variable.py @@ -3,7 +3,7 @@ Module detecting suicidal contract A suicidal contract is an unprotected function that calls selfdestruct """ -from typing import Any, Union, List +from typing import List from slither.core.declarations import Function, Contract from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification @@ -71,7 +71,7 @@ contract Buggy{ results.append(res) return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect the suicidal functions""" results = [] for contract in self.compilation_unit.contracts_derived: diff --git a/slither/detectors/functions/suicidal.py b/slither/detectors/functions/suicidal.py index 5cff0b63d..7741da57d 100644 --- a/slither/detectors/functions/suicidal.py +++ b/slither/detectors/functions/suicidal.py @@ -3,11 +3,11 @@ Module detecting suicidal contract A suicidal contract is an unprotected function that calls selfdestruct """ -from typing import Any, List, Union +from typing import List -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -64,14 +64,14 @@ Bob calls `kill` and destructs the contract.""" return True - def detect_suicidal(self, contract: Contract) -> List[Union[Any, FunctionContract]]: + def detect_suicidal(self, contract: Contract) -> List[FunctionContract]: ret = [] for f in contract.functions_declared: if self.detect_suicidal_func(f): ret.append(f) return ret - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect the suicidal functions""" results = [] for c in self.contracts: diff --git a/slither/detectors/functions/unimplemented.py b/slither/detectors/functions/unimplemented.py index 84f73a65a..11a1fad80 100644 --- a/slither/detectors/functions/unimplemented.py +++ b/slither/detectors/functions/unimplemented.py @@ -7,7 +7,7 @@ Check for unimplemented functions that are never implemented Consider public state variables as implemented functions Do not consider fallback function or constructor """ -from typing import Any, List, Set, Union +from typing import List, Set from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract @@ -91,7 +91,7 @@ All unimplemented functions must be implemented on a contract that is meant to b unimplemented.add(f) return unimplemented - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect unimplemented functions Recursively visit the calls diff --git a/slither/detectors/naming_convention/naming_convention.py b/slither/detectors/naming_convention/naming_convention.py index 5b081158f..96d3964fa 100644 --- a/slither/detectors/naming_convention/naming_convention.py +++ b/slither/detectors/naming_convention/naming_convention.py @@ -1,5 +1,5 @@ import re -from typing import Any, List, Union +from typing import List from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.formatters.naming_convention.naming_convention import custom_format from slither.utils.output import Output @@ -60,9 +60,7 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2 return re.search("^[lOI]$", name) is not None # pylint: disable=too-many-branches,too-many-statements - def _detect( - self, - ) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: results = [] for contract in self.contracts: diff --git a/slither/detectors/operations/block_timestamp.py b/slither/detectors/operations/block_timestamp.py index ab359c59f..b80c8c392 100644 --- a/slither/detectors/operations/block_timestamp.py +++ b/slither/detectors/operations/block_timestamp.py @@ -2,7 +2,7 @@ Module detecting dangerous use of block.timestamp """ -from typing import Any, Union, List, Tuple +from typing import List, Tuple from slither.analyses.data_dependency.data_dependency import is_dependent from slither.core.cfg.node import Node @@ -70,7 +70,7 @@ class Timestamp(AbstractDetector): WIKI_EXPLOIT_SCENARIO = """"Bob's contract relies on `block.timestamp` for its randomness. Eve is a miner and manipulates `block.timestamp` to exploit Bob's contract.""" WIKI_RECOMMENDATION = "Avoid relying on `block.timestamp`." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """""" results = [] diff --git a/slither/detectors/operations/low_level_calls.py b/slither/detectors/operations/low_level_calls.py index 6bbbdcf48..1ea91c37a 100644 --- a/slither/detectors/operations/low_level_calls.py +++ b/slither/detectors/operations/low_level_calls.py @@ -1,7 +1,7 @@ """ Module detecting usage of low level calls """ -from typing import Any, List, Tuple, Union +from typing import List, Tuple from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import LowLevelCall from slither.core.cfg.node import Node @@ -37,7 +37,7 @@ class LowLevelCalls(AbstractDetector): def detect_low_level_calls( self, contract: Contract - ) -> List[Union[Any, Tuple[FunctionContract, List[Node]]]]: + ) -> List[Tuple[FunctionContract, List[Node]]]: ret = [] for f in [f for f in contract.functions if contract == f.contract_declarer]: nodes = f.nodes @@ -46,7 +46,7 @@ class LowLevelCalls(AbstractDetector): ret.append((f, assembly_nodes)) return ret - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect the functions that use low level calls""" results = [] for c in self.contracts: diff --git a/slither/detectors/operations/missing_events_access_control.py b/slither/detectors/operations/missing_events_access_control.py index 74fcc74e9..20c229759 100644 --- a/slither/detectors/operations/missing_events_access_control.py +++ b/slither/detectors/operations/missing_events_access_control.py @@ -2,16 +2,17 @@ Module detecting missing events for critical contract parameters set by owners and used in access control """ -from typing import Any, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Tuple + from slither.analyses.data_dependency.data_dependency import is_tainted -from slither.slithir.operations.event_call import EventCall -from slither.core.solidity_types.elementary_type import ElementaryType from slither.core.cfg.node import Node from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract from slither.core.declarations.modifier import Modifier +from slither.core.solidity_types.elementary_type import ElementaryType from slither.core.variables.state_variable import StateVariable +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.slithir.operations.event_call import EventCall from slither.utils.output import Output @@ -53,7 +54,7 @@ contract C { @staticmethod def _detect_missing_events( contract: Contract, - ) -> List[Union[Any, Tuple[FunctionContract, List[Tuple[Node, StateVariable, Modifier]]]]]: + ) -> List[Tuple[FunctionContract, List[Tuple[Node, StateVariable, Modifier]]]]: """ Detects if critical contract parameters set by owners and used in access control are missing events :param contract: The contract to check @@ -88,7 +89,7 @@ contract C { results.append((function, nodes)) return results - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect missing events for critical contract parameters set by owners and used in access control Returns: list: {'(function, node)'} diff --git a/slither/detectors/operations/missing_events_arithmetic.py b/slither/detectors/operations/missing_events_arithmetic.py index 4978dfc54..6e1d5fbb5 100644 --- a/slither/detectors/operations/missing_events_arithmetic.py +++ b/slither/detectors/operations/missing_events_arithmetic.py @@ -2,15 +2,16 @@ Module detecting missing events for critical contract parameters set by owners and used in arithmetic """ -from typing import Any, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Tuple + from slither.analyses.data_dependency.data_dependency import is_tainted -from slither.slithir.operations.event_call import EventCall -from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint from slither.core.cfg.node import Node from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract +from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint from slither.core.variables.state_variable import StateVariable +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.slithir.operations.event_call import EventCall from slither.utils.output import Output @@ -56,7 +57,7 @@ contract C { @staticmethod def _detect_unprotected_use( contract: Contract, sv: StateVariable - ) -> List[Union[Tuple[Node, FunctionContract], Any]]: + ) -> List[Tuple[Node, FunctionContract]]: unprotected_functions = [ function for function in contract.functions_declared if not function.is_protected() ] @@ -69,9 +70,7 @@ contract C { def _detect_missing_events( self, contract: Contract - ) -> List[ - Union[Tuple[FunctionContract, List[Tuple[Node, List[Tuple[Node, FunctionContract]]]]], Any] - ]: + ) -> List[Tuple[FunctionContract, List[Tuple[Node, List[Tuple[Node, FunctionContract]]]]]]: """ Detects if critical contract parameters set by owners and used in arithmetic are missing events :param contract: The contract to check @@ -112,7 +111,7 @@ contract C { results.append((function, nodes)) return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect missing events for critical contract parameters set by owners and used in arithmetic Returns: list: {'(function, node)'} diff --git a/slither/detectors/operations/missing_zero_address_validation.py b/slither/detectors/operations/missing_zero_address_validation.py index f73b77978..a6c8de9ff 100644 --- a/slither/detectors/operations/missing_zero_address_validation.py +++ b/slither/detectors/operations/missing_zero_address_validation.py @@ -3,17 +3,18 @@ Module detecting missing zero address validation """ from collections import defaultdict -from typing import Any, DefaultDict, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import DefaultDict, List, Tuple, Union + from slither.analyses.data_dependency.data_dependency import is_tainted -from slither.core.solidity_types.elementary_type import ElementaryType -from slither.slithir.operations import Send, Transfer, LowLevelCall -from slither.slithir.operations import Call from slither.core.cfg.node import Node from slither.core.declarations.contract import Contract from slither.core.declarations.function import ModifierStatements from slither.core.declarations.function_contract import FunctionContract +from slither.core.solidity_types.elementary_type import ElementaryType from slither.core.variables.local_variable import LocalVariable +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.slithir.operations import Call +from slither.slithir.operations import Send, Transfer, LowLevelCall from slither.utils.output import Output @@ -53,7 +54,7 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi WIKI_RECOMMENDATION = "Check that the address is not zero." def _zero_address_validation_in_modifier( - self, var: LocalVariable, modifier_exprs: List[Union[ModifierStatements, Any]] + self, var: LocalVariable, modifier_exprs: List[ModifierStatements] ) -> bool: for mod in modifier_exprs: for node in mod.nodes: @@ -71,7 +72,7 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi return False def _zero_address_validation( - self, var: LocalVariable, node: Node, explored: List[Union[Any, Node]] + self, var: LocalVariable, node: Node, explored: List[Node] ) -> bool: """ Detects (recursively) if var is (zero address) checked in the function node @@ -95,7 +96,7 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi def _detect_missing_zero_address_validation( self, contract: Contract - ) -> List[Union[Tuple[FunctionContract, DefaultDict[LocalVariable, List[Node]]], Any]]: + ) -> List[Union[Tuple[FunctionContract, DefaultDict[LocalVariable, List[Node]]]]]: """ Detects if addresses are zero address validated before use. :param contract: The contract to check @@ -142,7 +143,7 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi results.append((function, var_nodes)) return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect if addresses are zero address validated before use. Returns: list: {'(function, node)'} diff --git a/slither/detectors/operations/unused_return_values.py b/slither/detectors/operations/unused_return_values.py index e36ab5124..7edde20fc 100644 --- a/slither/detectors/operations/unused_return_values.py +++ b/slither/detectors/operations/unused_return_values.py @@ -1,13 +1,14 @@ """ Module detecting unused return values from external calls """ -from typing import Any, List, Union +from typing import List + +from slither.core.cfg.node import Node +from slither.core.declarations import Function +from slither.core.declarations.function_contract import FunctionContract from slither.core.variables.state_variable import StateVariable from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import HighLevelCall -from slither.core.declarations import Function -from slither.core.cfg.node import Node -from slither.core.declarations.function_contract import FunctionContract from slither.slithir.operations.operation import Operation from slither.utils.output import Output @@ -56,7 +57,7 @@ contract MyConc{ def detect_unused_return_values( self, f: FunctionContract - ) -> List[Union[Node, Any]]: # pylint: disable=no-self-use + ) -> List[Node]: # pylint: disable=no-self-use """ Return the nodes where the return value of a call is unused Args: @@ -79,7 +80,7 @@ contract MyConc{ return [nodes_origin[value].node for value in values_returned] - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect high level calls which return a value that are never used""" results = [] for c in self.compilation_unit.contracts: diff --git a/slither/detectors/operations/void_constructor.py b/slither/detectors/operations/void_constructor.py index fac39254c..fb44ea98c 100644 --- a/slither/detectors/operations/void_constructor.py +++ b/slither/detectors/operations/void_constructor.py @@ -1,4 +1,5 @@ -from typing import Any, List, Union +from typing import List + from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import Nop from slither.utils.output import Output @@ -28,7 +29,7 @@ contract B is A{ When reading `B`'s constructor definition, we might assume that `A()` initiates the contract, but no code is executed.""" # endregion wiki_exploit_scenario - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """""" results = [] for c in self.contracts: diff --git a/slither/detectors/reentrancy/reentrancy_benign.py b/slither/detectors/reentrancy/reentrancy_benign.py index 3eddde76a..25fe0ff03 100644 --- a/slither/detectors/reentrancy/reentrancy_benign.py +++ b/slither/detectors/reentrancy/reentrancy_benign.py @@ -5,7 +5,7 @@ Iterate over all the nodes of the graph until reaching a fixpoint """ from collections import namedtuple, defaultdict -from typing import Any, DefaultDict, Set, Union, List +from typing import DefaultDict, Set, List from slither.detectors.abstract_detector import DetectorClassification from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable @@ -88,7 +88,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr result[finding_key] |= not_read_then_written return result - def _detect(self) -> List[Union[Output, Any]]: # pylint: disable=too-many-branches + def _detect(self) -> List[Output]: # pylint: disable=too-many-branches """""" super()._detect() diff --git a/slither/detectors/reentrancy/reentrancy_events.py b/slither/detectors/reentrancy/reentrancy_events.py index f794cf5ca..2d29442f7 100644 --- a/slither/detectors/reentrancy/reentrancy_events.py +++ b/slither/detectors/reentrancy/reentrancy_events.py @@ -5,12 +5,12 @@ Iterate over all the nodes of the graph until reaching a fixpoint """ from collections import namedtuple, defaultdict -from typing import Any, DefaultDict, List, Set, Union +from typing import DefaultDict, List, Set + from slither.detectors.abstract_detector import DetectorClassification from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable from slither.utils.output import Output - FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"]) FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"]) @@ -82,7 +82,7 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w result[finding_key] |= finding_vars return result - def _detect(self) -> List[Union[Any, Output]]: # pylint: disable=too-many-branches + def _detect(self) -> List[Output]: # pylint: disable=too-many-branches """""" super()._detect() diff --git a/slither/detectors/reentrancy/reentrancy_no_gas.py b/slither/detectors/reentrancy/reentrancy_no_gas.py index 2678f6a25..c559d76df 100644 --- a/slither/detectors/reentrancy/reentrancy_no_gas.py +++ b/slither/detectors/reentrancy/reentrancy_no_gas.py @@ -5,15 +5,16 @@ Iterate over all the nodes of the graph until reaching a fixpoint """ from collections import namedtuple, defaultdict -from typing import Any, DefaultDict, List, Union +from typing import DefaultDict, List, Union, Set + from slither.core.variables.variable import Variable from slither.detectors.abstract_detector import DetectorClassification -from slither.slithir.operations import Send, Transfer, EventCall from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable +from slither.slithir.operations import Send, Transfer, EventCall from slither.slithir.operations.high_level_call import HighLevelCall from slither.slithir.operations.member import Member from slither.slithir.operations.return_operation import Return - +from slither.utils.output import Output FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"]) FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"]) @@ -63,8 +64,8 @@ Only report reentrancy that is based on `transfer` or `send`.""" STANDARD_JSON = False - def find_reentrancies(self) -> DefaultDict[Any, Any]: - result = defaultdict(set) + def find_reentrancies(self) -> DefaultDict[FindingKey, Set[FindingValue]]: + result: DefaultDict[FindingKey, Set[FindingValue]] = defaultdict(set) for contract in self.contracts: for f in contract.functions_and_modifiers_declared: for node in f.nodes: @@ -101,7 +102,7 @@ Only report reentrancy that is based on `transfer` or `send`.""" result[finding_key] |= finding_vars return result - def _detect(self) -> List[Any]: # pylint: disable=too-many-branches,too-many-locals + def _detect(self) -> List[Output]: # pylint: disable=too-many-branches,too-many-locals """""" super()._detect() diff --git a/slither/detectors/reentrancy/token.py b/slither/detectors/reentrancy/token.py index 9f9ba97f4..c960bffa7 100644 --- a/slither/detectors/reentrancy/token.py +++ b/slither/detectors/reentrancy/token.py @@ -6,6 +6,7 @@ from slither.core.cfg.node import Node from slither.core.declarations import Function, Contract, SolidityVariableComposed from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import LowLevelCall, HighLevelCall +from slither.utils.output import Output def _detect_token_reentrant(contract: Contract) -> Dict[Function, List[Node]]: @@ -82,7 +83,7 @@ contract MyDefi{ If you do, ensure your users are aware of the potential issues.""" # endregion wiki_recommendation - def _detect(self): + def _detect(self) -> List[Output]: results = [] for contract in self.compilation_unit.contracts_derived: vulns = _detect_token_reentrant(contract) diff --git a/slither/detectors/shadowing/builtin_symbols.py b/slither/detectors/shadowing/builtin_symbols.py index 50654a853..b0a44c8e2 100644 --- a/slither/detectors/shadowing/builtin_symbols.py +++ b/slither/detectors/shadowing/builtin_symbols.py @@ -1,12 +1,15 @@ """ Module detecting reserved keyword shadowing """ -from typing import Any, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Tuple, Union, Optional + +from slither.core.declarations import Function, Event from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract from slither.core.declarations.modifier import Modifier +from slither.core.variables import Variable from slither.core.variables.local_variable import LocalVariable +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -119,7 +122,7 @@ contract Bug { "unchecked", ] - def is_builtin_symbol(self, word: str) -> bool: + def is_builtin_symbol(self, word: Optional[str]) -> bool: """Detects if a given word is a built-in symbol. Returns: @@ -129,7 +132,7 @@ contract Bug { def detect_builtin_shadowing_locals( self, function_or_modifier: Union[Modifier, FunctionContract] - ) -> List[Union[Any, Tuple[str, LocalVariable]]]: + ) -> List[Tuple[str, LocalVariable]]: """Detects if local variables in a given function/modifier are named after built-in symbols. Any such items are returned in a list. @@ -142,14 +145,16 @@ contract Bug { results.append((self.SHADOWING_LOCAL_VARIABLE, local)) return results - def detect_builtin_shadowing_definitions(self, contract: Contract) -> List[Any]: + def detect_builtin_shadowing_definitions( + self, contract: Contract + ) -> List[Tuple[str, Union[Function, Variable, Event]]]: """Detects if functions, access modifiers, events, state variables, or local variables are named after built-in symbols. Any such definitions are returned in a list. Returns: list of tuple: (type, definition, [local variable parent])""" - result = [] + result: List[Tuple[str, Union[Function, Variable, Event]]] = [] # Loop through all functions, modifiers, variables (state and local) to detect any built-in symbol keywords. for function in contract.functions_declared: @@ -171,7 +176,7 @@ contract Bug { return result - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect shadowing of built-in symbols Recursively visit the calls diff --git a/slither/detectors/shadowing/local.py b/slither/detectors/shadowing/local.py index dc370fb12..ad65b62d9 100644 --- a/slither/detectors/shadowing/local.py +++ b/slither/detectors/shadowing/local.py @@ -1,14 +1,15 @@ """ Module detecting local variable shadowing """ -from typing import Any, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Tuple, Union + from slither.core.declarations.contract import Contract from slither.core.declarations.event import Event from slither.core.declarations.function_contract import FunctionContract from slither.core.declarations.modifier import Modifier from slither.core.variables.local_variable import LocalVariable from slither.core.variables.state_variable import StateVariable +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -62,7 +63,6 @@ contract Bug { self, contract: Contract ) -> List[ Union[ - Any, Tuple[LocalVariable, List[Tuple[str, StateVariable]]], Tuple[LocalVariable, List[Tuple[str, FunctionContract]]], Tuple[LocalVariable, List[Tuple[str, Modifier]]], @@ -74,7 +74,14 @@ contract Bug { Returns: list of tuple: (type, contract name, definition)""" - result = [] + result: List[ + Union[ + Tuple[LocalVariable, List[Tuple[str, StateVariable]]], + Tuple[LocalVariable, List[Tuple[str, FunctionContract]]], + Tuple[LocalVariable, List[Tuple[str, Modifier]]], + Tuple[LocalVariable, List[Tuple[str, Event]]], + ] + ] = [] # Loop through all functions + modifiers in this contract. for function in contract.functions + contract.modifiers: @@ -111,7 +118,7 @@ contract Bug { return result - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect shadowing local variables Recursively visit the calls diff --git a/slither/detectors/shadowing/state.py b/slither/detectors/shadowing/state.py index abdd244f5..801c370a5 100644 --- a/slither/detectors/shadowing/state.py +++ b/slither/detectors/shadowing/state.py @@ -2,16 +2,16 @@ Module detecting shadowing of state variables """ -from typing import Any, List, Union +from typing import List from slither.core.declarations import Contract from slither.core.variables.state_variable import StateVariable from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification -from slither.utils.output import Output from slither.detectors.shadowing.common import is_upgradable_gap_variable +from slither.utils.output import Output -def detect_shadowing(contract: Contract) -> List[Union[List[StateVariable], Any]]: +def detect_shadowing(contract: Contract) -> List[List[StateVariable]]: ret = [] variables_fathers = [] for father in contract.inheritance: @@ -74,7 +74,7 @@ contract DerivedContract is BaseContract{ WIKI_RECOMMENDATION = "Remove the state variable shadowing." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect shadowing Recursively visit the calls diff --git a/slither/detectors/slither/name_reused.py b/slither/detectors/slither/name_reused.py index 5d4e3265c..f6f2820fa 100644 --- a/slither/detectors/slither/name_reused.py +++ b/slither/detectors/slither/name_reused.py @@ -1,5 +1,6 @@ from collections import defaultdict -from typing import Any, List, Union +from typing import Any, List + from slither.core.compilation_unit import SlitherCompilationUnit from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -52,9 +53,7 @@ As a result, the second contract cannot be analyzed. WIKI_RECOMMENDATION = "Rename the contract." # pylint: disable=too-many-locals,too-many-branches - def _detect( - self, - ) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: results = [] compilation_unit = self.compilation_unit diff --git a/slither/detectors/source/rtlo.py b/slither/detectors/source/rtlo.py index e05bd50ac..f89eb70eb 100644 --- a/slither/detectors/source/rtlo.py +++ b/slither/detectors/source/rtlo.py @@ -1,5 +1,6 @@ import re -from typing import Any, List, Union +from typing import List + from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -55,7 +56,7 @@ contract Token RTLO_CHARACTER_ENCODED = "\u202e".encode("utf-8") STANDARD_JSON = False - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: results = [] pattern = re.compile(".*\u202e.*".encode("utf-8")) diff --git a/slither/detectors/statements/assembly.py b/slither/detectors/statements/assembly.py index 7b12d019a..2c0c49f09 100644 --- a/slither/detectors/statements/assembly.py +++ b/slither/detectors/statements/assembly.py @@ -1,11 +1,12 @@ """ Module detecting usage of inline assembly """ -from typing import Any, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Tuple + from slither.core.cfg.node import Node, NodeType from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -34,9 +35,7 @@ class Assembly(AbstractDetector): """ return node.type == NodeType.ASSEMBLY - def detect_assembly( - self, contract: Contract - ) -> List[Union[Any, Tuple[FunctionContract, List[Node]]]]: + def detect_assembly(self, contract: Contract) -> List[Tuple[FunctionContract, List[Node]]]: ret = [] for f in contract.functions: if f.contract_declarer != contract: @@ -47,7 +46,7 @@ class Assembly(AbstractDetector): ret.append((f, assembly_nodes)) return ret - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect the functions that use inline assembly""" results = [] for c in self.contracts: diff --git a/slither/detectors/statements/assert_state_change.py b/slither/detectors/statements/assert_state_change.py index 5ff767717..c82919de6 100644 --- a/slither/detectors/statements/assert_state_change.py +++ b/slither/detectors/statements/assert_state_change.py @@ -1,18 +1,19 @@ """ Module detecting state changes in assert calls """ -from typing import Any, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification -from slither.slithir.operations.internal_call import InternalCall +from typing import List, Tuple + from slither.core.cfg.node import Node from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.slithir.operations.internal_call import InternalCall from slither.utils.output import Output def detect_assert_state_change( contract: Contract, -) -> List[Union[Tuple[FunctionContract, Node], Any]]: +) -> List[Tuple[FunctionContract, Node]]: """ Detects and returns all nodes with assert calls that change contract state from within the invariant :param contract: Contract to detect @@ -76,7 +77,7 @@ The assert in `bad()` increments the state variable `s_a` while checking for the WIKI_RECOMMENDATION = """Use `require` for invariants modifying the state.""" - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """ Detect assert calls that change state from within the invariant """ diff --git a/slither/detectors/statements/boolean_constant_equality.py b/slither/detectors/statements/boolean_constant_equality.py index bf8f3dcae..5b91f364f 100644 --- a/slither/detectors/statements/boolean_constant_equality.py +++ b/slither/detectors/statements/boolean_constant_equality.py @@ -1,16 +1,17 @@ """ Module detecting misuse of Boolean constants """ -from typing import Any, List, Set, Tuple, Union +from typing import List, Set, Tuple + +from slither.core.cfg.node import Node +from slither.core.declarations import Function +from slither.core.declarations.contract import Contract from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import ( Binary, BinaryType, ) from slither.slithir.variables import Constant -from slither.core.cfg.node import Node -from slither.core.declarations.contract import Contract -from slither.core.declarations.function_contract import FunctionContract from slither.utils.output import Output @@ -50,10 +51,10 @@ Boolean constants can be used directly and do not need to be compare to `true` o @staticmethod def _detect_boolean_equality( contract: Contract, - ) -> List[Union[Tuple[FunctionContract, Set[Any]], Tuple[FunctionContract, Set[Node]], Any]]: + ) -> List[Tuple[Function, Set[Node]]]: # Create our result set. - results = [] + results: List[Tuple[Function, Set[Node]]] = [] # Loop for each function and modifier. # pylint: disable=too-many-nested-blocks @@ -74,7 +75,7 @@ Boolean constants can be used directly and do not need to be compare to `true` o # Return the resulting set of nodes with improper uses of Boolean constants return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detect Boolean constant misuses """ diff --git a/slither/detectors/statements/boolean_constant_misuse.py b/slither/detectors/statements/boolean_constant_misuse.py index 6013d3c28..96dd2012f 100644 --- a/slither/detectors/statements/boolean_constant_misuse.py +++ b/slither/detectors/statements/boolean_constant_misuse.py @@ -1,8 +1,11 @@ """ Module detecting misuse of Boolean constants """ -from typing import Any, List, Set, Tuple, Union +from typing import List, Set, Tuple + from slither.core.cfg.node import Node, NodeType +from slither.core.declarations import Function +from slither.core.declarations.contract import Contract from slither.core.solidity_types import ElementaryType from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import ( @@ -15,8 +18,6 @@ from slither.slithir.operations import ( Condition, ) from slither.slithir.variables import Constant -from slither.core.declarations.contract import Contract -from slither.core.declarations.function_contract import FunctionContract from slither.utils.output import Output @@ -65,9 +66,7 @@ Other uses (in complex expressions, as conditionals) indicate either an error or @staticmethod def _detect_boolean_constant_misuses( contract: Contract, - ) -> List[ - Union[Tuple[FunctionContract, Set[Any]], Tuple[FunctionContract, Set[Node]], Any] - ]: # pylint: disable=too-many-branches + ) -> List[Tuple[Function, Set[Node]]]: # pylint: disable=too-many-branches """ Detects and returns all nodes which misuse a Boolean constant. :param contract: Contract to detect assignment within. @@ -75,7 +74,7 @@ Other uses (in complex expressions, as conditionals) indicate either an error or """ # Create our result set. - results = [] + results: List[Tuple[Function, Set[Node]]] = [] # Loop for each function and modifier. for function in contract.functions_declared: @@ -112,7 +111,7 @@ Other uses (in complex expressions, as conditionals) indicate either an error or # Return the resulting set of nodes with improper uses of Boolean constants return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detect Boolean constant misuses """ diff --git a/slither/detectors/statements/controlled_delegatecall.py b/slither/detectors/statements/controlled_delegatecall.py index 68d8e1f5b..08280940d 100644 --- a/slither/detectors/statements/controlled_delegatecall.py +++ b/slither/detectors/statements/controlled_delegatecall.py @@ -1,13 +1,14 @@ -from typing import Any, List, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification -from slither.slithir.operations import LowLevelCall +from typing import List + from slither.analyses.data_dependency.data_dependency import is_tainted from slither.core.cfg.node import Node from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.slithir.operations import LowLevelCall from slither.utils.output import Output -def controlled_delegatecall(function: FunctionContract) -> List[Union[Node, Any]]: +def controlled_delegatecall(function: FunctionContract) -> List[Node]: ret = [] for node in function.nodes: for ir in node.irs: @@ -46,7 +47,7 @@ Bob calls `delegate` and delegates the execution to his malicious contract. As a WIKI_RECOMMENDATION = "Avoid using `delegatecall`. Use only trusted destinations." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: results = [] for contract in self.compilation_unit.contracts_derived: diff --git a/slither/detectors/statements/deprecated_calls.py b/slither/detectors/statements/deprecated_calls.py index 4e590f9df..3d0ca4ba9 100644 --- a/slither/detectors/statements/deprecated_calls.py +++ b/slither/detectors/statements/deprecated_calls.py @@ -1,20 +1,20 @@ """ Module detecting deprecated standards. """ -from typing import Any, List, Tuple, Union +from typing import List, Tuple, Union + from slither.core.cfg.node import Node, NodeType +from slither.core.declarations.contract import Contract from slither.core.declarations.solidity_variables import ( SolidityVariableComposed, SolidityFunction, ) +from slither.core.expressions.expression import Expression +from slither.core.variables import StateVariable from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import LowLevelCall -from slither.visitors.expression.export_values import ExportValues -from slither.core.declarations.contract import Contract -from slither.core.expressions.binary_operation import BinaryOperation -from slither.core.expressions.call_expression import CallExpression -from slither.core.expressions.member_access import MemberAccess from slither.utils.output import Output +from slither.visitors.expression.export_values import ExportValues # Reference: https://smartcontractsecurity.github.io/SWC-registry/docs/SWC-111 @@ -79,8 +79,8 @@ contract ContractWithDeprecatedReferences { DEPRECATED_LOW_LEVEL_CALLS = [("callcode", "callcode", "delegatecall")] def detect_deprecation_in_expression( - self, expression: Union[BinaryOperation, MemberAccess, CallExpression] - ) -> List[Union[Any, Tuple[str, str, str]]]: + self, expression: Expression + ) -> List[Tuple[str, str, str]]: """Detects if an expression makes use of any deprecated standards. Returns: @@ -104,13 +104,13 @@ contract ContractWithDeprecatedReferences { def detect_deprecated_references_in_node( self, node: Node - ) -> List[Union[Any, Tuple[str, str, str], Tuple[NodeType, str, str]]]: + ) -> List[Tuple[Union[str, NodeType], str, str]]: """Detects if a node makes use of any deprecated standards. Returns: list of tuple: (detecting_signature, original_text, recommended_text)""" # Define our results list - results = [] + results: List[Tuple[Union[str, NodeType], str, str]] = [] # If this node has an expression, we check the underlying expression. if node.expression: @@ -127,16 +127,20 @@ contract ContractWithDeprecatedReferences { self, contract: Contract ) -> List[ Union[ - Any, - Tuple[Node, List[Tuple[str, str, str]]], - Tuple[Node, List[Tuple[NodeType, str, str]]], + Tuple[StateVariable, List[Tuple[str, str, str]]], + Tuple[Node, List[Tuple[Union[str, NodeType], str, str]]], ] ]: """Detects the usage of any deprecated built-in symbols. Returns: list of tuple: (state_variable | node, (detecting_signature, original_text, recommended_text))""" - results = [] + results: List[ + Union[ + Tuple[StateVariable, List[Tuple[str, str, str]]], + Tuple[Node, List[Tuple[Union[str, NodeType], str, str]]], + ] + ] = [] for state_variable in contract.state_variables_declared: if state_variable.expression: @@ -152,22 +156,22 @@ contract ContractWithDeprecatedReferences { # Loop through each node in this function. for node in function.nodes: # Detect deprecated references in the node. - deprecated_results = self.detect_deprecated_references_in_node(node) + deprecated_results_node = self.detect_deprecated_references_in_node(node) # Detect additional deprecated low-level-calls. for ir in node.irs: if isinstance(ir, LowLevelCall): for dep_llc in self.DEPRECATED_LOW_LEVEL_CALLS: if ir.function_name == dep_llc[0]: - deprecated_results.append(dep_llc) + deprecated_results_node.append(dep_llc) # If we have any results from this iteration, add them to our results list. - if deprecated_results: - results.append((node, deprecated_results)) + if deprecated_results_node: + results.append((node, deprecated_results_node)) return results - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detects if an expression makes use of any deprecated standards. Recursively visit the calls diff --git a/slither/detectors/statements/divide_before_multiply.py b/slither/detectors/statements/divide_before_multiply.py index f51115c66..a9de76b40 100644 --- a/slither/detectors/statements/divide_before_multiply.py +++ b/slither/detectors/statements/divide_before_multiply.py @@ -2,23 +2,18 @@ Module detecting possible loss of precision due to divide before multiple """ from collections import defaultdict -from typing import Any, DefaultDict, List, Set, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification -from slither.slithir.operations import Binary, Assignment, BinaryType, LibraryCall -from slither.slithir.variables import Constant -import slither.slithir.operations.binary +from typing import Any, DefaultDict, List, Set, Tuple + from slither.core.cfg.node import Node from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract -from slither.slithir.operations.high_level_call import HighLevelCall -from slither.slithir.operations.member import Member -from slither.slithir.operations.return_operation import Return +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.slithir.operations import Binary, Assignment, BinaryType, LibraryCall, Operation +from slither.slithir.variables import Constant from slither.utils.output import Output -def is_division( - ir: Union[Member, slither.slithir.operations.binary.Binary, HighLevelCall, Return] -) -> bool: +def is_division(ir: Operation) -> bool: if isinstance(ir, Binary): if ir.type == BinaryType.DIVISION: return True @@ -34,9 +29,7 @@ def is_division( return False -def is_multiplication( - ir: Union[Member, slither.slithir.operations.binary.Binary, HighLevelCall, Return] -) -> bool: +def is_multiplication(ir: Operation) -> bool: if isinstance(ir, Binary): if ir.type == BinaryType.MULTIPLICATION: return True @@ -64,7 +57,9 @@ def is_assert(node: Node) -> bool: # pylint: disable=too-many-branches -def _explore(to_explore: Set[Node], f_results: List[Any], divisions: DefaultDict[Any, Any]) -> None: +def _explore( + to_explore: Set[Node], f_results: List[Node], divisions: DefaultDict[Any, Any] +) -> None: explored = set() while to_explore: # pylint: disable=too-many-nested-blocks node = to_explore.pop() @@ -119,7 +114,7 @@ def _explore(to_explore: Set[Node], f_results: List[Any], divisions: DefaultDict def detect_divide_before_multiply( contract: Contract, -) -> List[Union[Tuple[FunctionContract, List[Node]], Any]]: +) -> List[Tuple[FunctionContract, List[Node]]]: """ Detects and returns all nodes with multiplications of division results. :param contract: Contract to detect assignment within. @@ -185,7 +180,7 @@ In general, it's usually a good idea to re-arrange arithmetic to perform multipl WIKI_RECOMMENDATION = """Consider ordering multiplication before division.""" - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detect divisions before multiplications """ diff --git a/slither/detectors/statements/incorrect_strict_equality.py b/slither/detectors/statements/incorrect_strict_equality.py index 8926f4967..bc7b0cebe 100644 --- a/slither/detectors/statements/incorrect_strict_equality.py +++ b/slither/detectors/statements/incorrect_strict_equality.py @@ -163,7 +163,7 @@ contract Crowdsale{ return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: results = [] for c in self.compilation_unit.contracts_derived: diff --git a/slither/detectors/statements/mapping_deletion.py b/slither/detectors/statements/mapping_deletion.py index 2bc31167b..59882cc96 100644 --- a/slither/detectors/statements/mapping_deletion.py +++ b/slither/detectors/statements/mapping_deletion.py @@ -1,15 +1,15 @@ """ Detect deletion on structure containing a mapping """ -from typing import Any, List, Tuple, Union +from typing import List, Tuple + +from slither.core.cfg.node import Node from slither.core.declarations import Structure +from slither.core.declarations.contract import Contract +from slither.core.declarations.function_contract import FunctionContract from slither.core.solidity_types import MappingType, UserDefinedType from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import Delete -from slither.core.cfg.node import Node -from slither.core.declarations.contract import Contract -from slither.core.declarations.function_contract import FunctionContract -from slither.core.declarations.structure_contract import StructureContract from slither.utils.output import Output @@ -52,13 +52,13 @@ The mapping `balances` is never deleted, so `remove` does not work as intended." @staticmethod def detect_mapping_deletion( contract: Contract, - ) -> List[Union[Any, Tuple[FunctionContract, StructureContract, Node]]]: + ) -> List[Tuple[FunctionContract, Structure, Node]]: """Detect deletion on structure containing a mapping Returns: list (function, structure, node) """ - ret = [] + ret: List[Tuple[FunctionContract, Structure, Node]] = [] # pylint: disable=too-many-nested-blocks for f in contract.functions: for node in f.nodes: @@ -73,7 +73,7 @@ The mapping `balances` is never deleted, so `remove` does not work as intended." ret.append((f, st, node)) return ret - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect mapping deletion Returns: diff --git a/slither/detectors/statements/redundant_statements.py b/slither/detectors/statements/redundant_statements.py index a0619d46f..7e7223134 100644 --- a/slither/detectors/statements/redundant_statements.py +++ b/slither/detectors/statements/redundant_statements.py @@ -1,12 +1,13 @@ """ Module detecting redundant statements. """ -from typing import Any, List, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List + from slither.core.cfg.node import Node, NodeType +from slither.core.declarations.contract import Contract from slither.core.expressions.elementary_type_name_expression import ElementaryTypeNameExpression from slither.core.expressions.identifier import Identifier -from slither.core.declarations.contract import Contract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -52,7 +53,7 @@ Each commented line references types/identifiers, but performs no action with th # This is a disallowed list of tuple (node.type, type(node.expression)) REDUNDANT_TOP_LEVEL_EXPRESSIONS = (ElementaryTypeNameExpression, Identifier) - def detect_redundant_statements_contract(self, contract: Contract) -> List[Union[Any, Node]]: + def detect_redundant_statements_contract(self, contract: Contract) -> List[Node]: """Detects the usage of redundant statements in a contract. Returns: @@ -72,7 +73,7 @@ Each commented line references types/identifiers, but performs no action with th return results - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect redundant statements Recursively visit the calls diff --git a/slither/detectors/statements/too_many_digits.py b/slither/detectors/statements/too_many_digits.py index 00b9e99cd..239efa4be 100644 --- a/slither/detectors/statements/too_many_digits.py +++ b/slither/detectors/statements/too_many_digits.py @@ -3,14 +3,14 @@ Module detecting numbers with too many digits. """ import re -from typing import Any, List, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification -from slither.slithir.variables import Constant +from typing import List + from slither.core.cfg.node import Node from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.slithir.variables import Constant from slither.utils.output import Output - _HEX_ADDRESS_REGEXP = re.compile("(0[xX])?[0-9a-fA-F]{40}") @@ -62,7 +62,7 @@ Use: # endregion wiki_recommendation @staticmethod - def _detect_too_many_digits(f: FunctionContract) -> List[Union[Any, Node]]: + def _detect_too_many_digits(f: FunctionContract) -> List[Node]: ret = [] for node in f.nodes: # each node contains a list of IR instruction @@ -78,7 +78,7 @@ Use: ret.append(node) return ret - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: results = [] # iterate over all contracts diff --git a/slither/detectors/statements/tx_origin.py b/slither/detectors/statements/tx_origin.py index ad57cd198..34f8173d5 100644 --- a/slither/detectors/statements/tx_origin.py +++ b/slither/detectors/statements/tx_origin.py @@ -1,11 +1,12 @@ """ Module detecting usage of `tx.origin` in a conditional node """ -from typing import Any, List, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Tuple + from slither.core.cfg.node import Node from slither.core.declarations.contract import Contract from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -56,9 +57,7 @@ Bob is the owner of `TxOrigin`. Bob calls Eve's contract. Eve's contract calls ` ) return False - def detect_tx_origin( - self, contract: Contract - ) -> List[Union[Tuple[FunctionContract, List[Node]], Any]]: + def detect_tx_origin(self, contract: Contract) -> List[Tuple[FunctionContract, List[Node]]]: ret = [] for f in contract.functions: @@ -73,7 +72,7 @@ Bob is the owner of `TxOrigin`. Bob calls Eve's contract. Eve's contract calls ` ret.append((f, bad_tx_nodes)) return ret - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect the functions that use tx.origin in a conditional node""" results = [] for c in self.contracts: diff --git a/slither/detectors/statements/type_based_tautology.py b/slither/detectors/statements/type_based_tautology.py index fe78ca4c1..9edb1f53e 100644 --- a/slither/detectors/statements/type_based_tautology.py +++ b/slither/detectors/statements/type_based_tautology.py @@ -1,14 +1,15 @@ """ Module detecting tautologies and contradictions based on types in comparison operations over integers """ -from typing import Any, List, Set, Tuple, Union +from typing import List, Set, Tuple + +from slither.core.cfg.node import Node +from slither.core.declarations import Function +from slither.core.declarations.contract import Contract +from slither.core.solidity_types.elementary_type import Int, Uint from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import Binary, BinaryType from slither.slithir.variables import Constant -from slither.core.solidity_types.elementary_type import Int, Uint -from slither.core.cfg.node import Node -from slither.core.declarations.contract import Contract -from slither.core.declarations.function_contract import FunctionContract from slither.utils.output import Output @@ -114,9 +115,7 @@ contract A { BinaryType.LESS_EQUAL: BinaryType.GREATER_EQUAL, } - def detect_type_based_tautologies( - self, contract: Contract - ) -> List[Union[Any, Tuple[FunctionContract, Set[Node]], Tuple[FunctionContract, Set[Any]]]]: + def detect_type_based_tautologies(self, contract: Contract) -> List[Tuple[Function, Set[Node]]]: """ Detects and returns all nodes with tautology/contradiction comparisons (based on type alone). :param contract: Contract to detect assignment within. @@ -124,7 +123,7 @@ contract A { """ # Create our result set. - results = [] + results: List[Tuple[Function, Set[Node]]] = [] allInts = Int + Uint # Loop for each function and modifier. @@ -157,7 +156,7 @@ contract A { # Return the resulting set of nodes with tautologies and contradictions return results - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """ Detect tautological (or contradictory) comparisons """ diff --git a/slither/detectors/statements/unary.py b/slither/detectors/statements/unary.py index 641df91be..5bb8d9c3c 100644 --- a/slither/detectors/statements/unary.py +++ b/slither/detectors/statements/unary.py @@ -1,12 +1,13 @@ """ Module detecting the incorrect use of unary expressions """ -from typing import Any, List, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification -from slither.visitors.expression.expression import ExpressionVisitor -from slither.core.expressions.unary_operation import UnaryOperationType, UnaryOperation +from typing import List + from slither.core.expressions.assignment_operation import AssignmentOperation +from slither.core.expressions.unary_operation import UnaryOperationType, UnaryOperation +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output +from slither.visitors.expression.expression import ExpressionVisitor class InvalidUnaryExpressionDetector(ExpressionVisitor): @@ -62,7 +63,7 @@ contract Bug{ WIKI_RECOMMENDATION = "Remove the unary expression." - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """ Detect the incorrect use of unary expressions """ diff --git a/slither/detectors/statements/unprotected_upgradeable.py b/slither/detectors/statements/unprotected_upgradeable.py index 6cafbf3f9..1adf49540 100644 --- a/slither/detectors/statements/unprotected_upgradeable.py +++ b/slither/detectors/statements/unprotected_upgradeable.py @@ -1,4 +1,4 @@ -from typing import Any, Union, List +from typing import List from slither.core.declarations import SolidityFunction, Function from slither.core.declarations.contract import Contract @@ -88,7 +88,7 @@ Buggy is an upgradeable contract. Anyone can call initialize on the logic contra """Add a constructor to ensure `initialize` cannot be called on the logic contract.""" ) - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: results = [] for contract in self.compilation_unit.contracts_derived: diff --git a/slither/detectors/statements/write_after_write.py b/slither/detectors/statements/write_after_write.py index 770fc3962..5b2e29925 100644 --- a/slither/detectors/statements/write_after_write.py +++ b/slither/detectors/statements/write_after_write.py @@ -1,4 +1,4 @@ -from typing import Any, Union, List, Set, Tuple, Dict +from typing import List, Set, Tuple, Dict from slither.core.cfg.node import Node, NodeType from slither.core.solidity_types import ElementaryType @@ -122,7 +122,7 @@ class WriteAfterWrite(AbstractDetector): WIKI_RECOMMENDATION = """Fix or remove the writes.""" - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: results = [] for contract in self.compilation_unit.contracts_derived: diff --git a/slither/detectors/variables/function_init_state_variables.py b/slither/detectors/variables/function_init_state_variables.py index 988a5e29d..e35cfe351 100644 --- a/slither/detectors/variables/function_init_state_variables.py +++ b/slither/detectors/variables/function_init_state_variables.py @@ -1,16 +1,17 @@ """ Module detecting state variables initializing from an immediate function call (prior to constructor run). """ -from typing import Any, List, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification -from slither.visitors.expression.export_values import ExportValues +from typing import List + +from slither.core.declarations.contract import Contract from slither.core.declarations.function import Function from slither.core.variables.state_variable import StateVariable -from slither.core.declarations.contract import Contract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output +from slither.visitors.expression.export_values import ExportValues -def detect_function_init_state_vars(contract: Contract) -> List[Union[StateVariable, Any]]: +def detect_function_init_state_vars(contract: Contract) -> List[StateVariable]: """ Detect any state variables that are initialized from an immediate function call (prior to constructor run). :param contract: The contract to detect state variable definitions for. @@ -89,7 +90,7 @@ Special care must be taken when initializing state variables from an immediate f WIKI_RECOMMENDATION = "Remove any initialization of state variables via non-constant state variables or function calls. If variables must be set upon contract deployment, locate initialization in the constructor instead." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detect state variables defined from an immediate function call (pre-contract deployment). diff --git a/slither/detectors/variables/predeclaration_usage_local.py b/slither/detectors/variables/predeclaration_usage_local.py index 0d51c3c12..2ba539a91 100644 --- a/slither/detectors/variables/predeclaration_usage_local.py +++ b/slither/detectors/variables/predeclaration_usage_local.py @@ -1,12 +1,13 @@ """ Module detecting any path leading to usage of a local variable before it is declared. """ -from typing import Any, List, Set, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Set, Tuple + from slither.core.cfg.node import Node +from slither.core.declarations import Function from slither.core.declarations.contract import Contract -from slither.core.declarations.function_contract import FunctionContract from slither.core.variables.local_variable import LocalVariable +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -56,7 +57,7 @@ Additionally, the for-loop uses the variable `max`, which is declared in a previ def detect_predeclared_local_usage( self, node: Node, - results: List[Union[Tuple[Node, LocalVariable], Any]], + results: List[Tuple[Node, LocalVariable]], already_declared: Set[LocalVariable], visited: Set[Node], ) -> None: @@ -100,7 +101,7 @@ Additionally, the for-loop uses the variable `max`, which is declared in a previ def detect_predeclared_in_contract( self, contract: Contract - ) -> List[Union[Any, Tuple[FunctionContract, List[Tuple[Node, LocalVariable]]]]]: + ) -> List[Tuple[Function, List[Tuple[Node, LocalVariable]]]]: """ Detects and returns all nodes in a contract which use a variable before it is declared. :param contract: Contract to detect pre-declaration usage of locals within. @@ -108,11 +109,11 @@ Additionally, the for-loop uses the variable `max`, which is declared in a previ """ # Create our result set. - results = [] + results: List[Tuple[Function, List[Tuple[Node, LocalVariable]]]] = [] # Loop for each function and modifier's nodes and analyze for predeclared local variable usage. for function in contract.functions_and_modifiers_declared: - predeclared_usage = [] + predeclared_usage: List[Tuple[Node, LocalVariable]] = [] if function.nodes: self.detect_predeclared_local_usage( function.nodes[0], @@ -126,7 +127,7 @@ Additionally, the for-loop uses the variable `max`, which is declared in a previ # Return the resulting set of nodes which set array length. return results - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """ Detect usage of a local variable before it is declared. """ diff --git a/slither/detectors/variables/similar_variables.py b/slither/detectors/variables/similar_variables.py index 98163dbb3..d0a15aaab 100644 --- a/slither/detectors/variables/similar_variables.py +++ b/slither/detectors/variables/similar_variables.py @@ -3,10 +3,11 @@ Check for state variables too similar Do not check contract inheritance """ import difflib -from typing import Any, List, Set, Tuple, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List, Set, Tuple + from slither.core.declarations.contract import Contract from slither.core.variables.local_variable import LocalVariable +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -72,7 +73,7 @@ class SimilarVarsDetection(AbstractDetector): return set(ret) - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect similar variables name Returns: diff --git a/slither/detectors/variables/uninitialized_local_variables.py b/slither/detectors/variables/uninitialized_local_variables.py index af75f09ab..759691d50 100644 --- a/slither/detectors/variables/uninitialized_local_variables.py +++ b/slither/detectors/variables/uninitialized_local_variables.py @@ -4,11 +4,11 @@ Recursively explore the CFG to only report uninitialized local variables that are read before being written """ -from typing import Any, List, Union +from typing import List -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.core.cfg.node import Node from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -42,7 +42,7 @@ Bob calls `transfer`. As a result, all Ether is sent to the address `0x0` and is key = "UNINITIALIZEDLOCAL" def _detect_uninitialized( - self, function: FunctionContract, node: Node, visited: List[Union[Any, Node]] + self, function: FunctionContract, node: Node, visited: List[Node] ) -> None: if node in visited: return @@ -79,7 +79,7 @@ Bob calls `transfer`. As a result, all Ether is sent to the address `0x0` and is for son in node.sons: self._detect_uninitialized(function, son, visited) - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect uninitialized local variables Recursively visit the calls diff --git a/slither/detectors/variables/uninitialized_state_variables.py b/slither/detectors/variables/uninitialized_state_variables.py index 81d04c2b0..0fbb73b5d 100644 --- a/slither/detectors/variables/uninitialized_state_variables.py +++ b/slither/detectors/variables/uninitialized_state_variables.py @@ -8,13 +8,15 @@ Only analyze "leaf" contracts (contracts that are not inherited by another contract) """ -from typing import Any, List, Tuple, Union +from typing import List, Tuple + +from slither.core.declarations import Function +from slither.core.declarations.contract import Contract +from slither.core.variables import Variable +from slither.core.variables.state_variable import StateVariable from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.slithir.operations import InternalCall, LibraryCall from slither.slithir.variables import ReferenceVariable -from slither.core.declarations.contract import Contract -from slither.core.declarations.function_contract import FunctionContract -from slither.core.variables.state_variable import StateVariable from slither.utils.output import Output @@ -55,7 +57,7 @@ Initialize all the variables. If a variable is meant to be initialized to zero, # endregion wiki_recommendation @staticmethod - def _written_variables(contract: Contract) -> List[Union[Any, StateVariable]]: + def _written_variables(contract: Contract) -> List[StateVariable]: ret = [] # pylint: disable=too-many-nested-blocks for f in contract.all_functions_called + contract.modifiers: @@ -92,8 +94,8 @@ Initialize all the variables. If a variable is meant to be initialized to zero, self.__variables_written_in_proxy = list({v.name for v in variables_written_in_proxy}) return self.__variables_written_in_proxy - def _written_variables_in_proxy(self, contract: Contract) -> List[Any]: - variables = [] + def _written_variables_in_proxy(self, contract: Contract) -> List[StateVariable]: + variables: List[StateVariable] = [] if contract.is_upgradeable: variables_name_written_in_proxy = self._variable_written_in_proxy() if variables_name_written_in_proxy: @@ -101,20 +103,20 @@ Initialize all the variables. If a variable is meant to be initialized to zero, contract.get_state_variable_from_name(v) for v in variables_name_written_in_proxy ] - variables_in_contract = [v for v in variables_in_contract if v] - variables += variables_in_contract + variables += [v for v in variables_in_contract if v] return list(set(variables)) @staticmethod - def _read_variables(contract: Contract) -> List[Union[Any, StateVariable]]: + def _read_variables(contract: Contract) -> List[StateVariable]: ret = [] - for f in contract.all_functions_called + contract.modifiers: - ret += f.state_variables_read + for f in contract.all_functions_called: + if isinstance(f, Function): + ret += f.state_variables_read + for m in contract.modifiers: + ret += m.state_variables_read return ret - def _detect_uninitialized( - self, contract: Contract - ) -> List[Union[Any, Tuple[StateVariable, List[FunctionContract]]]]: + def _detect_uninitialized(self, contract: Contract) -> List[Tuple[Variable, List[Function]]]: written_variables = self._written_variables(contract) written_variables += self._written_variables_in_proxy(contract) read_variables = self._read_variables(contract) @@ -126,7 +128,7 @@ Initialize all the variables. If a variable is meant to be initialized to zero, and variable in read_variables ] - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect uninitialized state variables Recursively visit the calls diff --git a/slither/detectors/variables/uninitialized_storage_variables.py b/slither/detectors/variables/uninitialized_storage_variables.py index 9296416b4..422996646 100644 --- a/slither/detectors/variables/uninitialized_storage_variables.py +++ b/slither/detectors/variables/uninitialized_storage_variables.py @@ -4,10 +4,11 @@ Recursively explore the CFG to only report uninitialized storage variables that are written before being read """ -from typing import Any, List, Union -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from typing import List + from slither.core.cfg.node import Node from slither.core.declarations.function_contract import FunctionContract +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.utils.output import Output @@ -49,7 +50,7 @@ Bob calls `func`. As a result, `owner` is overridden to `0`. key = "UNINITIALIZEDSTORAGE" def _detect_uninitialized( - self, function: FunctionContract, node: Node, visited: List[Union[Any, Node]] + self, function: FunctionContract, node: Node, visited: List[Node] ) -> None: if node in visited: return @@ -86,7 +87,7 @@ Bob calls `func`. As a result, `owner` is overridden to `0`. for son in node.sons: self._detect_uninitialized(function, son, visited) - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: """Detect uninitialized storage variables Recursively visit the calls diff --git a/slither/detectors/variables/unused_state_variables.py b/slither/detectors/variables/unused_state_variables.py index 10c999351..d542f67d3 100644 --- a/slither/detectors/variables/unused_state_variables.py +++ b/slither/detectors/variables/unused_state_variables.py @@ -1,15 +1,16 @@ """ Module detecting unused state variables """ -from typing import Any, List, Optional, Union +from typing import List, Optional + from slither.core.compilation_unit import SlitherCompilationUnit -from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification +from slither.core.declarations.contract import Contract from slither.core.solidity_types import ArrayType -from slither.visitors.expression.export_values import ExportValues from slither.core.variables.state_variable import StateVariable +from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification from slither.formatters.variables.unused_state_variables import custom_format -from slither.core.declarations.contract import Contract from slither.utils.output import Output +from slither.visitors.expression.export_values import ExportValues def detect_unused(contract: Contract) -> Optional[List[StateVariable]]: @@ -57,7 +58,7 @@ class UnusedStateVars(AbstractDetector): WIKI_EXPLOIT_SCENARIO = "" WIKI_RECOMMENDATION = "Remove unused state variables." - def _detect(self) -> List[Union[Output, Any]]: + def _detect(self) -> List[Output]: """Detect unused state variables""" results = [] for c in self.compilation_unit.contracts_derived: diff --git a/slither/detectors/variables/var_read_using_this.py b/slither/detectors/variables/var_read_using_this.py index d9f8fba70..b224f8c17 100644 --- a/slither/detectors/variables/var_read_using_this.py +++ b/slither/detectors/variables/var_read_using_this.py @@ -1,4 +1,4 @@ -from typing import Any, Union, List +from typing import List from slither.core.cfg.node import Node from slither.core.declarations import Function, SolidityVariable @@ -30,7 +30,7 @@ contract C { WIKI_RECOMMENDATION = "Read the variable directly from storage instead of calling the contract." - def _detect(self) -> List[Union[Any, Output]]: + def _detect(self) -> List[Output]: results = [] for c in self.contracts: for func in c.functions: