Catch stack underflow (#33)

* Stack underflow: Add failing test to catch #31

* ensurePop, use proc instead of template + add comment for future refactoring of popInternal

* Check stack underflows before popping values

* run json tests again
This commit is contained in:
Mamy Ratsimbazafy 2018-05-17 20:59:17 +02:00 committed by GitHub
parent 74a558f187
commit 507bdda25a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 14 deletions

View File

@ -132,7 +132,7 @@ VMTests
+ mul5.json OK + mul5.json OK
+ mul6.json OK + mul6.json OK
+ mul7.json OK + mul7.json OK
- mulUnderFlow.json Fail + mulUnderFlow.json OK
+ mulmod0.json OK + mulmod0.json OK
+ mulmod1.json OK + mulmod1.json OK
+ mulmod1_overflow.json OK + mulmod1_overflow.json OK
@ -163,7 +163,7 @@ VMTests
+ sdivByZero0.json OK + sdivByZero0.json OK
+ sdivByZero1.json OK + sdivByZero1.json OK
+ sdivByZero2.json OK + sdivByZero2.json OK
- sdiv_dejavu.json Fail + sdiv_dejavu.json OK
+ sdiv_i256min.json OK + sdiv_i256min.json OK
+ sdiv_i256min2.json OK + sdiv_i256min2.json OK
+ sdiv_i256min3.json OK + sdiv_i256min3.json OK
@ -198,7 +198,7 @@ VMTests
+ sub3.json OK + sub3.json OK
+ sub4.json OK + sub4.json OK
``` ```
OK: 186/195 Fail: 8/195 Skip: 1/195 OK: 188/195 Fail: 6/195 Skip: 1/195
## vmBitwiseLogicOperation ## vmBitwiseLogicOperation
```diff ```diff
+ and0.json OK + and0.json OK

View File

@ -75,28 +75,31 @@ proc push*(stack: var Stack, value: Bytes) =
stack.values.add(value.toType(UInt256)) stack.values.add(value.toType(UInt256))
proc internalPop(stack: var Stack, numItems: int): seq[UInt256] = proc internalPop(stack: var Stack, numItems: int): seq[UInt256] =
if len(stack) < numItems: # TODO: it is very inefficient to allocate a seq
result = @[] assert numItems <= stack.len
else:
result = stack.values[^numItems .. ^1] result = stack.values[^numItems .. ^1]
stack.values = stack.values[0 ..< ^numItems] stack.values = stack.values[0 ..< ^numItems]
proc internalPop(stack: var Stack, numItems: int, T: typedesc): seq[T] = proc internalPop(stack: var Stack, numItems: int, T: typedesc): seq[T] =
# TODO: it is very inefficient to allocate a seq
assert numItems <= stack.len
result = @[] result = @[]
if len(stack) < numItems:
return
for z in 0 ..< numItems: for z in 0 ..< numItems:
var value = stack.values.pop() var value = stack.values.pop()
result.add(toType(value, T)) result.add(toType(value, T))
template ensurePop(elements: untyped, a: untyped): untyped = proc ensurePop(elements: seq|Stack, a: int) =
if len(`elements`) < `a`: let num = elements.len
raise newException(InsufficientStack, "No stack items") let expected = a
if num < expected:
raise newException(InsufficientStack,
&"Stack underflow: expected {expected} elements, got {num} instead.")
proc popInt*(stack: var Stack): UInt256 = proc popInt*(stack: var Stack): UInt256 =
ensurePop(stack, 1)
var elements = stack.internalPop(1, UInt256) var elements = stack.internalPop(1, UInt256)
ensurePop(elements, 1)
result = elements[0] result = elements[0]
macro internalPopTuple(numItems: static[int]): untyped = macro internalPopTuple(numItems: static[int]): untyped =
@ -110,6 +113,8 @@ macro internalPopTuple(numItems: static[int]): untyped =
result = quote: result = quote:
proc `name`*(`stackNode`: var Stack, `t`: typedesc): `typ` proc `name`*(`stackNode`: var Stack, `t`: typedesc): `typ`
result[^1] = nnkStmtList.newTree() result[^1] = nnkStmtList.newTree()
result[^1].add quote do:
ensurePop(`stackNode`, `numItems`)
for z in 0 ..< numItems: for z in 0 ..< numItems:
var zNode = newLit(z) var zNode = newLit(z)
var element = quote: var element = quote:

View File

@ -93,3 +93,12 @@ suite "stack":
var stack = newStack() var stack = newStack()
expect(InsufficientStack): expect(InsufficientStack):
stack.dup(0) stack.dup(0)
test "binary operations raises InsufficientStack appropriately":
# https://github.com/status-im/nimbus/issues/31
# ./tests/fixtures/VMTests/vmArithmeticTest/mulUnderFlow.json
var stack = newStack()
stack.push(123)
expect(InsufficientStack):
discard stack.popInt(2)