summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndreas Rumpf <rumpf_a@web.de>2014-04-02 19:59:26 +0200
committerAndreas Rumpf <rumpf_a@web.de>2014-04-02 19:59:26 +0200
commite810c760fd602a2de0386714fc333a8a5df8afeb (patch)
tree80b84ec242d3ecb525d47e0da98f3061aaa270c4
parent207874aa2d80035d0f9e72981cec78ba3ab12260 (diff)
parentc75b247a90e7e51c4ca9e8bb6ecbd823c820609c (diff)
downloadNim-e810c760fd602a2de0386714fc333a8a5df8afeb.tar.gz
Merge pull request #1060 from EXetoC/vm-arithmetic-overflow
Arithmetic underflow/overflow checking for the VM
-rw-r--r--compiler/vm.nim55
-rw-r--r--tests/vm/toverflowopcaddimmint.nim11
-rw-r--r--tests/vm/toverflowopcaddint.nim12
-rw-r--r--tests/vm/toverflowopcmulint.nim11
-rw-r--r--tests/vm/toverflowopcsubimmint.nim10
-rw-r--r--tests/vm/toverflowopcsubint.nim12
6 files changed, 105 insertions, 6 deletions
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 0d5386502..7355e85fe 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -495,18 +495,46 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       else: stackTrace(c, tos, pc, errNilAccess)
     of opcAddInt:
       decodeBC(rkInt)
-      regs[ra].intVal = regs[rb].intVal + regs[rc].intVal
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        sum = bVal +% cVal
+      if (sum xor bVal) >= 0 or (sum xor cVal) >= 0:
+        regs[ra].intVal = sum
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcAddImmInt:
       decodeBImm(rkInt)
       #message(c.debug[pc], warnUser, "came here")
       #debug regs[rb].node
-      regs[ra].intVal = regs[rb].intVal + imm
+      let
+        bVal = regs[rb].intVal
+        cVal = imm
+        sum = bVal +% cVal
+      if (sum xor bVal) >= 0 or (sum xor cVal) >= 0:
+        regs[ra].intVal = sum
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcSubInt:
       decodeBC(rkInt)
-      regs[ra].intVal = regs[rb].intVal - regs[rc].intVal
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        diff = bVal -% cVal
+      if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0:
+        regs[ra].intVal = diff
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcSubImmInt:
       decodeBImm(rkInt)
-      regs[ra].intVal = regs[rb].intVal - imm
+      let
+        bVal = regs[rb].intVal
+        cVal = imm
+        diff = bVal -% cVal
+      if (diff xor bVal) >= 0 or (diff xor not cVal) >= 0:
+        regs[ra].intVal = diff
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcLenSeq:
       decodeBImm(rkInt)
       #assert regs[rb].kind == nkBracket
@@ -539,7 +567,18 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
       regs[ra].intVal = nimsets.cardSet(regs[rb].node)
     of opcMulInt:
       decodeBC(rkInt)
-      regs[ra].intVal = regs[rb].intVal * regs[rc].intVal
+      let
+        bVal = regs[rb].intVal
+        cVal = regs[rc].intVal
+        product = bVal *% cVal
+        floatProd = toBiggestFloat(bVal) * toBiggestFloat(cVal)
+        resAsFloat = toBiggestFloat(product)
+      if resAsFloat == floatProd:
+        regs[ra].intVal = product
+      elif 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd):
+        regs[ra].intVal = product
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcDivInt:
       decodeBC(rkInt)
       if regs[rc].intVal == 0: stackTrace(c, tos, pc, errConstantDivisionByZero)
@@ -632,7 +671,11 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcUnaryMinusInt:
       decodeB(rkInt)
       assert regs[rb].kind == rkInt
-      regs[ra].intVal = -regs[rb].intVal
+      let val = regs[rb].intVal
+      if val != int64.low:
+        regs[ra].intVal = -val
+      else:
+        stackTrace(c, tos, pc, errOverOrUnderflow)
     of opcUnaryMinusFloat:
       decodeB(rkFloat)
       assert regs[rb].kind == rkFloat
diff --git a/tests/vm/toverflowopcaddimmint.nim b/tests/vm/toverflowopcaddimmint.nim
new file mode 100644
index 000000000..c36b9ed9b
--- /dev/null
+++ b/tests/vm/toverflowopcaddimmint.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.high
+    discard x + 1
+    assert false
+  p()
diff --git a/tests/vm/toverflowopcaddint.nim b/tests/vm/toverflowopcaddint.nim
new file mode 100644
index 000000000..6d96afc78
--- /dev/null
+++ b/tests/vm/toverflowopcaddint.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.high
+      y = 1
+    discard x + y
+    assert false
+  p()
diff --git a/tests/vm/toverflowopcmulint.nim b/tests/vm/toverflowopcmulint.nim
new file mode 100644
index 000000000..81b3234ba
--- /dev/null
+++ b/tests/vm/toverflowopcmulint.nim
@@ -0,0 +1,11 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = 1 shl 62
+    discard x * 2
+    assert false
+  p()
diff --git a/tests/vm/toverflowopcsubimmint.nim b/tests/vm/toverflowopcsubimmint.nim
new file mode 100644
index 000000000..09d6f745b
--- /dev/null
+++ b/tests/vm/toverflowopcsubimmint.nim
@@ -0,0 +1,10 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var x = int64.low
+    discard x - 1
+    assert false
+  p()
diff --git a/tests/vm/toverflowopcsubint.nim b/tests/vm/toverflowopcsubint.nim
new file mode 100644
index 000000000..8d114f200
--- /dev/null
+++ b/tests/vm/toverflowopcsubint.nim
@@ -0,0 +1,12 @@
+discard """
+  errormsg: "over- or underflow"
+"""
+
+static:
+  proc p =
+    var
+      x = int64.low
+      y = 1
+    discard x - y
+    assert false
+  p()