Merge branch 'random-alignment' into 'master'
Don't assume u32 alignment of random() state buffer See merge request redox-os/relibc!286
This commit is contained in:
@@ -388,12 +388,12 @@ pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: size_
|
||||
_ => 63,
|
||||
};
|
||||
|
||||
random::X_PTR = (state as *mut u32).offset(1);
|
||||
random::X_PTR = (state.cast::<[u8; 4]>()).offset(1);
|
||||
random::seed(seed);
|
||||
random::save_state();
|
||||
// TODO: unlock?
|
||||
|
||||
old_state as _
|
||||
old_state.cast::<_>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -763,12 +763,18 @@ pub unsafe extern "C" fn random() -> c_long {
|
||||
random::ensure_x_ptr_init();
|
||||
|
||||
if random::N == 0 {
|
||||
*random::X_PTR = random::lcg31_step(*random::X_PTR);
|
||||
k = *random::X_PTR;
|
||||
let x_old = u32::from_ne_bytes(*random::X_PTR);
|
||||
let x_new = random::lcg31_step(x_old);
|
||||
*random::X_PTR = x_new.to_ne_bytes();
|
||||
k = x_new;
|
||||
} else {
|
||||
*random::X_PTR.add(usize::from(random::I)) += *random::X_PTR.add(usize::from(random::J));
|
||||
// The non-u32-aligned way of saying x[i] += x[j]...
|
||||
let x_i_old = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::I)));
|
||||
let x_j = u32::from_ne_bytes(*random::X_PTR.add(usize::from(random::J)));
|
||||
let x_i_new = x_i_old.wrapping_add(x_j);
|
||||
*random::X_PTR.add(usize::from(random::I)) = x_i_new.to_ne_bytes();
|
||||
|
||||
k = *random::X_PTR.add(usize::from(random::I)) >> 1;
|
||||
k = x_i_new >> 1;
|
||||
|
||||
random::I += 1;
|
||||
if random::I == random::N {
|
||||
@@ -916,9 +922,9 @@ pub unsafe extern "C" fn setstate(state: *mut c_char) -> *mut c_char {
|
||||
|
||||
// TODO: lock?
|
||||
let old_state = random::save_state();
|
||||
random::load_state(state as *mut u32);
|
||||
random::load_state(state.cast::<_>());
|
||||
// TODO: unlock?
|
||||
old_state as _
|
||||
old_state.cast::<_>()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
+22
-14
@@ -24,14 +24,20 @@ pub static mut N: u8 = 31;
|
||||
pub static mut I: u8 = 3;
|
||||
pub static mut J: u8 = 0;
|
||||
|
||||
/* Unlike in C, we can't take the address of the initializing array
|
||||
* outside of a function. */
|
||||
pub static mut X_PTR: *mut u32 = ptr::null_mut();
|
||||
/* As such, random() and related functions work on u32 values, but POSIX
|
||||
* allows the user to supply a custom state data array as a `char *`
|
||||
* with no requirements on alignment. Thus, we must assume the worst in
|
||||
* terms of alignment and convert back and forth from [u8; 4].
|
||||
*
|
||||
* Also, unlike in C, we can't take the address of the initializing
|
||||
* array outside of a function. */
|
||||
pub static mut X_PTR: *mut [u8; 4] = ptr::null_mut();
|
||||
|
||||
// To be called in any function that may read from X_PTR
|
||||
pub unsafe fn ensure_x_ptr_init() {
|
||||
if X_PTR.is_null() {
|
||||
X_PTR = &mut X_INIT[1];
|
||||
let x_u32_ptr: *mut u32 = &mut X_INIT[1];
|
||||
X_PTR = x_u32_ptr.cast::<[u8; 4]>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,24 +49,26 @@ pub fn lcg64_step(x: u64) -> u64 {
|
||||
6364136223846793005_u64.wrapping_mul(x).wrapping_add(1_u64)
|
||||
}
|
||||
|
||||
pub unsafe fn save_state() -> *mut u32 {
|
||||
pub unsafe fn save_state() -> *mut [u8; 4] {
|
||||
ensure_x_ptr_init();
|
||||
*X_PTR.offset(-1) = (u32::from(N) << 16) | (u32::from(I) << 8) | u32::from(J);
|
||||
|
||||
let stash_value: u32 = (u32::from(N) << 16) | (u32::from(I) << 8) | u32::from(J);
|
||||
*X_PTR.offset(-1) = stash_value.to_ne_bytes();
|
||||
X_PTR.offset(-1)
|
||||
}
|
||||
|
||||
pub unsafe fn load_state(state_ptr: *mut u32) {
|
||||
let prev_x = *state_ptr;
|
||||
pub unsafe fn load_state(state_ptr: *mut [u8; 4]) {
|
||||
let stash_value = u32::from_ne_bytes(*state_ptr);
|
||||
X_PTR = state_ptr.offset(1);
|
||||
|
||||
/* This calculation of N does not have a bit mask in the musl
|
||||
* original, in principle resulting in a u16, but obtaining a value
|
||||
* larger than 63 can probably be dismissed as pathological. */
|
||||
N = u8::try_from((prev_x >> 16) & 0xff).unwrap();
|
||||
N = u8::try_from((stash_value >> 16) & 0xff).unwrap();
|
||||
|
||||
// I and J calculations are straight from musl
|
||||
I = u8::try_from((prev_x >> 8) & 0xff).unwrap();
|
||||
J = u8::try_from(prev_x & 0xff).unwrap();
|
||||
I = u8::try_from((stash_value >> 8) & 0xff).unwrap();
|
||||
J = u8::try_from(stash_value & 0xff).unwrap();
|
||||
}
|
||||
|
||||
pub unsafe fn seed(seed: c_uint) {
|
||||
@@ -69,7 +77,7 @@ pub unsafe fn seed(seed: c_uint) {
|
||||
let mut s = seed as u64;
|
||||
|
||||
if N == 0 {
|
||||
*X_PTR = s as u32;
|
||||
*X_PTR = (s as u32).to_ne_bytes();
|
||||
} else {
|
||||
I = if N == 31 || N == 7 { 3 } else { 1 };
|
||||
|
||||
@@ -80,10 +88,10 @@ pub unsafe fn seed(seed: c_uint) {
|
||||
|
||||
// Conversion will always succeed (value is a 32-bit right-
|
||||
// shift of a 64-bit integer).
|
||||
*X_PTR.add(k) = u32::try_from(s >> 32).unwrap();
|
||||
*X_PTR.add(k) = u32::try_from(s >> 32).unwrap().to_ne_bytes();
|
||||
}
|
||||
|
||||
// ensure X contains at least one odd number
|
||||
*X_PTR |= 1;
|
||||
*X_PTR = (u32::from_ne_bytes(*X_PTR) | 1).to_ne_bytes();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user