Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions src/evm.c
Original file line number Diff line number Diff line change
Expand Up @@ -746,24 +746,22 @@ 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)
|| (op >= SWAP1 && op <= SWAP16 && callContext->top - (op - DUP15) < callContext->bottom)
) {
// 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:
Expand Down Expand Up @@ -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:
Expand Down
31 changes: 31 additions & 0 deletions tst/evm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -2423,6 +2453,7 @@ int main() {
test_create();
test_createRevertRollback();
test_returnDataCopyOOB();
test_stackOverflow();
test_jumpDestInsidePush();
test_jumpiDestInsidePush();
test_staticcallSstore();
Expand Down
4 changes: 4 additions & 0 deletions tst/in/stackoverflow.evm
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
0
loop:
ADD(1, DUP1)
JUMPI(loop, LT(DUP2, 1024))
1 change: 1 addition & 0 deletions tst/out/stackoverflow.out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5f5b806001016104008110600157