diff --git a/slither/core/expressions/elementary_type_name_expression.py b/slither/core/expressions/elementary_type_name_expression.py index 6c10acd5b..217217fbc 100644 --- a/slither/core/expressions/elementary_type_name_expression.py +++ b/slither/core/expressions/elementary_type_name_expression.py @@ -15,5 +15,10 @@ class ElementaryTypeNameExpression(Expression): 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) diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index 810b0e878..7458854f1 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -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 diff --git a/slither/slithir/operations/solidity_call.py b/slither/slithir/operations/solidity_call.py index a0ec01637..4d4ea7592 100644 --- a/slither/slithir/operations/solidity_call.py +++ b/slither/slithir/operations/solidity_call.py @@ -30,8 +30,17 @@ class SolidityCall(Call, OperationWithLValue): 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) diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py index a674c5975..b564bfb93 100644 --- a/slither/solc_parsing/declarations/function.py +++ b/slither/solc_parsing/declarations/function.py @@ -631,6 +631,8 @@ class FunctionSolc: i = 0 new_node = node for variable in variables: + if variable is None: + continue init = inits[i] src = variable["src"] i = i + 1 diff --git a/slither/solc_parsing/expressions/expression_parsing.py b/slither/solc_parsing/expressions/expression_parsing.py index 4b78a2a10..fb1764dcc 100644 --- a/slither/solc_parsing/expressions/expression_parsing.py +++ b/slither/solc_parsing/expressions/expression_parsing.py @@ -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 @@ -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) diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index 19f9fd782..3606dce4b 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -5,6 +5,7 @@ from slither.core.expressions import (AssignmentOperationType, 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, @@ -130,6 +131,14 @@ class ExpressionToSlithIR(ExpressionVisitor): 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];