Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Several improvements in tuples and abi.decode support #548

Merged
merged 1 commit into from
Jul 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions slither/core/expressions/elementary_type_name_expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,10 @@ def __init__(self, t):
def type(self) -> Type:
return self._type

@type.setter
def type(self, new_type: Type):
assert isinstance(new_type, Type)
self._type = new_type

def __str__(self):
return str(self._type)
6 changes: 6 additions & 0 deletions slither/slithir/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,6 +803,12 @@ def convert_to_solidity_func(ir):
new_ir.set_node(ir.node)
if isinstance(call.return_type, list) and len(call.return_type) == 1:
new_ir.lvalue.set_type(call.return_type[0])
elif (isinstance(new_ir.lvalue, TupleVariable) and
call == SolidityFunction("abi.decode()") and
len(new_ir.arguments) == 2 and
isinstance(new_ir.arguments[1], list)):
types = [x for x in new_ir.arguments[1]]
new_ir.lvalue.set_type(types)
else:
new_ir.lvalue.set_type(call.return_type)
return new_ir
Expand Down
19 changes: 14 additions & 5 deletions slither/slithir/operations/solidity_call.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,17 @@ def type_call(self):
return self._type_call

def __str__(self):
args = [str(a) for a in self.arguments]
return str(self.lvalue) +' = SOLIDITY_CALL {}({})'.format(self.function.full_name, ','.join(args))
# return str(self.lvalue) +' = INTERNALCALL {} (arg {})'.format(self.function,
# self.nbr_arguments)

if (self.function == SolidityFunction("abi.decode()") and
len(self.arguments) == 2 and
isinstance(self.arguments[1], list)):
args = str(self.arguments[0]) + '(' + ','.join([str(a) for a in self.arguments[1]]) + ')'
else:
args = ','.join([str(a) for a in self.arguments])

lvalue = ''
if self.lvalue:
if isinstance(self.lvalue.type, (list,)):
lvalue = '{}({}) = '.format(self.lvalue, ','.join(str(x) for x in self.lvalue.type))
else:
lvalue = '{}({}) = '.format(self.lvalue, self.lvalue.type)
return lvalue + 'SOLIDITY_CALL {}({})'.format(self.function.full_name, args)
2 changes: 2 additions & 0 deletions slither/solc_parsing/declarations/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,8 @@ def _parse_variable_definition(self, statement: Dict, node: NodeSolc) -> NodeSol
i = 0
new_node = node
for variable in variables:
if variable is None:
continue
init = inits[i]
src = variable["src"]
i = i + 1
Expand Down
8 changes: 6 additions & 2 deletions slither/solc_parsing/expressions/expression_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,6 @@ def parse_expression(expression: Dict, caller_context: CallerContext) -> "Expres
# | Expression '?' Expression ':' Expression
# | Expression ('=' | '|=' | '^=' | '&=' | '<<=' | '>>=' | '+=' | '-=' | '*=' | '/=' | '%=') Expression
# | PrimaryExpression

# The AST naming does not follow the spec
name = expression[caller_context.get_key()]
is_compact_ast = caller_context.is_compact_ast
Expand Down Expand Up @@ -646,7 +645,12 @@ def parse_expression(expression: Dict, caller_context: CallerContext) -> "Expres
# if abi.decode is used
# For example, abi.decode(data, ...(uint[]) )
if right is None:
return parse_expression(left, caller_context)
ret = parse_expression(left, caller_context)
# Nested array are not yet available in abi.decode
if isinstance(ret, ElementaryTypeNameExpression):
old_type = ret.type
ret.type = ArrayType(old_type, None)
return ret

left_expression = parse_expression(left, caller_context)
right_expression = parse_expression(right, caller_context)
Expand Down
9 changes: 9 additions & 0 deletions slither/visitors/slithir/expression_to_slithir.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
UnaryOperationType, BinaryOperationType)
from slither.core.solidity_types import ArrayType, ElementaryType
from slither.core.solidity_types.type import Type
from slither.core.variables.local_variable_init_from_tuple import LocalVariableInitFromTuple
from slither.slithir.operations import (Assignment, Binary, BinaryType, Delete,
Index, InitArray, InternalCall, Member,
NewArray, NewContract,
Expand Down Expand Up @@ -130,6 +131,14 @@ def _post_assignement_operation(self, expression):
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, None)
# Tuple with only one element. We need to convert the assignment to a Unpack
# Ex:
# (uint a,,) = g()
elif isinstance(left, LocalVariableInitFromTuple) and left.tuple_index:
operation = Unpack(left, right, left.tuple_index)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, None)
else:
# Init of array, like
# uint8[2] var = [1,2];
Expand Down