diff --git a/src/evm.c b/src/evm.c index c3d06b3..742c277 100644 --- a/src/evm.c +++ b/src/evm.c @@ -746,6 +746,13 @@ static result_t doCall(context_t *callContext) { } fprintf(stderr, "op %s\n", opString[op]); } + #define FAIL_INVALID \ + callContext->gas = 0; \ + result.returnData.size = 0; \ + return result + #define OUT_OF_GAS \ + fprintf(stderr, "Out of gas at pc %" PRIu64 " op %s\n", pc - 1, opString[op]);\ + FAIL_INVALID if ( (callContext->top < callContext->bottom + argCount[op]) || (op >= DUP1 && op <= DUP16 && callContext->top - (op - PUSH32) < callContext->bottom) @@ -753,17 +760,8 @@ static result_t doCall(context_t *callContext) { ) { // stack underflow fprintf(stderr, "Stack underflow at pc %" PRIu64 " op %s stack depth %lu\n", pc - 1, opString[op], callContext->top - callContext->bottom); - callContext->gas = 0; - result.returnData.size = 0; - return result; + FAIL_INVALID; } - #define FAIL_INVALID \ - callContext->gas = 0; \ - result.returnData.size = 0; \ - return result - #define OUT_OF_GAS \ - fprintf(stderr, "Out of gas at pc %" PRIu64 " op %s\n", pc - 1, opString[op]);\ - FAIL_INVALID // Check staticcall switch (op) { case CALL: @@ -794,6 +792,10 @@ static result_t doCall(context_t *callContext) { } callContext->gas -= gasCost[op]; callContext->top += retCount[op] - argCount[op]; + if (callContext->top >= callContext->bottom + 1024) { + fprintf(stderr, "Stack overflow at pc %" PRIu64 " op %s stack depth %lu\n", pc - 1, opString[op], callContext->top - callContext->bottom); + FAIL_INVALID; + } switch (op) { case PUSH0: case PUSH1: diff --git a/tst/evm.c b/tst/evm.c index ef8346d..852f54a 100644 --- a/tst/evm.c +++ b/tst/evm.c @@ -2271,6 +2271,36 @@ void test_returnDataCopyOOB() { evmFinalize(); } +// Each loop iteration nets +1 stack item; the temporary depth peaks at +4 per +// iteration, hitting 1024 at DUP2 after ~1021 iterations. +void test_stackOverflow() { + evmInit(); + + address_t from = AddressFromHex42("0x4a6f6B9fF1fc974096f9063a45Fd12bD5B928AD1"); + address_t to = AddressFromHex42("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"); + val_t value; + value[0] = value[1] = value[2] = 0; + + // 0; loop: ADD(1,DUP1); JUMPI(loop, LT(DUP2, 1024)) + op_t code[] = { PUSH0, JUMPDEST, DUP1, PUSH1, 1, ADD, PUSH2, 4, 0, DUP2, LT, PUSH1, 1, JUMPI }; + data_t codeData; + codeData.content = code; + codeData.size = sizeof(code); + evmMockCode(to, codeData); + + data_t empty; + empty.content = NULL; + empty.size = 0; + assertStderr( + "Stack overflow at pc 9 op DUP2 stack depth 1024\n", + result_t result = txCall(from, 0xffffff, to, value, empty, NULL) + ); + assertFailedInvalid(result); + + evmMockCode(to, empty); + evmFinalize(); +} + // JUMP to a 0x5b byte that is PUSH1 data → exceptional halt void test_jumpDestInsidePush() { evmInit(); @@ -2423,6 +2453,7 @@ int main() { test_create(); test_createRevertRollback(); test_returnDataCopyOOB(); + test_stackOverflow(); test_jumpDestInsidePush(); test_jumpiDestInsidePush(); test_staticcallSstore(); diff --git a/tst/in/stackoverflow.evm b/tst/in/stackoverflow.evm new file mode 100644 index 0000000..eac53c5 --- /dev/null +++ b/tst/in/stackoverflow.evm @@ -0,0 +1,4 @@ +0 +loop: +ADD(1, DUP1) +JUMPI(loop, LT(DUP2, 1024)) diff --git a/tst/out/stackoverflow.out b/tst/out/stackoverflow.out new file mode 100644 index 0000000..f6f9e32 --- /dev/null +++ b/tst/out/stackoverflow.out @@ -0,0 +1 @@ +5f5b806001016104008110600157