Skip to content

Commit 801c0ff

Browse files
authored
new(tests): Add exhaustive EOF stack underflow tests (#1378)
1 parent fef73b1 commit 801c0ff

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

tests/osaka/eip7692_eof_v1/eip5450_stack/test_code_validation.py

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,19 @@
22

33
import itertools
44
from enum import Enum, auto, unique
5-
from typing import Tuple
5+
from typing import Generator, Tuple
66

77
import pytest
88

99
from ethereum_test_exceptions.exceptions import EOFException
1010
from ethereum_test_tools import EOFTestFiller
1111
from ethereum_test_tools.eof.v1 import Container, Section
1212
from ethereum_test_tools.vm.opcode import Opcodes as Op
13-
from ethereum_test_types.eof.v1.constants import NON_RETURNING_SECTION
13+
from ethereum_test_types.eof.v1.constants import MAX_OPERAND_STACK_HEIGHT, NON_RETURNING_SECTION
1414
from ethereum_test_vm.bytecode import Bytecode
1515

1616
from .. import EOF_FORK_NAME
17+
from ..eip3540_eof_v1.test_all_opcodes_in_container import valid_eof_opcodes
1718

1819
REFERENCE_SPEC_GIT_PATH = "EIPS/eip-5450.md"
1920
REFERENCE_SPEC_VERSION = "f20b164b00ae5553f7536a6d7a83a0f254455e09"
@@ -433,3 +434,54 @@ def test_rjumps_jumpf_nonreturning(
433434
possible_exceptions.append(EOFException.INVALID_NON_RETURNING_FLAG)
434435

435436
eof_test(container=Container(sections=sections), expect_exception=possible_exceptions or None)
437+
438+
439+
def gen_stack_underflow_params() -> Generator[Tuple[Op, int], None, None]:
440+
"""Generate parameters for stack underflow tests."""
441+
for op in sorted(valid_eof_opcodes):
442+
if op.min_stack_height == 0:
443+
continue
444+
if op in (Op.EOFCREATE, Op.RETURNCODE):
445+
continue
446+
yield op, 0
447+
if op.min_stack_height > 1:
448+
yield op, op.min_stack_height - 1
449+
450+
451+
@pytest.mark.parametrize("spread", [0, 1, MAX_OPERAND_STACK_HEIGHT])
452+
@pytest.mark.parametrize("op,stack_height", gen_stack_underflow_params())
453+
def test_all_opcodes_variadic_stack_underflow(
454+
eof_test: EOFTestFiller, op: Op, stack_height: int, spread: int
455+
):
456+
"""
457+
Test EOF validation failing due to stack overflow
458+
caused by the specific instruction `op`.
459+
There is similar non-variadic test variant in test_all_opcodes_stack_underflow().
460+
"""
461+
code = Bytecode()
462+
463+
# Check if the op increases the stack height (e.g. DUP instructions).
464+
# We need to leave space for this increase not to cause stack overflow.
465+
stack_height_increase = max(op.pushed_stack_items - op.popped_stack_items, 0)
466+
# Cap the spread if it would exceed the maximum stack height.
467+
spread = min(spread, MAX_OPERAND_STACK_HEIGHT - (stack_height + stack_height_increase))
468+
# Create a range stack height of 0-spread.
469+
code = Op.RJUMPI[spread](Op.CALLVALUE) + Op.PUSH0 * spread
470+
471+
# Create the desired stack height.
472+
code += Op.PUSH0 * stack_height
473+
474+
if op.has_data_portion():
475+
code += op[0] # produce required imm bytes
476+
else:
477+
code += op
478+
479+
if not op.terminating:
480+
code += Op.STOP
481+
482+
eof_test(
483+
container=Container(
484+
sections=[Section.Code(code)],
485+
validity_error=EOFException.STACK_UNDERFLOW,
486+
)
487+
)

tests/osaka/eip7692_eof_v1/eof_tracker.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,10 @@
237237

238238
#### Stack underflow
239239

240-
- [ ] Stack underflows (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml )
240+
- [x] Stack underflows ([`tests/osaka/eip7692_eof_v1/eip5450_stack/test_code_validation.py::test_all_opcodes_variadic_stack_underflow`](./eip5450_stack/test_code_validation/test_all_opcodes_variadic_stack_underflow.md))
241241
- [x] Stack underflow with enough items available in caller stack - can't dig into caller frame ([`tests/osaka/eip7692_eof_v1/eip4750_functions/test_code_validation.py::test_eof_validity`](./eip4750_functions/test_code_validation/test_eof_validity.md))
242-
- [ ] Stack underflow in variable stack segment, only min underflow (ethereum/tests: src/EOFTestsFiller/efStack/underflow_variable_stack_Copier.json)
243-
- [ ] Stack underflow in variable stack segment, both min and max underflow (ethereum/tests: src/EOFTestsFiller/efStack/underflow_variable_stack_Copier.json)
242+
- [x] Stack underflow in variable stack segment, only min underflow ([`tests/osaka/eip7692_eof_v1/eip5450_stack/test_code_validation.py::test_all_opcodes_variadic_stack_underflow`](./eip5450_stack/test_code_validation/test_all_opcodes_variadic_stack_underflow.md))
243+
- [x] Stack underflow in variable stack segment, both min and max underflow ([`tests/osaka/eip7692_eof_v1/eip5450_stack/test_code_validation.py::test_all_opcodes_variadic_stack_underflow`](./eip5450_stack/test_code_validation/test_all_opcodes_variadic_stack_underflow.md))
244244

245245
#### CALLF
246246

0 commit comments

Comments
 (0)