diff options
-rw-r--r-- | compiler/vmconv.nim | 4 | ||||
-rw-r--r-- | compiler/vmhooks.nim | 7 | ||||
-rw-r--r-- | compiler/vmops.nim | 54 | ||||
-rw-r--r-- | lib/std/sysrand.nim | 9 | ||||
-rw-r--r-- | tests/stdlib/tsysrand.nim | 35 |
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() |