From 4cecb25a792e7e1bfed491eb36af51f646f3a56e Mon Sep 17 00:00:00 2001 From: Ngalim Siregar Date: Fri, 28 Feb 2025 20:39:04 +0700 Subject: [PATCH 1/4] add VariableLocation enum for LocalVariable class --- slither/core/variables/local_variable.py | 21 ++++++++++++++------- tests/unit/slithir/test_ssa_generation.py | 4 ++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/slither/core/variables/local_variable.py b/slither/core/variables/local_variable.py index 9baf804457..5d1762da4c 100644 --- a/slither/core/variables/local_variable.py +++ b/slither/core/variables/local_variable.py @@ -1,3 +1,4 @@ +import enum from typing import Optional, TYPE_CHECKING from slither.core.variables.variable import Variable @@ -10,11 +11,17 @@ if TYPE_CHECKING: # type: ignore from slither.core.declarations import Function +class VariableLocation(enum.Enum): + MEMORY = "memory" + CALLDATA = "calldata" + STORAGE = "storage" + REFERENCE_TO_STORAGE = "reference_to_storage" + class LocalVariable(Variable): def __init__(self) -> None: super().__init__() - self._location: Optional[str] = None + self._location: Optional[VariableLocation] = None self._function: Optional["Function"] = None def set_function(self, function: "Function") -> None: @@ -25,11 +32,11 @@ def function(self) -> "Function": assert self._function return self._function - def set_location(self, loc: str) -> None: + def set_location(self, loc: VariableLocation) -> None: self._location = loc @property - def location(self) -> Optional[str]: + def location(self) -> Optional[VariableLocation]: """ Variable Location Can be storage/memory or default @@ -53,14 +60,14 @@ def is_storage(self) -> bool: # pylint: disable=import-outside-toplevel from slither.core.solidity_types.array_type import ArrayType - if self.location == "memory": + if self.location == VariableLocation.MEMORY: return False - if self.location == "calldata": + if self.location == VariableLocation.CALLDATA: return False # Use by slithIR SSA - if self.location == "reference_to_storage": + if self.location == VariableLocation.REFERENCE_TO_STORAGE: return False - if self.location == "storage": + if self.location == VariableLocation.STORAGE: return True if isinstance(self.type, (ArrayType, MappingType)): diff --git a/tests/unit/slithir/test_ssa_generation.py b/tests/unit/slithir/test_ssa_generation.py index 1358fa957c..2efac7ebe1 100644 --- a/tests/unit/slithir/test_ssa_generation.py +++ b/tests/unit/slithir/test_ssa_generation.py @@ -12,7 +12,7 @@ from slither.core.cfg.node import Node, NodeType from slither.core.declarations import Function, Contract from slither.core.solidity_types import ArrayType, ElementaryType -from slither.core.variables.local_variable import LocalVariable +from slither.core.variables.local_variable import LocalVariable, VariableLocation from slither.core.variables.state_variable import StateVariable from slither.slithir.operations import ( OperationWithLValue, @@ -134,7 +134,7 @@ def check_property_5_and_6( assert var.is_storage == ssa_var.is_storage if ssa_var.is_storage: assert len(ssa_var.refers_to) == 1 - assert ssa_var.refers_to[0].location == "reference_to_storage" + assert ssa_var.refers_to[0].location == VariableLocation.REFERENCE_TO_STORAGE # 5 check_property_5_and_6(function.parameters, function.parameters_ssa) From f36d7dc91bd50fc70e1aa09de91099fd67e631aa Mon Sep 17 00:00:00 2001 From: Ngalim Siregar Date: Tue, 4 Mar 2025 20:48:28 +0700 Subject: [PATCH 2/4] update state variable to use VariableLocation enum --- slither/core/variables/local_variable.py | 15 ++++++++------- slither/core/variables/state_variable.py | 17 ++++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/slither/core/variables/local_variable.py b/slither/core/variables/local_variable.py index 5d1762da4c..767137f9b4 100644 --- a/slither/core/variables/local_variable.py +++ b/slither/core/variables/local_variable.py @@ -1,21 +1,22 @@ import enum -from typing import Optional, TYPE_CHECKING - -from slither.core.variables.variable import Variable -from slither.core.solidity_types.user_defined_type import UserDefinedType -from slither.core.solidity_types.mapping_type import MappingType -from slither.core.solidity_types.elementary_type import ElementaryType +from typing import TYPE_CHECKING, Optional from slither.core.declarations.structure import Structure +from slither.core.solidity_types.elementary_type import ElementaryType +from slither.core.solidity_types.mapping_type import MappingType +from slither.core.solidity_types.user_defined_type import UserDefinedType +from slither.core.variables.variable import Variable if TYPE_CHECKING: # type: ignore from slither.core.declarations import Function + class VariableLocation(enum.Enum): MEMORY = "memory" CALLDATA = "calldata" STORAGE = "storage" REFERENCE_TO_STORAGE = "reference_to_storage" + TRANSIENT = "transient" class LocalVariable(Variable): @@ -41,7 +42,7 @@ def location(self) -> Optional[VariableLocation]: Variable Location Can be storage/memory or default Returns: - (str) + (VariableLocation) """ return self._location diff --git a/slither/core/variables/state_variable.py b/slither/core/variables/state_variable.py index d3e3e60182..15ab53487d 100644 --- a/slither/core/variables/state_variable.py +++ b/slither/core/variables/state_variable.py @@ -1,6 +1,7 @@ -from typing import Optional, TYPE_CHECKING +from typing import TYPE_CHECKING, Optional from slither.core.declarations.contract_level import ContractLevel +from slither.core.variables.local_variable import VariableLocation from slither.core.variables.variable import Variable if TYPE_CHECKING: @@ -12,7 +13,7 @@ class StateVariable(ContractLevel, Variable): def __init__(self) -> None: super().__init__() self._node_initialization: Optional["Node"] = None - self._location: Optional[str] = None + self._location: Optional[VariableLocation] = None def is_declared_by(self, contract: "Contract") -> bool: """ @@ -22,16 +23,16 @@ def is_declared_by(self, contract: "Contract") -> bool: """ return self.contract == contract - def set_location(self, loc: str) -> None: + def set_location(self, loc: VariableLocation) -> None: self._location = loc @property - def location(self) -> Optional[str]: + def location(self) -> Optional[VariableLocation]: """ Variable Location Can be default or transient Returns: - (str) + (VariableLocation) """ return self._location @@ -41,7 +42,9 @@ def is_stored(self) -> bool: Checks if the state variable is stored, based on it not being constant or immutable or transient. """ return ( - not self._is_constant and not self._is_immutable and not self._location == "transient" + not self._is_constant + and not self._is_immutable + and not self._location == VariableLocation.TRANSIENT ) @property @@ -49,7 +52,7 @@ def is_transient(self) -> bool: """ Checks if the state variable is transient. A transient variable can not be constant or immutable. """ - return self._location == "transient" + return self._location == VariableLocation.TRANSIENT # endregion ################################################################################### From 2546eee8887ba0148335fdc0f06bb7b471caac4c Mon Sep 17 00:00:00 2001 From: Ngalim Siregar Date: Wed, 5 Mar 2025 20:05:32 +0700 Subject: [PATCH 3/4] set comparison to enum value --- slither/core/variables/local_variable.py | 8 ++++---- slither/core/variables/state_variable.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/slither/core/variables/local_variable.py b/slither/core/variables/local_variable.py index 767137f9b4..fd586153ce 100644 --- a/slither/core/variables/local_variable.py +++ b/slither/core/variables/local_variable.py @@ -61,14 +61,14 @@ def is_storage(self) -> bool: # pylint: disable=import-outside-toplevel from slither.core.solidity_types.array_type import ArrayType - if self.location == VariableLocation.MEMORY: + if self.location == VariableLocation.MEMORY.value: return False - if self.location == VariableLocation.CALLDATA: + if self.location == VariableLocation.CALLDATA.value: return False # Use by slithIR SSA - if self.location == VariableLocation.REFERENCE_TO_STORAGE: + if self.location == VariableLocation.REFERENCE_TO_STORAGE.value: return False - if self.location == VariableLocation.STORAGE: + if self.location == VariableLocation.STORAGE.value: return True if isinstance(self.type, (ArrayType, MappingType)): diff --git a/slither/core/variables/state_variable.py b/slither/core/variables/state_variable.py index 15ab53487d..229ca54787 100644 --- a/slither/core/variables/state_variable.py +++ b/slither/core/variables/state_variable.py @@ -44,7 +44,7 @@ def is_stored(self) -> bool: return ( not self._is_constant and not self._is_immutable - and not self._location == VariableLocation.TRANSIENT + and not self._location == VariableLocation.TRANSIENT.value ) @property @@ -52,7 +52,7 @@ def is_transient(self) -> bool: """ Checks if the state variable is transient. A transient variable can not be constant or immutable. """ - return self._location == VariableLocation.TRANSIENT + return self._location == VariableLocation.TRANSIENT.value # endregion ################################################################################### From d2698c58ef972b116b489a8a97d8e663c22a318a Mon Sep 17 00:00:00 2001 From: Ngalim Siregar Date: Wed, 5 Mar 2025 20:09:41 +0700 Subject: [PATCH 4/4] update test_ssa_generation property check --- tests/unit/slithir/test_ssa_generation.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/unit/slithir/test_ssa_generation.py b/tests/unit/slithir/test_ssa_generation.py index 2efac7ebe1..e8337c5706 100644 --- a/tests/unit/slithir/test_ssa_generation.py +++ b/tests/unit/slithir/test_ssa_generation.py @@ -3,36 +3,36 @@ from argparse import ArgumentTypeError from collections import defaultdict from inspect import getsourcefile -from typing import Union, List, Dict, Callable +from typing import Callable, Dict, List, Union import pytest from solc_select.solc_select import valid_version as solc_valid_version from slither import Slither from slither.core.cfg.node import Node, NodeType -from slither.core.declarations import Function, Contract +from slither.core.declarations import Contract, Function from slither.core.solidity_types import ArrayType, ElementaryType from slither.core.variables.local_variable import LocalVariable, VariableLocation from slither.core.variables.state_variable import StateVariable from slither.slithir.operations import ( - OperationWithLValue, - Phi, Assignment, - HighLevelCall, - Return, - Operation, Binary, BinaryType, - InternalCall, + HighLevelCall, Index, InitArray, + InternalCall, NewArray, + Operation, + OperationWithLValue, + Phi, + Return, ) from slither.slithir.utils.ssa import is_used_later from slither.slithir.variables import ( Constant, - ReferenceVariable, LocalIRVariable, + ReferenceVariable, StateIRVariable, TemporaryVariableSSA, ) @@ -120,7 +120,7 @@ def ssa_basic_properties(function: Function) -> None: if v and v.name: ssa_defs[v.name] += 1 - for (k, count) in lvalue_assignments.items(): + for k, count in lvalue_assignments.items(): assert ssa_defs[k] >= count # Helper 5/6 @@ -134,7 +134,7 @@ def check_property_5_and_6( assert var.is_storage == ssa_var.is_storage if ssa_var.is_storage: assert len(ssa_var.refers_to) == 1 - assert ssa_var.refers_to[0].location == VariableLocation.REFERENCE_TO_STORAGE + assert ssa_var.refers_to[0].location == VariableLocation.REFERENCE_TO_STORAGE.value # 5 check_property_5_and_6(function.parameters, function.parameters_ssa)