Add more types

pull/1666/head
Feist Josselin 2 years ago
parent 371e3cbe47
commit efed98327a
  1. 30
      slither/analyses/data_dependency/data_dependency.py
  2. 29
      slither/analyses/write/are_variables_written.py
  3. 2
      slither/core/children/child_expression.py
  4. 2
      slither/core/declarations/contract.py
  5. 5
      slither/core/solidity_types/array_type.py
  6. 2
      slither/detectors/abstract_detector.py
  7. 6
      slither/detectors/attributes/const_functions_asm.py
  8. 9
      slither/detectors/attributes/const_functions_state.py
  9. 15
      slither/detectors/attributes/constant_pragma.py
  10. 8
      slither/detectors/attributes/incorrect_solc.py
  11. 8
      slither/detectors/attributes/locked_ether.py
  12. 8
      slither/detectors/attributes/unimplemented_interface.py
  13. 8
      slither/detectors/compiler_bugs/array_by_reference.py
  14. 11
      slither/detectors/compiler_bugs/enum_conversion.py
  15. 11
      slither/detectors/compiler_bugs/multiple_constructor_schemes.py
  16. 3
      slither/detectors/compiler_bugs/reused_base_constructor.py
  17. 9
      slither/detectors/compiler_bugs/storage_ABIEncoderV2_array.py
  18. 32
      slither/detectors/compiler_bugs/storage_signed_integer_array.py
  19. 5
      slither/detectors/compiler_bugs/uninitialized_function_ptr_in_constructor.py
  20. 8
      slither/detectors/erc/erc20/incorrect_erc20_interface.py
  21. 8
      slither/detectors/erc/incorrect_erc721_interface.py
  22. 8
      slither/detectors/examples/backdoor.py
  23. 7
      slither/detectors/functions/arbitrary_send_eth.py
  24. 8
      slither/detectors/functions/cyclomatic_complexity.py
  25. 8
      slither/detectors/functions/dead_code.py
  26. 12
      slither/detectors/functions/modifier.py
  27. 8
      slither/detectors/functions/permit_domain_signature_collision.py
  28. 8
      slither/detectors/functions/protected_variable.py
  29. 8
      slither/detectors/functions/suicidal.py
  30. 14
      slither/detectors/functions/unimplemented.py
  31. 7
      slither/detectors/naming_convention/naming_convention.py
  32. 9
      slither/detectors/operations/bad_prng.py
  33. 29
      slither/detectors/operations/block_timestamp.py
  34. 8
      slither/detectors/operations/low_level_calls.py
  35. 8
      slither/detectors/operations/missing_events_access_control.py
  36. 8
      slither/detectors/operations/missing_events_arithmetic.py
  37. 8
      slither/detectors/operations/missing_zero_address_validation.py
  38. 8
      slither/detectors/operations/unused_return_values.py
  39. 8
      slither/detectors/operations/void_constructor.py
  40. 8
      slither/detectors/reentrancy/token.py
  41. 8
      slither/detectors/shadowing/builtin_symbols.py
  42. 10
      slither/detectors/shadowing/local.py
  43. 8
      slither/detectors/shadowing/state.py
  44. 8
      slither/detectors/slither/name_reused.py
  45. 8
      slither/detectors/source/rtlo.py
  46. 17
      slither/detectors/statements/array_length_assignment.py
  47. 13
      slither/detectors/statements/assert_state_change.py
  48. 8
      slither/detectors/statements/boolean_constant_equality.py
  49. 8
      slither/detectors/statements/boolean_constant_misuse.py
  50. 8
      slither/detectors/statements/calls_in_loop.py
  51. 10
      slither/detectors/statements/controlled_delegatecall.py
  52. 8
      slither/detectors/statements/costly_operations_in_loop.py
  53. 13
      slither/detectors/statements/delegatecall_in_loop.py
  54. 8
      slither/detectors/statements/deprecated_calls.py
  55. 35
      slither/detectors/statements/divide_before_multiply.py
  56. 8
      slither/detectors/statements/mapping_deletion.py
  57. 8
      slither/detectors/statements/msg_value_in_loop.py
  58. 14
      slither/detectors/statements/redundant_statements.py
  59. 10
      slither/detectors/statements/too_many_digits.py
  60. 8
      slither/detectors/statements/tx_origin.py
  61. 7
      slither/detectors/statements/type_based_tautology.py
  62. 11
      slither/detectors/statements/unary.py
  63. 26
      slither/detectors/statements/unprotected_upgradeable.py
  64. 17
      slither/detectors/statements/write_after_write.py
  65. 8
      slither/detectors/variables/function_init_state_variables.py
  66. 8
      slither/detectors/variables/predeclaration_usage_local.py
  67. 14
      slither/detectors/variables/similar_variables.py
  68. 8
      slither/detectors/variables/uninitialized_state_variables.py
  69. 25
      slither/detectors/variables/unused_state_variables.py
  70. 8
      slither/detectors/variables/var_read_using_this.py
  71. 3
      slither/formatters/attributes/const_functions.py
  72. 5
      slither/formatters/attributes/constant_pragma.py
  73. 163
      slither/formatters/naming_convention/naming_convention.py
  74. 8
      slither/formatters/variables/unused_state_variables.py
  75. 37
      slither/slithir/operations/assignment.py
  76. 49
      slither/slithir/operations/binary.py
  77. 4
      slither/slithir/operations/internal_call.py
  78. 17
      slither/slithir/tmp_operations/argument.py

