diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 86892cb97c19bcb7fdc5868a20f01fad1ad3ff7a..866643ebec07c765a4d7ab0ffcf2adb4f50f664d 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -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] diff --git a/src/header/stdlib/random.rs b/src/header/stdlib/random.rs index b390d5e487b8d3754cc8564ae170e86ce1167067..f08155924ea6993478352a69833d46f14e4b374b 100644 --- a/src/header/stdlib/random.rs +++ b/src/header/stdlib/random.rs @@ -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(); } }