def _post_unary_operation(self, expression): # pylint: disable=too-many-branches,too-many-statements value = get(expression.expression) if expression.type in [ UnaryOperationType.BANG, UnaryOperationType.TILD ]: lvalue = TemporaryVariable(self._node) operation = Unary(lvalue, value, expression.type) operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) elif expression.type in [UnaryOperationType.DELETE]: operation = Delete(value, value) operation.set_expression(expression) self._result.append(operation) set_val(expression, value) elif expression.type in [UnaryOperationType.PLUSPLUS_PRE]: operation = Binary(value, value, Constant("1", value.type), BinaryType.ADDITION) operation.set_expression(expression) self._result.append(operation) set_val(expression, value) elif expression.type in [UnaryOperationType.MINUSMINUS_PRE]: operation = Binary(value, value, Constant("1", value.type), BinaryType.SUBTRACTION) operation.set_expression(expression) self._result.append(operation) set_val(expression, value) elif expression.type in [UnaryOperationType.PLUSPLUS_POST]: lvalue = TemporaryVariable(self._node) operation = Assignment(lvalue, value, value.type) operation.set_expression(expression) self._result.append(operation) operation = Binary(value, value, Constant("1", value.type), BinaryType.ADDITION) operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) elif expression.type in [UnaryOperationType.MINUSMINUS_POST]: lvalue = TemporaryVariable(self._node) operation = Assignment(lvalue, value, value.type) operation.set_expression(expression) self._result.append(operation) operation = Binary(value, value, Constant("1", value.type), BinaryType.SUBTRACTION) operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) elif expression.type in [UnaryOperationType.PLUS_PRE]: set_val(expression, value) elif expression.type in [UnaryOperationType.MINUS_PRE]: lvalue = TemporaryVariable(self._node) operation = Binary(lvalue, Constant("0", value.type), value, BinaryType.SUBTRACTION) operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) else: raise SlithIRError( "Unary operation to IR not supported {}".format(expression))
def _post_type_conversion(self, expression): expr = get(expression.expression) val = TemporaryVariable(self._node) operation = TypeConversion(val, expr, expression.type) operation.set_expression(expression) self._result.append(operation) set_val(expression, val)
def _post_index_access(self, expression): left = get(expression.expression_left) right = get(expression.expression_right) # Left can be a type for abi.decode(var, uint[2]) if isinstance(left, Type): # Nested type are not yet supported by abi.decode, so the assumption # Is that the right variable must be a constant assert isinstance(right, Constant) t = ArrayType(left, right.value) set_val(expression, t) return val = ReferenceVariable(self._node) # access to anonymous array # such as [0,1][x] if isinstance(left, list): init_array_val = TemporaryVariable(self._node) init_array_right = left left = init_array_val operation = InitArray(init_array_right, init_array_val) operation.set_expression(expression) self._result.append(operation) operation = Index(val, left, right, expression.type) operation.set_expression(expression) self._result.append(operation) set_val(expression, val)
def _post_new_elementary_type(self, expression): # TODO unclear if this is ever used? val = TemporaryVariable(self._node) operation = TmpNewElementaryType(expression.type, val) operation.set_expression(expression) self._result.append(operation) set_val(expression, val)
def _post_new_contract(self, expression): val = TemporaryVariable(self._node) operation = TmpNewContract(expression.contract_name, val) operation.set_expression(expression) if expression.call_value: call_value = get(expression.call_value) operation.call_value = call_value if expression.call_salt: call_salt = get(expression.call_salt) operation.call_salt = call_salt self._result.append(operation) set_val(expression, val)
def _post_binary_operation(self, expression): left = get(expression.expression_left) right = get(expression.expression_right) val = TemporaryVariable(self._node) if expression.type in _signed_to_unsigned: new_left = TemporaryVariable(self._node) conv_left = TypeConversion(new_left, left, ElementaryType("int256")) conv_left.set_expression(expression) self._result.append(conv_left) if expression.type != BinaryOperationType.RIGHT_SHIFT_ARITHMETIC: new_right = TemporaryVariable(self._node) conv_right = TypeConversion(new_right, right, ElementaryType("int256")) conv_right.set_expression(expression) self._result.append(conv_right) else: new_right = right new_final = TemporaryVariable(self._node) operation = Binary(new_final, new_left, new_right, _signed_to_unsigned[expression.type]) operation.set_expression(expression) self._result.append(operation) conv_final = TypeConversion(val, new_final, ElementaryType("uint256")) conv_final.set_expression(expression) self._result.append(conv_final) else: operation = Binary(val, left, right, _binary_to_binary[expression.type]) operation.set_expression(expression) self._result.append(operation) set_val(expression, val)
def _post_member_access(self, expression): expr = get(expression.expression) # Look for type(X).max / min # Because we looked at the AST structure, we need to look into the nested expression # Hopefully this is always on a direct sub field, and there is no weird construction if isinstance(expression.expression, CallExpression) and expression.member_name in [ "min", "max", ]: if isinstance(expression.expression.called, Identifier): if expression.expression.called.value == SolidityFunction( "type()"): assert len(expression.expression.arguments) == 1 val = TemporaryVariable(self._node) type_expression_found = expression.expression.arguments[0] assert isinstance(type_expression_found, ElementaryTypeNameExpression) type_found = type_expression_found.type if expression.member_name == "min:": op = Assignment( val, Constant(str(type_found.min), type_found), type_found, ) else: op = Assignment( val, Constant(str(type_found.max), type_found), type_found, ) self._result.append(op) set_val(expression, val) return val = ReferenceVariable(self._node) member = Member(expr, Constant(expression.member_name), val) member.set_expression(expression) self._result.append(member) set_val(expression, val)
def _post_new_array(self, expression): val = TemporaryVariable(self._node) operation = TmpNewArray(expression.depth, expression.array_type, val) operation.set_expression(expression) self._result.append(operation) set_val(expression, val)
def _post_call_expression(self, expression): # pylint: disable=too-many-branches,too-many-statements called = get(expression.called) args = [get(a) for a in expression.arguments if a] for arg in args: arg_ = Argument(arg) arg_.set_expression(expression) self._result.append(arg_) if isinstance(called, Function): # internal call # If tuple if expression.type_call.startswith( "tuple(") and expression.type_call != "tuple()": val = TupleVariable(self._node) else: val = TemporaryVariable(self._node) internal_call = InternalCall(called, len(args), val, expression.type_call) internal_call.set_expression(expression) self._result.append(internal_call) set_val(expression, val) else: # yul things if called.name == "caller()": val = TemporaryVariable(self._node) var = Assignment(val, SolidityVariableComposed("msg.sender"), "uint256") self._result.append(var) set_val(expression, val) elif called.name == "origin()": val = TemporaryVariable(self._node) var = Assignment(val, SolidityVariableComposed("tx.origin"), "uint256") self._result.append(var) set_val(expression, val) elif called.name == "extcodesize(uint256)": val = ReferenceVariable(self._node) var = Member(args[0], Constant("codesize"), val) self._result.append(var) set_val(expression, val) elif called.name == "selfbalance()": val = TemporaryVariable(self._node) var = TypeConversion(val, SolidityVariable("this"), ElementaryType("address")) self._result.append(var) val1 = ReferenceVariable(self._node) var1 = Member(val, Constant("balance"), val1) self._result.append(var1) set_val(expression, val1) elif called.name == "address()": val = TemporaryVariable(self._node) var = TypeConversion(val, SolidityVariable("this"), ElementaryType("address")) self._result.append(var) set_val(expression, val) elif called.name == "callvalue()": val = TemporaryVariable(self._node) var = Assignment(val, SolidityVariableComposed("msg.value"), "uint256") self._result.append(var) set_val(expression, val) else: # If tuple if expression.type_call.startswith( "tuple(") and expression.type_call != "tuple()": val = TupleVariable(self._node) else: val = TemporaryVariable(self._node) message_call = TmpCall(called, len(args), val, expression.type_call) message_call.set_expression(expression) # Gas/value are only accessible here if the syntax {gas: , value: } # Is used over .gas().value() if expression.call_gas: call_gas = get(expression.call_gas) message_call.call_gas = call_gas if expression.call_value: call_value = get(expression.call_value) message_call.call_value = call_value if expression.call_salt: call_salt = get(expression.call_salt) message_call.call_salt = call_salt self._result.append(message_call) set_val(expression, val)