def get(variable): if isinstance(variable, LocalVariable): if variable.name in local_variables_instances: return local_variables_instances[variable.name] new_var = LocalIRVariable(variable) local_variables_instances[variable.name] = new_var all_local_variables_instances[variable.name] = new_var return new_var if isinstance( variable, StateVariable ) and variable.canonical_name in state_variables_instances: return state_variables_instances[variable.canonical_name] elif isinstance(variable, ReferenceVariable): if not variable.index in reference_variables_instances: new_variable = ReferenceVariable(variable.node, index=variable.index) if variable.points_to: new_variable.points_to = get(variable.points_to) new_variable.set_type(variable.type) reference_variables_instances[variable.index] = new_variable return reference_variables_instances[variable.index] elif isinstance(variable, TemporaryVariable): if not variable.index in temporary_variables_instances: new_variable = TemporaryVariable(variable.node, index=variable.index) new_variable.set_type(variable.type) temporary_variables_instances[variable.index] = new_variable return temporary_variables_instances[variable.index] return variable
def _post_member_access(self, expression): expr = get(expression.expression) 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_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_index_access(self, expression): left = get(expression.expression_left) right = get(expression.expression_right) val = ReferenceVariable(self._node) operation = Index(val, left, right, expression.type) 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_index_access(self, expression): left = get(expression.expression_left) right = get(expression.expression_right) 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) self._result.append(operation) operation = Index(val, left, right, expression.type) self._result.append(operation) set_val(expression, val)
def _post_call_expression(self, expression): 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)
def convert_to_pop(ir, node): """ Convert pop operators Return a list of 6 operations """ ret = [] arr = ir.destination length = ReferenceVariable(node) length.set_type(ElementaryType('uint256')) ir_length = Length(arr, length) ir_length.set_expression(ir.expression) ir_length.set_node(ir.node) ir_length.lvalue.points_to = arr ret.append(ir_length) val = TemporaryVariable(node) ir_sub_1 = Binary(val, length, Constant("1", ElementaryType('uint256')), BinaryType.SUBTRACTION) ir_sub_1.set_expression(ir.expression) ir_sub_1.set_node(ir.node) ret.append(ir_sub_1) element_to_delete = ReferenceVariable(node) ir_assign_element_to_delete = Index(element_to_delete, arr, val, ElementaryType('uint256')) ir_length.lvalue.points_to = arr element_to_delete.set_type(ElementaryType('uint256')) ir_assign_element_to_delete.set_expression(ir.expression) ir_assign_element_to_delete.set_node(ir.node) ret.append(ir_assign_element_to_delete) ir_delete = Delete(element_to_delete, element_to_delete) ir_delete.set_expression(ir.expression) ir_delete.set_node(ir.node) ret.append(ir_delete) length_to_assign = ReferenceVariable(node) length_to_assign.set_type(ElementaryType('uint256')) ir_length = Length(arr, length_to_assign) ir_length.set_expression(ir.expression) ir_length.lvalue.points_to = arr ir_length.set_node(ir.node) ret.append(ir_length) ir_assign_length = Assignment(length_to_assign, val, ElementaryType('uint256')) ir_assign_length.set_expression(ir.expression) ir_assign_length.set_node(ir.node) ret.append(ir_assign_length) return ret
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)
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 # This does not support solidity 0.4 contract_name.balance if (isinstance(expr, Variable) and expr.type == ElementaryType("address") and expression.member_name in ["balance", "code", "codehash"]): val = TemporaryVariable(self._node) name = expression.member_name + "(address)" sol_func = SolidityFunction(name) s = SolidityCall( sol_func, 1, val, sol_func.return_type, ) s.set_expression(expression) s.arguments.append(expr) self._result.append(s) set_val(expression, val) return if isinstance(expr, TypeAlias) and expression.member_name in [ "wrap", "unwrap" ]: # The logic is be handled by _post_call_expression set_val(expression, expr) return # Early lookup to detect user defined types from other contracts definitions # contract A { type MyInt is int} # contract B { function f() public{ A.MyInt test = A.MyInt.wrap(1);}} # The logic is handled by _post_call_expression if isinstance(expr, Contract): if expression.member_name in expr.file_scope.user_defined_types: set_val( expression, expr.file_scope.user_defined_types[expression.member_name]) 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)