Merge pull request #2383 from crytic/fix/guard-implicit-conversion-of-literals

fix: guard literal implicit conversion for arrays
pull/2392/head
alpharush 8 months ago committed by GitHub
commit c704a32ac3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 45
      slither/slithir/convert.py
  2. 9
      slither/slithir/operations/init_array.py
  3. 4
      slither/slithir/operations/new_array.py
  4. 12
      slither/visitors/slithir/expression_to_slithir.py
  5. 2
      tests/e2e/vyper_parsing/snapshots/ast_parsing__vyper_cfgir_for2_for_loop__0.txt
  6. 55
      tests/unit/slithir/test_ssa_generation.py

@ -1926,35 +1926,21 @@ def convert_constant_types(irs: List[Operation]) -> None:
while was_changed:
was_changed = False
for ir in irs:
if isinstance(ir, Assignment):
if isinstance(ir.lvalue.type, ElementaryType):
if ir.lvalue.type.type in ElementaryTypeInt:
if isinstance(ir.rvalue, Function):
continue
if isinstance(ir.rvalue, TupleVariable):
# TODO: fix missing Unpack conversion
continue
if isinstance(ir.rvalue.type, TypeAlias):
ir.rvalue.set_type(ElementaryType(ir.lvalue.type.name))
was_changed = True
elif ir.rvalue.type.type not in ElementaryTypeInt:
ir.rvalue.set_type(ElementaryType(ir.lvalue.type.type))
if isinstance(ir, (Assignment, Binary)):
if (
isinstance(ir.lvalue.type, ElementaryType)
and ir.lvalue.type.type in ElementaryTypeInt
):
for r in ir.read:
if isinstance(r, Constant) and r.type.type not in ElementaryTypeInt:
r.set_type(ElementaryType(ir.lvalue.type.type))
was_changed = True
if isinstance(ir, Binary):
if isinstance(ir.lvalue.type, ElementaryType):
if ir.lvalue.type.type in ElementaryTypeInt:
for r in ir.read:
if r.type.type not in ElementaryTypeInt:
r.set_type(ElementaryType(ir.lvalue.type.type))
was_changed = True
if isinstance(ir, (HighLevelCall, InternalCall)):
func = ir.function
if isinstance(func, StateVariable):
types = export_nested_types_from_variable(func)
else:
if func is None:
# TODO: add POP instruction
break
types = [p.type for p in func.parameters]
assert len(types) == len(ir.arguments)
for idx, arg in enumerate(ir.arguments):
@ -1964,6 +1950,7 @@ def convert_constant_types(irs: List[Operation]) -> None:
if arg.type.type not in ElementaryTypeInt:
arg.set_type(ElementaryType(t.type))
was_changed = True
if isinstance(ir, NewStructure):
st = ir.structure
for idx, arg in enumerate(ir.arguments):
@ -1973,11 +1960,15 @@ def convert_constant_types(irs: List[Operation]) -> None:
if arg.type.type not in ElementaryTypeInt:
arg.set_type(ElementaryType(e.type.type))
was_changed = True
def is_elementary_array(t):
return isinstance(t, ArrayType) and isinstance(t.type, ElementaryType)
if isinstance(ir, InitArray):
if isinstance(ir.lvalue.type, ArrayType):
if isinstance(ir.lvalue.type.type, ElementaryType):
if ir.lvalue.type.type.type in ElementaryTypeInt:
for r in ir.read:
if is_elementary_array(ir.lvalue.type):
if ir.lvalue.type.type.type in ElementaryTypeInt:
for r in ir.read:
if isinstance(r, Constant) and is_elementary_array(r.type):
if r.type.type.type not in ElementaryTypeInt:
r.set_type(ElementaryType(ir.lvalue.type.type.type))
was_changed = True

@ -1,14 +1,13 @@
from typing import List, Union
from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_rvalue
from slither.slithir.variables.constant import Constant
from slither.slithir.utils.utils import is_valid_rvalue, RVALUE
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
class InitArray(OperationWithLValue):
def __init__(
self, init_values: List[Constant], lvalue: Union[TemporaryVariableSSA, TemporaryVariable]
self, init_values: List[RVALUE], lvalue: Union[TemporaryVariableSSA, TemporaryVariable]
) -> None:
# init_values can be an array of n dimension
# reduce was removed in py3
@ -30,11 +29,11 @@ class InitArray(OperationWithLValue):
self._lvalue = lvalue
@property
def read(self) -> List[Constant]:
def read(self) -> List[RVALUE]:
return self._unroll(self.init_values)
@property
def init_values(self) -> List[Constant]:
def init_values(self) -> List[RVALUE]:
return list(self._init_values)
def __str__(self):