@ -16,6 +16,7 @@ from slither.core.declarations import (
FunctionContract,
)
from slither.core.declarations.solidity_import_placeholder import SolidityImportPlaceHolder
from slither.core.solidity_types.type import Type
from slither.core.variables.top_level_variable import TopLevelVariable
from slither.core.variables.variable import Variable
from slither.slithir.operations import Index, OperationWithLValue, InternalCall, Operation
@ -28,12 +29,10 @@ from slither.slithir.variables import (
TemporaryVariableSSA,
TupleVariableSSA,
)
from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
from slither.core.compilation_unit import SlitherCompilationUnit
###################################################################################
###################################################################################
# region User APIs
@ -41,7 +40,8 @@ if TYPE_CHECKING:
###################################################################################
Variable_types = Union[Variable, SolidityVariable]
SUPPORTED_TYPES = Union[Variable, SolidityVariable]
# TODO refactor the data deps to be better suited for top level function object
# Right now we allow to pass a node to ease the API, but we need something
# better
@ -51,8 +51,8 @@ Context_types = Union[Contract, Function]
def is_dependent(
variable: Variable_types,
source: Variable_types,
variable: SUPPORTED_TYPES,
source: SUPPORTED_TYPES,
context: Context_types_API,
only_unprotected: bool = False,
) -> bool:
@ -88,8 +88,8 @@ def is_dependent(
def is_dependent_ssa(
variable: Variable_types,
source: Variable_types,
variable: SUPPORTED_TYPES,
source: SUPPORTED_TYPES,
context: Context_types_API,
only_unprotected: bool = False,
) -> bool:
@ -131,7 +131,7 @@ GENERIC_TAINT = {
def is_tainted(
variable: Variable_types,
variable: SUPPORTED_TYPES,
context: Context_types_API,
only_unprotected: bool = False,
ignore_generic_taint: bool = False,
@ -164,7 +164,7 @@ def is_tainted(
def is_tainted_ssa(
variable: Variable_types,
variable: SUPPORTED_TYPES,
context: Context_types_API,
only_unprotected: bool = False,
ignore_generic_taint: bool = False,
@ -197,7 +197,7 @@ def is_tainted_ssa(
def get_dependencies(
variable: Variable_types,
variable: SUPPORTED_TYPES,
context: Context_types_API,
only_unprotected: bool = False,
) -> Set[Variable]:
@ -244,7 +244,7 @@ def get_all_dependencies(
def get_dependencies_ssa(
variable: Variable_types,
variable: SUPPORTED_TYPES,
context: Context_types_API,
only_unprotected: bool = False,
) -> Set[Variable]:
@ -459,7 +459,7 @@ def compute_dependency_function(function: Function) -> None:
)
def convert_variable_to_non_ssa(v: Variable_types) -> Variable_types:
def convert_variable_to_non_ssa(v: SUPPORTED_TYPES) -> SUPPORTED_TYPES:
if isinstance(
v,
(
@ -490,10 +490,10 @@ def convert_variable_to_non_ssa(v: Variable_types) -> Variable_types:
def convert_to_non_ssa(
data_depencies: Dict[Variable_types, Set[Variable_types]]
) -> Dict[Variable_types, Set[Variable_types]]:
data_depencies: Dict[SUPPORTED_TYPES, Set[SUPPORTED_TYPES]]
) -> Dict[SUPPORTED_TYPES, Set[SUPPORTED_TYPES]]:
# Need to create new set() as its changed during iteration
ret: Dict[Variable_types, Set[Variable_types]] = {}
ret: Dict[SUPPORTED_TYPES, Set[SUPPORTED_TYPES]] = {}
for (k, values) in data_depencies.items():
var = convert_variable_to_non_ssa(k)
if not var in ret:

@ -2,10 +2,10 @@
Detect if all the given variables are written in all the paths of the function
"""
from collections import defaultdict
from typing import Dict, Set, List
from typing import Dict, Set, List, Any, Optional
from slither.core.cfg.node import NodeType, Node
from slither.core.declarations import SolidityFunction
from slither.core.declarations import SolidityFunction, Function
from slither.core.variables.variable import Variable
from slither.slithir.operations import (
Index,
@ -18,7 +18,7 @@ from slither.slithir.variables import ReferenceVariable, TemporaryVariable
class State: # pylint: disable=too-few-public-methods
def __init__(self):
def __init__(self) -> None:
# Map node -> list of variables set
# Were each variables set represents a configuration of a path
# If two paths lead to the exact same set of variables written, we dont need to explore both
@ -34,11 +34,11 @@ class State: # pylint: disable=too-few-public-methods
# pylint: disable=too-many-branches
def _visit(
node: Node,
node: Optional[Node],
state: State,
variables_written: Set[Variable],
variables_to_write: List[Variable],
):
) -> List[Variable]:
"""
Explore all the nodes to look for values not written when the node's function return
Fixpoint reaches if no new written variables are found
@ -51,6 +51,8 @@ def _visit(
refs = {}
variables_written = set(variables_written)
if not node:
return []
for ir in node.irs:
if isinstance(ir, SolidityCall):
# TODO convert the revert to a THROW node
@ -70,17 +72,20 @@ def _visit(
if ir.lvalue and not isinstance(ir.lvalue, (TemporaryVariable, ReferenceVariable)):
variables_written.add(ir.lvalue)
lvalue = ir.lvalue
lvalue: Any = ir.lvalue
while isinstance(lvalue, ReferenceVariable):
if lvalue not in refs:
break
if refs[lvalue] and not isinstance(
refs[lvalue], (TemporaryVariable, ReferenceVariable)
refs_lvalues = refs[lvalue]
if (
refs_lvalues
and isinstance(refs_lvalues, Variable)
and not isinstance(refs_lvalues, (TemporaryVariable, ReferenceVariable))
):
variables_written.add(refs[lvalue])
lvalue = refs[lvalue]
variables_written.add(refs_lvalues)
lvalue = refs_lvalues
ret = []
ret: List[Variable] = []
if not node.sons and node.type not in [NodeType.THROW, NodeType.RETURN]:
ret += [v for v in variables_to_write if v not in variables_written]
@ -96,7 +101,7 @@ def _visit(
return ret
def are_variables_written(function, variables_to_write):
def are_variables_written(function: Function, variables_to_write: List[Variable]) -> List[Variable]:
"""
Return the list of variable that are not written at the end of the function

@ -19,5 +19,5 @@ class ChildExpression:
self._expression = expression
@property
def expression(self) -> Union["Expression", "Operation"]:
def expression(self) -> "Expression":
return self._expression # type: ignore

@ -455,7 +455,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
)
@property
def constructors(self) -> List["Function"]:
def constructors(self) -> List["FunctionContract"]:
"""
Return the list of constructors (including inherited)
"""

@ -23,16 +23,17 @@ class ArrayType(Type):
if length:
if isinstance(length, int):
length = Literal(length, ElementaryType("uint256"))
assert isinstance(length, Expression)
super().__init__()
self._type: Type = t
assert length is None or isinstance(length, Expression)
self._length: Optional[Expression] = length
if length:
if not isinstance(length, Literal):
cf = ConstantFolding(length, "uint256")
length = cf.result()
self._length_value = length
self._length_value: Optional[Literal] = length
else:
self._length_value = None

@ -59,7 +59,7 @@ ALL_SOLC_VERSIONS_06 = make_solc_versions(6, 0, 12)
ALL_SOLC_VERSIONS_07 = make_solc_versions(7, 0, 6)
# No VERSIONS_08 as it is still in dev
DETECTOR_INFO = Union[str, List[Union[str, SupportedOutput]]]
DETECTOR_INFO = List[Union[str, SupportedOutput]]
class AbstractDetector(metaclass=abc.ABCMeta):

@ -2,7 +2,9 @@
Module detecting constant functions
Recursively check the called functions
"""
from typing import List
from typing import List, Dict
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
@ -85,5 +87,5 @@ All the calls to `get` revert, breaking Bob's smart contract execution."""
return results
@staticmethod
def _format(comilation_unit, result):
def _format(comilation_unit: SlitherCompilationUnit, result: Dict) -> None:
custom_format(comilation_unit, result)

@ -2,11 +2,14 @@
Module detecting constant functions
Recursively check the called functions
"""
from typing import List
from typing import List, Dict
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
ALL_SOLC_VERSIONS_04,
DETECTOR_INFO,
)
from slither.formatters.attributes.const_functions import custom_format
from slither.utils.output import Output
@ -74,7 +77,7 @@ All the calls to `get` revert, breaking Bob's smart contract execution."""
if variables_written:
attr = "view" if f.view else "pure"
info = [
info: DETECTOR_INFO = [
f,
f" is declared {attr} but changes state variables:\n",
]
@ -89,5 +92,5 @@ All the calls to `get` revert, breaking Bob's smart contract execution."""
return results
@staticmethod
def _format(slither, result):
def _format(slither: SlitherCompilationUnit, result: Dict) -> None:
custom_format(slither, result)

@ -1,9 +1,14 @@
"""
Check that the same pragma is used in all the files
"""
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from typing import List, Dict
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.formatters.attributes.constant_pragma import custom_format
from slither.utils.output import Output
@ -31,7 +36,7 @@ class ConstantPragma(AbstractDetector):
versions = sorted(list(set(versions)))
if len(versions) > 1:
info = ["Different versions of Solidity are used:\n"]
info: DETECTOR_INFO = ["Different versions of Solidity are used:\n"]
info += [f"\t- Version used: {[str(v) for v in versions]}\n"]
for p in sorted(pragma, key=lambda x: x.version):
@ -44,5 +49,5 @@ class ConstantPragma(AbstractDetector):
return results
@staticmethod
def _format(slither, result):
def _format(slither: SlitherCompilationUnit, result: Dict) -> None:
custom_format(slither, result)

@ -5,7 +5,11 @@
import re
from typing import List, Optional, Tuple
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.formatters.attributes.incorrect_solc import custom_format
from slither.utils.output import Output
@ -143,7 +147,7 @@ Consider using the latest version of Solidity for testing."""
# If we found any disallowed pragmas, we output our findings.
if disallowed_pragmas:
for (reason, p) in disallowed_pragmas:
info = ["Pragma version", p, f" {reason}\n"]
info: DETECTOR_INFO = ["Pragma version", p, f" {reason}\n"]
json = self.generate_result(info)

@ -4,7 +4,11 @@
from typing import List
from slither.core.declarations.contract import Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import (
HighLevelCall,
LowLevelCall,
@ -85,7 +89,7 @@ Every Ether sent to `Locked` will be lost."""
funcs_payable = [function for function in contract.functions if function.payable]
if funcs_payable:
if self.do_no_send_ether(contract):
info = ["Contract locking ether found:\n"]
info: DETECTOR_INFO = ["Contract locking ether found:\n"]
info += ["\tContract ", contract, " has payable functions:\n"]
for function in funcs_payable:
info += ["\t - ", function, "\n"]

@ -5,7 +5,11 @@ Collect all the interfaces
Check for contracts which implement all interface functions but do not explicitly derive from those interfaces.
"""
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.core.declarations.contract import Contract
from slither.utils.output import Output
@ -139,7 +143,7 @@ contract Something {
continue
intended_interfaces = self.detect_unimplemented_interface(contract, interfaces)
for interface in intended_interfaces:
info = [contract, " should inherit from ", interface, "\n"]
info: DETECTOR_INFO = [contract, " should inherit from ", interface, "\n"]
res = self.generate_result(info)
results.append(res)
return results

@ -2,7 +2,11 @@
Detects the passing of arrays located in memory to functions which expect to modify arrays via storage reference.
"""
from typing import List, Set, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.core.solidity_types.array_type import ArrayType
from slither.core.variables.state_variable import StateVariable
from slither.core.variables.local_variable import LocalVariable
@ -164,7 +168,7 @@ As a result, Bob's usage of the contract is incorrect."""
if problematic_calls:
for calling_node, affected_argument, invoked_function in problematic_calls:
info = [
info: DETECTOR_INFO = [
calling_node.function,
" passes array ",
affected_argument,

@ -10,6 +10,7 @@ from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
make_solc_versions,
DETECTOR_INFO,
)
from slither.slithir.operations import TypeConversion
from slither.core.declarations.enum import Enum
@ -73,10 +74,14 @@ Attackers can trigger unexpected behaviour by calling `bug(1)`."""
for c in self.compilation_unit.contracts:
ret = _detect_dangerous_enum_conversions(c)
for node, var in ret:
func_info = [node, " has a dangerous enum conversion\n"]
func_info: DETECTOR_INFO = [node, " has a dangerous enum conversion\n"]
# Output each node with the function info header as a separate result.
variable_info = ["\t- Variable: ", var, f" of type: {str(var.type)}\n"]
node_info = ["\t- Enum conversion: ", node, "\n"]
variable_info: DETECTOR_INFO = [
"\t- Variable: ",
var,
f" of type: {str(var.type)}\n",
]
node_info: DETECTOR_INFO = ["\t- Enum conversion: ", node, "\n"]
json = self.generate_result(func_info + variable_info + node_info)
results.append(json)

@ -1,6 +1,10 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -58,7 +62,10 @@ In Solidity [0.4.22](https://github.com/ethereum/solidity/releases/tag/v0.4.23),
# If there is more than one, we encountered the described issue occurring.
if constructors and len(constructors) > 1:
info = [contract, " contains multiple constructors in the same contract:\n"]
info: DETECTOR_INFO = [
contract,
" contains multiple constructors in the same contract:\n",
]
for constructor in constructors:
info += ["\t- ", constructor, "\n"]

@ -6,6 +6,7 @@ from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
ALL_SOLC_VERSIONS_04,
DETECTOR_INFO,
)
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
@ -151,7 +152,7 @@ The constructor of `A` is called multiple times in `D` and `E`:
continue
# Generate data to output.
info = [
info: DETECTOR_INFO = [
contract,
" gives base constructor ",
base_constructor,

@ -6,6 +6,7 @@ from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
make_solc_versions,
DETECTOR_INFO,
)
from slither.core.solidity_types import ArrayType
from slither.core.solidity_types import UserDefinedType
@ -122,7 +123,13 @@ contract A {
for contract in self.contracts:
storage_abiencoderv2_arrays = self._detect_storage_abiencoderv2_arrays(contract)
for function, node in storage_abiencoderv2_arrays:
info = ["Function ", function, " trigger an abi encoding bug:\n\t- ", node, "\n"]
info: DETECTOR_INFO = [
"Function ",
function,
" trigger an abi encoding bug:\n\t- ",
node,
"\n",
]
res = self.generate_result(info)
results.append(res)

@ -1,18 +1,21 @@
"""
Module detecting storage signed integer array bug
"""
from typing import List
from typing import List, Tuple, Set
from slither.core.declarations import Function, Contract
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
make_solc_versions,
DETECTOR_INFO,
)
from slither.core.cfg.node import NodeType
from slither.core.cfg.node import NodeType, Node
from slither.core.solidity_types import ArrayType
from slither.core.solidity_types.elementary_type import Int, ElementaryType
from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable
from slither.slithir.operations import Operation, OperationWithLValue
from slither.slithir.operations.assignment import Assignment
from slither.slithir.operations.init_array import InitArray
from slither.utils.output import Output
@ -60,7 +63,7 @@ contract A {
VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 7, 25) + make_solc_versions(5, 0, 9)
@staticmethod
def _is_vulnerable_type(ir):
def _is_vulnerable_type(ir: Operation) -> bool:
"""
Detect if the IR lvalue is a vulnerable type
Must be a storage allocation, and an array of Int
@ -68,23 +71,28 @@ contract A {
"""
# Storage allocation
# Base type is signed integer
if not isinstance(ir, OperationWithLValue):
return False
return (
(
isinstance(ir.lvalue, StateVariable)
or (isinstance(ir.lvalue, LocalVariable) and ir.lvalue.is_storage)
)
and isinstance(ir.lvalue.type.type, ElementaryType)
and ir.lvalue.type.type.type in Int
and isinstance(ir.lvalue.type.type, ElementaryType) # type: ignore
and ir.lvalue.type.type.type in Int # type: ignore
)
def detect_storage_signed_integer_arrays(self, contract):
def detect_storage_signed_integer_arrays(
self, contract: Contract
) -> Set[Tuple[Function, Node]]:
"""
Detects and returns all nodes with storage-allocated signed integer array init/assignment
:param contract: Contract to detect within
:return: A list of tuples with (function, node) where function node has storage-allocated signed integer array init/assignment
"""
# Create our result set.
results = set()
results: Set[Tuple[Function, Node]] = set()
# Loop for each function and modifier.
for function in contract.functions_and_modifiers_declared:
@ -118,9 +126,13 @@ contract A {
for contract in self.contracts:
storage_signed_integer_arrays = self.detect_storage_signed_integer_arrays(contract)
for function, node in storage_signed_integer_arrays:
contract_info = ["Contract ", contract, " \n"]
function_info = ["\t- Function ", function, "\n"]
node_info = ["\t\t- ", node, " has a storage signed integer array assignment\n"]
contract_info: DETECTOR_INFO = ["Contract ", contract, " \n"]
function_info: DETECTOR_INFO = ["\t- Function ", function, "\n"]
node_info: DETECTOR_INFO = [
"\t\t- ",
node,
" has a storage signed integer array assignment\n",
]
res = self.generate_result(contract_info + function_info + node_info)
results.append(res)

@ -6,6 +6,7 @@ from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
make_solc_versions,
DETECTOR_INFO,
)
from slither.slithir.operations import InternalDynamicCall, OperationWithLValue
from slither.slithir.variables import ReferenceVariable
@ -115,10 +116,10 @@ The call to `a(10)` will lead to unexpected behavior because function pointer `a
results = []
for contract in self.compilation_unit.contracts:
contract_info = ["Contract ", contract, " \n"]
contract_info: DETECTOR_INFO = ["Contract ", contract, " \n"]
nodes = self._detect_uninitialized_function_ptr_in_constructor(contract)
for node in nodes:
node_info = [
node_info: DETECTOR_INFO = [
"\t ",
node,
" is an unintialized function pointer call in a constructor\n",

@ -6,7 +6,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -109,7 +113,7 @@ contract Token{
functions = IncorrectERC20InterfaceDetection.detect_incorrect_erc20_interface(c)
if functions:
for function in functions:
info = [
info: DETECTOR_INFO = [
c,
" has incorrect ERC20 function interface:",
function,

@ -2,7 +2,11 @@
Detect incorrect erc721 interface.
"""
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
@ -119,7 +123,7 @@ contract Token{
functions = IncorrectERC721InterfaceDetection.detect_incorrect_erc721_interface(c)
if functions:
for function in functions:
info = [
info: DETECTOR_INFO = [
c,
" has incorrect ERC721 function interface:",
function,

@ -1,6 +1,10 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -28,7 +32,7 @@ class Backdoor(AbstractDetector):
for f in contract.functions:
if "backdoor" in f.name:
# Info to be printed
info = ["Backdoor function found in ", f, "\n"]
info: DETECTOR_INFO = ["Backdoor function found in ", f, "\n"]
# Add the result in result
res = self.generate_result(info)

@ -18,7 +18,9 @@ from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.solidity_variables import (
SolidityFunction,
SolidityVariableComposed,
SolidityVariable,
)
from slither.core.variables import Variable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import (
HighLevelCall,
@ -72,8 +74,9 @@ def arbitrary_send(func: Function) -> Union[bool, List[Node]]:
):
continue
if is_tainted(ir.destination, node):
ret.append(node)
if isinstance(ir.destination, (Variable, SolidityVariable)):
if is_tainted(ir.destination, node):
ret.append(node)
return ret

@ -1,7 +1,11 @@
from typing import List, Tuple
from slither.core.declarations import Function
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.code_complexity import compute_cyclomatic_complexity
from slither.utils.output import Output
@ -44,7 +48,7 @@ class CyclomaticComplexity(AbstractDetector):
_check_for_high_cc(high_cc_functions, f)
for f, cc in high_cc_functions:
info = [f, f" has a high cyclomatic complexity ({cc}).\n"]
info: DETECTOR_INFO = [f, f" has a high cyclomatic complexity ({cc}).\n"]
res = self.generate_result(info)
results.append(res)
return results

@ -4,7 +4,11 @@ Module detecting dead code
from typing import List, Tuple
from slither.core.declarations import Function, FunctionContract, Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -72,7 +76,7 @@ contract Contract{
# Continue if the functon is not implemented because it means the contract is abstract
if not function.is_implemented:
continue
info = [function, " is never used and should be removed\n"]
info: DETECTOR_INFO = [function, " is never used and should be removed\n"]
res = self.generate_result(info)
results.append(res)

@ -6,7 +6,11 @@ are in the outermost scope, they do not guarantee a revert, so a
default value can still be returned.
"""
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.core.cfg.node import Node, NodeType
from slither.utils.output import Output
@ -82,7 +86,11 @@ If the condition in `myModif` is false, the execution of `get()` will return 0."
node = None
else:
# Nothing was found in the outer scope
info = ["Modifier ", mod, " does not always execute _; or revert"]
info: DETECTOR_INFO = [
"Modifier ",
mod,
" does not always execute _; or revert",
]
res = self.generate_result(info)
results.append(res)

@ -6,7 +6,11 @@ from typing import Union, List
from slither.core.declarations import Function
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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.function import get_function_id
from slither.utils.output import Output
@ -63,7 +67,7 @@ contract Contract{
assert isinstance(func_or_var, StateVariable)
incorrect_return_type = func_or_var.type != ElementaryType("bytes32")
if hash_collision or incorrect_return_type:
info = [
info: DETECTOR_INFO = [
"The function signature of ",
func_or_var,
" collides with DOMAIN_SEPARATOR and should be renamed or removed.\n",

@ -6,7 +6,11 @@ A suicidal contract is an unprotected function that calls selfdestruct
from typing import List
from slither.core.declarations import Function, Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -58,7 +62,7 @@ contract Buggy{
self.logger.error(f"{function_sig} not found")
continue
if function_protection not in function.all_internal_calls():
info = [
info: DETECTOR_INFO = [
function,
" should have ",
function_protection,

@ -7,7 +7,11 @@ from typing import List
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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -78,7 +82,7 @@ Bob calls `kill` and destructs the contract."""
functions = self.detect_suicidal(c)
for func in functions:
info = [func, " allows anyone to destruct the contract\n"]
info: DETECTOR_INFO = [func, " allows anyone to destruct the contract\n"]
res = self.generate_result(info)

@ -8,7 +8,13 @@ Consider public state variables as implemented functions
Do not consider fallback function or constructor
"""
from typing import List, Set
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations import Function
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
@ -62,7 +68,7 @@ All unimplemented functions must be implemented on a contract that is meant to b
def _match_state_variable(contract: Contract, f: FunctionContract) -> bool:
return any(s.full_name == f.full_name for s in contract.state_variables)
def _detect_unimplemented_function(self, contract: Contract) -> Set[FunctionContract]:
def _detect_unimplemented_function(self, contract: Contract) -> Set[Function]:
"""
Detects any function definitions which are not implemented in the given contract.
:param contract: The contract to search unimplemented functions for.
@ -77,6 +83,8 @@ All unimplemented functions must be implemented on a contract that is meant to b
# fallback function and constructor.
unimplemented = set()
for f in contract.all_functions_called:
if not isinstance(f, Function):
continue
if (
not f.is_implemented
and not f.is_constructor
@ -102,7 +110,7 @@ All unimplemented functions must be implemented on a contract that is meant to b
for contract in self.compilation_unit.contracts_derived:
functions = self._detect_unimplemented_function(contract)
if functions:
info = [contract, " does not implement functions:\n"]
info: DETECTOR_INFO = [contract, " does not implement functions:\n"]
for function in sorted(functions, key=lambda x: x.full_name):
info += ["\t- ", function, "\n"]

@ -1,6 +1,10 @@
import re
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.formatters.naming_convention.naming_convention import custom_format
from slither.utils.output import Output
@ -63,6 +67,7 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
def _detect(self) -> List[Output]:
results = []
info: DETECTOR_INFO
for contract in self.contracts:
if not self.is_cap_words(contract.name):

@ -50,14 +50,17 @@ def contains_bad_PRNG_sources(func: Function, blockhash_ret_values: List[Variabl
for node in func.nodes:
for ir in node.irs_ssa:
if isinstance(ir, Binary) and ir.type == BinaryType.MODULO:
var_left = ir.variable_left
if not isinstance(var_left, (Variable, SolidityVariable)):
continue
if is_dependent_ssa(
ir.variable_left, SolidityVariableComposed("block.timestamp"), func.contract
) or is_dependent_ssa(ir.variable_left, SolidityVariable("now"), func.contract):
var_left, SolidityVariableComposed("block.timestamp"), node
) or is_dependent_ssa(var_left, SolidityVariable("now"), node):
ret.add(node)
break
for ret_val in blockhash_ret_values:
if is_dependent_ssa(ir.variable_left, ret_val, func.contract):
if is_dependent_ssa(var_left, ret_val, node):
ret.add(node)
break
return list(ret)

@ -6,12 +6,17 @@ from typing import List, Tuple
from slither.analyses.data_dependency.data_dependency import is_dependent
from slither.core.cfg.node import Node
from slither.core.declarations import Function, Contract
from slither.core.declarations import Function, Contract, FunctionContract
from slither.core.declarations.solidity_variables import (
SolidityVariableComposed,
SolidityVariable,
)
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.variables import Variable
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import Binary, BinaryType
from slither.utils.output import Output
@ -21,25 +26,25 @@ def _timestamp(func: Function) -> List[Node]:
for node in func.nodes:
if node.contains_require_or_assert():
for var in node.variables_read:
if is_dependent(var, SolidityVariableComposed("block.timestamp"), func.contract):
if is_dependent(var, SolidityVariableComposed("block.timestamp"), node):
ret.add(node)
if is_dependent(var, SolidityVariable("now"), func.contract):
if is_dependent(var, SolidityVariable("now"), node):
ret.add(node)
for ir in node.irs:
if isinstance(ir, Binary) and BinaryType.return_bool(ir.type):
for var in ir.read:
if is_dependent(
var, SolidityVariableComposed("block.timestamp"), func.contract
):
for var_read in ir.read:
if not isinstance(var_read, (Variable, SolidityVariable)):
continue
if is_dependent(var_read, SolidityVariableComposed("block.timestamp"), node):
ret.add(node)
if is_dependent(var, SolidityVariable("now"), func.contract):
if is_dependent(var_read, SolidityVariable("now"), node):
ret.add(node)
return sorted(list(ret), key=lambda x: x.node_id)
def _detect_dangerous_timestamp(
contract: Contract,
) -> List[Tuple[Function, List[Node]]]:
) -> List[Tuple[FunctionContract, List[Node]]]:
"""
Args:
contract (Contract)
@ -48,7 +53,7 @@ def _detect_dangerous_timestamp(
"""
ret = []
for f in [f for f in contract.functions if f.contract_declarer == contract]:
nodes = _timestamp(f)
nodes: List[Node] = _timestamp(f)
if nodes:
ret.append((f, nodes))
return ret
@ -78,7 +83,7 @@ class Timestamp(AbstractDetector):
dangerous_timestamp = _detect_dangerous_timestamp(c)
for (func, nodes) in dangerous_timestamp:
info = [func, " uses timestamp for comparisons\n"]
info: DETECTOR_INFO = [func, " uses timestamp for comparisons\n"]
info += ["\tDangerous comparisons:\n"]

@ -2,7 +2,11 @@
Module detecting usage of low level calls
"""
from typing import List, Tuple
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import LowLevelCall
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
@ -52,7 +56,7 @@ class LowLevelCalls(AbstractDetector):
for c in self.contracts:
values = self.detect_low_level_calls(c)
for func, nodes in values:
info = ["Low level call in ", func, ":\n"]
info: DETECTOR_INFO = ["Low level call in ", func, ":\n"]
# sort the nodes to get deterministic results
nodes.sort(key=lambda x: x.node_id)

@ -11,7 +11,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations.event_call import EventCall
from slither.utils.output import Output
@ -100,7 +104,7 @@ contract C {
for contract in self.compilation_unit.contracts_derived:
missing_events = self._detect_missing_events(contract)
for (function, nodes) in missing_events:
info = [function, " should emit an event for: \n"]
info: DETECTOR_INFO = [function, " should emit an event for: \n"]
for (node, _sv, _mod) in nodes:
info += ["\t- ", node, " \n"]
res = self.generate_result(info)

@ -10,7 +10,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations.event_call import EventCall
from slither.utils.output import Output
@ -122,7 +126,7 @@ contract C {
for contract in self.compilation_unit.contracts_derived:
missing_events = self._detect_missing_events(contract)
for (function, nodes) in missing_events:
info = [function, " should emit an event for: \n"]
info: DETECTOR_INFO = [function, " should emit an event for: \n"]
for (node, _) in nodes:
info += ["\t- ", node, " \n"]
res = self.generate_result(info)

@ -12,7 +12,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import Call
from slither.slithir.operations import Send, Transfer, LowLevelCall
from slither.utils.output import Output
@ -155,7 +159,7 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
missing_zero_address_validation = self._detect_missing_zero_address_validation(contract)
for (_, var_nodes) in missing_zero_address_validation:
for var, nodes in var_nodes.items():
info = [var, " lacks a zero-check on ", ":\n"]
info: DETECTOR_INFO = [var, " lacks a zero-check on ", ":\n"]
for node in nodes:
info += ["\t\t- ", node, "\n"]
res = self.generate_result(info)

@ -7,7 +7,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import HighLevelCall
from slither.slithir.operations.operation import Operation
from slither.utils.output import Output
@ -91,7 +95,7 @@ contract MyConc{
if unused_return:
for node in unused_return:
info = [f, " ignores return value by ", node, "\n"]
info: DETECTOR_INFO = [f, " ignores return value by ", node, "\n"]
res = self.generate_result(info)

@ -1,6 +1,10 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import Nop
from slither.utils.output import Output
@ -39,7 +43,7 @@ When reading `B`'s constructor definition, we might assume that `A()` initiates
for constructor_call in cst.explicit_base_constructor_calls_statements:
for node in constructor_call.nodes:
if any(isinstance(ir, Nop) for ir in node.irs):
info = ["Void constructor called in ", cst, ":\n"]
info: DETECTOR_INFO = ["Void constructor called in ", cst, ":\n"]
info += ["\t- ", node, "\n"]
res = self.generate_result(info)

@ -4,7 +4,11 @@ from typing import Dict, List
from slither.analyses.data_dependency.data_dependency import is_dependent
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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import LowLevelCall, HighLevelCall
from slither.utils.output import Output
@ -88,7 +92,7 @@ If you do, ensure your users are aware of the potential issues."""
for contract in self.compilation_unit.contracts_derived:
vulns = _detect_token_reentrant(contract)
for function, nodes in vulns.items():
info = [function, " is an reentrancy unsafe token function:\n"]
info: DETECTOR_INFO = [function, " is an reentrancy unsafe token function:\n"]
for node in nodes:
info += ["\t-", node, "\n"]
json = self.generate_result(info)

@ -9,7 +9,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -194,7 +198,7 @@ contract Bug {
shadow_type = shadow[0]
shadow_object = shadow[1]
info = [
info: DETECTOR_INFO = [
shadow_object,
f' ({shadow_type}) shadows built-in symbol"\n',
]

@ -9,7 +9,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -84,7 +88,7 @@ contract Bug {
] = []
# Loop through all functions + modifiers in this contract.
for function in contract.functions + contract.modifiers:
for function in contract.functions + list(contract.modifiers):
# We should only look for functions declared directly in this contract (not in a base contract).
if function.contract_declarer != contract:
continue
@ -134,7 +138,7 @@ contract Bug {
for shadow in shadows:
local_variable = shadow[0]
overshadowed = shadow[1]
info = [local_variable, " shadows:\n"]
info: DETECTOR_INFO = [local_variable, " shadows:\n"]
for overshadowed_entry in overshadowed:
info += [
"\t- ",

@ -6,7 +6,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.detectors.shadowing.common import is_upgradable_gap_variable
from slither.utils.output import Output
@ -89,7 +93,7 @@ contract DerivedContract is BaseContract{
for all_variables in shadowing:
shadow = all_variables[0]
variables = all_variables[1:]
info = [shadow, " shadows:\n"]
info: DETECTOR_INFO = [shadow, " shadows:\n"]
for var in variables:
info += ["\t- ", var, "\n"]

@ -2,7 +2,11 @@ from collections import defaultdict
from typing import Any, List
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -80,7 +84,7 @@ As a result, the second contract cannot be analyzed.
inheritance_corrupted[father.name].append(contract)
for contract_name, files in names_reused.items():
info = [contract_name, " is re-used:\n"]
info: DETECTOR_INFO = [contract_name, " is re-used:\n"]
for file in files:
if file is None:
info += ["\t- In an file not found, most likely in\n"]

@ -1,7 +1,11 @@
import re
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -78,7 +82,7 @@ contract Token
idx = start_index + result_index
relative = self.slither.crytic_compile.filename_lookup(filename).relative
info = f"{relative} contains a unicode right-to-left-override character at byte offset {idx}:\n"
info: DETECTOR_INFO = f"{relative} contains a unicode right-to-left-override character at byte offset {idx}:\n"
# We have a patch, so pattern.find will return at least one result

@ -1,13 +1,14 @@
"""
Module detecting assignment of array length
"""
from typing import List, Set
from typing import List, Set, Union
from slither.core.variables import Variable
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
ALL_SOLC_VERSIONS_04,
ALL_SOLC_VERSIONS_05,
DETECTOR_INFO,
)
from slither.core.cfg.node import Node, NodeType
from slither.slithir.operations import Assignment, Length
@ -15,7 +16,7 @@ from slither.slithir.variables.reference import ReferenceVariable
from slither.slithir.operations.binary import Binary
from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.core.declarations.contract import Contract
from slither.utils.output import Output
from slither.utils.output import Output, SupportedOutput
def detect_array_length_assignment(contract: Contract) -> Set[Node]:
@ -51,7 +52,7 @@ def detect_array_length_assignment(contract: Contract) -> Set[Node]:
elif isinstance(ir, (Assignment, Binary)):
if isinstance(ir.lvalue, ReferenceVariable):
if ir.lvalue in array_length_refs and any(
is_tainted(v, contract) for v in ir.read
is_tainted(v, contract) for v in ir.read if isinstance(v, Variable)
):
# the taint is not precise enough yet
# as a result, REF_0 = REF_0 + 1
@ -121,12 +122,16 @@ Otherwise, thoroughly review the contract to ensure a user-controlled variable c
for contract in self.contracts:
array_length_assignments = detect_array_length_assignment(contract)
if array_length_assignments:
contract_info: DETECTOR_INFO = [
contract_info: List[Union[str, SupportedOutput]] = [
contract,
" contract sets array length with a user-controlled value:\n",
]
for node in array_length_assignments:
node_info = contract_info + ["\t- ", node, "\n"]
node_info: List[Union[str, SupportedOutput]] = contract_info + [
"\t- ",
node,
"\n",
]
res = self.generate_result(node_info)
results.append(res)

@ -6,7 +6,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations.internal_call import InternalCall
from slither.utils.output import Output
@ -25,7 +29,7 @@ def detect_assert_state_change(
results = []
# Loop for each function and modifier.
for function in contract.functions_declared + contract.modifiers_declared:
for function in contract.functions_declared + list(contract.modifiers_declared):
for node in function.nodes:
# Detect assert() calls
if any(c.name == "assert(bool)" for c in node.internal_calls) and (
@ -85,7 +89,10 @@ The assert in `bad()` increments the state variable `s_a` while checking for the
for contract in self.contracts:
assert_state_change = detect_assert_state_change(contract)
for (func, node) in assert_state_change:
info = [func, " has an assert() call which possibly changes state.\n"]
info: DETECTOR_INFO = [
func,
" has an assert() call which possibly changes state.\n",
]
info += ["\t-", node, "\n"]
info += [
"Consider using require() or change the invariant to not modify the state.\n"

@ -6,7 +6,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import (
Binary,
BinaryType,
@ -84,7 +88,7 @@ Boolean constants can be used directly and do not need to be compare to `true` o
boolean_constant_misuses = self._detect_boolean_equality(contract)
for (func, nodes) in boolean_constant_misuses:
for node in nodes:
info = [
info: DETECTOR_INFO = [
func,
" compares to a boolean constant:\n\t-",
node,

@ -7,7 +7,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import (
Assignment,
Call,
@ -120,7 +124,7 @@ Other uses (in complex expressions, as conditionals) indicate either an error or
boolean_constant_misuses = self._detect_boolean_constant_misuses(contract)
for (func, nodes) in boolean_constant_misuses:
for node in nodes:
info = [
info: DETECTOR_INFO = [
func,
" uses a Boolean constant improperly:\n\t-",
node,

@ -1,6 +1,10 @@
from typing import List, Optional
from slither.core.cfg.node import NodeType, Node
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.core.declarations import Contract
from slither.utils.output import Output
from slither.slithir.operations import (
@ -94,7 +98,7 @@ If one of the destinations has a fallback function that reverts, `bad` will alwa
for node in values:
func = node.function
info = [func, " has external calls inside a loop: ", node, "\n"]
info: DETECTOR_INFO = [func, " has external calls inside a loop: ", node, "\n"]
res = self.generate_result(info)
results.append(res)

@ -3,7 +3,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import LowLevelCall
from slither.utils.output import Output
@ -58,13 +62,13 @@ Bob calls `delegate` and delegates the execution to his malicious contract. As a
continue
nodes = controlled_delegatecall(f)
if nodes:
func_info = [
func_info: DETECTOR_INFO = [
f,
" uses delegatecall to a input-controlled function id\n",
]
for node in nodes:
node_info = func_info + ["\t- ", node, "\n"]
node_info: DETECTOR_INFO = func_info + ["\t- ", node, "\n"]
res = self.generate_result(node_info)
results.append(res)

@ -1,6 +1,10 @@
from typing import List, Optional
from slither.core.cfg.node import NodeType, Node
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.core.declarations import Contract
from slither.utils.output import Output
from slither.slithir.operations import InternalCall, OperationWithLValue
@ -98,7 +102,7 @@ Incrementing `state_variable` in a loop incurs a lot of gas because of expensive
values = detect_costly_operations_in_loop(c)
for node in values:
func = node.function
info = [func, " has costly operations inside a loop:\n"]
info: DETECTOR_INFO = [func, " has costly operations inside a loop:\n"]
info += ["\t- ", node, "\n"]
res = self.generate_result(info)
results.append(res)

@ -1,6 +1,10 @@
from typing import List, Optional
from slither.core.cfg.node import NodeType, Node
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import LowLevelCall, InternalCall
from slither.core.declarations import Contract
from slither.utils.output import Output
@ -94,7 +98,12 @@ Carefully check that the function called by `delegatecall` is not payable/doesn'
for node in values:
func = node.function
info = [func, " has delegatecall inside a loop in a payable function: ", node, "\n"]
info: DETECTOR_INFO = [
func,
" has delegatecall inside a loop in a payable function: ",
node,
"\n",
]
res = self.generate_result(info)
results.append(res)

@ -11,7 +11,11 @@ from slither.core.declarations.solidity_variables import (
)
from slither.core.expressions.expression import Expression
from slither.core.variables import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import LowLevelCall
from slither.utils.output import Output
from slither.visitors.expression.export_values import ExportValues
@ -186,7 +190,7 @@ contract ContractWithDeprecatedReferences {
for deprecated_reference in deprecated_references:
source_object = deprecated_reference[0]
deprecated_entries = deprecated_reference[1]
info = ["Deprecated standard detected ", source_object, ":\n"]
info: DETECTOR_INFO = ["Deprecated standard detected ", source_object, ":\n"]
for (_dep_id, original_desc, recommended_disc) in deprecated_entries:
info += [

@ -2,13 +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
from typing import 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.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import Binary, Assignment, BinaryType, LibraryCall, Operation
from slither.slithir.utils.utils import LVALUE
from slither.slithir.variables import Constant
from slither.utils.output import Output
@ -19,7 +24,7 @@ def is_division(ir: Operation) -> bool:
return True
if isinstance(ir, LibraryCall):
if ir.function.name.lower() in [
if ir.function.name and ir.function.name.lower() in [
"div",
"safediv",
]:
@ -35,7 +40,7 @@ def is_multiplication(ir: Operation) -> bool:
return True
if isinstance(ir, LibraryCall):
if ir.function.name.lower() in [
if ir.function.name and ir.function.name.lower() in [
"mul",
"safemul",
]:
@ -58,7 +63,7 @@ def is_assert(node: Node) -> bool:
# pylint: disable=too-many-branches
def _explore(
to_explore: Set[Node], f_results: List[Node], divisions: DefaultDict[Any, Any]
to_explore: Set[Node], f_results: List[List[Node]], divisions: DefaultDict[LVALUE, List[Node]]
) -> None:
explored = set()
while to_explore: # pylint: disable=too-many-nested-blocks
@ -70,22 +75,22 @@ def _explore(
equality_found = False
# List of nodes related to one bug instance
node_results = []
node_results: List[Node] = []
for ir in node.irs:
if isinstance(ir, Assignment):
if ir.rvalue in divisions:
# Avoid dupplicate. We dont use set so we keep the order of the nodes
if node not in divisions[ir.rvalue]:
divisions[ir.lvalue] = divisions[ir.rvalue] + [node]
if node not in divisions[ir.rvalue]: # type: ignore
divisions[ir.lvalue] = divisions[ir.rvalue] + [node] # type: ignore
else:
divisions[ir.lvalue] = divisions[ir.rvalue]
divisions[ir.lvalue] = divisions[ir.rvalue] # type: ignore
if is_division(ir):
divisions[ir.lvalue] = [node]
divisions[ir.lvalue] = [node] # type: ignore
if is_multiplication(ir):
mul_arguments = ir.read if isinstance(ir, Binary) else ir.arguments
mul_arguments = ir.read if isinstance(ir, Binary) else ir.arguments # type: ignore
nodes = []
for r in mul_arguments:
if not isinstance(r, Constant) and (r in divisions):
@ -125,7 +130,7 @@ def detect_divide_before_multiply(
# List of tuple (function -> list(list(nodes)))
# Each list(nodes) of the list is one bug instances
# Each node in the list(nodes) is involved in the bug
results = []
results: List[Tuple[FunctionContract, List[Node]]] = []
# Loop for each function and modifier.
for function in contract.functions_declared:
@ -134,11 +139,11 @@ def detect_divide_before_multiply(
# List of list(nodes)
# Each list(nodes) is one bug instances
f_results = []
f_results: List[List[Node]] = []
# lvalue -> node
# track all the division results (and the assignment of the division results)
divisions = defaultdict(list)
divisions: DefaultDict[LVALUE, List[Node]] = defaultdict(list)
_explore({function.entry_point}, f_results, divisions)
@ -190,7 +195,7 @@ In general, it's usually a good idea to re-arrange arithmetic to perform multipl
if divisions_before_multiplications:
for (func, nodes) in divisions_before_multiplications:
info = [
info: DETECTOR_INFO = [
func,
" performs a multiplication on the result of a division:\n",
]

@ -8,7 +8,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import Delete
from slither.utils.output import Output
@ -83,7 +87,7 @@ The mapping `balances` is never deleted, so `remove` does not work as intended."
for c in self.contracts:
mapping = MappingDeletionDetection.detect_mapping_deletion(c)
for (func, struct, node) in mapping:
info = [func, " deletes ", struct, " which contains a mapping:\n"]
info: DETECTOR_INFO = [func, " deletes ", struct, " which contains a mapping:\n"]
info += ["\t-", node, "\n"]
res = self.generate_result(info)

@ -1,6 +1,10 @@
from typing import List, Optional
from slither.core.cfg.node import NodeType, Node
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import InternalCall
from slither.core.declarations import SolidityVariableComposed, Contract
from slither.utils.output import Output
@ -86,7 +90,7 @@ Track msg.value through a local variable and decrease its amount on every iterat
for node in values:
func = node.function
info = [func, " use msg.value in a loop: ", node, "\n"]
info: DETECTOR_INFO = [func, " use msg.value in a loop: ", node, "\n"]
res = self.generate_result(info)
results.append(res)

@ -7,7 +7,11 @@ 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.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -87,7 +91,13 @@ Each commented line references types/identifiers, but performs no action with th
if redundant_statements:
for redundant_statement in redundant_statements:
info = ['Redundant expression "', redundant_statement, '" in', contract, "\n"]
info: DETECTOR_INFO = [
'Redundant expression "',
redundant_statement,
'" in',
contract,
"\n",
]
json = self.generate_result(info)
results.append(json)

@ -7,7 +7,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.variables import Constant
from slither.utils.output import Output
@ -88,9 +92,9 @@ Use:
# iterate over all the nodes
ret = self._detect_too_many_digits(f)
if ret:
func_info = [f, " uses literals with too many digits:"]
func_info: DETECTOR_INFO = [f, " uses literals with too many digits:"]
for node in ret:
node_info = func_info + ["\n\t- ", node, "\n"]
node_info: DETECTOR_INFO = func_info + ["\n\t- ", node, "\n"]
# Add the result in result
res = self.generate_result(node_info)

@ -6,7 +6,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -80,7 +84,7 @@ Bob is the owner of `TxOrigin`. Bob calls Eve's contract. Eve's contract calls `
for func, nodes in values:
for node in nodes:
info = [func, " uses tx.origin for authorization: ", node, "\n"]
info: DETECTOR_INFO = [func, " uses tx.origin for authorization: ", node, "\n"]
res = self.generate_result(info)
results.append(res)

@ -17,10 +17,9 @@ def typeRange(t: str) -> Tuple[int, int]:
bits = int(t.split("int")[1])
if t in Uint:
return 0, (2**bits) - 1
if t in Int:
v = (2 ** (bits - 1)) - 1
return -v, v
return None
assert t in Int
v = (2 ** (bits - 1)) - 1
return -v, v
def _detect_tautology_or_contradiction(low: int, high: int, cval: int, op: BinaryType) -> bool:

@ -5,7 +5,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
from slither.visitors.expression.expression import ExpressionVisitor
@ -74,7 +78,10 @@ contract Bug{
variable.expression
and InvalidUnaryStateVariableDetector(variable.expression).result()
):
info = [variable, f" uses an dangerous unary operator: {variable.expression}\n"]
info: DETECTOR_INFO = [
variable,
f" uses an dangerous unary operator: {variable.expression}\n",
]
json = self.generate_result(info)
results.append(json)

@ -2,7 +2,11 @@ from typing import List
from slither.core.declarations import SolidityFunction, Function
from slither.core.declarations.contract import Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import LowLevelCall, SolidityCall
from slither.utils.output import Output
@ -110,17 +114,15 @@ Buggy is an upgradeable contract. Anyone can call initialize on the logic contra
item for sublist in vars_init_in_constructors_ for item in sublist
]
if vars_init and (set(vars_init) - set(vars_init_in_constructors)):
info = (
[
contract,
" is an upgradeable contract that does not protect its initialize functions: ",
]
+ initialize_functions
+ [
". Anyone can delete the contract with: ",
]
+ functions_that_can_destroy
)
info: DETECTOR_INFO = [
contract,
" is an upgradeable contract that does not protect its initialize functions: ",
]
info += initialize_functions
info += [
". Anyone can delete the contract with: ",
]
info += functions_that_can_destroy
res = self.generate_result(info)
results.append(res)

@ -4,7 +4,11 @@ from slither.core.cfg.node import Node, NodeType
from slither.core.solidity_types import ElementaryType
from slither.core.variables.state_variable import StateVariable
from slither.core.variables.variable import Variable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import (
OperationWithLValue,
HighLevelCall,
@ -128,10 +132,17 @@ class WriteAfterWrite(AbstractDetector):
for contract in self.compilation_unit.contracts_derived:
for function in contract.functions:
if function.entry_point:
ret = []
ret: List[Tuple[Variable, Node, Node]] = []
_detect_write_after_write(function.entry_point, set(), {}, ret)
for var, node1, node2 in ret:
info = [var, " is written in both\n\t", node1, "\n\t", node2, "\n"]
info: DETECTOR_INFO = [
var,
" is written in both\n\t",
node1,
"\n\t",
node2,
"\n",
]
res = self.generate_result(info)
results.append(res)

@ -6,7 +6,11 @@ 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.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
from slither.visitors.expression.export_values import ExportValues
@ -104,7 +108,7 @@ Special care must be taken when initializing state variables from an immediate f
state_variables = detect_function_init_state_vars(contract)
if state_variables:
for state_variable in state_variables:
info = [
info: DETECTOR_INFO = [
state_variable,
" is set pre-construction with a non-constant function or state variable:\n",
]

@ -7,7 +7,11 @@ from slither.core.cfg.node import Node
from slither.core.declarations import Function
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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -148,7 +152,7 @@ Additionally, the for-loop uses the variable `max`, which is declared in a previ
predeclared_usage_node,
predeclared_usage_local_variable,
) in predeclared_usage_nodes:
info = [
info: DETECTOR_INFO = [
"Variable '",
predeclared_usage_local_variable,
"' in ",

@ -7,7 +7,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.utils.output import Output
@ -86,7 +90,13 @@ class SimilarVarsDetection(AbstractDetector):
for (v1, v2) in sorted(allVars, key=lambda x: (x[0].name, x[1].name)):
v_left = v1 if v1.name < v2.name else v2
v_right = v2 if v_left == v1 else v1
info = ["Variable ", v_left, " is too similar to ", v_right, "\n"]
info: DETECTOR_INFO = [
"Variable ",
v_left,
" is too similar to ",
v_right,
"\n",
]
json = self.generate_result(info)
results.append(json)
return results

@ -14,7 +14,11 @@ 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.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations import InternalCall, LibraryCall
from slither.slithir.variables import ReferenceVariable
from slither.utils.output import Output
@ -140,7 +144,7 @@ Initialize all the variables. If a variable is meant to be initialized to zero,
ret = self._detect_uninitialized(c)
for variable, functions in ret:
info = [variable, " is never initialized. It is used in:\n"]
info: DETECTOR_INFO = [variable, " is never initialized. It is used in:\n"]
for f in functions:
info += ["\t- ", f, "\n"]

@ -1,13 +1,19 @@
"""
Module detecting unused state variables
"""
from typing import List, Optional
from typing import List, Optional, Dict
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.declarations import Function
from slither.core.declarations.contract import Contract
from slither.core.solidity_types import ArrayType
from slither.core.variables import Variable
from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.formatters.variables.unused_state_variables import custom_format
from slither.utils.output import Output
from slither.visitors.expression.export_values import ExportValues
@ -18,14 +24,19 @@ def detect_unused(contract: Contract) -> Optional[List[StateVariable]]:
return None
# Get all the variables read in all the functions and modifiers
all_functions = contract.all_functions_called + contract.modifiers
all_functions = [
f
for f in contract.all_functions_called + list(contract.modifiers)
if isinstance(f, Function)
]
variables_used = [x.state_variables_read for x in all_functions]
variables_used += [
x.state_variables_written for x in all_functions if not x.is_constructor_variables
]
array_candidates = [x.variables for x in all_functions]
array_candidates = [i for sl in array_candidates for i in sl] + contract.state_variables
array_candidates_ = [x.variables for x in all_functions]
array_candidates: List[Variable] = [i for sl in array_candidates_ for i in sl]
array_candidates += contract.state_variables
array_candidates = [
x.type.length for x in array_candidates if isinstance(x.type, ArrayType) and x.type.length
]
@ -65,12 +76,12 @@ class UnusedStateVars(AbstractDetector):
unusedVars = detect_unused(c)
if unusedVars:
for var in unusedVars:
info = [var, " is never used in ", c, "\n"]
info: DETECTOR_INFO = [var, " is never used in ", c, "\n"]
json = self.generate_result(info)
results.append(json)
return results
@staticmethod
def _format(compilation_unit: SlitherCompilationUnit, result):
def _format(compilation_unit: SlitherCompilationUnit, result: Dict) -> None:
custom_format(compilation_unit, result)

@ -2,7 +2,11 @@ from typing import List
from slither.core.cfg.node import Node
from slither.core.declarations import Function, SolidityVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
DETECTOR_INFO,
)
from slither.slithir.operations.high_level_call import HighLevelCall
from slither.utils.output import Output
@ -35,7 +39,7 @@ contract C {
for c in self.contracts:
for func in c.functions:
for node in self._detect_var_read_using_this(func):
info = [
info: DETECTOR_INFO = [
"The function ",
func,
" reads ",

@ -1,11 +1,12 @@
import re
from typing import Dict
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.formatters.exceptions import FormatError
from slither.formatters.utils.patches import create_patch
def custom_format(compilation_unit: SlitherCompilationUnit, result):
def custom_format(compilation_unit: SlitherCompilationUnit, result: Dict) -> None:
for file_scope in compilation_unit.scopes.values():
elements = result["elements"]
for element in elements:

@ -1,4 +1,7 @@
import re
from typing import Dict
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.formatters.exceptions import FormatImpossible
from slither.formatters.utils.patches import create_patch
@ -16,7 +19,7 @@ REPLACEMENT_VERSIONS = ["^0.4.25", "^0.5.3"]
PATTERN = re.compile(r"(\^|>|>=|<|<=)?([ ]+)?(\d+)\.(\d+)\.(\d+)")
def custom_format(slither, result):
def custom_format(slither: SlitherCompilationUnit, result: Dict) -> None:
elements = result["elements"]
versions_used = []
for element in elements:

@ -1,9 +1,10 @@
import re
import logging
from typing import List
from typing import List, Set, Dict, Union, Optional, Callable, Type, Sequence
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.variables import Variable
from slither.slithir.operations import (
Send,
Transfer,
@ -14,7 +15,7 @@ from slither.slithir.operations import (
InternalDynamicCall,
Operation,
)
from slither.core.declarations import Modifier
from slither.core.declarations import Modifier, Event
from slither.core.solidity_types import UserDefinedType, MappingType
from slither.core.declarations import Enum, Contract, Structure, Function
from slither.core.solidity_types.elementary_type import ElementaryTypeName
@ -29,7 +30,7 @@ logger = logging.getLogger("Slither.Format")
# pylint: disable=anomalous-backslash-in-string
def custom_format(compilation_unit: SlitherCompilationUnit, result):
def custom_format(compilation_unit: SlitherCompilationUnit, result: Dict) -> None:
elements = result["elements"]
for element in elements:
target = element["additional_fields"]["target"]
@ -129,24 +130,24 @@ SOLIDITY_KEYWORDS += [
SOLIDITY_KEYWORDS += ElementaryTypeName
def _name_already_use(slither, name):
def _name_already_use(slither: SlitherCompilationUnit, name: str) -> bool:
# Do not convert to a name used somewhere else
if not KEY in slither.context:
all_names = set()
all_names: Set[str] = set()
for contract in slither.contracts_derived:
all_names = all_names.union({st.name for st in contract.structures})
all_names = all_names.union({f.name for f in contract.functions_and_modifiers})
all_names = all_names.union({e.name for e in contract.enums})
all_names = all_names.union({s.name for s in contract.state_variables})
all_names = all_names.union({s.name for s in contract.state_variables if s.name})
for function in contract.functions:
all_names = all_names.union({v.name for v in function.variables})
all_names = all_names.union({v.name for v in function.variables if v.name})
slither.context[KEY] = all_names
return name in slither.context[KEY]
def _convert_CapWords(original_name, slither):
def _convert_CapWords(original_name: str, slither: SlitherCompilationUnit) -> str:
name = original_name.capitalize()
while "_" in name:
@ -162,10 +163,13 @@ def _convert_CapWords(original_name, slither):
return name
def _convert_mixedCase(original_name, compilation_unit: SlitherCompilationUnit):
name = original_name
if isinstance(name, bytes):
name = name.decode("utf8")
def _convert_mixedCase(
original_name: Union[str, bytes], compilation_unit: SlitherCompilationUnit
) -> str:
if isinstance(original_name, bytes):
name = original_name.decode("utf8")
else:
name = original_name
while "_" in name:
offset = name.find("_")
@ -174,13 +178,15 @@ def _convert_mixedCase(original_name, compilation_unit: SlitherCompilationUnit):
name = name[0].lower() + name[1:]
if _name_already_use(compilation_unit, name):
raise FormatImpossible(f"{original_name} cannot be converted to {name} (already used)")
raise FormatImpossible(f"{original_name} cannot be converted to {name} (already used)") # type: ignore
if name in SOLIDITY_KEYWORDS:
raise FormatImpossible(f"{original_name} cannot be converted to {name} (Solidity keyword)")
raise FormatImpossible(f"{original_name} cannot be converted to {name} (Solidity keyword)") # type: ignore
return name
def _convert_UPPER_CASE_WITH_UNDERSCORES(name, compilation_unit: SlitherCompilationUnit):
def _convert_UPPER_CASE_WITH_UNDERSCORES(
name: str, compilation_unit: SlitherCompilationUnit
) -> str:
if _name_already_use(compilation_unit, name.upper()):
raise FormatImpossible(f"{name} cannot be converted to {name.upper()} (already used)")
if name.upper() in SOLIDITY_KEYWORDS:
@ -188,7 +194,10 @@ def _convert_UPPER_CASE_WITH_UNDERSCORES(name, compilation_unit: SlitherCompilat
return name.upper()
conventions = {
TARGET_TYPE = Union[Contract, Variable, Function]
CONVENTION_F_TYPE = Callable[[str, SlitherCompilationUnit], str]
conventions: Dict[str, CONVENTION_F_TYPE] = {
"CapWords": _convert_CapWords,
"mixedCase": _convert_mixedCase,
"UPPER_CASE_WITH_UNDERSCORES": _convert_UPPER_CASE_WITH_UNDERSCORES,
@ -203,7 +212,9 @@ conventions = {
###################################################################################
def _get_from_contract(compilation_unit: SlitherCompilationUnit, element, name, getter):
def _get_from_contract(
compilation_unit: SlitherCompilationUnit, element: Dict, name: str, getter: str
) -> TARGET_TYPE:
scope = compilation_unit.get_scope(element["source_mapping"]["filename_absolute"])
contract_name = element["type_specific_fields"]["parent"]["name"]
contract = scope.get_contract_from_name(contract_name)
@ -218,9 +229,13 @@ def _get_from_contract(compilation_unit: SlitherCompilationUnit, element, name,
###################################################################################
def _patch(compilation_unit: SlitherCompilationUnit, result, element, _target):
def _patch(
compilation_unit: SlitherCompilationUnit, result: Dict, element: Dict, _target: str
) -> None:
scope = compilation_unit.get_scope(element["source_mapping"]["filename_absolute"])
target: Optional[TARGET_TYPE] = None
if _target == "contract":
target = scope.get_contract_from_name(element["name"])
@ -257,7 +272,9 @@ def _patch(compilation_unit: SlitherCompilationUnit, result, element, _target):
]
param_name = element["name"]
contract = scope.get_contract_from_name(contract_name)
assert contract
function = contract.get_function_from_full_name(function_sig)
assert function
target = function.get_local_variable_from_name(param_name)
elif _target in ["variable", "variable_constant"]:
@ -271,7 +288,9 @@ def _patch(compilation_unit: SlitherCompilationUnit, result, element, _target):
]
var_name = element["name"]
contract = scope.get_contract_from_name(contract_name)
assert contract
function = contract.get_function_from_full_name(function_sig)
assert function
target = function.get_local_variable_from_name(var_name)
# State variable
else:
@ -287,6 +306,7 @@ def _patch(compilation_unit: SlitherCompilationUnit, result, element, _target):
else:
raise FormatError("Unknown naming convention! " + _target)
assert target
_explore(
compilation_unit, result, target, conventions[element["additional_fields"]["convention"]]
)
@ -310,7 +330,7 @@ RE_MAPPING = (
)
def _is_var_declaration(slither, filename, start):
def _is_var_declaration(slither: SlitherCompilationUnit, filename: str, start: int) -> bool:
"""
Detect usage of 'var ' for Solidity < 0.5
:param slither:
@ -319,12 +339,19 @@ def _is_var_declaration(slither, filename, start):
:return:
"""
v = "var "
return slither.source_code[filename][start : start + len(v)] == v
return slither.core.source_code[filename][start : start + len(v)] == v
def _explore_type( # pylint: disable=too-many-arguments,too-many-locals,too-many-branches
slither, result, target, convert, custom_type, filename_source_code, start, end
):
slither: SlitherCompilationUnit,
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
custom_type: Optional[Union[Type, List[Type]]],
filename_source_code: str,
start: int,
end: int,
) -> None:
if isinstance(custom_type, UserDefinedType):
# Patch type based on contract/enum
if isinstance(custom_type.type, (Enum, Contract)):
@ -358,7 +385,7 @@ def _explore_type( # pylint: disable=too-many-arguments,too-many-locals,too-man
# Structure contain a list of elements, that might need patching
# .elems return a list of VariableStructure
_explore_variables_declaration(
slither, custom_type.type.elems.values(), result, target, convert
slither, list(custom_type.type.elems.values()), result, target, convert
)
if isinstance(custom_type, MappingType):
@ -377,7 +404,7 @@ def _explore_type( # pylint: disable=too-many-arguments,too-many-locals,too-man
full_txt_start = start
full_txt_end = end
full_txt = slither.source_code[filename_source_code].encode("utf8")[
full_txt = slither.core.source_code[filename_source_code].encode("utf8")[
full_txt_start:full_txt_end
]
re_match = re.match(RE_MAPPING, full_txt)
@ -417,14 +444,19 @@ def _explore_type( # pylint: disable=too-many-arguments,too-many-locals,too-man
def _explore_variables_declaration( # pylint: disable=too-many-arguments,too-many-locals,too-many-nested-blocks
slither, variables, result, target, convert, patch_comment=False
):
slither: SlitherCompilationUnit,
variables: Sequence[Variable],
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
patch_comment: bool = False,
) -> None:
for variable in variables:
# First explore the type of the variable
filename_source_code = variable.source_mapping.filename.absolute
full_txt_start = variable.source_mapping.start
full_txt_end = full_txt_start + variable.source_mapping.length
full_txt = slither.source_code[filename_source_code].encode("utf8")[
full_txt = slither.core.source_code[filename_source_code].encode("utf8")[
full_txt_start:full_txt_end
]
@ -442,6 +474,8 @@ def _explore_variables_declaration( # pylint: disable=too-many-arguments,too-ma
# If the variable is the target
if variable == target:
old_str = variable.name
if old_str is None:
old_str = ""
new_str = convert(old_str, slither)
loc_start = full_txt_start + full_txt.find(old_str.encode("utf8"))
@ -458,10 +492,10 @@ def _explore_variables_declaration( # pylint: disable=too-many-arguments,too-ma
idx = len(func.parameters) - func.parameters.index(variable) + 1
first_line = end_line - idx - 2
potential_comments = slither.source_code[filename_source_code].encode(
potential_comments_ = slither.core.source_code[filename_source_code].encode(
"utf8"
)
potential_comments = potential_comments.splitlines(keepends=True)[
potential_comments = potential_comments_.splitlines(keepends=True)[
first_line : end_line - 1
]
@ -491,10 +525,16 @@ def _explore_variables_declaration( # pylint: disable=too-many-arguments,too-ma
idx_beginning += len(line)
def _explore_structures_declaration(slither, structures, result, target, convert):
def _explore_structures_declaration(
slither: SlitherCompilationUnit,
structures: Sequence[Structure],
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
) -> None:
for st in structures:
# Explore the variable declared within the structure (VariableStructure)
_explore_variables_declaration(slither, st.elems.values(), result, target, convert)
_explore_variables_declaration(slither, list(st.elems.values()), result, target, convert)
# If the structure is the target
if st == target:
@ -504,7 +544,7 @@ def _explore_structures_declaration(slither, structures, result, target, convert
filename_source_code = st.source_mapping.filename.absolute
full_txt_start = st.source_mapping.start
full_txt_end = full_txt_start + st.source_mapping.length
full_txt = slither.source_code[filename_source_code].encode("utf8")[
full_txt = slither.core.source_code[filename_source_code].encode("utf8")[
full_txt_start:full_txt_end
]
@ -517,7 +557,13 @@ def _explore_structures_declaration(slither, structures, result, target, convert
create_patch(result, filename_source_code, loc_start, loc_end, old_str, new_str)
def _explore_events_declaration(slither, events, result, target, convert):
def _explore_events_declaration(
slither: SlitherCompilationUnit,
events: Sequence[Event],
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
) -> None:
for event in events:
# Explore the parameters
_explore_variables_declaration(slither, event.elems, result, target, convert)
@ -535,7 +581,7 @@ def _explore_events_declaration(slither, events, result, target, convert):
create_patch(result, filename_source_code, loc_start, loc_end, old_str, new_str)
def get_ir_variables(ir):
def get_ir_variables(ir: Operation) -> List[Union[Variable, Function]]:
all_vars = ir.read
if isinstance(ir, (InternalCall, InternalDynamicCall, HighLevelCall)):
@ -553,9 +599,15 @@ def get_ir_variables(ir):
return [v for v in all_vars if v]
def _explore_irs(slither, irs: List[Operation], result, target, convert):
def _explore_irs(
slither: SlitherCompilationUnit,
irs: List[Operation],
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
) -> None:
# pylint: disable=too-many-locals
if irs is None:
if not irs:
return
for ir in irs:
for v in get_ir_variables(ir):
@ -568,7 +620,7 @@ def _explore_irs(slither, irs: List[Operation], result, target, convert):
filename_source_code = source_mapping.filename.absolute
full_txt_start = source_mapping.start
full_txt_end = full_txt_start + source_mapping.length
full_txt = slither.source_code[filename_source_code].encode("utf8")[
full_txt = slither.core.source_code[filename_source_code].encode("utf8")[
full_txt_start:full_txt_end
]
@ -600,7 +652,13 @@ def _explore_irs(slither, irs: List[Operation], result, target, convert):
)
def _explore_functions(slither, functions, result, target, convert):
def _explore_functions(
slither: SlitherCompilationUnit,
functions: List[Function],
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
) -> None:
for function in functions:
_explore_variables_declaration(slither, function.variables, result, target, convert, True)
_explore_irs(slither, function.all_slithir_operations(), result, target, convert)
@ -612,7 +670,7 @@ def _explore_functions(slither, functions, result, target, convert):
filename_source_code = function.source_mapping.filename.absolute
full_txt_start = function.source_mapping.start
full_txt_end = full_txt_start + function.source_mapping.length
full_txt = slither.source_code[filename_source_code].encode("utf8")[
full_txt = slither.core.source_code[filename_source_code].encode("utf8")[
full_txt_start:full_txt_end
]
@ -628,7 +686,13 @@ def _explore_functions(slither, functions, result, target, convert):
create_patch(result, filename_source_code, loc_start, loc_end, old_str, new_str)
def _explore_enums(slither, enums, result, target, convert):
def _explore_enums(
slither: SlitherCompilationUnit,
enums: Sequence[Enum],
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
) -> None:
for enum in enums:
if enum == target:
old_str = enum.name
@ -637,7 +701,7 @@ def _explore_enums(slither, enums, result, target, convert):
filename_source_code = enum.source_mapping.filename.absolute
full_txt_start = enum.source_mapping.start
full_txt_end = full_txt_start + enum.source_mapping.length
full_txt = slither.source_code[filename_source_code].encode("utf8")[
full_txt = slither.core.source_code[filename_source_code].encode("utf8")[
full_txt_start:full_txt_end
]
@ -650,7 +714,13 @@ def _explore_enums(slither, enums, result, target, convert):
create_patch(result, filename_source_code, loc_start, loc_end, old_str, new_str)
def _explore_contract(slither, contract, result, target, convert):
def _explore_contract(
slither: SlitherCompilationUnit,
contract: Contract,
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
) -> None:
_explore_variables_declaration(slither, contract.state_variables, result, target, convert)
_explore_structures_declaration(slither, contract.structures, result, target, convert)
_explore_functions(slither, contract.functions_and_modifiers, result, target, convert)
@ -660,7 +730,7 @@ def _explore_contract(slither, contract, result, target, convert):
filename_source_code = contract.source_mapping.filename.absolute
full_txt_start = contract.source_mapping.start
full_txt_end = full_txt_start + contract.source_mapping.length
full_txt = slither.source_code[filename_source_code].encode("utf8")[
full_txt = slither.core.source_code[filename_source_code].encode("utf8")[
full_txt_start:full_txt_end
]
@ -677,7 +747,12 @@ def _explore_contract(slither, contract, result, target, convert):
create_patch(result, filename_source_code, loc_start, loc_end, old_str, new_str)
def _explore(compilation_unit: SlitherCompilationUnit, result, target, convert):
def _explore(
compilation_unit: SlitherCompilationUnit,
result: Dict,
target: TARGET_TYPE,
convert: CONVENTION_F_TYPE,
) -> None:
for contract in compilation_unit.contracts_derived:
_explore_contract(compilation_unit, contract, result, target, convert)

@ -1,8 +1,10 @@
from typing import Dict
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.formatters.utils.patches import create_patch
def custom_format(compilation_unit: SlitherCompilationUnit, result):
def custom_format(compilation_unit: SlitherCompilationUnit, result: Dict) -> None:
elements = result["elements"]
for element in elements:
if element["type"] == "variable":
@ -14,7 +16,9 @@ def custom_format(compilation_unit: SlitherCompilationUnit, result):
)
def _patch(compilation_unit: SlitherCompilationUnit, result, in_file, modify_loc_start):
def _patch(
compilation_unit: SlitherCompilationUnit, result: Dict, in_file: str, modify_loc_start: int
) -> None:
in_file_str = compilation_unit.core.source_code[in_file].encode("utf8")
old_str_of_interest = in_file_str[modify_loc_start:]
old_str = (

@ -1,20 +1,21 @@
import logging
from typing import List
from typing import List, Union
from slither.core.declarations.function import Function
from slither.core.solidity_types import Type
from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue, RVALUE, LVALUE
from slither.slithir.variables import TupleVariable, ReferenceVariable
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.variable import Variable
logger = logging.getLogger("AssignmentOperationIR")
class Assignment(OperationWithLValue):
def __init__(
self, left_variable: Variable, right_variable: SourceMapping, variable_return_type
self,
left_variable: LVALUE,
right_variable: Union[RVALUE, Function, TupleVariable],
variable_return_type: Type,
) -> None:
assert is_valid_lvalue(left_variable)
assert is_valid_rvalue(right_variable) or isinstance(
@ -22,30 +23,32 @@ class Assignment(OperationWithLValue):
)
super().__init__()
self._variables = [left_variable, right_variable]
self._lvalue = left_variable
self._rvalue = right_variable
self._lvalue: LVALUE = left_variable
self._rvalue: Union[RVALUE, Function, TupleVariable] = right_variable
self._variable_return_type = variable_return_type
@property
def variables(self):
def variables(self) -> List[Union[LVALUE, RVALUE, Function, TupleVariable]]:
return list(self._variables)
@property
def read(self) -> List[SourceMapping]:
def read(self) -> List[Union[RVALUE, Function, TupleVariable]]:
return [self.rvalue]
@property
def variable_return_type(self):
def variable_return_type(self) -> Type:
return self._variable_return_type
@property
def rvalue(self) -> SourceMapping:
def rvalue(self) -> Union[RVALUE, Function, TupleVariable]:
return self._rvalue
def __str__(self):
if isinstance(self.lvalue, ReferenceVariable):
points = self.lvalue.points_to
def __str__(self) -> str:
lvalue = self.lvalue
assert lvalue
if lvalue and isinstance(lvalue, ReferenceVariable):
points = lvalue.points_to
while isinstance(points, ReferenceVariable):
points = points.points_to
return f"{self.lvalue} (->{points}) := {self.rvalue}({self.rvalue.type})"
return f"{self.lvalue}({self.lvalue.type}) := {self.rvalue}({self.rvalue.type})"
return f"{lvalue} (->{points}) := {self.rvalue}({self.rvalue.type})"
return f"{lvalue}({lvalue.type}) := {self.rvalue}({self.rvalue.type})"

@ -1,17 +1,14 @@
import logging
from typing import List
from enum import Enum
from typing import List, Union
from slither.core.declarations import Function
from slither.core.solidity_types import ElementaryType
from slither.core.variables.variable import Variable
from slither.slithir.exceptions import SlithIRError
from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue, LVALUE, RVALUE
from slither.slithir.variables import ReferenceVariable
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.variable import Variable
logger = logging.getLogger("BinaryOperationIR")
@ -51,7 +48,7 @@ class BinaryType(Enum):
]
@staticmethod
def get_type(operation_type): # pylint: disable=too-many-branches
def get_type(operation_type: str) -> "BinaryType": # pylint: disable=too-many-branches
if operation_type == "**":
return BinaryType.POWER
if operation_type == "*":
@ -93,7 +90,7 @@ class BinaryType(Enum):
raise SlithIRError(f"get_type: Unknown operation type {operation_type})")
def can_be_checked_for_overflow(self):
def can_be_checked_for_overflow(self) -> bool:
return self in [
BinaryType.POWER,
BinaryType.MULTIPLICATION,
@ -108,8 +105,8 @@ class Binary(OperationWithLValue):
def __init__(
self,
result: Variable,
left_variable: SourceMapping,
right_variable: Variable,
left_variable: Union[LVALUE, Function],
right_variable: Union[RVALUE, Function],
operation_type: BinaryType,
) -> None:
assert is_valid_rvalue(left_variable) or isinstance(left_variable, Function)
@ -126,36 +123,38 @@ class Binary(OperationWithLValue):
result.set_type(left_variable.type)
@property
def read(self) -> List[SourceMapping]:
def read(self) -> List[Union[RVALUE, LVALUE, Function]]:
return [self.variable_left, self.variable_right]
@property
def get_variable(self):
def get_variable(self) -> List[Union[RVALUE, LVALUE, Function]]:
return self._variables
@property
def variable_left(self) -> SourceMapping:
return self._variables[0]
def variable_left(self) -> Union[LVALUE, Function]:
return self._variables[0] # type: ignore
@property
def variable_right(self) -> Variable:
return self._variables[1]
def variable_right(self) -> Union[RVALUE, Function]:
return self._variables[1] # type: ignore
@property
def type(self) -> BinaryType:
return self._type
@property
def type_str(self):
def type_str(self) -> str:
if self.node.scope.is_checked and self._type.can_be_checked_for_overflow():
return "(c)" + self._type.value
return self._type.value
def __str__(self):
if isinstance(self.lvalue, ReferenceVariable):
points = self.lvalue.points_to
return "(c)" + str(self._type.value)
return str(self._type.value)
def __str__(self) -> str:
lvalue = self.lvalue
assert lvalue
if isinstance(lvalue, ReferenceVariable):
points = lvalue.points_to
while isinstance(points, ReferenceVariable):
points = points.points_to
return f"{str(self.lvalue)}(-> {points}) = {self.variable_left} {self.type_str} {self.variable_right}"
return f"{str(lvalue)}(-> {points}) = {self.variable_left} {self.type_str} {self.variable_right}"
return f"{str(self.lvalue)}({self.lvalue.type}) = {self.variable_left} {self.type_str} {self.variable_right}"
return f"{str(lvalue)}({lvalue.type}) = {self.variable_left} {self.type_str} {self.variable_right}"

@ -24,7 +24,7 @@ class InternalCall(Call, OperationWithLValue): # pylint: disable=too-many-insta
super().__init__()
self._contract_name = ""
if isinstance(function, Function):
self._function = function
self._function: Optional[Function] = function
self._function_name = function.name
if isinstance(function, FunctionContract):
self._contract_name = function.contract_declarer.name
@ -45,7 +45,7 @@ class InternalCall(Call, OperationWithLValue): # pylint: disable=too-many-insta
return list(self._unroll(self.arguments))
@property
def function(self):
def function(self) -> Optional[Function]:
return self._function
@function.setter

@ -1,4 +1,7 @@
from enum import Enum
from typing import Optional, List
from slither.core.expressions.expression import Expression
from slither.slithir.operations.operation import Operation
@ -10,26 +13,26 @@ class ArgumentType(Enum):
class Argument(Operation):
def __init__(self, argument) -> None:
def __init__(self, argument: Expression) -> None:
super().__init__()
self._argument = argument
self._type = ArgumentType.CALL
self._callid = None
self._callid: Optional[str] = None
@property
def argument(self):
def argument(self) -> Expression:
return self._argument
@property
def call_id(self):
def call_id(self) -> Optional[str]:
return self._callid
@call_id.setter
def call_id(self, c):
def call_id(self, c: str) -> None:
self._callid = c
@property
def read(self):
def read(self) -> List[Expression]:
return [self.argument]
def set_type(self, t: ArgumentType) -> None:
@ -39,7 +42,7 @@ class Argument(Operation):
def get_type(self) -> ArgumentType:
return self._type
def __str__(self):
def __str__(self) -> str:
call_id = "none"
if self.call_id:
call_id = f"(id ({self.call_id}))"

Loading…
Cancel
Save