Add support to top level variables

Fix #995
pull/1032/head
Josselin 3 years ago
parent de0d526cfd
commit 4e66acb46c
  1. 2
      slither/analyses/data_dependency/data_dependency.py
  2. 5
      slither/core/scope/scope.py
  3. 4
      slither/core/variables/top_level_variable.py
  4. 2
      slither/slithir/utils/ssa.py
  5. 2
      slither/slithir/utils/utils.py
  6. 18
      slither/solc_parsing/expressions/find_variable.py
  7. 10
      slither/solc_parsing/slither_compilation_unit_solc.py
  8. 5
      slither/solc_parsing/solidity_types/type_parsing.py
  9. 32
      slither/solc_parsing/variables/top_level_variable.py

@ -14,6 +14,7 @@ from slither.core.declarations import (
Structure, Structure,
) )
from slither.core.declarations.solidity_import_placeholder import SolidityImportPlaceHolder from slither.core.declarations.solidity_import_placeholder import SolidityImportPlaceHolder
from slither.core.variables.top_level_variable import TopLevelVariable
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.slithir.operations import Index, OperationWithLValue, InternalCall from slither.slithir.operations import Index, OperationWithLValue, InternalCall
from slither.slithir.variables import ( from slither.slithir.variables import (
@ -410,6 +411,7 @@ def convert_variable_to_non_ssa(v):
Function, Function,
Type, Type,
SolidityImportPlaceHolder, SolidityImportPlaceHolder,
TopLevelVariable,
), ),
) )
return v return v

@ -6,6 +6,7 @@ from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel
from slither.core.declarations.enum_top_level import EnumTopLevel from slither.core.declarations.enum_top_level import EnumTopLevel
from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.structure_top_level import StructureTopLevel from slither.core.declarations.structure_top_level import StructureTopLevel
from slither.core.variables.top_level_variable import TopLevelVariable
from slither.slithir.variables import Constant from slither.slithir.variables import Constant
@ -36,6 +37,7 @@ class FileScope:
self.imports: Set[Import] = set() self.imports: Set[Import] = set()
self.pragmas: Set[Pragma] = set() self.pragmas: Set[Pragma] = set()
self.structures: Dict[str, StructureTopLevel] = {} self.structures: Dict[str, StructureTopLevel] = {}
self.variables: Dict[str, TopLevelVariable] = {}
def add_accesible_scopes(self) -> bool: def add_accesible_scopes(self) -> bool:
""" """
@ -69,6 +71,9 @@ class FileScope:
if not _dict_contain(new_scope.structures, self.structures): if not _dict_contain(new_scope.structures, self.structures):
self.structures.update(new_scope.structures) self.structures.update(new_scope.structures)
learn_something = True learn_something = True
if not _dict_contain(new_scope.variables, self.variables):
self.variables.update(new_scope.variables)
learn_something = True
return learn_something return learn_something

@ -5,12 +5,14 @@ from slither.core.variables.variable import Variable
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
from slither.core.scope.scope import FileScope
class TopLevelVariable(TopLevel, Variable): class TopLevelVariable(TopLevel, Variable):
def __init__(self): def __init__(self, scope: "FileScope"):
super().__init__() super().__init__()
self._node_initialization: Optional["Node"] = None self._node_initialization: Optional["Node"] = None
self.file_scope = scope
# endregion # endregion
################################################################################### ###################################################################################

@ -13,6 +13,7 @@ from slither.core.declarations.solidity_import_placeholder import SolidityImport
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.variables.local_variable import LocalVariable from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.core.variables.top_level_variable import TopLevelVariable
from slither.slithir.operations import ( from slither.slithir.operations import (
Assignment, Assignment,
Binary, Binary,
@ -617,6 +618,7 @@ def get(
Function, Function,
Type, Type,
SolidityImportPlaceHolder, SolidityImportPlaceHolder,
TopLevelVariable,
), ),
) # type for abi.decode(.., t) ) # type for abi.decode(.., t)
return variable return variable

