about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2013-02-19 07:06:20 -0800
committerGraydon Hoare <graydon@mozilla.com>2013-02-19 07:06:36 -0800
commit968ab03026d716f1e648aadebe8f199bdacbe4ad (patch)
tree4a27364dcfcab05c01198462ab343e0a968ce5da
parenta8efa2133392cc846d4ea3cae14f0eb4eccb5f1e (diff)
downloadrust-968ab03026d716f1e648aadebe8f199bdacbe4ad.tar.gz
rust-968ab03026d716f1e648aadebe8f199bdacbe4ad.zip
rt: fix memory-unsafe random seed logic, r=valgrindclean
-rw-r--r--src/libcore/rand.rs44
-rw-r--r--src/rt/rust_builtin.cpp35
-rw-r--r--src/rt/rust_rng.cpp37
-rw-r--r--src/rt/rust_rng.h8
-rw-r--r--src/rt/rust_sched_loop.cpp2
-rw-r--r--src/rt/rustrt.def.in4
6 files changed, 64 insertions, 66 deletions
diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs
index 97812602ce7..79dd29604e4 100644
--- a/src/libcore/rand.rs
+++ b/src/libcore/rand.rs
@@ -18,6 +18,7 @@ use u32;
 use uint;
 use util;
 use vec;
