Skip to content

Commit

Permalink
get max stack right (#4776)
Browse files Browse the repository at this point in the history
  • Loading branch information
gcolvin authored Feb 5, 2022
1 parent 21e5a91 commit 494c1c5
Showing 1 changed file with 34 additions and 36 deletions.
70 changes: 34 additions & 36 deletions EIPS/eip-3779.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,22 +167,21 @@ _Note: Because valid code has a control-flow graph that can be traversed in line
For simplicity's sake we assume that _jumpdest analysis_ has been done and that we have some helper functions.
* `is_valid_instruction(pc)` returns true if `pc` points at a valid instruction
* `is_valid_jumpdest(dest)` returns true if `dest` is a valid jumpdest
* `is_immediate_data(pc)` returns true if `pc` points at immediate data
* `immediate_data(pc)` returns the immediate data for the instruction at `pc`.
* `advance_pc(pc)` returns next `pc`, skipping any immediate data.
* `remove_items(pc)`returns the new `sp` after items are removed from the `data_stack` by the instruction at `pc`.
* `add_items(pc)`returns the new SP after items are added to the `data_stack` by the instruction at `pc`.
* `remove_items(pc,sp)` returns the number of items removed from the `data_stack` by the instruction at `pc`.
* `add_items(pc,sp)` returns the number of items added to the `data_stack` by the instruction at `pc`.

```
// emulated machine state
var code [code_len]byte
var avail_items [code_len]int
var return_stack [1024]int = { -1 }
var data_stack [1024]uint256 = { -1 }
// return the maximum stack used or else the PC and an error
func validate(pc := 0, sp := 0, bp := 0, rp := 0) int, error {
used_items := 0
max_stack := 0
for pc < code_len {
if !is_valid_instruction(pc) {
return pc, invalid_instruction
Expand All @@ -197,7 +196,7 @@ func validate(pc := 0, sp := 0, bp := 0, rp := 0) int, error {
if avail_items[pc] != sp - bp {
return pc, invalid_stack
}
return used_items, nil
return max_stack, nil
}
avail_items[pc] = sp - bp
Expand All @@ -209,15 +208,15 @@ func validate(pc := 0, sp := 0, bp := 0, rp := 0) int, error {
// successful termination
case STOP:
return used_items, nil
return max_stack, nil
case RETURN:
return used_items, nil
return max_stack, nil
case SELFDESTRUCT:
return used_items, nil
return max_stack, nil
case REVERT:
return used_items, nil
return max_stack, nil
case INVALID:
return pc, invalid_opcode
return pc, invalid_instruction
// track constants pushed on data stack
case PUSH1 <= code[pc] && code[pc] <= PUSH32 {
Expand Down Expand Up @@ -258,36 +257,32 @@ func validate(pc := 0, sp := 0, bp := 0, rp := 0) int, error {
}
// recurse to validate true side of conditional
if is_immediate_data(jumpdest) {
if !is_valid_jumpdest(jumpdest) {
return pc, invalid_destination
}
left_used, err = validate(jumpdest, sp, bp, rp)
max_left, err = validate(jumpdest, sp, bp, rp)
if err {
return pc, err
}
// recurse to validate false side of conditional
pc = advance_pc(pc)
right_used, err = validate(pc, sp, bp, rp)
max_right, err = validate(pc, sp, bp, rp)
if err {
return pc, err
}
// both sides valid, check stack and return used_items
used_items += max(left_used, right_used)
sp += used_items
if (sp > 1023) {
return pc, stack_overflow
}
return used_items, nil
// both sides valid, return max_stack
max_stack = max(max_stack, sp + max(max_left, max_right))
return max_stack, nil
case RJUMP:
// will enter basic block at destination
bp = sp
// check for valid jump destination
if is_immediate_data(jumpdest) {
if !is_valid_jumpdest(jumpdest) {
return pc, invalid_destination
}
Expand All @@ -300,34 +295,34 @@ func validate(pc := 0, sp := 0, bp := 0, rp := 0) int, error {
bp = sp
// recurse to validate true side of conditional
jumpdest := pc + immediate_data(pc)
if is_immediate_data(jumpdest) {
jumpdest = pc + immediate_data(pc)
if !is_valid_jumpdest(pc + jumpdest) {
return pc, invalid_destination
}
left_used, err = validate(jumpdest, sp, bp, rp)
max_left, err = validate(jumpdest, sp, bp, rp)
if err {
return pc, err
}
// recurse to validate false side of conditional
pc = advance_pc(pc)
right_used, err = validate(pc, sp, bp, rp)
max_right, err = validate(pc, sp, bp, rp)
if err {
return pc, err
}
// both sides valid, check stack and return used_items
used_items += max(left_used, right_used)
if (sp += used_items > 1023) {
// both sides valid, return max_stack
max_stack += max(max_left, max_right)
if (max_stack > 1023) {
return pc, stack_overflow
}
return used_items, nil
return max_stack, nil
case RJUMPSUB:
// check for valid jump destination
jumpdest = imm_data(pc)
if is_immediate_data(pc + jumpdest) {
if !is_valid_jumpdest(pc + jumpdest) {
return pc, invalid_destination
}
Expand Down Expand Up @@ -356,18 +351,21 @@ func validate(pc := 0, sp := 0, bp := 0, rp := 0) int, error {
pc = advance_pc(pc)
// apply other instructions to stack pointer
// removed and added items are filled with INVALID
used_items -= remove_items(pc)
used_items += add_items(pc)
sp += used_items
// removed and added items are filled with -1
sp -= remove_items(pc, sp)
if (sp < 0) {
return pc, stack_underflow
}
sp += add_items(pc, sp)
if (sp > 1023) {
return pc, stack_overflow
}
max_stack = max(max_stack, sp)
}
}
// successful termination
return used_items, nil
return max_stack, nil
}
```

Expand Down

0 comments on commit 494c1c5

Please sign in to comment.