@ -2,6 +2,7 @@ from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.core.declarations.solidity_variables import SolidityVariable from slither.core.declarations.solidity_variables import SolidityVariable
from slither.core.variables.top_level_variable import TopLevelVariable
from slither.slithir.variables.temporary import TemporaryVariable from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.constant import Constant from slither.slithir.variables.constant import Constant
@ -15,6 +16,7 @@ def is_valid_rvalue(v):
( (
StateVariable, StateVariable,
LocalVariable, LocalVariable,
TopLevelVariable,
TemporaryVariable, TemporaryVariable,
Constant, Constant,
SolidityVariable, SolidityVariable,

@ -19,6 +19,7 @@ from slither.core.solidity_types import (
FunctionType, FunctionType,
MappingType, MappingType,
) )
from slither.core.variables.top_level_variable import TopLevelVariable
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.exceptions import SlitherError from slither.exceptions import SlitherError
from slither.solc_parsing.declarations.caller_context import CallerContextExpression from slither.solc_parsing.declarations.caller_context import CallerContextExpression
@ -98,7 +99,9 @@ def _find_variable_in_function_parser(
def _find_top_level( def _find_top_level(
var_name: str, scope: "FileScope" var_name: str, scope: "FileScope"
) -> Tuple[Optional[Union[Enum, Structure, SolidityImportPlaceHolder, CustomError]], bool]: ) -> Tuple[
Optional[Union[Enum, Structure, SolidityImportPlaceHolder, CustomError, TopLevelVariable]], bool
]:
""" """
Return the top level variable use, and a boolean indicating if the variable returning was cretead Return the top level variable use, and a boolean indicating if the variable returning was cretead
If the variable was created, it has no source_mapping If the variable was created, it has no source_mapping
@ -126,6 +129,9 @@ def _find_top_level(
if custom_error.solidity_signature == var_name: if custom_error.solidity_signature == var_name:
return custom_error, False return custom_error, False
if var_name in scope.variables:
return scope.variables[var_name], False
return None, False return None, False
@ -210,6 +216,8 @@ def _find_variable_init(
) -> Tuple[List[Contract], List["Function"], FileScope,]: ) -> Tuple[List[Contract], List["Function"], FileScope,]:
from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.contract import ContractSolc
from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.function import FunctionSolc
from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc
from slither.solc_parsing.variables.top_level_variable import TopLevelVariableSolc
direct_contracts: List[Contract] direct_contracts: List[Contract]
direct_functions_parser: List[Function] direct_functions_parser: List[Function]
@ -244,6 +252,14 @@ def _find_variable_init(
else: else:
assert isinstance(underlying_function, FunctionContract) assert isinstance(underlying_function, FunctionContract)
scope = underlying_function.contract.file_scope scope = underlying_function.contract.file_scope
elif isinstance(caller_context, StructureTopLevelSolc):
direct_contracts = []
direct_functions_parser = []
scope = caller_context.underlying_structure.file_scope
elif isinstance(caller_context, TopLevelVariableSolc):
direct_contracts = []
direct_functions_parser = []
scope = caller_context.underlying_variable.file_scope
else: else:
raise SlitherError( raise SlitherError(
f"{type(caller_context)} ({caller_context} is not valid for find_variable" f"{type(caller_context)} ({caller_context} is not valid for find_variable"

@ -239,12 +239,13 @@ class SlitherCompilationUnitSolc:
self._parse_enum(top_level_data, filename) self._parse_enum(top_level_data, filename)
elif top_level_data[self.get_key()] == "VariableDeclaration": elif top_level_data[self.get_key()] == "VariableDeclaration":
var = TopLevelVariable() var = TopLevelVariable(scope)
var_parser = TopLevelVariableSolc(var, top_level_data) var_parser = TopLevelVariableSolc(var, top_level_data, self)
var.set_offset(top_level_data["src"], self._compilation_unit) var.set_offset(top_level_data["src"], self._compilation_unit)
self._compilation_unit.variables_top_level.append(var) self._compilation_unit.variables_top_level.append(var)
self._variables_top_level_parser.append(var_parser) self._variables_top_level_parser.append(var_parser)
scope.variables[var.name] = var
elif top_level_data[self.get_key()] == "FunctionDefinition": elif top_level_data[self.get_key()] == "FunctionDefinition":
scope = self.compilation_unit.get_scope(filename) scope = self.compilation_unit.get_scope(filename)
func = FunctionTopLevel(self._compilation_unit, scope) func = FunctionTopLevel(self._compilation_unit, scope)
@ -495,6 +496,7 @@ Please rename it, this name is reserved for Slither's internals"""
for lib in libraries: for lib in libraries:
self._analyze_struct_events(lib) self._analyze_struct_events(lib)
self._analyze_top_level_variables()
self._analyze_top_level_structures() self._analyze_top_level_structures()
# Start with the contracts without inheritance # Start with the contracts without inheritance
@ -580,9 +582,9 @@ Please rename it, this name is reserved for Slither's internals"""
def _analyze_top_level_variables(self): def _analyze_top_level_variables(self):
try: try:
for var in self._variables_top_level_parser: for var in self._variables_top_level_parser:
var.analyze(self) var.analyze(var)
except (VariableNotFound, KeyError) as e: except (VariableNotFound, KeyError) as e:
raise SlitherException(f"Missing struct {e} during top level structure analyze") from e raise SlitherException(f"Missing {e} during variable analyze") from e
def _analyze_params_top_level_function(self): def _analyze_params_top_level_function(self):
for func_parser in self._functions_top_level_parser: for func_parser in self._functions_top_level_parser:

@ -220,6 +220,7 @@ def parse_type(
from slither.solc_parsing.declarations.custom_error import CustomErrorSolc from slither.solc_parsing.declarations.custom_error import CustomErrorSolc
from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc
from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc
from slither.solc_parsing.variables.top_level_variable import TopLevelVariableSolc
sl: "SlitherCompilationUnit" sl: "SlitherCompilationUnit"
# Note: for convenicence top level functions use the same parser than function in contract # Note: for convenicence top level functions use the same parser than function in contract
@ -245,9 +246,11 @@ def parse_type(
all_enums += enums_direct_access all_enums += enums_direct_access
contracts = sl.contracts contracts = sl.contracts
functions = [] functions = []
elif isinstance(caller_context, (StructureTopLevelSolc, CustomErrorSolc)): elif isinstance(caller_context, (StructureTopLevelSolc, CustomErrorSolc, TopLevelVariableSolc)):
if isinstance(caller_context, StructureTopLevelSolc): if isinstance(caller_context, StructureTopLevelSolc):
scope = caller_context.underlying_structure.file_scope scope = caller_context.underlying_structure.file_scope
elif isinstance(caller_context, TopLevelVariableSolc):
scope = caller_context.underlying_variable.file_scope
else: else:
assert isinstance(caller_context, CustomErrorSolc) assert isinstance(caller_context, CustomErrorSolc)
custom_error = caller_context.underlying_custom_error custom_error = caller_context.underlying_custom_error

@ -1,12 +1,38 @@
from typing import Dict from typing import Dict, TYPE_CHECKING
from slither.core.variables.top_level_variable import TopLevelVariable from slither.core.variables.top_level_variable import TopLevelVariable
from slither.solc_parsing.variables.variable_declaration import VariableDeclarationSolc from slither.solc_parsing.variables.variable_declaration import VariableDeclarationSolc
from slither.solc_parsing.declarations.caller_context import CallerContextExpression
if TYPE_CHECKING:
from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc
from slither.core.compilation_unit import SlitherCompilationUnit
class TopLevelVariableSolc(VariableDeclarationSolc):
def __init__(self, variable: TopLevelVariable, variable_data: Dict): class TopLevelVariableSolc(VariableDeclarationSolc, CallerContextExpression):
def __init__(
self,
variable: TopLevelVariable,
variable_data: Dict,
slither_parser: "SlitherCompilationUnitSolc",
):
super().__init__(variable, variable_data) super().__init__(variable, variable_data)
self._slither_parser = slither_parser
@property
def is_compact_ast(self) -> bool:
return self._slither_parser.is_compact_ast
@property
def compilation_unit(self) -> "SlitherCompilationUnit":
return self._slither_parser.compilation_unit
def get_key(self) -> str:
return self._slither_parser.get_key()
@property
def slither_parser(self) -> "SlitherCompilationUnitSolc":
return self._slither_parser
@property @property
def underlying_variable(self) -> TopLevelVariable: def underlying_variable(self) -> TopLevelVariable:

Loading…
Cancel
Save