|
|
@ -1,6 +1,6 @@ |
|
|
|
import logging |
|
|
|
import logging |
|
|
|
import re |
|
|
|
import re |
|
|
|
from typing import Any, List, Dict, Callable, TYPE_CHECKING, Union, Set |
|
|
|
from typing import Any, List, Dict, Callable, TYPE_CHECKING, Union, Set, Sequence |
|
|
|
|
|
|
|
|
|
|
|
from slither.core.declarations import ( |
|
|
|
from slither.core.declarations import ( |
|
|
|
Modifier, |
|
|
|
Modifier, |
|
|
@ -9,10 +9,10 @@ from slither.core.declarations import ( |
|
|
|
StructureContract, |
|
|
|
StructureContract, |
|
|
|
Function, |
|
|
|
Function, |
|
|
|
) |
|
|
|
) |
|
|
|
from slither.core.declarations.contract import Contract |
|
|
|
from slither.core.declarations.contract import Contract, USING_FOR_KEY |
|
|
|
from slither.core.declarations.custom_error_contract import CustomErrorContract |
|
|
|
from slither.core.declarations.custom_error_contract import CustomErrorContract |
|
|
|
from slither.core.declarations.function_contract import FunctionContract |
|
|
|
from slither.core.declarations.function_contract import FunctionContract |
|
|
|
from slither.core.solidity_types import ElementaryType, TypeAliasContract, Type |
|
|
|
from slither.core.solidity_types import ElementaryType, TypeAliasContract |
|
|
|
from slither.core.variables.state_variable import StateVariable |
|
|
|
from slither.core.variables.state_variable import StateVariable |
|
|
|
from slither.solc_parsing.declarations.caller_context import CallerContextExpression |
|
|
|
from slither.solc_parsing.declarations.caller_context import CallerContextExpression |
|
|
|
from slither.solc_parsing.declarations.custom_error import CustomErrorSolc |
|
|
|
from slither.solc_parsing.declarations.custom_error import CustomErrorSolc |
|
|
@ -302,7 +302,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
st.set_contract(self._contract) |
|
|
|
st.set_contract(self._contract) |
|
|
|
st.set_offset(struct["src"], self._contract.compilation_unit) |
|
|
|
st.set_offset(struct["src"], self._contract.compilation_unit) |
|
|
|
|
|
|
|
|
|
|
|
st_parser = StructureContractSolc(st, struct, self) |
|
|
|
st_parser = StructureContractSolc(st, struct, self) # type: ignore |
|
|
|
self._contract.structures_as_dict[st.name] = st |
|
|
|
self._contract.structures_as_dict[st.name] = st |
|
|
|
self._structures_parser.append(st_parser) |
|
|
|
self._structures_parser.append(st_parser) |
|
|
|
|
|
|
|
|
|
|
@ -312,7 +312,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
|
|
|
|
|
|
|
|
for struct in self._structuresNotParsed: |
|
|
|
for struct in self._structuresNotParsed: |
|
|
|
self._parse_struct(struct) |
|
|
|
self._parse_struct(struct) |
|
|
|
self._structuresNotParsed = None |
|
|
|
self._structuresNotParsed = [] |
|
|
|
|
|
|
|
|
|
|
|
def _parse_custom_error(self, custom_error: Dict) -> None: |
|
|
|
def _parse_custom_error(self, custom_error: Dict) -> None: |
|
|
|
ce = CustomErrorContract(self.compilation_unit) |
|
|
|
ce = CustomErrorContract(self.compilation_unit) |
|
|
@ -329,7 +329,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
|
|
|
|
|
|
|
|
for custom_error in self._customErrorParsed: |
|
|
|
for custom_error in self._customErrorParsed: |
|
|
|
self._parse_custom_error(custom_error) |
|
|
|
self._parse_custom_error(custom_error) |
|
|
|
self._customErrorParsed = None |
|
|
|
self._customErrorParsed = [] |
|
|
|
|
|
|
|
|
|
|
|
def parse_state_variables(self) -> None: |
|
|
|
def parse_state_variables(self) -> None: |
|
|
|
for father in self._contract.inheritance_reverse: |
|
|
|
for father in self._contract.inheritance_reverse: |
|
|
@ -356,6 +356,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
var_parser = StateVariableSolc(var, varNotParsed) |
|
|
|
var_parser = StateVariableSolc(var, varNotParsed) |
|
|
|
self._variables_parser.append(var_parser) |
|
|
|
self._variables_parser.append(var_parser) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert var.name |
|
|
|
self._contract.variables_as_dict[var.name] = var |
|
|
|
self._contract.variables_as_dict[var.name] = var |
|
|
|
self._contract.add_variables_ordered([var]) |
|
|
|
self._contract.add_variables_ordered([var]) |
|
|
|
|
|
|
|
|
|
|
@ -365,7 +366,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
modif.set_contract(self._contract) |
|
|
|
modif.set_contract(self._contract) |
|
|
|
modif.set_contract_declarer(self._contract) |
|
|
|
modif.set_contract_declarer(self._contract) |
|
|
|
|
|
|
|
|
|
|
|
modif_parser = ModifierSolc(modif, modifier_data, self, self.slither_parser) |
|
|
|
modif_parser = ModifierSolc(modif, modifier_data, self, self.slither_parser) # type: ignore |
|
|
|
self._contract.compilation_unit.add_modifier(modif) |
|
|
|
self._contract.compilation_unit.add_modifier(modif) |
|
|
|
self._modifiers_no_params.append(modif_parser) |
|
|
|
self._modifiers_no_params.append(modif_parser) |
|
|
|
self._modifiers_parser.append(modif_parser) |
|
|
|
self._modifiers_parser.append(modif_parser) |
|
|
@ -375,7 +376,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
def parse_modifiers(self) -> None: |
|
|
|
def parse_modifiers(self) -> None: |
|
|
|
for modifier in self._modifiersNotParsed: |
|
|
|
for modifier in self._modifiersNotParsed: |
|
|
|
self._parse_modifier(modifier) |
|
|
|
self._parse_modifier(modifier) |
|
|
|
self._modifiersNotParsed = None |
|
|
|
self._modifiersNotParsed = [] |
|
|
|
|
|
|
|
|
|
|
|
def _parse_function(self, function_data: Dict) -> None: |
|
|
|
def _parse_function(self, function_data: Dict) -> None: |
|
|
|
func = FunctionContract(self._contract.compilation_unit) |
|
|
|
func = FunctionContract(self._contract.compilation_unit) |
|
|
@ -383,7 +384,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
func.set_contract(self._contract) |
|
|
|
func.set_contract(self._contract) |
|
|
|
func.set_contract_declarer(self._contract) |
|
|
|
func.set_contract_declarer(self._contract) |
|
|
|
|
|
|
|
|
|
|
|
func_parser = FunctionSolc(func, function_data, self, self._slither_parser) |
|
|
|
func_parser = FunctionSolc(func, function_data, self, self._slither_parser) # type: ignore |
|
|
|
self._contract.compilation_unit.add_function(func) |
|
|
|
self._contract.compilation_unit.add_function(func) |
|
|
|
self._functions_no_params.append(func_parser) |
|
|
|
self._functions_no_params.append(func_parser) |
|
|
|
self._functions_parser.append(func_parser) |
|
|
|
self._functions_parser.append(func_parser) |
|
|
@ -395,7 +396,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
for function in self._functionsNotParsed: |
|
|
|
for function in self._functionsNotParsed: |
|
|
|
self._parse_function(function) |
|
|
|
self._parse_function(function) |
|
|
|
|
|
|
|
|
|
|
|
self._functionsNotParsed = None |
|
|
|
self._functionsNotParsed = [] |
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
# endregion |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
@ -439,7 +440,8 @@ class ContractSolc(CallerContextExpression): |
|
|
|
Cls_parser, |
|
|
|
Cls_parser, |
|
|
|
self._modifiers_parser, |
|
|
|
self._modifiers_parser, |
|
|
|
) |
|
|
|
) |
|
|
|
self._contract.set_modifiers(modifiers) |
|
|
|
# modifiers will be using Modifier so we can ignore the next type check |
|
|
|
|
|
|
|
self._contract.set_modifiers(modifiers) # type: ignore |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
self.log_incorrect_parsing(f"Missing params {e}") |
|
|
|
self.log_incorrect_parsing(f"Missing params {e}") |
|
|
|
self._modifiers_no_params = [] |
|
|
|
self._modifiers_no_params = [] |
|
|
@ -459,7 +461,8 @@ class ContractSolc(CallerContextExpression): |
|
|
|
Cls_parser, |
|
|
|
Cls_parser, |
|
|
|
self._functions_parser, |
|
|
|
self._functions_parser, |
|
|
|
) |
|
|
|
) |
|
|
|
self._contract.set_functions(functions) |
|
|
|
# function will be using FunctionContract so we can ignore the next type check |
|
|
|
|
|
|
|
self._contract.set_functions(functions) # type: ignore |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
self.log_incorrect_parsing(f"Missing params {e}") |
|
|
|
self.log_incorrect_parsing(f"Missing params {e}") |
|
|
|
self._functions_no_params = [] |
|
|
|
self._functions_no_params = [] |
|
|
@ -470,7 +473,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
Cls_parser: Callable, |
|
|
|
Cls_parser: Callable, |
|
|
|
element_parser: FunctionSolc, |
|
|
|
element_parser: FunctionSolc, |
|
|
|
explored_reference_id: Set[str], |
|
|
|
explored_reference_id: Set[str], |
|
|
|
parser: List[FunctionSolc], |
|
|
|
parser: Union[List[FunctionSolc], List[ModifierSolc]], |
|
|
|
all_elements: Dict[str, Function], |
|
|
|
all_elements: Dict[str, Function], |
|
|
|
) -> None: |
|
|
|
) -> None: |
|
|
|
elem = Cls(self._contract.compilation_unit) |
|
|
|
elem = Cls(self._contract.compilation_unit) |
|
|
@ -508,13 +511,13 @@ class ContractSolc(CallerContextExpression): |
|
|
|
|
|
|
|
|
|
|
|
def _analyze_params_elements( # pylint: disable=too-many-arguments,too-many-locals |
|
|
|
def _analyze_params_elements( # pylint: disable=too-many-arguments,too-many-locals |
|
|
|
self, |
|
|
|
self, |
|
|
|
elements_no_params: List[FunctionSolc], |
|
|
|
elements_no_params: Sequence[FunctionSolc], |
|
|
|
getter: Callable[["ContractSolc"], List[FunctionSolc]], |
|
|
|
getter: Callable[["ContractSolc"], List[FunctionSolc]], |
|
|
|
getter_available: Callable[[Contract], List[FunctionContract]], |
|
|
|
getter_available: Callable[[Contract], List[FunctionContract]], |
|
|
|
Cls: Callable, |
|
|
|
Cls: Callable, |
|
|
|
Cls_parser: Callable, |
|
|
|
Cls_parser: Callable, |
|
|
|
parser: List[FunctionSolc], |
|
|
|
parser: Union[List[FunctionSolc], List[ModifierSolc]], |
|
|
|
) -> Dict[str, Union[FunctionContract, Modifier]]: |
|
|
|
) -> Dict[str, Function]: |
|
|
|
""" |
|
|
|
""" |
|
|
|
Analyze the parameters of the given elements (Function or Modifier). |
|
|
|
Analyze the parameters of the given elements (Function or Modifier). |
|
|
|
The function iterates over the inheritance to create an instance or inherited elements (Function or Modifier) |
|
|
|
The function iterates over the inheritance to create an instance or inherited elements (Function or Modifier) |
|
|
@ -526,13 +529,13 @@ class ContractSolc(CallerContextExpression): |
|
|
|
:param Cls: Class to create for collision |
|
|
|
:param Cls: Class to create for collision |
|
|
|
:return: |
|
|
|
:return: |
|
|
|
""" |
|
|
|
""" |
|
|
|
all_elements = {} |
|
|
|
all_elements: Dict[str, Function] = {} |
|
|
|
|
|
|
|
|
|
|
|
explored_reference_id = set() |
|
|
|
explored_reference_id: Set[str] = set() |
|
|
|
try: |
|
|
|
try: |
|
|
|
for father in self._contract.inheritance: |
|
|
|
for father in self._contract.inheritance: |
|
|
|
father_parser = self._slither_parser.underlying_contract_to_parser[father] |
|
|
|
father_parser = self._slither_parser.underlying_contract_to_parser[father] |
|
|
|
for element_parser in getter(father_parser): |
|
|
|
for element_parser in getter(father_parser): # type: ignore |
|
|
|
self._analyze_params_element( |
|
|
|
self._analyze_params_element( |
|
|
|
Cls, Cls_parser, element_parser, explored_reference_id, parser, all_elements |
|
|
|
Cls, Cls_parser, element_parser, explored_reference_id, parser, all_elements |
|
|
|
) |
|
|
|
) |
|
|
@ -597,7 +600,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
if self.is_compact_ast: |
|
|
|
if self.is_compact_ast: |
|
|
|
for using_for in self._usingForNotParsed: |
|
|
|
for using_for in self._usingForNotParsed: |
|
|
|
if "typeName" in using_for and using_for["typeName"]: |
|
|
|
if "typeName" in using_for and using_for["typeName"]: |
|
|
|
type_name = parse_type(using_for["typeName"], self) |
|
|
|
type_name: USING_FOR_KEY = parse_type(using_for["typeName"], self) |
|
|
|
else: |
|
|
|
else: |
|
|
|
type_name = "*" |
|
|
|
type_name = "*" |
|
|
|
if type_name not in self._contract.using_for: |
|
|
|
if type_name not in self._contract.using_for: |
|
|
@ -616,7 +619,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
assert children and len(children) <= 2 |
|
|
|
assert children and len(children) <= 2 |
|
|
|
if len(children) == 2: |
|
|
|
if len(children) == 2: |
|
|
|
new = parse_type(children[0], self) |
|
|
|
new = parse_type(children[0], self) |
|
|
|
old = parse_type(children[1], self) |
|
|
|
old: USING_FOR_KEY = parse_type(children[1], self) |
|
|
|
else: |
|
|
|
else: |
|
|
|
new = parse_type(children[0], self) |
|
|
|
new = parse_type(children[0], self) |
|
|
|
old = "*" |
|
|
|
old = "*" |
|
|
@ -627,7 +630,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
self.log_incorrect_parsing(f"Missing using for {e}") |
|
|
|
self.log_incorrect_parsing(f"Missing using for {e}") |
|
|
|
|
|
|
|
|
|
|
|
def _analyze_function_list(self, function_list: List, type_name: Type) -> None: |
|
|
|
def _analyze_function_list(self, function_list: List, type_name: USING_FOR_KEY) -> None: |
|
|
|
for f in function_list: |
|
|
|
for f in function_list: |
|
|
|
full_name_split = f["function"]["name"].split(".") |
|
|
|
full_name_split = f["function"]["name"].split(".") |
|
|
|
if len(full_name_split) == 1: |
|
|
|
if len(full_name_split) == 1: |
|
|
@ -646,7 +649,9 @@ class ContractSolc(CallerContextExpression): |
|
|
|
function_name = full_name_split[2] |
|
|
|
function_name = full_name_split[2] |
|
|
|
self._analyze_library_function(library_name, function_name, type_name) |
|
|
|
self._analyze_library_function(library_name, function_name, type_name) |
|
|
|
|
|
|
|
|
|
|
|
def _check_aliased_import(self, first_part: str, function_name: str, type_name: Type) -> None: |
|
|
|
def _check_aliased_import( |
|
|
|
|
|
|
|
self, first_part: str, function_name: str, type_name: USING_FOR_KEY |
|
|
|
|
|
|
|
) -> None: |
|
|
|
# We check if the first part appear as alias for an import |
|
|
|
# We check if the first part appear as alias for an import |
|
|
|
# if it is then function_name must be a top level function |
|
|
|
# if it is then function_name must be a top level function |
|
|
|
# otherwise it's a library function |
|
|
|
# otherwise it's a library function |
|
|
@ -656,13 +661,13 @@ class ContractSolc(CallerContextExpression): |
|
|
|
return |
|
|
|
return |
|
|
|
self._analyze_library_function(first_part, function_name, type_name) |
|
|
|
self._analyze_library_function(first_part, function_name, type_name) |
|
|
|
|
|
|
|
|
|
|
|
def _analyze_top_level_function(self, function_name: str, type_name: Type) -> None: |
|
|
|
def _analyze_top_level_function(self, function_name: str, type_name: USING_FOR_KEY) -> None: |
|
|
|
for tl_function in self.compilation_unit.functions_top_level: |
|
|
|
for tl_function in self.compilation_unit.functions_top_level: |
|
|
|
if tl_function.name == function_name: |
|
|
|
if tl_function.name == function_name: |
|
|
|
self._contract.using_for[type_name].append(tl_function) |
|
|
|
self._contract.using_for[type_name].append(tl_function) |
|
|
|
|
|
|
|
|
|
|
|
def _analyze_library_function( |
|
|
|
def _analyze_library_function( |
|
|
|
self, library_name: str, function_name: str, type_name: Type |
|
|
|
self, library_name: str, function_name: str, type_name: USING_FOR_KEY |
|
|
|
) -> None: |
|
|
|
) -> None: |
|
|
|
# Get the library function |
|
|
|
# Get the library function |
|
|
|
found = False |
|
|
|
found = False |
|
|
@ -689,22 +694,13 @@ class ContractSolc(CallerContextExpression): |
|
|
|
# for enum, we can parse and analyze it |
|
|
|
# for enum, we can parse and analyze it |
|
|
|
# at the same time |
|
|
|
# at the same time |
|
|
|
self._analyze_enum(enum) |
|
|
|
self._analyze_enum(enum) |
|
|
|
self._enumsNotParsed = None |
|
|
|
self._enumsNotParsed = [] |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
self.log_incorrect_parsing(f"Missing enum {e}") |
|
|
|
self.log_incorrect_parsing(f"Missing enum {e}") |
|
|
|
|
|
|
|
|
|
|
|
def _analyze_enum( |
|
|
|
def _analyze_enum( |
|
|
|
self, |
|
|
|
self, |
|
|
|
enum: Dict[ |
|
|
|
enum: Dict, |
|
|
|
str, |
|
|
|
|
|
|
|
Union[ |
|
|
|
|
|
|
|
str, |
|
|
|
|
|
|
|
int, |
|
|
|
|
|
|
|
List[Dict[str, Union[int, str]]], |
|
|
|
|
|
|
|
Dict[str, str], |
|
|
|
|
|
|
|
List[Dict[str, Union[Dict[str, str], int, str]]], |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
], |
|
|
|
|
|
|
|
) -> None: |
|
|
|
) -> None: |
|
|
|
# Enum can be parsed in one pass |
|
|
|
# Enum can be parsed in one pass |
|
|
|
if self.is_compact_ast: |
|
|
|
if self.is_compact_ast: |
|
|
@ -753,13 +749,13 @@ class ContractSolc(CallerContextExpression): |
|
|
|
event.set_contract(self._contract) |
|
|
|
event.set_contract(self._contract) |
|
|
|
event.set_offset(event_to_parse["src"], self._contract.compilation_unit) |
|
|
|
event.set_offset(event_to_parse["src"], self._contract.compilation_unit) |
|
|
|
|
|
|
|
|
|
|
|
event_parser = EventSolc(event, event_to_parse, self) |
|
|
|
event_parser = EventSolc(event, event_to_parse, self) # type: ignore |
|
|
|
event_parser.analyze(self) |
|
|
|
event_parser.analyze(self) # type: ignore |
|
|
|
self._contract.events_as_dict[event.full_name] = event |
|
|
|
self._contract.events_as_dict[event.full_name] = event |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
except (VariableNotFound, KeyError) as e: |
|
|
|
self.log_incorrect_parsing(f"Missing event {e}") |
|
|
|
self.log_incorrect_parsing(f"Missing event {e}") |
|
|
|
|
|
|
|
|
|
|
|
self._eventsNotParsed = None |
|
|
|
self._eventsNotParsed = [] |
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
# endregion |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
@ -768,7 +764,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
def delete_content(self): |
|
|
|
def delete_content(self) -> None: |
|
|
|
""" |
|
|
|
""" |
|
|
|
Remove everything not parsed from the contract |
|
|
|
Remove everything not parsed from the contract |
|
|
|
This is used only if something went wrong with the inheritance parsing |
|
|
|
This is used only if something went wrong with the inheritance parsing |
|
|
@ -810,7 +806,7 @@ class ContractSolc(CallerContextExpression): |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
def __hash__(self): |
|
|
|
def __hash__(self) -> int: |
|
|
|
return self._contract.id |
|
|
|
return self._contract.id |
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
# endregion |
|
|
|