rt: fix memory-unsafe random seed logic, r=valgrindclean
This commit is contained in:
@@ -18,6 +18,7 @@ use u32;
|
|||||||
use uint;
|
use uint;
|
||||||
use util;
|
use util;
|
||||||
use vec;
|
use vec;
|
||||||
|
use libc::size_t;
|
||||||
|
|
||||||
/// A type that can be randomly generated using an RNG
|
/// A type that can be randomly generated using an RNG
|
||||||
pub trait Rand {
|
pub trait Rand {
|
||||||
@@ -120,9 +121,9 @@ enum rust_rng {}
|
|||||||
|
|
||||||
#[abi = "cdecl"]
|
#[abi = "cdecl"]
|
||||||
extern mod rustrt {
|
extern mod rustrt {
|
||||||
unsafe fn rand_seed() -> ~[u8];
|
unsafe fn rand_seed_size() -> size_t;
|
||||||
unsafe fn rand_new() -> *rust_rng;
|
unsafe fn rand_gen_seed(buf: *mut u8, sz: size_t);
|
||||||
unsafe fn rand_new_seeded2(&&seed: ~[u8]) -> *rust_rng;
|
unsafe fn rand_new_seeded(buf: *u8, sz: size_t) -> *rust_rng;
|
||||||
unsafe fn rand_next(rng: *rust_rng) -> u32;
|
unsafe fn rand_next(rng: *rust_rng) -> u32;
|
||||||
unsafe fn rand_free(rng: *rust_rng);
|
unsafe fn rand_free(rng: *rust_rng);
|
||||||
}
|
}
|
||||||
@@ -388,15 +389,18 @@ impl Rng for @RandRes {
|
|||||||
/// Create a new random seed for seeded_rng
|
/// Create a new random seed for seeded_rng
|
||||||
pub fn seed() -> ~[u8] {
|
pub fn seed() -> ~[u8] {
|
||||||
unsafe {
|
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
|
/// Create a random number generator with a system specified seed
|
||||||
pub fn Rng() -> Rng {
|
pub fn Rng() -> Rng {
|
||||||
unsafe {
|
seeded_rng(seed())
|
||||||
@RandRes(rustrt::rand_new()) as Rng
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -405,9 +409,15 @@ pub fn Rng() -> Rng {
|
|||||||
* all other generators constructed with the same seed. The seed may be any
|
* all other generators constructed with the same seed. The seed may be any
|
||||||
* length.
|
* 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 {
|
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 {
|
match r {
|
||||||
None => {
|
None => {
|
||||||
unsafe {
|
unsafe {
|
||||||
let rng = @RandRes(rustrt::rand_new());
|
let rng = seeded_randres(seed());
|
||||||
task::local_data::local_data_set(tls_rng_state, rng);
|
task::local_data::local_data_set(tls_rng_state, rng);
|
||||||
rng as Rng
|
rng as Rng
|
||||||
}
|
}
|
||||||
@@ -483,24 +493,24 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn rng_seeded() {
|
pub fn rng_seeded() {
|
||||||
let seed = rand::seed();
|
let seed = rand::seed();
|
||||||
let ra = rand::seeded_rng(&seed);
|
let ra = rand::seeded_rng(seed);
|
||||||
let rb = rand::seeded_rng(&seed);
|
let rb = rand::seeded_rng(seed);
|
||||||
assert ra.gen_str(100u) == rb.gen_str(100u);
|
assert ra.gen_str(100u) == rb.gen_str(100u);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn rng_seeded_custom_seed() {
|
pub fn rng_seeded_custom_seed() {
|
||||||
// much shorter than generated seeds which are 1024 bytes
|
// much shorter than generated seeds which are 1024 bytes
|
||||||
let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
|
let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
|
||||||
let ra = rand::seeded_rng(&seed);
|
let ra = rand::seeded_rng(seed);
|
||||||
let rb = rand::seeded_rng(&seed);
|
let rb = rand::seeded_rng(seed);
|
||||||
assert ra.gen_str(100u) == rb.gen_str(100u);
|
assert ra.gen_str(100u) == rb.gen_str(100u);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn rng_seeded_custom_seed2() {
|
pub fn rng_seeded_custom_seed2() {
|
||||||
let seed = ~[2u8, 32u8, 4u8, 32u8, 51u8];
|
let seed = [2u8, 32u8, 4u8, 32u8, 51u8];
|
||||||
let ra = rand::seeded_rng(&seed);
|
let ra = rand::seeded_rng(seed);
|
||||||
// Regression test that isaac is actually using the above vector
|
// Regression test that isaac is actually using the above vector
|
||||||
let r = ra.next();
|
let r = ra.next();
|
||||||
error!("%?", r);
|
error!("%?", r);
|
||||||
|
|||||||
@@ -128,49 +128,30 @@ vec_reserve_shared(type_desc* ty, rust_vec_box** vp,
|
|||||||
reserve_vec_exact(task, vp, n_elts * ty->size);
|
reserve_vec_exact(task, vp, n_elts * ty->size);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" CDECL rust_vec*
|
extern "C" CDECL size_t
|
||||||
rand_seed() {
|
rand_seed_size() {
|
||||||
size_t size = sizeof(ub4) * RANDSIZ;
|
return rng_seed_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" CDECL void
|
||||||
|
rand_gen_seed(uint8_t* dest, size_t size) {
|
||||||
rust_task *task = rust_get_current_task();
|
rust_task *task = rust_get_current_task();
|
||||||
rust_vec *v = (rust_vec *) task->kernel->malloc(vec_size<uint8_t>(size),
|
rng_gen_seed(task->kernel, dest, size);
|
||||||
"rand_seed");
|
|
||||||
v->fill = v->alloc = size;
|
|
||||||
rng_gen_seed(task->kernel, (uint8_t*) &v->data, size);
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" CDECL void *
|
extern "C" CDECL void *
|
||||||
rand_new() {
|
rand_new_seeded(uint8_t* seed, size_t seed_size) {
|
||||||
rust_task *task = rust_get_current_task();
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" CDECL void *
|
|
||||||
rand_new_seeded(rust_vec_box* seed) {
|
|
||||||
rust_task *task = rust_get_current_task();
|
|
||||||
rust_sched_loop *thread = task->sched_loop;
|
|
||||||
rust_rng *rng = (rust_rng *) task->malloc(sizeof(rust_rng),
|
rust_rng *rng = (rust_rng *) task->malloc(sizeof(rust_rng),
|
||||||
"rand_new_seeded");
|
"rand_new_seeded");
|
||||||
if (!rng) {
|
if (!rng) {
|
||||||
task->fail();
|
task->fail();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
rng_init(thread->kernel, rng, seed);
|
rng_init(task->kernel, rng, seed, seed_size);
|
||||||
return rng;
|
return rng;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" CDECL void *
|
|
||||||
rand_new_seeded2(rust_vec_box** seed) {
|
|
||||||
return rand_new_seeded(*seed);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" CDECL uint32_t
|
extern "C" CDECL uint32_t
|
||||||
rand_next(rust_rng *rng) {
|
rand_next(rust_rng *rng) {
|
||||||
rust_task *task = rust_get_current_task();
|
rust_task *task = rust_get_current_task();
|
||||||
|
|||||||
@@ -12,6 +12,12 @@
|
|||||||
#include "rust_rng.h"
|
#include "rust_rng.h"
|
||||||
#include "rust_util.h"
|
#include "rust_util.h"
|
||||||
|
|
||||||
|
size_t
|
||||||
|
rng_seed_size() {
|
||||||
|
randctx rctx;
|
||||||
|
return sizeof(rctx.randrsl);
|
||||||
|
}
|
||||||
|
|
||||||
// Initialization helpers for ISAAC RNG
|
// Initialization helpers for ISAAC RNG
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -48,15 +54,17 @@ rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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));
|
memset(rctx, 0, sizeof(randctx));
|
||||||
|
|
||||||
char *env_seed = kernel->env->rust_seed;
|
char *env_seed = kernel->env->rust_seed;
|
||||||
if (user_seed != NULL) {
|
if (user_seed != NULL) {
|
||||||
// ignore bytes after the required length
|
// ignore bytes after the required length
|
||||||
size_t seed_len = user_seed->body.fill < sizeof(rctx->randrsl)
|
if (seed_len > sizeof(rctx->randrsl)) {
|
||||||
? user_seed->body.fill : sizeof(rctx->randrsl);
|
seed_len = sizeof(rctx->randrsl);
|
||||||
memcpy(&rctx->randrsl, user_seed->body.data, seed_len);
|
}
|
||||||
|
memcpy(&rctx->randrsl, user_seed, seed_len);
|
||||||
} else if (env_seed != NULL) {
|
} else if (env_seed != NULL) {
|
||||||
ub4 seed = (ub4) atoi(env_seed);
|
ub4 seed = (ub4) atoi(env_seed);
|
||||||
for (size_t i = 0; i < RANDSIZ; i ++) {
|
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);
|
seed = (seed + 0x7ed55d16) + (seed << 12);
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
randinit(rctx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rng_init(rust_kernel* kernel, rust_rng* rng, rust_vec_box* user_seed) {
|
rng_init(rust_kernel* kernel, rust_rng* rng,
|
||||||
isaac_init(kernel, &rng->rctx, user_seed);
|
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;
|
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) {
|
if (bytes_generated < RESEED_THRESHOLD || !rng->reseedable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
rng_gen_seed(kernel,
|
||||||
uint32_t new_seed[RANDSIZ];
|
(uint8_t*)rng->rctx.randrsl,
|
||||||
rng_gen_seed(kernel, (uint8_t*) new_seed, RANDSIZ * sizeof(uint32_t));
|
sizeof(rng->rctx.randrsl));
|
||||||
|
|
||||||
// Stir new seed into PRNG's entropy pool.
|
|
||||||
for (size_t i = 0; i < RANDSIZ; i++) {
|
|
||||||
rng->rctx.randrsl[i] ^= new_seed[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
randinit(&rng->rctx, 1);
|
randinit(&rng->rctx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
|
|
||||||
class rust_kernel;
|
class rust_kernel;
|
||||||
struct rust_vec_box;
|
|
||||||
|
|
||||||
// Initialization helpers for ISAAC RNG
|
// Initialization helpers for ISAAC RNG
|
||||||
|
|
||||||
@@ -23,8 +22,11 @@ struct rust_rng {
|
|||||||
bool reseedable;
|
bool reseedable;
|
||||||
};
|
};
|
||||||
|
|
||||||
void rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size);
|
size_t rng_seed_size();
|
||||||
void rng_init(rust_kernel *kernel, rust_rng *rng, rust_vec_box* user_seed);
|
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);
|
uint32_t rng_gen_u32(rust_kernel *kernel, rust_rng *rng);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, int id, bool killed) :
|
|||||||
name("main")
|
name("main")
|
||||||
{
|
{
|
||||||
LOGPTR(this, "new dom", (uintptr_t)this);
|
LOGPTR(this, "new dom", (uintptr_t)this);
|
||||||
rng_init(kernel, &rng, NULL);
|
rng_init(kernel, &rng, NULL, 0);
|
||||||
|
|
||||||
if (!tls_initialized)
|
if (!tls_initialized)
|
||||||
init_tls();
|
init_tls();
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ rust_mktime
|
|||||||
new_task
|
new_task
|
||||||
precise_time_ns
|
precise_time_ns
|
||||||
rand_free
|
rand_free
|
||||||
rand_new
|
|
||||||
rand_new_seeded
|
rand_new_seeded
|
||||||
rand_new_seeded2
|
rand_seed_size
|
||||||
|
rand_gen_seed
|
||||||
rand_next
|
rand_next
|
||||||
rand_seed
|
rand_seed
|
||||||
rust_get_sched_id
|
rust_get_sched_id
|
||||||
|
|||||||
Reference in New Issue
Block a user