Types improvements

pull/1640/head
Feist Josselin 2 years ago
parent faba84efc1
commit 8eec95be2a
  1. 5
      slither/core/declarations/function_top_level.py
  2. 4
      slither/core/solidity_types/array_type.py
  3. 76
      slither/slithir/convert.py
  4. 89
      slither/slithir/utils/ssa.py
  5. 22
      slither/visitors/slithir/expression_to_slithir.py

@ -9,6 +9,7 @@ from slither.core.declarations.top_level import TopLevel
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.scope.scope import FileScope from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
class FunctionTopLevel(Function, TopLevel): class FunctionTopLevel(Function, TopLevel):
@ -78,7 +79,9 @@ class FunctionTopLevel(Function, TopLevel):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def generate_slithir_ssa(self, all_ssa_state_variables_instances: Dict[Any, Any]) -> None: def generate_slithir_ssa(
self, all_ssa_state_variables_instances: Dict[str, "StateIRVariable"]
) -> None:
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.core.dominators.utils import ( from slither.core.dominators.utils import (

@ -17,7 +17,7 @@ class ArrayType(Type):
def __init__( def __init__(
self, self,
t: Union["TypeAliasTopLevel", "ArrayType", "FunctionType", "ElementaryType"], t: Union["TypeAliasTopLevel", "ArrayType", "FunctionType", "ElementaryType"],
length: Optional[Union["Identifier", "Literal", "BinaryOperation"]], length: Optional[Union["Identifier", Literal, "BinaryOperation"]],
) -> None: ) -> None:
assert isinstance(t, Type) assert isinstance(t, Type)
if length: if length:
@ -49,7 +49,7 @@ class ArrayType(Type):
return self._length return self._length
@property @property
def length_value(self) -> Optional["Literal"]: def length_value(self) -> Optional[Literal]:
return self._length_value return self._length_value
@property @property

@ -165,7 +165,7 @@ def convert_expression(expression: Expression, node: "Node") -> List[Any]:
################################################################################### ###################################################################################
def is_value(ins: slither.slithir.operations.operation.Operation) -> bool: def is_value(ins: Operation) -> bool:
if isinstance(ins, TmpCall): if isinstance(ins, TmpCall):
if isinstance(ins.ori, Member): if isinstance(ins.ori, Member):
if ins.ori.variable_right == "value": if ins.ori.variable_right == "value":
@ -173,7 +173,7 @@ def is_value(ins: slither.slithir.operations.operation.Operation) -> bool:
return False return False
def is_gas(ins: slither.slithir.operations.operation.Operation) -> bool: def is_gas(ins: Operation) -> bool:
if isinstance(ins, TmpCall): if isinstance(ins, TmpCall):
if isinstance(ins.ori, Member): if isinstance(ins.ori, Member):
if ins.ori.variable_right == "gas": if ins.ori.variable_right == "gas":
@ -293,7 +293,7 @@ def _find_function_from_parameter(
return None return None
def is_temporary(ins: slither.slithir.operations.operation.Operation) -> bool: def is_temporary(ins: Operation) -> bool:
return isinstance( return isinstance(
ins, ins,
(Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure), (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure),
@ -1153,12 +1153,8 @@ def can_be_low_level(ir: slither.slithir.operations.high_level_call.HighLevelCal
def convert_to_low_level( def convert_to_low_level(
ir: slither.slithir.operations.high_level_call.HighLevelCall, ir: HighLevelCall,
) -> Union[ ) -> Union[Send, LowLevelCall, Transfer,]:
slither.slithir.operations.send.Send,
slither.slithir.operations.low_level_call.LowLevelCall,
slither.slithir.operations.transfer.Transfer,
]:
""" """
Convert to a transfer/send/or low level call Convert to a transfer/send/or low level call
The funciton assume to receive a correct IR The funciton assume to receive a correct IR
@ -1198,7 +1194,7 @@ def convert_to_low_level(
raise SlithIRError(f"Incorrect conversion to low level {ir}") raise SlithIRError(f"Incorrect conversion to low level {ir}")
def can_be_solidity_func(ir: slither.slithir.operations.high_level_call.HighLevelCall) -> bool: def can_be_solidity_func(ir: HighLevelCall) -> bool:
if not isinstance(ir, HighLevelCall): if not isinstance(ir, HighLevelCall):
return False return False
return ir.destination.name == "abi" and ir.function_name in [ return ir.destination.name == "abi" and ir.function_name in [
@ -1212,8 +1208,8 @@ def can_be_solidity_func(ir: slither.slithir.operations.high_level_call.HighLeve
def convert_to_solidity_func( def convert_to_solidity_func(
ir: slither.slithir.operations.high_level_call.HighLevelCall, ir: HighLevelCall,
) -> slither.slithir.operations.solidity_call.SolidityCall: ) -> SolidityCall:
""" """
Must be called after can_be_solidity_func Must be called after can_be_solidity_func
:param ir: :param ir:
@ -1250,8 +1246,8 @@ def convert_to_solidity_func(
def convert_to_push_expand_arr( def convert_to_push_expand_arr(
ir: slither.slithir.operations.high_level_call.HighLevelCall, node: "Node", ret: List[Any] ir: HighLevelCall, node: "Node", ret: List[Any]
) -> slither.slithir.variables.temporary.TemporaryVariable: ) -> TemporaryVariable:
arr = ir.destination arr = ir.destination
length = ReferenceVariable(node) length = ReferenceVariable(node)
@ -1287,14 +1283,14 @@ def convert_to_push_expand_arr(
def convert_to_push_set_val( def convert_to_push_set_val(
ir: slither.slithir.operations.high_level_call.HighLevelCall, ir: HighLevelCall,
node: "Node", node: "Node",
length_val: slither.slithir.variables.temporary.TemporaryVariable, length_val: TemporaryVariable,
ret: List[ ret: List[
Union[ Union[
slither.slithir.operations.length.Length, Length,
slither.slithir.operations.assignment.Assignment, Assignment,
slither.slithir.operations.binary.Binary, Binary,
] ]
], ],
) -> None: ) -> None:
@ -1417,21 +1413,16 @@ def convert_to_pop(ir, node):
def look_for_library_or_top_level( def look_for_library_or_top_level(
contract: slither.core.declarations.contract.Contract, contract: Contract,
ir: slither.slithir.operations.high_level_call.HighLevelCall, ir: HighLevelCall,
using_for, using_for,
t: Union[ t: Union[
slither.core.solidity_types.user_defined_type.UserDefinedType, UserDefinedType,
slither.core.solidity_types.elementary_type.ElementaryType, ElementaryType,
str, str,
TypeAliasTopLevel, TypeAliasTopLevel,
], ],
) -> Optional[ ) -> Optional[Union[LibraryCall, InternalCall,]]:
Union[
slither.slithir.operations.library_call.LibraryCall,
slither.slithir.operations.internal_call.InternalCall,
]
]:
for destination in using_for[t]: for destination in using_for[t]:
if isinstance(destination, FunctionTopLevel) and destination.name == ir.function_name: if isinstance(destination, FunctionTopLevel) and destination.name == ir.function_name:
arguments = [ir.destination] + ir.arguments arguments = [ir.destination] + ir.arguments
@ -1477,13 +1468,8 @@ def look_for_library_or_top_level(
def convert_to_library_or_top_level( def convert_to_library_or_top_level(
ir: slither.slithir.operations.high_level_call.HighLevelCall, node: "Node", using_for ir: HighLevelCall, node: "Node", using_for
) -> Optional[ ) -> Optional[Union[LibraryCall, InternalCall,]]:
Union[
slither.slithir.operations.library_call.LibraryCall,
slither.slithir.operations.internal_call.InternalCall,
]
]:
# We use contract_declarer, because Solidity resolve the library # We use contract_declarer, because Solidity resolve the library
# before resolving the inheritance. # before resolving the inheritance.
# Though we could use .contract as libraries cannot be shadowed # Though we could use .contract as libraries cannot be shadowed
@ -1504,8 +1490,8 @@ def convert_to_library_or_top_level(
def get_type( def get_type(
t: Union[ t: Union[
slither.core.solidity_types.user_defined_type.UserDefinedType, UserDefinedType,
slither.core.solidity_types.elementary_type.ElementaryType, ElementaryType,
] ]
) -> str: ) -> str:
""" """
@ -1526,9 +1512,7 @@ def _can_be_implicitly_converted(source: str, target: str) -> bool:
return source == target return source == target
def convert_type_library_call( def convert_type_library_call(ir: HighLevelCall, lib_contract: Contract) -> Optional[LibraryCall]:
ir: HighLevelCall, lib_contract: Contract
) -> Optional[slither.slithir.operations.library_call.LibraryCall]:
func = None func = None
candidates = [ candidates = [
f f
@ -1739,7 +1723,7 @@ def convert_type_of_high_and_internal_level_call(
################################################################################### ###################################################################################
def find_references_origin(irs: List[Any]) -> None: def find_references_origin(irs: List[Operation]) -> None:
""" """
Make lvalue of each Index, Member operation Make lvalue of each Index, Member operation
points to the left variable points to the left variable
@ -1776,7 +1760,7 @@ def remove_temporary(result):
return result return result
def remove_unused(result: List[Any]) -> List[Any]: def remove_unused(result: List[Operation]) -> List[Operation]:
removed = True removed = True
if not result: if not result:
@ -1823,7 +1807,7 @@ def remove_unused(result: List[Any]) -> List[Any]:
################################################################################### ###################################################################################
def convert_constant_types(irs: List[Any]) -> None: def convert_constant_types(irs: List[Operation]) -> None:
""" """
late conversion of uint -> type for constant (Literal) late conversion of uint -> type for constant (Literal)
:param irs: :param irs:
@ -1899,7 +1883,7 @@ def convert_constant_types(irs: List[Any]) -> None:
################################################################################### ###################################################################################
def convert_delete(irs: List[Any]) -> None: def convert_delete(irs: List[Operation]) -> None:
""" """
Convert the lvalue of the Delete to point to the variable removed Convert the lvalue of the Delete to point to the variable removed
This can only be done after find_references_origin is called This can only be done after find_references_origin is called
@ -1935,7 +1919,7 @@ def _find_source_mapping_references(irs: List[Operation]) -> None:
################################################################################### ###################################################################################
def apply_ir_heuristics(irs: List[Operation], node: "Node") -> List[Any]: def apply_ir_heuristics(irs: List[Operation], node: "Node") -> List[Operation]:
""" """
Apply a set of heuristic to improve slithIR Apply a set of heuristic to improve slithIR
""" """

@ -215,18 +215,12 @@ def add_ssa_ir(
def generate_ssa_irs( def generate_ssa_irs(
node: Node, node: Node,
local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable], local_variables_instances: Dict[str, LocalIRVariable],
all_local_variables_instances: Dict[ all_local_variables_instances: Dict[str, LocalIRVariable],
str, slither.slithir.variables.local_variable.LocalIRVariable state_variables_instances: Dict[str, StateIRVariable],
], all_state_variables_instances: Dict[str, StateIRVariable],
state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable], init_local_variables_instances: Dict[str, LocalIRVariable],
all_state_variables_instances: Dict[ visited: List[Node],
str, slither.slithir.variables.state_variable.StateIRVariable
],
init_local_variables_instances: Dict[
str, slither.slithir.variables.local_variable.LocalIRVariable
],
visited: List[Union[Node, Any]],
) -> None: ) -> None:
if node in visited: if node in visited:
@ -347,14 +341,11 @@ def generate_ssa_irs(
def last_name( def last_name(
n: Node, n: Node,
var: Union[ var: Union[
slither.slithir.variables.state_variable.StateIRVariable, StateIRVariable,
slither.slithir.variables.local_variable.LocalIRVariable, LocalIRVariable,
], ],
init_vars: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable], init_vars: Dict[str, LocalIRVariable],
) -> Union[ ) -> Union[StateIRVariable, LocalIRVariable,]:
slither.slithir.variables.state_variable.StateIRVariable,
slither.slithir.variables.local_variable.LocalIRVariable,
]:
candidates = [] candidates = []
# Todo optimize by creating a variables_ssa_written attribute # Todo optimize by creating a variables_ssa_written attribute
for ir_ssa in n.irs_ssa: for ir_ssa in n.irs_ssa:
@ -375,7 +366,7 @@ def last_name(
def is_used_later( def is_used_later(
initial_node: Node, initial_node: Node,
variable: Union[slither.slithir.variables.state_variable.StateIRVariable, LocalVariable], variable: Union[StateIRVariable, LocalVariable],
) -> bool: ) -> bool:
# TODO: does not handle the case where its read and written in the declaration node # TODO: does not handle the case where its read and written in the declaration node
# It can be problematic if this happens in a loop/if structure # It can be problematic if this happens in a loop/if structure
@ -425,14 +416,10 @@ def is_used_later(
def update_lvalue( def update_lvalue(
new_ir: Operation, new_ir: Operation,
node: Node, node: Node,
local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable], local_variables_instances: Dict[str, LocalIRVariable],
all_local_variables_instances: Dict[ all_local_variables_instances: Dict[str, LocalIRVariable],
str, slither.slithir.variables.local_variable.LocalIRVariable state_variables_instances: Dict[str, StateIRVariable],
], all_state_variables_instances: Dict[str, StateIRVariable],
state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable],
all_state_variables_instances: Dict[
str, slither.slithir.variables.state_variable.StateIRVariable
],
) -> None: ) -> None:
if isinstance(new_ir, OperationWithLValue): if isinstance(new_ir, OperationWithLValue):
lvalue = new_ir.lvalue lvalue = new_ir.lvalue
@ -476,10 +463,8 @@ def update_lvalue(
def initiate_all_local_variables_instances( def initiate_all_local_variables_instances(
nodes: List[Node], nodes: List[Node],
local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable], local_variables_instances: Dict[str, LocalIRVariable],
all_local_variables_instances: Dict[ all_local_variables_instances: Dict[str, LocalIRVariable],
str, slither.slithir.variables.local_variable.LocalIRVariable
],
) -> None: ) -> None:
for node in nodes: for node in nodes:
if node.variable_declaration: if node.variable_declaration:
@ -500,17 +485,11 @@ def initiate_all_local_variables_instances(
def fix_phi_rvalues_and_storage_ref( def fix_phi_rvalues_and_storage_ref(
node: Node, node: Node,
local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable], local_variables_instances: Dict[str, LocalIRVariable],
all_local_variables_instances: Dict[ all_local_variables_instances: Dict[str, LocalIRVariable],
str, slither.slithir.variables.local_variable.LocalIRVariable state_variables_instances: Dict[str, StateIRVariable],
], all_state_variables_instances: Dict[str, StateIRVariable],
state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable], init_local_variables_instances: Dict[str, LocalIRVariable],
all_state_variables_instances: Dict[
str, slither.slithir.variables.state_variable.StateIRVariable
],
init_local_variables_instances: Dict[
str, slither.slithir.variables.local_variable.LocalIRVariable
],
) -> None: ) -> None:
for ir in node.irs_ssa: for ir in node.irs_ssa:
if isinstance(ir, (Phi)) and not ir.rvalues: if isinstance(ir, (Phi)) and not ir.rvalues:
@ -609,18 +588,12 @@ def add_phi_origins(
def get( def get(
variable, variable,
local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable], local_variables_instances: Dict[str, LocalIRVariable],
state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable], state_variables_instances: Dict[str, StateIRVariable],
temporary_variables_instances: Dict[ temporary_variables_instances: Dict[int, TemporaryVariableSSA],
int, slither.slithir.variables.temporary_ssa.TemporaryVariableSSA reference_variables_instances: Dict[int, ReferenceVariableSSA],
], tuple_variables_instances: Dict[int, TupleVariableSSA],
reference_variables_instances: Dict[ all_local_variables_instances: Dict[str, LocalIRVariable],
int, slither.slithir.variables.reference_ssa.ReferenceVariableSSA
],
tuple_variables_instances: Dict[int, slither.slithir.variables.tuple_ssa.TupleVariableSSA],
all_local_variables_instances: Dict[
str, slither.slithir.variables.local_variable.LocalIRVariable
],
): ):
# variable can be None # variable can be None
# for example, on LowLevelCall, ir.lvalue can be none # for example, on LowLevelCall, ir.lvalue can be none
@ -706,9 +679,9 @@ def get_arguments(ir: Call, *instances) -> List[Any]:
def get_rec_values( def get_rec_values(
ir: Union[ ir: Union[
slither.slithir.operations.init_array.InitArray, InitArray,
slither.slithir.operations.return_operation.Return, Return,
slither.slithir.operations.new_array.NewArray, NewArray,
], ],
f: Callable, f: Callable,
*instances, *instances,

@ -119,15 +119,11 @@ _signed_to_unsigned = {
def convert_assignment( def convert_assignment(
left: Union[ left: Union[LocalVariable, StateVariable, ReferenceVariable],
LocalVariable, StateVariable, slither.slithir.variables.reference.ReferenceVariable
],
right: SourceMapping, right: SourceMapping,
t: slither.core.expressions.assignment_operation.AssignmentOperationType, t: AssignmentOperationType,
return_type, return_type,
) -> Union[ ) -> Union[Binary, Assignment]:
slither.slithir.operations.binary.Binary, slither.slithir.operations.assignment.Assignment
]:
if t == AssignmentOperationType.ASSIGN: if t == AssignmentOperationType.ASSIGN:
return Assignment(left, right, return_type) return Assignment(left, right, return_type)
if t == AssignmentOperationType.ASSIGN_OR: if t == AssignmentOperationType.ASSIGN_OR:
@ -173,9 +169,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
def result(self) -> List[Any]: def result(self) -> List[Any]:
return self._result return self._result
def _post_assignement_operation( def _post_assignement_operation(self, expression: AssignmentOperation) -> None:
self, expression: slither.core.expressions.assignment_operation.AssignmentOperation
) -> None:
left = get(expression.expression_left) left = get(expression.expression_left)
right = get(expression.expression_right) right = get(expression.expression_right)
if isinstance(left, list): # tuple expression: if isinstance(left, list): # tuple expression:
@ -275,9 +269,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
set_val(expression, val) set_val(expression, val)
# pylint: disable=too-many-branches,too-many-statements,too-many-locals # pylint: disable=too-many-branches,too-many-statements,too-many-locals
def _post_call_expression( def _post_call_expression(self, expression: CallExpression) -> None:
self, expression: slither.core.expressions.call_expression.CallExpression
) -> None:
assert isinstance(expression, CallExpression) assert isinstance(expression, CallExpression)
@ -387,11 +379,11 @@ class ExpressionToSlithIR(ExpressionVisitor):
def _post_elementary_type_name_expression( def _post_elementary_type_name_expression(
self, self,
expression: slither.core.expressions.elementary_type_name_expression.ElementaryTypeNameExpression, expression: ElementaryTypeNameExpression,
) -> None: ) -> None:
set_val(expression, expression.type) set_val(expression, expression.type)
def _post_identifier(self, expression: slither.core.expressions.identifier.Identifier) -> None: def _post_identifier(self, expression: Identifier) -> None:
set_val(expression, expression.value) set_val(expression, expression.value)
def _post_index_access(self, expression: IndexAccess) -> None: def _post_index_access(self, expression: IndexAccess) -> None:

Loading…
Cancel
Save