summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/vmconv.nim4
-rw-r--r--compiler/vmhooks.nim7
-rw-r--r--compiler/vmops.nim54
-rw-r--r--lib/std/sysrand.nim9
-rw-r--r--tests/stdlib/tsysrand.nim35
5 files changed, 90 insertions, 19 deletions
diff --git a/compiler/vmconv.nim b/compiler/vmconv.nim
index 7db3906c2..b82fb2ff3 100644
--- a/compiler/vmconv.nim
+++ b/compiler/vmconv.nim
@@ -28,6 +28,10 @@ proc toLit*[T](a: T): PNode =
   elif T is tuple:
     result = newTree(nkTupleConstr)
     for ai in fields(a): result.add toLit(ai)
+  elif T is seq:
+    result = newNode(nkBracket)
+    for ai in a:
+      result.add toLit(ai)
   elif T is object:
     result = newTree(nkObjConstr)
     result.add(newNode(nkEmpty))
diff --git a/compiler/vmhooks.nim b/compiler/vmhooks.nim
index 9f68eb434..573d84853 100644
--- a/compiler/vmhooks.nim
+++ b/compiler/vmhooks.nim
@@ -56,3 +56,10 @@ proc getNode*(a: VmArgs; i: Natural): PNode =
   doAssert i < a.rc-1
   doAssert a.slots[i+a.rb+1].kind == rkNode
   result = a.slots[i+a.rb+1].node
+
+proc getNodeAddr*(a: VmArgs; i: Natural): PNode =
+  doAssert i < a.rc-1
+  doAssert a.slots[i+a.rb+1].kind == rkNodeAddr
+  let nodeAddr = a.slots[i+a.rb+1].nodeAddr
+  doAssert nodeAddr != nil
+  result = nodeAddr[]
diff --git a/compiler/vmops.nim b/compiler/vmops.nim
index eb861cd54..b49901ee2 100644
--- a/compiler/vmops.nim
+++ b/compiler/vmops.nim
@@ -9,24 +9,28 @@
 
 # Unfortunately this cannot be a module yet:
 #import vmdeps, vm
-from math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
+from std/math import sqrt, ln, log10, log2, exp, round, arccos, arcsin,
   arctan, arctan2, cos, cosh, hypot, sinh, sin, tan, tanh, pow, trunc,
   floor, ceil, `mod`
 
 when declared(math.copySign):
-  from math import copySign
+  from std/math import copySign
 
 when declared(math.signbit):
-  from math import signbit
+  from std/math import signbit
 
-from os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir, getAppFilename
-from md5 import getMD5
-from sighashes import symBodyDigest
-from times import cpuTime
+from std/os import getEnv, existsEnv, dirExists, fileExists, putEnv, walkDir,
+                   getAppFilename, raiseOSError, osLastError
+
+from std/md5 import getMD5
+from std/times import cpuTime
+from std/hashes import hash
+from std/osproc import nil
+from std/sysrand import urandom
 
-from hashes import hash
-from osproc import nil
+from sighashes import symBodyDigest
 
+# There are some useful procs in vmconv.
 import vmconv
 
 template mathop(op) {.dirty.} =
@@ -304,3 +308,35 @@ proc registerAdditionalOps*(c: PCtx) =
     let fn = getNode(a, 0)
     setResult(a, (fn.typ != nil and tfNoSideEffect in fn.typ.flags) or
                  (fn.kind == nkSym and fn.sym.kind == skFunc))
+
+  if vmopsDanger in c.config.features:
+    proc urandomImpl(a: VmArgs) =
+      doAssert a.numArgs == 1
+      let kind = a.slots[a.rb+1].kind
+      case kind
+      of rkInt:
+        setResult(a, urandom(a.getInt(0)).toLit)
+      of rkNode, rkNodeAddr:
+        let n =
+          if kind == rkNode:
+            a.getNode(0)
+          else:
+            a.getNodeAddr(0)
+
+        let length = n.len
+
+        ## TODO refactor using vmconv.fromLit
+        var res = newSeq[uint8](length)
+        for i in 0 ..< length:
+          res[i] = byte(n[i].intVal)
+
+        let isSuccess = urandom(res)
+
+        for i in 0 ..< length:
+          n[i].intVal = BiggestInt(res[i])
+
+        setResult(a, isSuccess)
+      else:
+        doAssert false, $kind
+
+    registerCallback c, "stdlib.sysrand.urandom", urandomImpl
diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim
index 9a143adb3..75a1af5a9 100644
--- a/lib/std/sysrand.nim
+++ b/lib/std/sysrand.nim
@@ -158,7 +158,8 @@ elif defined(windows):
     result = randomBytes(addr dest[0], size)
 
 elif defined(linux):
-  let SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
+  # TODO using let, pending bootstrap >= 1.4.0
+  var SYS_getrandom {.importc: "SYS_getrandom", header: "<sys/syscall.h>".}: clong
   const syscallHeader = """#include <unistd.h>
 #include <sys/syscall.h>"""
 
@@ -209,7 +210,7 @@ elif defined(freebsd):
     # errno is set to indicate the error.
 
   proc getRandomImpl(p: pointer, size: int): int {.inline.} =
-    result = getrandom(p, csize_t(batchSize), 0)
+    result = getrandom(p, csize_t(size), 0)
 
 elif defined(ios):
   {.passL: "-framework Security".}
@@ -284,7 +285,7 @@ proc urandomInternalImpl(dest: var openArray[byte]): int {.inline.} =
 
 proc urandom*(dest: var openArray[byte]): bool =
   ## Fills `dest` with random bytes suitable for cryptographic use.
-  ## If succeed, returns `true`.
+  ## If the call succeeds, returns `true`.
   ##
   ## If `dest` is empty, `urandom` immediately returns success,
   ## without calling underlying operating system api.
@@ -305,4 +306,4 @@ proc urandom*(size: Natural): seq[byte] {.inline.} =
   when defined(js): discard urandomInternalImpl(result)
   else:
     if not urandom(result):
-      raiseOsError(osLastError())
+      raiseOSError(osLastError())
diff --git a/tests/stdlib/tsysrand.nim b/tests/stdlib/tsysrand.nim
index d248849f8..2d00dafe0 100644
--- a/tests/stdlib/tsysrand.nim
+++ b/tests/stdlib/tsysrand.nim
@@ -1,13 +1,36 @@
 discard """
   targets: "c cpp js"
+  matrix: "--experimental:vmopsDanger"
 """
 
 import std/sysrand
 
 
-doAssert urandom(0).len == 0
-doAssert urandom(10).len == 10
-doAssert urandom(20).len == 20
-doAssert urandom(120).len == 120
-doAssert urandom(113).len == 113
-doAssert urandom(1234) != urandom(1234) # unlikely to fail in practice
+template main() =
+  block:
+    var x = array[5, byte].default
+    doAssert urandom(x)
+
+  block:
+    var x = newSeq[byte](5)
+    doAssert urandom(x)
+
+  block:
+    var x = @[byte(0), 0, 0, 0, 0]
+    doAssert urandom(x)
+
+  block:
+    var x = @[byte(1), 2, 3, 4, 5]
+    doAssert urandom(x)
+
+  block:
+    doAssert urandom(0).len == 0
+    doAssert urandom(10).len == 10
+    doAssert urandom(20).len == 20
+    doAssert urandom(120).len == 120
+    doAssert urandom(113).len == 113
+    doAssert urandom(1234) != urandom(1234) # unlikely to fail in practice
+
+
+static: main()
+main()