@ -3,9 +3,9 @@ from typing import List, Union, TYPE_CHECKING
from slither.core.solidity_types.array_type import ArrayType
from slither.slithir.operations.call import Call
from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import RVALUE
if TYPE_CHECKING:
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
@ -27,7 +27,7 @@ class NewArray(Call, OperationWithLValue):
return self._array_type
@property
def read(self) -> List["Constant"]:
def read(self) -> List[RVALUE]:
return self._unroll(self.arguments)
def __str__(self):

@ -227,15 +227,16 @@ class ExpressionToSlithIR(ExpressionVisitor):
self._result.append(operation)
set_val(expression, None)
else:
# Init of array, like
# uint8[2] var = [1,2];
# For `InitArray`, the rhs is a list or singleton of `TupleExpression` elements.
# Init of array e.g. uint8[2] var = [1,2];
if isinstance(right, list):
operation = InitArray(right, left)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, left)
elif isinstance(left.type, ArrayType):
# Special case for init of array, when the right has only one element
# Special case for init of array, when the right has only one element e.g. arr = [1];
elif isinstance(left.type, ArrayType) and not isinstance(right.type, ArrayType):
operation = InitArray([right], left)
operation.set_expression(expression)
self._result.append(operation)
@ -270,6 +271,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
self._result.append(operation)
else:
operation = convert_assignment(
left, right, expression.type, expression.expression_return_type
)
@ -430,7 +432,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
set_val(expression, val)
def _post_conditional_expression(self, expression: ConditionalExpression) -> None:
raise Exception(f"Ternary operator are not convertible to SlithIR {expression}")
raise SlithIRError(f"Ternary operator are not convertible to SlithIR {expression}")
def _post_elementary_type_name_expression(
self,

@ -8,7 +8,7 @@ EXPRESSION:
_strategies = strategies
IRs:
_strategies(address[3]) = ['strategies(address[3])']"];
_strategies(address[3]) := strategies(address[3])"];
1->2;
2[label="Node Type: BEGIN_LOOP 2
"];

@ -26,6 +26,7 @@ from slither.slithir.operations import (
InternalCall,
Index,
InitArray,
NewArray,
)
from slither.slithir.utils.ssa import is_used_later
from slither.slithir.variables import (
@ -1131,8 +1132,62 @@ def test_issue_2016(slither_from_solidity_source):
f = c.functions[0]
operations = f.slithir_operations
new_op = operations[0]
assert isinstance(new_op, NewArray)
lvalue = new_op.lvalue
lvalue_type = lvalue.type
assert isinstance(lvalue_type, ArrayType)
assert lvalue_type.type == ElementaryType("int256")
assert lvalue_type.is_dynamic
def test_issue_2210(slither_from_solidity_source):
source = """
contract C {
function f (int x) public returns(int) {
int h = 1;
int k = 5;
int[5] memory arr = [x, C.x, C.y, h - k, h + k];
}
int x= 4;
int y = 5;
}
"""
with slither_from_solidity_source(source) as slither:
c = slither.get_contract_from_name("C")[0]
f = c.functions[0]
operations = f.slithir_operations
new_op = operations[6]
assert isinstance(new_op, InitArray)
lvalue = new_op.lvalue
lvalue_type = lvalue.type
assert isinstance(lvalue_type, ArrayType)
assert lvalue_type.type == ElementaryType("int256")
assert not lvalue_type.is_dynamic
source2 = """
contract X {
function _toInts(uint256[] memory a) private pure returns (int256[] memory casted) {
/// @solidity memory-safe-assembly
assembly {
casted := a
}
}
}
"""
with slither_from_solidity_source(source2) as slither:
x = slither.get_contract_from_name("X")[0]
f2 = x.functions[0]
operations = f2.slithir_operations
new_op2 = operations[0]
assert isinstance(new_op2, Assignment)
lvalue = new_op2.lvalue
lvalue_type = lvalue.type
assert isinstance(lvalue_type, ArrayType)
assert lvalue_type.type == ElementaryType("int256")
assert lvalue_type.is_dynamic
rvalue_type = new_op2.rvalue.type
assert isinstance(rvalue_type, ArrayType)
assert rvalue_type.type == ElementaryType("uint256")
assert rvalue_type.is_dynamic

Loading…
Cancel
Save