+use libc::size_t;
 
 /// A type that can be randomly generated using an RNG
 pub trait Rand {
@@ -120,9 +121,9 @@ enum rust_rng {}
 
 #[abi = "cdecl"]
 extern mod rustrt {
-    unsafe fn rand_seed() -> ~[u8];
-    unsafe fn rand_new() -> *rust_rng;
-    unsafe fn rand_new_seeded2(&&seed: ~[u8]) -> *rust_rng;
+    unsafe fn rand_seed_size() -> size_t;
+    unsafe fn rand_gen_seed(buf: *mut u8, sz: size_t);
+    unsafe fn rand_new_seeded(buf: *u8, sz: size_t) -> *rust_rng;
     unsafe fn rand_next(rng: *rust_rng) -> u32;
     unsafe fn rand_free(rng: *rust_rng);
 }
@@ -388,15 +389,18 @@ impl Rng for @RandRes {
 /// Create a new random seed for seeded_rng
 pub fn seed() -> ~[u8] {
     unsafe {
-        rustrt::rand_seed()
+        let n = rustrt::rand_seed_size() as uint;
+        let mut s = vec::from_elem(n, 0_u8);
+        do vec::as_mut_buf(s) |p, sz| {
+            rustrt::rand_gen_seed(p, sz as size_t)
+        }
+        s
     }
 }
 
 /// Create a random number generator with a system specified seed
 pub fn Rng() -> Rng {
-    unsafe {
-        @RandRes(rustrt::rand_new()) as Rng
-    }
+    seeded_rng(seed())
 }
 
 /**
@@ -405,9 +409,15 @@ pub fn Rng() -> Rng {
  * all other generators constructed with the same seed. The seed may be any
  * length.
  */
-pub fn seeded_rng(seed: &~[u8]) -> Rng {
+pub fn seeded_rng(seed: &[u8]) -> Rng {
+    seeded_randres(seed) as Rng
+}
+
+fn seeded_randres(seed: &[u8]) -> @RandRes {
     unsafe {
-        @RandRes(rustrt::rand_new_seeded2(*seed)) as Rng
+        do vec::as_imm_buf(seed) |p, sz| {
+            @RandRes(rustrt::rand_new_seeded(p, sz as size_t))
+        }
     }
 }
 
@@ -457,7 +467,7 @@ pub fn task_rng() -> Rng {
     match r {
         None => {
             unsafe {
-                let rng = @RandRes(rustrt::rand_new());
+                let rng = seeded_randres(seed());
                 task::local_data::local_data_set(tls_rng_state, rng);
                 rng as Rng
             }
@@ -483,24 +493,24 @@ pub mod tests {
     #[test]
     pub fn rng_seeded() {
         let seed = rand::seed();
-        let ra = rand::seeded_rng(&seed);
-        let rb = rand::seeded_rng(&seed);
+        let ra = rand::seeded_rng(seed);
+        let rb = rand::seeded_rng(seed);
         assert ra.gen_str(100u) == rb.gen_str(100u);
     }
 
     #[test]
     pub fn rng_seeded_custom_seed() {
         // much shorter than generated seeds which are 1024 bytes
-        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
-        let ra = rand::seeded_rng(&seed);
-        let rb = rand::seeded_rng(&seed);
+        let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
+        let ra = rand::seeded_rng(seed);
+        let rb = rand::seeded_rng(seed);
         assert ra.gen_str(100u) == rb.gen_str(100u);
     }
 
     #[test]
     pub fn rng_seeded_custom_seed2() {
-        let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
-        let ra = rand::seeded_rng(&seed);
+        let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
+        let ra = rand::seeded_rng(seed);
         // Regression test that isaac is actually using the above vector
         let r = ra.next();
         error!("%?", r);
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 85caf7b2e53..2c5b56f3fa4 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -128,49 +128,30 @@ vec_reserve_shared(type_desc* ty, rust_vec_box** vp,
     reserve_vec_exact(task, vp, n_elts * ty->size);
 }
 
-extern "C" CDECL rust_vec*
-rand_seed() {
-    size_t size = sizeof(ub4) * RANDSIZ;
-    rust_task *task = rust_get_current_task();
-    rust_vec *v = (rust_vec *) task->kernel->malloc(vec_size<uint8_t>(size),
-                                            "rand_seed");
-    v->fill = v->alloc = size;
-    rng_gen_seed(task->kernel, (uint8_t*) &v->data, size);
-    return v;
+extern "C" CDECL size_t
+rand_seed_size() {
+    return rng_seed_size();
 }
 
-extern "C" CDECL void *
-rand_new() {
+extern "C" CDECL void
+rand_gen_seed(uint8_t* dest, size_t size) {
     rust_task *task = rust_get_current_task();
-    rust_sched_loop *thread = task->sched_loop;
-    rust_rng *rng = (rust_rng *) task->malloc(sizeof(rust_rng), "rand_new");
-    if (!rng) {
-        task->fail();
-        return NULL;
-    }
-    rng_init(thread->kernel, rng, NULL);
-    return rng;
+    rng_gen_seed(task->kernel, dest, size);
 }
 
 extern "C" CDECL void *
-rand_new_seeded(rust_vec_box* seed) {
+rand_new_seeded(uint8_t* seed, size_t seed_size) {
     rust_task *task = rust_get_current_task();
-    rust_sched_loop *thread = task->sched_loop;
     rust_rng *rng = (rust_rng *) task->malloc(sizeof(rust_rng),
                                               "rand_new_seeded");
     if (!rng) {
         task->fail();
         return NULL;
     }
-    rng_init(thread->kernel, rng, seed);
+    rng_init(task->kernel, rng, seed, seed_size);
     return rng;
 }
 
-extern "C" CDECL void *
-rand_new_seeded2(rust_vec_box** seed) {
-    return rand_new_seeded(*seed);
-}
-
 extern "C" CDECL uint32_t
 rand_next(rust_rng *rng) {
     rust_task *task = rust_get_current_task();
diff --git a/src/rt/rust_rng.cpp b/src/rt/rust_rng.cpp
index 3d6bfdf7dbb..2c11691bf86 100644
--- a/src/rt/rust_rng.cpp
+++ b/src/rt/rust_rng.cpp
@@ -12,6 +12,12 @@
 #include "rust_rng.h"
 #include "rust_util.h"
 
+size_t
+rng_seed_size() {
+    randctx rctx;
+    return sizeof(rctx.randrsl);
+}
+
 // Initialization helpers for ISAAC RNG
 
 void
@@ -48,15 +54,17 @@ rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size) {
 }
 
 static void
-isaac_init(rust_kernel *kernel, randctx *rctx, rust_vec_box* user_seed) {
+isaac_init(rust_kernel *kernel, randctx *rctx,
+           uint8_t* user_seed, size_t seed_len) {
     memset(rctx, 0, sizeof(randctx));
 
     char *env_seed = kernel->env->rust_seed;
     if (user_seed != NULL) {
         // ignore bytes after the required length
-        size_t seed_len = user_seed->body.fill < sizeof(rctx->randrsl)
-            ? user_seed->body.fill : sizeof(rctx->randrsl);
-        memcpy(&rctx->randrsl, user_seed->body.data, seed_len);
+        if (seed_len > sizeof(rctx->randrsl)) {
+            seed_len = sizeof(rctx->randrsl);
+        }
+        memcpy(&rctx->randrsl, user_seed, seed_len);
     } else if (env_seed != NULL) {
         ub4 seed = (ub4) atoi(env_seed);
         for (size_t i = 0; i < RANDSIZ; i ++) {
@@ -64,15 +72,18 @@ isaac_init(rust_kernel *kernel, randctx *rctx, rust_vec_box* user_seed) {
             seed = (seed + 0x7ed55d16) + (seed << 12);
         }
     } else {
-        rng_gen_seed(kernel, (uint8_t*)&rctx->randrsl, sizeof(rctx->randrsl));
+        rng_gen_seed(kernel,
+                     (uint8_t*)&rctx->randrsl,
+                     sizeof(rctx->randrsl));
     }
 
     randinit(rctx, 1);
 }
 
 void
-rng_init(rust_kernel* kernel, rust_rng* rng, rust_vec_box* user_seed) {
-    isaac_init(kernel, &rng->rctx, user_seed);
+rng_init(rust_kernel* kernel, rust_rng* rng,
+         uint8_t *user_seed, size_t seed_len) {
+    isaac_init(kernel, &rng->rctx, user_seed, seed_len);
     rng->reseedable = !user_seed && !kernel->env->rust_seed;
 }
 
@@ -85,15 +96,9 @@ rng_maybe_reseed(rust_kernel* kernel, rust_rng* rng) {
     if (bytes_generated < RESEED_THRESHOLD || !rng->reseedable) {
         return;
     }
-
-    uint32_t new_seed[RANDSIZ];
-    rng_gen_seed(kernel, (uint8_t*) new_seed, RANDSIZ * sizeof(uint32_t));
-
-    // Stir new seed into PRNG's entropy pool.
-    for (size_t i = 0; i < RANDSIZ; i++) {
-        rng->rctx.randrsl[i] ^= new_seed[i];
-    }
-
+    rng_gen_seed(kernel,
+                 (uint8_t*)rng->rctx.randrsl,
+                 sizeof(rng->rctx.randrsl));
     randinit(&rng->rctx, 1);
 }
 
diff --git a/src/rt/rust_rng.h b/src/rt/rust_rng.h
index 2f1e680623f..3879b1138fa 100644
--- a/src/rt/rust_rng.h
+++ b/src/rt/rust_rng.h
@@ -14,7 +14,6 @@
 #include "rand.h"
 
 class rust_kernel;
-struct rust_vec_box;
 
 // Initialization helpers for ISAAC RNG
 
@@ -23,8 +22,11 @@ struct rust_rng {
     bool reseedable;
 };
 
-void rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size);
-void rng_init(rust_kernel *kernel, rust_rng *rng, rust_vec_box* user_seed);
+size_t rng_seed_size();
+void rng_gen_seed(rust_kernel* kernel,
+                  uint8_t* dest, size_t size);
+void rng_init(rust_kernel *kernel, rust_rng *rng,
+              uint8_t *user_seed, size_t seed_len);
 uint32_t rng_gen_u32(rust_kernel *kernel, rust_rng *rng);
 
 //
diff --git a/src/rt/rust_sched_loop.cpp b/src/rt/rust_sched_loop.cpp
index 7143bf88d46..c215752d8dd 100644
--- a/src/rt/rust_sched_loop.cpp
+++ b/src/rt/rust_sched_loop.cpp
@@ -41,7 +41,7 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, int id, bool killed) :
     name("main")
 {
     LOGPTR(this, "new dom", (uintptr_t)this);
-    rng_init(kernel, &rng, NULL);
+    rng_init(kernel, &rng, NULL, 0);
 
     if (!tls_initialized)
         init_tls();
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index a19f9053cbe..8fc8fceff86 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -17,9 +17,9 @@ rust_mktime
 new_task
 precise_time_ns
 rand_free
-rand_new
 rand_new_seeded
-rand_new_seeded2
+rand_seed_size
+rand_gen_seed
 rand_next
 rand_seed
 rust_get_sched_id