diff --git a/vyper/builtins/functions.py b/vyper/builtins/functions.py index e6f301ad99..2ff03e4266 100644 --- a/vyper/builtins/functions.py +++ b/vyper/builtins/functions.py @@ -228,6 +228,13 @@ def build_IR(self, expr, context): ADHOC_SLICE_NODE_MACROS = ["~calldata", "~selfcode", "~extcode"] +def _make_slice_bounds_check(start, length, src_len): + return [ + "with", + "end", + ["add", start, length], + ["assert", ["iszero", ["or", ["gt", "end", src_len], ["lt", "end", start]]]], + ] def _build_adhoc_slice_node(sub: IRnode, start: IRnode, length: IRnode, context: Context) -> IRnode: assert length.is_literal, "typechecker failed" @@ -241,7 +248,7 @@ def _build_adhoc_slice_node(sub: IRnode, start: IRnode, length: IRnode, context: if sub.value == "~calldata": node = [ "seq", - ["assert", ["le", ["add", start, length], "calldatasize"]], # runtime bounds check + _make_slice_bounds_check(start, length, "calldatasize"), ["mstore", np, length], ["calldatacopy", np + 32, start, length], np, @@ -251,7 +258,7 @@ def _build_adhoc_slice_node(sub: IRnode, start: IRnode, length: IRnode, context: elif sub.value == "~selfcode": node = [ "seq", - ["assert", ["le", ["add", start, length], "codesize"]], # runtime bounds check + _make_slice_bounds_check(start, length, "codesize"), ["mstore", np, length], ["codecopy", np + 32, start, length], np, @@ -266,8 +273,7 @@ def _build_adhoc_slice_node(sub: IRnode, start: IRnode, length: IRnode, context: sub.args[0], [ "seq", - # runtime bounds check - ["assert", ["le", ["add", start, length], ["extcodesize", "_extcode_address"]]], + _make_slice_bounds_check(start, length, ["extcodesize", "_extcode_address"]), ["mstore", np, length], ["extcodecopy", "_extcode_address", np + 32, start, length], np, @@ -451,7 +457,7 @@ def build_IR(self, expr, args, kwargs, context): ret = [ "seq", - bounds_check, + _make_slice_bounds_check(start, length, src_len), do_copy, ["mstore", dst, length], # set length dst, # return pointer to dst