Use unsafe blocks in stdlib.h implementation

This commit is contained in:
sourceturner
2026-01-18 21:10:34 +01:00
parent 891eb61239
commit 59fb13ee2c
3 changed files with 228 additions and 195 deletions
+194 -167
View File
@@ -2,6 +2,9 @@
//!
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/stdlib.h.html>.
// TODO: set this for entire crate when possible
#![deny(unsafe_op_in_unsafe_fn)]
use core::{convert::TryFrom, intrinsics, iter, mem, ptr, slice};
use rand::{
Rng, SeedableRng,
@@ -82,7 +85,7 @@ pub unsafe extern "C" fn a64l(s: *const c_char) -> c_long {
// Handle up to 6 input characters (excl. null terminator)
for i in 0..6 {
let digit_char = *s.offset(i);
let digit_char = unsafe { *s.offset(i) };
let digit_value = match digit_char {
0 => break, // Null terminator encountered
@@ -124,7 +127,7 @@ static __stack_chk_guard: uintptr_t = 0xd048c37519fcadfe;
#[unsafe(no_mangle)]
unsafe extern "C" fn __stack_chk_fail() -> ! {
abort();
unsafe { abort() };
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/abs.html>.
@@ -139,7 +142,7 @@ pub unsafe extern "C" fn aligned_alloc(alignment: size_t, size: size_t) -> *mut
if size % alignment == 0 {
/* The size-is-multiple-of-alignment requirement is the only
* difference between aligned_alloc() and memalign(). */
memalign(alignment, size)
unsafe { memalign(alignment, size) }
} else {
platform::ERRNO.set(EINVAL);
ptr::null_mut()
@@ -149,9 +152,9 @@ pub unsafe extern "C" fn aligned_alloc(alignment: size_t, size: size_t) -> *mut
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/at_quick_exit.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn at_quick_exit(func: Option<extern "C" fn()>) -> c_int {
for i in 0..AT_QUICK_EXIT_FUNCS.unsafe_ref().len() {
if AT_QUICK_EXIT_FUNCS.unsafe_ref()[i] == None {
AT_QUICK_EXIT_FUNCS.unsafe_mut()[i] = func;
for i in 0..unsafe { AT_QUICK_EXIT_FUNCS.unsafe_ref().len() } {
if unsafe { AT_QUICK_EXIT_FUNCS.unsafe_ref() }[i] == None {
(unsafe { AT_QUICK_EXIT_FUNCS.unsafe_mut() })[i] = func;
return 0;
}
}
@@ -162,9 +165,9 @@ pub unsafe extern "C" fn at_quick_exit(func: Option<extern "C" fn()>) -> c_int {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/atexit.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn atexit(func: Option<extern "C" fn()>) -> c_int {
for i in 0..ATEXIT_FUNCS.unsafe_ref().len() {
if ATEXIT_FUNCS.unsafe_ref()[i] == None {
ATEXIT_FUNCS.unsafe_mut()[i] = func;
for i in 0..unsafe { ATEXIT_FUNCS.unsafe_ref().len() } {
if unsafe { ATEXIT_FUNCS.unsafe_ref() }[i] == None {
(unsafe { ATEXIT_FUNCS.unsafe_mut() })[i] = func;
return 0;
}
}
@@ -175,35 +178,35 @@ pub unsafe extern "C" fn atexit(func: Option<extern "C" fn()>) -> c_int {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/atof.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn atof(s: *const c_char) -> c_double {
strtod(s, ptr::null_mut())
unsafe { strtod(s, ptr::null_mut()) }
}
macro_rules! dec_num_from_ascii {
($s:expr, $t:ty) => {{
let mut s = $s;
// Iterate past whitespace
while ctype::isspace(*s as c_int) != 0 {
s = s.offset(1);
while ctype::isspace(unsafe { *s } as c_int) != 0 {
s = unsafe { s.offset(1) };
}
// Find out if there is a - sign
let neg_sign = match *s {
let neg_sign = match unsafe { *s } {
0x2d => {
s = s.offset(1);
s = unsafe { s.offset(1) };
true
}
// '+' increment s and continue parsing
0x2b => {
s = s.offset(1);
s = unsafe { s.offset(1) };
false
}
_ => false,
};
let mut n: $t = 0;
while ctype::isdigit(*s as c_int) != 0 {
n = 10 * n - (*s as $t - 0x30);
s = s.offset(1);
while ctype::isdigit(unsafe { *s } as c_int) != 0 {
n = 10 * n - (unsafe { *s } as $t - 0x30);
s = unsafe { s.offset(1) };
}
if neg_sign { n } else { -n }
@@ -213,7 +216,7 @@ macro_rules! dec_num_from_ascii {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/atoi.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn atoi(s: *const c_char) -> c_int {
dec_num_from_ascii!(s, c_int)
unsafe { dec_num_from_ascii!(s, c_int) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/atol.html>.
@@ -229,7 +232,7 @@ pub unsafe extern "C" fn atoll(s: *const c_char) -> c_longlong {
}
unsafe extern "C" fn void_cmp(a: *const c_void, b: *const c_void) -> c_int {
*(a as *const i32) - *(b as *const i32) as c_int
(unsafe { *(a as *const i32) }) - unsafe { *(b as *const i32) } as c_int
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/bsearch.html>.
@@ -246,7 +249,7 @@ pub unsafe extern "C" fn bsearch(
let cmp_fn = compar.unwrap_or(void_cmp);
while len > 0 {
let med = (start as size_t + (len >> 1) * width) as *const c_void;
let diff = cmp_fn(key, med);
let diff = unsafe { cmp_fn(key, med) };
if diff == 0 {
return med as *mut c_void;
} else if diff > 0 {
@@ -266,9 +269,9 @@ pub unsafe extern "C" fn calloc(nelem: size_t, elsize: size_t) -> *mut c_void {
Some(size) => {
/* If allocation fails here, errno setting will be handled
* by malloc() */
let ptr = malloc(size);
let ptr = unsafe { malloc(size) };
if !ptr.is_null() {
ptr.write_bytes(0, size);
unsafe { ptr.write_bytes(0, size) };
}
ptr
}
@@ -337,7 +340,8 @@ pub extern "C" fn ecvt(
#[unsafe(no_mangle)]
pub unsafe extern "C" fn erand48(xsubi: *mut c_ushort) -> c_double {
let params = rand48::params();
let xsubi_mut: &mut [c_ushort; 3] = slice::from_raw_parts_mut(xsubi, 3).try_into().unwrap();
let xsubi_mut: &mut [c_ushort; 3] =
unsafe { slice::from_raw_parts_mut(xsubi, 3).try_into().unwrap() };
let new_xsubi_value = params.step(xsubi_mut.into());
*xsubi_mut = new_xsubi_value.into();
new_xsubi_value.get_f64()
@@ -353,30 +357,30 @@ pub unsafe extern "C" fn exit(status: c_int) -> ! {
fn _fini();
}
for i in (0..ATEXIT_FUNCS.unsafe_ref().len()).rev() {
if let Some(func) = ATEXIT_FUNCS.unsafe_ref()[i] {
for i in (0..unsafe { ATEXIT_FUNCS.unsafe_ref().len() }).rev() {
if let Some(func) = unsafe { ATEXIT_FUNCS.unsafe_ref() }[i] {
(func)();
}
}
// Look for the neighbor functions in memory until the end
let mut f = &__fini_array_end as *const _;
let mut f = unsafe { &__fini_array_end } as *const _;
#[allow(clippy::op_ref)]
while f > &__fini_array_start {
f = f.offset(-1);
(*f)();
while f > unsafe { &__fini_array_start } {
f = unsafe { f.offset(-1) };
(unsafe { *f })();
}
#[cfg(not(target_arch = "riscv64"))] // risc-v uses arrays exclusively
{
_fini();
unsafe { _fini() };
}
ld_so::fini();
unsafe { ld_so::fini() };
crate::pthread::terminate_from_main_thread();
unsafe { crate::pthread::terminate_from_main_thread() };
flush_io_streams();
unsafe { flush_io_streams() };
Sys::exit(status);
}
@@ -400,7 +404,7 @@ pub extern "C" fn fcvt(
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/free.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn free(ptr: *mut c_void) {
platform::free(ptr);
unsafe { platform::free(ptr) };
}
/// See <https://pubs.opengroup.org/onlinepubs/009695399/functions/ecvt.html>.
@@ -418,26 +422,26 @@ unsafe fn find_env(search: *const c_char) -> Option<(usize, *mut c_char)> {
for (i, mut item) in platform::environ_iter().enumerate() {
let mut search = search;
loop {
let end_of_query = *search == 0 || *search == b'=' as c_char;
if *item == 0 {
let end_of_query = unsafe { *search } == 0 || unsafe { *search } == b'=' as c_char;
if unsafe { *item } == 0 {
//TODO: environ has an item without value, is this a problem?
break;
}
if *item == b'=' as c_char || end_of_query {
if *item == b'=' as c_char && end_of_query {
if unsafe { *item } == b'=' as c_char || end_of_query {
if unsafe { *item } == b'=' as c_char && end_of_query {
// Both keys env here
return Some((i, item.add(1)));
return Some((i, unsafe { item.add(1) }));
} else {
break;
}
}
if *item != *search {
if unsafe { *item } != unsafe { *search } {
break;
}
item = item.add(1);
search = search.add(1);
item = unsafe { item.add(1) };
search = unsafe { search.add(1) };
}
}
@@ -447,7 +451,9 @@ unsafe fn find_env(search: *const c_char) -> Option<(usize, *mut c_char)> {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getenv.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char {
find_env(name).map(|val| val.1).unwrap_or(ptr::null_mut())
unsafe { find_env(name) }
.map(|val| val.1)
.unwrap_or(ptr::null_mut())
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getsubopt.html>.
@@ -457,48 +463,52 @@ pub unsafe extern "C" fn getsubopt(
keylistp: *const *mut c_char,
valuep: *mut *mut c_char,
) -> c_int {
if optionp.is_null() || (*optionp).is_null() || keylistp.is_null() || valuep.is_null() {
if optionp.is_null()
|| (unsafe { *optionp }).is_null()
|| keylistp.is_null()
|| valuep.is_null()
{
return -1;
}
let start = *optionp;
let start = unsafe { *optionp };
let mut cursor = start;
let mut found_comma = false;
while *cursor != 0 {
if *cursor == b',' as c_char {
*cursor = 0;
*optionp = cursor.add(1);
while unsafe { *cursor } != 0 {
if unsafe { *cursor } == b',' as c_char {
unsafe { *cursor = 0 };
unsafe { *optionp = cursor.add(1) };
found_comma = true;
break;
}
cursor = cursor.add(1);
cursor = unsafe { cursor.add(1) };
}
if !found_comma {
*optionp = cursor;
unsafe { *optionp = cursor };
}
let mut i = 0;
while !(*keylistp.add(i)).is_null() {
let token = *keylistp.add(i);
let token_len = strlen(token);
while !(unsafe { *keylistp.add(i) }).is_null() {
let token = unsafe { *keylistp.add(i) };
let token_len = unsafe { strlen(token) };
if strncmp(start, token, token_len) == 0 {
let suffix_char = *start.add(token_len);
if unsafe { strncmp(start, token, token_len) } == 0 {
let suffix_char = unsafe { *start.add(token_len) };
if suffix_char == b'=' as c_char {
*valuep = start.add(token_len + 1);
unsafe { *valuep = start.add(token_len + 1) };
return i as c_int;
} else if suffix_char == 0 {
*valuep = ptr::null_mut();
unsafe { *valuep = ptr::null_mut() };
return i as c_int;
}
}
i += 1;
}
*valuep = start;
unsafe { *valuep = start };
-1
}
@@ -517,7 +527,7 @@ pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: size_
ptr::null_mut()
} else {
let mut random_state = random::state_lock();
let old_state = random_state.save();
let old_state = unsafe { random_state.save() };
random_state.n = match size {
0..=7 => unreachable!(), // ensured above
8..=31 => 0,
@@ -527,9 +537,9 @@ pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: size_
_ => 63,
};
random_state.x_ptr = (state.cast::<[u8; 4]>()).offset(1);
random_state.seed(seed);
random_state.save();
random_state.x_ptr = unsafe { (state.cast::<[u8; 4]>()).offset(1) };
unsafe { random_state.seed(seed) };
unsafe { random_state.save() };
old_state.cast::<_>()
}
@@ -547,7 +557,9 @@ pub unsafe extern "C" fn initstate(seed: c_uint, state: *mut c_char, size: size_
#[unsafe(no_mangle)]
pub unsafe extern "C" fn jrand48(xsubi: *mut c_ushort) -> c_long {
let params = rand48::params();
let xsubi_mut: &mut [c_ushort; 3] = slice::from_raw_parts_mut(xsubi, 3).try_into().unwrap();
let xsubi_mut: &mut [c_ushort; 3] = unsafe { slice::from_raw_parts_mut(xsubi, 3) }
.try_into()
.unwrap();
let new_xsubi_value = params.step(xsubi_mut.into());
*xsubi_mut = new_xsubi_value.into();
new_xsubi_value.get_i32()
@@ -567,13 +579,13 @@ pub unsafe extern "C" fn l64a(value: c_long) -> *mut c_char {
let num_output_digits = usize::try_from(6 - (value_as_i32.leading_zeros() + 4) / 6).unwrap();
// Reset buffer (and have null terminator in place for any result)
L64A_BUFFER.unsafe_set([0; 7]);
unsafe { L64A_BUFFER.unsafe_set([0; 7]) };
for i in 0..num_output_digits {
// Conversion to c_char always succeeds for the range 0..=63
let digit_value = c_char::try_from((value_as_i32 >> 6 * i) & 63).unwrap();
L64A_BUFFER.unsafe_mut()[i] = match digit_value {
(unsafe { L64A_BUFFER.unsafe_mut() })[i] = match digit_value {
0..=11 => {
// ./0123456789 for values 0 to 11. b'.' == 46
46 + digit_value
@@ -590,7 +602,7 @@ pub unsafe extern "C" fn l64a(value: c_long) -> *mut c_char {
};
}
L64A_BUFFER.unsafe_mut().as_mut_ptr()
unsafe { L64A_BUFFER.unsafe_mut().as_mut_ptr() }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/labs.html>.
@@ -613,7 +625,7 @@ pub unsafe extern "C" fn lcong48(param: *mut c_ushort) {
let mut xsubi = rand48::xsubi_lock();
let mut params = rand48::params_mut();
let param_slice = slice::from_raw_parts(param, 7);
let param_slice = unsafe { slice::from_raw_parts(param, 7) };
let xsubi_ref: &[c_ushort; 3] = param_slice[0..3].try_into().unwrap();
let a_ref: &[c_ushort; 3] = param_slice[3..6].try_into().unwrap();
@@ -677,7 +689,7 @@ pub extern "C" fn lrand48() -> c_long {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/malloc.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
let ptr = platform::alloc(size);
let ptr = unsafe { platform::alloc(size) };
if ptr.is_null() {
platform::ERRNO.set(ENOMEM);
}
@@ -689,7 +701,7 @@ pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memalign(alignment: size_t, size: size_t) -> *mut c_void {
if alignment.is_power_of_two() {
let ptr = platform::alloc_align(size, alignment);
let ptr = unsafe { platform::alloc_align(size, alignment) };
if ptr.is_null() {
platform::ERRNO.set(ENOMEM);
}
@@ -705,7 +717,7 @@ pub unsafe extern "C" fn memalign(alignment: size_t, size: size_t) -> *mut c_voi
pub unsafe extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int {
let mut wc: wchar_t = 0;
let mut state: mbstate_t = mbstate_t {};
let result: usize = mbrtowc(&mut wc, s, n, &mut state);
let result: usize = unsafe { mbrtowc(&mut wc, s, n, &mut state) };
if result == -1isize as usize {
return -1;
@@ -721,14 +733,14 @@ pub unsafe extern "C" fn mblen(s: *const c_char, n: size_t) -> c_int {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mbstowcs(pwcs: *mut wchar_t, mut s: *const c_char, n: size_t) -> size_t {
let mut state: mbstate_t = mbstate_t {};
mbsrtowcs(pwcs, &mut s, n, &mut state)
unsafe { mbsrtowcs(pwcs, &mut s, n, &mut state) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mbtowc.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mbtowc(pwc: *mut wchar_t, s: *const c_char, n: size_t) -> c_int {
let mut state: mbstate_t = mbstate_t {};
mbrtowc(pwc, s, n, &mut state) as c_int
(unsafe { mbrtowc(pwc, s, n, &mut state) }) as c_int
}
fn inner_mktemp<T, F>(name: *mut c_char, suffix_len: c_int, mut attempt: F) -> Option<T>
@@ -786,7 +798,7 @@ fn get_nstime() -> u64 {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mkdtemp(name: *mut c_char) -> *mut c_char {
inner_mktemp(name, 0, || {
let name_c = CStr::from_ptr(name);
let name_c = unsafe { CStr::from_ptr(name) };
match Sys::mkdir(name_c, 0o700) {
Ok(()) => Some(name),
Err(_) => None,
@@ -798,7 +810,7 @@ pub unsafe extern "C" fn mkdtemp(name: *mut c_char) -> *mut c_char {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdtemp.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mkostemp(name: *mut c_char, flags: c_int) -> c_int {
mkostemps(name, 0, flags)
unsafe { mkostemps(name, 0, flags) }
}
/// Non-POSIX, see <https://www.man7.org/linux/man-pages/man3/mkstemp.3.html>.
@@ -814,7 +826,7 @@ pub unsafe extern "C" fn mkostemps(
flags |= O_RDWR | O_CREAT | O_EXCL;
inner_mktemp(name, suffix_len, || {
let name = CStr::from_ptr(name);
let name = unsafe { CStr::from_ptr(name) };
let fd = Sys::open(name, flags, 0o600).or_minus_one_errno();
if fd >= 0 { Some(fd) } else { None }
@@ -825,13 +837,13 @@ pub unsafe extern "C" fn mkostemps(
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdtemp.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mkstemp(name: *mut c_char) -> c_int {
mkostemps(name, 0, 0)
unsafe { mkostemps(name, 0, 0) }
}
/// Non-POSIX, see <https://www.man7.org/linux/man-pages/man3/mkstemp.3.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mkstemps(name: *mut c_char, suffix_len: c_int) -> c_int {
mkostemps(name, suffix_len, 0)
unsafe { mkostemps(name, suffix_len, 0) }
}
/// See <https://pubs.opengroup.org/onlinepubs/009695399/functions/mktemp.html>.
@@ -843,7 +855,7 @@ pub unsafe extern "C" fn mkstemps(name: *mut c_char, suffix_len: c_int) -> c_int
#[unsafe(no_mangle)]
pub unsafe extern "C" fn mktemp(name: *mut c_char) -> *mut c_char {
if inner_mktemp(name, 0, || {
let name = CStr::from_ptr(name);
let name = unsafe { CStr::from_ptr(name) };
if Sys::access(name, 0) == Err(Errno(ENOENT)) {
Some(())
} else {
@@ -852,7 +864,7 @@ pub unsafe extern "C" fn mktemp(name: *mut c_char) -> *mut c_char {
})
.is_none()
{
*name = 0;
unsafe { *name = 0 };
}
name
}
@@ -882,7 +894,9 @@ pub extern "C" fn mrand48() -> c_long {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn nrand48(xsubi: *mut c_ushort) -> c_long {
let params = rand48::params();
let xsubi_mut: &mut [c_ushort; 3] = slice::from_raw_parts_mut(xsubi, 3).try_into().unwrap();
let xsubi_mut: &mut [c_ushort; 3] = unsafe { slice::from_raw_parts_mut(xsubi, 3) }
.try_into()
.unwrap();
let new_xsubi_value = params.step(xsubi_mut.into());
*xsubi_mut = new_xsubi_value.into();
new_xsubi_value.get_u31()
@@ -898,11 +912,11 @@ pub unsafe extern "C" fn posix_memalign(
const VOID_PTR_SIZE: usize = mem::size_of::<*mut c_void>();
if alignment % VOID_PTR_SIZE == 0 && alignment.is_power_of_two() {
let ptr = platform::alloc_align(size, alignment);
*memptr = ptr;
let ptr = unsafe { platform::alloc_align(size, alignment) };
unsafe { *memptr = ptr };
if ptr.is_null() { ENOMEM } else { 0 }
} else {
*memptr = ptr::null_mut();
unsafe { *memptr = ptr::null_mut() };
EINVAL
}
}
@@ -914,7 +928,7 @@ pub unsafe extern "C" fn posix_openpt(flags: c_int) -> c_int {
let r = open((b"/scheme/pty\0" as *const u8).cast(), O_CREAT);
#[cfg(target_os = "linux")]
let r = open((b"/dev/ptmx\0" as *const u8).cast(), flags);
let r = unsafe { open((b"/dev/ptmx\0" as *const u8).cast(), flags) };
if r < 0 && platform::ERRNO.get() == ENOSPC {
platform::ERRNO.set(EAGAIN);
@@ -928,7 +942,7 @@ pub unsafe extern "C" fn posix_openpt(flags: c_int) -> c_int {
pub unsafe extern "C" fn ptsname(fd: c_int) -> *mut c_char {
const PTS_BUFFER_LEN: usize = 9 + mem::size_of::<c_int>() * 3 + 1;
static mut PTS_BUFFER: [c_char; PTS_BUFFER_LEN] = [0; PTS_BUFFER_LEN];
if ptsname_r(fd, &raw mut PTS_BUFFER as *mut _, PTS_BUFFER_LEN) != 0 {
if unsafe { ptsname_r(fd, &raw mut PTS_BUFFER as *mut _, PTS_BUFFER_LEN) } != 0 {
ptr::null_mut()
} else {
&raw mut PTS_BUFFER as *mut _
@@ -942,7 +956,7 @@ pub unsafe extern "C" fn ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t)
platform::ERRNO.set(EINVAL);
EINVAL
} else {
__ptsname_r(fd, buf, buflen)
unsafe { __ptsname_r(fd, buf, buflen) }
}
}
@@ -975,7 +989,7 @@ unsafe fn __ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
let mut pty = 0;
let err = platform::ERRNO.get();
if ioctl(fd, TIOCGPTN, &mut pty as *mut _ as *mut c_void) == 0 {
if unsafe { ioctl(fd, TIOCGPTN, &mut pty as *mut _ as *mut c_void) } == 0 {
let name = format!("/dev/pts/{}", pty);
let len = name.len();
if len > buflen {
@@ -985,7 +999,7 @@ unsafe fn __ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
// we have checked the string will fit in the buffer
// so can use strcpy safely
let s = name.as_ptr().cast();
ptr::copy_nonoverlapping(s, buf, len);
unsafe { ptr::copy_nonoverlapping(s, buf, len) };
platform::ERRNO.set(err);
0
}
@@ -997,23 +1011,23 @@ unsafe fn __ptsname_r(fd: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
unsafe fn put_new_env(insert: *mut c_char) {
// XXX: Another problem is that `environ` can be set to any pointer, which means there is a
// chance of a memory leak. But we can check if it was the same as before, like musl does.
if platform::environ == platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() {
if unsafe { platform::environ } == unsafe { platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() } {
{
let mut our_environ = &mut *platform::OUR_ENVIRON.as_mut_ptr();
let mut our_environ = unsafe { &mut *platform::OUR_ENVIRON.as_mut_ptr() };
*our_environ.last_mut().unwrap() = insert;
our_environ.push(core::ptr::null_mut());
}
// Likely a no-op but is needed due to Stacked Borrows.
platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr();
unsafe { platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() };
} else {
{
let mut our_environ = &mut *platform::OUR_ENVIRON.as_mut_ptr();
let mut our_environ = unsafe { &mut *platform::OUR_ENVIRON.as_mut_ptr() };
our_environ.clear();
our_environ.extend(platform::environ_iter());
our_environ.push(insert);
our_environ.push(core::ptr::null_mut());
}
platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr();
unsafe { platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() };
}
}
@@ -1021,13 +1035,13 @@ unsafe fn put_new_env(insert: *mut c_char) {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn putenv(insert: *mut c_char) -> c_int {
assert_ne!(insert, ptr::null_mut(), "putenv(NULL)");
if let Some((i, _)) = find_env(insert) {
if let Some((i, _)) = unsafe { find_env(insert) } {
// XXX: The POSIX manual states that environment variables can be *set* via the `environ`
// global variable. While we can check if a pointer belongs to our allocator, or check
// `environ` against a vector which we control, it is likely not worth the effort.
platform::environ.add(i).write(insert);
unsafe { platform::environ.add(i).write(insert) };
} else {
put_new_env(insert);
unsafe { put_new_env(insert) };
}
0
}
@@ -1045,7 +1059,7 @@ pub unsafe extern "C" fn qsort(
if nel > 0 {
// XXX: maybe try to do mergesort/timsort first and fallback to introsort if memory
// allocation fails? not sure what is ideal
sort::introsort(base as *mut c_char, nel, width, comp);
unsafe { sort::introsort(base as *mut c_char, nel, width, comp) };
}
}
}
@@ -1065,8 +1079,8 @@ pub unsafe extern "C" fn qsort_r(
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/quick_exit.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn quick_exit(status: c_int) -> ! {
for i in (0..AT_QUICK_EXIT_FUNCS.unsafe_ref().len()).rev() {
if let Some(func) = AT_QUICK_EXIT_FUNCS.unsafe_ref()[i] {
for i in (0..unsafe { AT_QUICK_EXIT_FUNCS.unsafe_ref() }.len()).rev() {
if let Some(func) = unsafe { AT_QUICK_EXIT_FUNCS.unsafe_ref() }[i] {
(func)();
}
}
@@ -1077,13 +1091,15 @@ pub unsafe extern "C" fn quick_exit(status: c_int) -> ! {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/rand.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn rand() -> c_int {
match RNG {
Some(ref mut rng) => rng_sampler().sample(rng),
None => {
let mut rng = XorShiftRng::from_seed([1; 16]);
let ret = rng_sampler().sample(&mut rng);
RNG = Some(rng);
ret
unsafe {
match RNG {
Some(ref mut rng) => rng_sampler().sample(rng),
None => {
let mut rng = XorShiftRng::from_seed([1; 16]);
let ret = rng_sampler().sample(&mut rng);
unsafe { RNG = Some(rng) };
ret
}
}
}
}
@@ -1099,12 +1115,12 @@ pub unsafe extern "C" fn rand_r(seed: *mut c_uint) -> c_int {
errno::EINVAL
} else {
// set the type explicitly so this will fail if the array size for XorShiftRng changes
let seed_arr: [u8; 16] = mem::transmute([*seed; 16 / mem::size_of::<c_uint>()]);
let seed_arr: [u8; 16] = unsafe { mem::transmute([*seed; 16 / mem::size_of::<c_uint>()]) };
let mut rng = XorShiftRng::from_seed(seed_arr);
let ret = rng_sampler().sample(&mut rng);
*seed = ret as _;
unsafe { *seed = ret as _ };
ret
}
@@ -1118,19 +1134,21 @@ pub unsafe extern "C" fn random() -> c_long {
let k: u32;
random_state.ensure_x_ptr_init();
unsafe { random_state.ensure_x_ptr_init() };
if random_state.n == 0 {
let x_old = u32::from_ne_bytes(*random_state.x_ptr);
let x_old = u32::from_ne_bytes(unsafe { *random_state.x_ptr });
let x_new = random::lcg31_step(x_old);
*random_state.x_ptr = x_new.to_ne_bytes();
unsafe { *random_state.x_ptr = x_new.to_ne_bytes() };
k = x_new;
} else {
// The non-u32-aligned way of saying x[i] += x[j]...
let x_i_old = u32::from_ne_bytes(*random_state.x_ptr.add(usize::from(random_state.i)));
let x_j = u32::from_ne_bytes(*random_state.x_ptr.add(usize::from(random_state.j)));
let x_i_old =
u32::from_ne_bytes(unsafe { *random_state.x_ptr.add(usize::from(random_state.i)) });
let x_j =
u32::from_ne_bytes(unsafe { *random_state.x_ptr.add(usize::from(random_state.j)) });
let x_i_new = x_i_old.wrapping_add(x_j);
*random_state.x_ptr.add(usize::from(random_state.i)) = x_i_new.to_ne_bytes();
unsafe { *random_state.x_ptr.add(usize::from(random_state.i)) = x_i_new.to_ne_bytes() };
k = x_i_new >> 1;
@@ -1153,7 +1171,7 @@ pub unsafe extern "C" fn random() -> c_long {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/realloc.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
let new_ptr = platform::realloc(ptr, size);
let new_ptr = unsafe { platform::realloc(ptr, size) };
if new_ptr.is_null() {
platform::ERRNO.set(ENOMEM);
}
@@ -1165,7 +1183,7 @@ pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void
pub unsafe extern "C" fn reallocarray(ptr: *mut c_void, m: size_t, n: size_t) -> *mut c_void {
//Handle possible integer overflow in size calculation
match m.checked_mul(n) {
Some(size) => realloc(ptr, size),
Some(size) => unsafe { realloc(ptr, size) },
None => {
// For overflowing multiplication, we have to set errno here
platform::ERRNO.set(ENOMEM);
@@ -1178,14 +1196,14 @@ pub unsafe extern "C" fn reallocarray(ptr: *mut c_void, m: size_t, n: size_t) ->
#[unsafe(no_mangle)]
pub unsafe extern "C" fn realpath(pathname: *const c_char, resolved: *mut c_char) -> *mut c_char {
let ptr = if resolved.is_null() {
malloc(limits::PATH_MAX) as *mut c_char
(unsafe { malloc(limits::PATH_MAX) }) as *mut c_char
} else {
resolved
};
let out = slice::from_raw_parts_mut(ptr as *mut u8, limits::PATH_MAX);
let out = unsafe { slice::from_raw_parts_mut(ptr as *mut u8, limits::PATH_MAX) };
{
let file = match File::open(CStr::from_ptr(pathname), O_PATH | O_CLOEXEC) {
let file = match File::open(unsafe { CStr::from_ptr(pathname) }, O_PATH | O_CLOEXEC) {
Ok(file) => file,
Err(_) => return ptr::null_mut(),
};
@@ -1228,9 +1246,11 @@ pub unsafe extern "C" fn seed48(seed16v: *mut c_ushort) -> *mut c_ushort {
let mut params = rand48::params_mut();
let mut xsubi = rand48::xsubi_lock();
let seed16v_ref: &[c_ushort; 3] = slice::from_raw_parts(seed16v, 3).try_into().unwrap();
let seed16v_ref: &[c_ushort; 3] = unsafe { slice::from_raw_parts(seed16v, 3) }
.try_into()
.unwrap();
BUFFER = (*xsubi).into();
unsafe { BUFFER = (*xsubi).into() };
*xsubi = seed16v_ref.into();
params.reset();
&raw mut BUFFER as *mut _
@@ -1243,10 +1263,10 @@ unsafe fn copy_kv(
key_len: usize,
value_len: usize,
) {
core::ptr::copy_nonoverlapping(key, existing, key_len);
core::ptr::write(existing.add(key_len), b'=' as c_char);
core::ptr::copy_nonoverlapping(value, existing.add(key_len + 1), value_len);
core::ptr::write(existing.add(key_len + 1 + value_len), 0);
unsafe { core::ptr::copy_nonoverlapping(key, existing, key_len) };
unsafe { core::ptr::write(existing.add(key_len), b'=' as c_char) };
unsafe { core::ptr::copy_nonoverlapping(value, existing.add(key_len + 1), value_len) };
unsafe { core::ptr::write(existing.add(key_len + 1 + value_len), 0) };
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/setenv.html>.
@@ -1256,32 +1276,34 @@ pub unsafe extern "C" fn setenv(
value: *const c_char,
overwrite: c_int,
) -> c_int {
let key_len = strlen(key);
let value_len = strlen(value);
let key_len = unsafe { strlen(key) };
let value_len = unsafe { strlen(value) };
if let Some((i, existing)) = find_env(key) {
if let Some((i, existing)) = unsafe { find_env(key) } {
if overwrite == 0 {
return 0;
}
let existing_len = strlen(existing);
let existing_len = unsafe { strlen(existing) };
if existing_len >= value_len {
// Reuse existing element's allocation
core::ptr::copy_nonoverlapping(value, existing, value_len);
unsafe { core::ptr::copy_nonoverlapping(value, existing, value_len) };
//TODO: fill to end with zeroes
core::ptr::write(existing.add(value_len), 0);
unsafe { core::ptr::write(existing.add(value_len), 0) };
} else {
// Reuse platform::environ slot, but allocate a new pointer.
let ptr = platform::alloc(key_len as usize + 1 + value_len as usize + 1) as *mut c_char;
copy_kv(ptr, key, value, key_len, value_len);
platform::environ.add(i).write(ptr);
let ptr = unsafe { platform::alloc(key_len as usize + 1 + value_len as usize + 1) }
as *mut c_char;
unsafe { copy_kv(ptr, key, value, key_len, value_len) };
unsafe { platform::environ.add(i).write(ptr) };
}
} else {
// Expand platform::environ and allocate a new pointer.
let ptr = platform::alloc(key_len as usize + 1 + value_len as usize + 1) as *mut c_char;
copy_kv(ptr, key, value, key_len, value_len);
put_new_env(ptr);
let ptr = unsafe { platform::alloc(key_len as usize + 1 + value_len as usize + 1) }
as *mut c_char;
unsafe { copy_kv(ptr, key, value, key_len, value_len) };
unsafe { put_new_env(ptr) };
}
//platform::free(platform::inner_environ[index] as *mut c_void);
@@ -1306,8 +1328,8 @@ pub unsafe extern "C" fn setkey(key: *const c_char) {
pub unsafe extern "C" fn setstate(state: *mut c_char) -> *mut c_char {
let mut random_state = random::state_lock();
let old_state = random_state.save();
random_state.load(state.cast::<_>());
let old_state = unsafe { random_state.save() };
unsafe { random_state.load(state.cast::<_>()) };
old_state.cast::<_>()
}
@@ -1315,7 +1337,7 @@ pub unsafe extern "C" fn setstate(state: *mut c_char) -> *mut c_char {
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/rand.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn srand(seed: c_uint) {
RNG = Some(XorShiftRng::from_seed([seed as u8; 16]));
unsafe { RNG = Some(XorShiftRng::from_seed([seed as u8; 16])) };
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/drand48.html>.
@@ -1343,7 +1365,7 @@ pub extern "C" fn srand48(seedval: c_long) {
pub unsafe extern "C" fn srandom(seed: c_uint) {
let mut random_state = random::state_lock();
random_state.seed(seed);
unsafe { random_state.seed(seed) };
}
pub fn is_positive(ch: c_char) -> Option<(bool, isize)> {
@@ -1356,11 +1378,11 @@ pub fn is_positive(ch: c_char) -> Option<(bool, isize)> {
}
pub unsafe fn detect_base(s: *const c_char) -> Option<(c_int, isize)> {
let first = *s as u8;
let first = unsafe { *s } as u8;
match first {
0 => None,
b'0' => {
let second = *s.offset(1) as u8;
let second = unsafe { *s.offset(1) } as u8;
if second == b'X' || second == b'x' {
Some((16, 2))
} else if second >= b'0' && second <= b'7' {
@@ -1375,8 +1397,8 @@ pub unsafe fn detect_base(s: *const c_char) -> Option<(c_int, isize)> {
}
pub unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
if *s != 0 && *s == b'0' as c_char {
if let Some((val, idx, overflow)) = convert_integer(s.offset(1), 8) {
if unsafe { *s } != 0 && unsafe { *s } == b'0' as c_char {
if let Some((val, idx, overflow)) = unsafe { convert_integer(s.offset(1), 8) } {
Some((val, idx + 1, overflow))
} else {
// in case the prefix is not actually a prefix
@@ -1388,12 +1410,15 @@ pub unsafe fn convert_octal(s: *const c_char) -> Option<(c_ulong, isize, bool)>
}
pub unsafe fn convert_hex(s: *const c_char) -> Option<(c_ulong, isize, bool)> {
if (*s != 0 && *s == b'0' as c_char)
&& (*s.offset(1) != 0 && (*s.offset(1) == b'x' as c_char || *s.offset(1) == b'X' as c_char))
if (unsafe { *s } != 0 && unsafe { *s } == b'0' as c_char)
&& (unsafe { *s.offset(1) } != 0
&& (unsafe { *s.offset(1) } == b'x' as c_char
|| unsafe { *s.offset(1) } == b'X' as c_char))
{
convert_integer(s.offset(2), 16).map(|(val, idx, overflow)| (val, idx + 2, overflow))
unsafe { convert_integer(s.offset(2), 16) }
.map(|(val, idx, overflow)| (val, idx + 2, overflow))
} else {
convert_integer(s, 16).map(|(val, idx, overflow)| (val, idx, overflow))
unsafe { convert_integer(s, 16) }.map(|(val, idx, overflow)| (val, idx, overflow))
}
}
@@ -1427,7 +1452,7 @@ pub unsafe fn convert_integer(s: *const c_char, base: c_int) -> Option<(c_ulong,
// `-1 as usize` is usize::MAX
// `-1 as u8 as usize` is u8::MAX
// It extends by the sign bit unless we cast it to unsigned first.
let val = LOOKUP_TABLE[*s.offset(idx) as u8 as usize];
let val = LOOKUP_TABLE[unsafe { *s.offset(idx) } as u8 as usize];
if val == -1 || val as c_int >= base {
break;
} else {
@@ -1543,7 +1568,7 @@ pub unsafe extern "C" fn system(command: *const c_char) -> c_int {
// handle shell detection on command == NULL
if command.is_null() {
let status = system("exit 0\0".as_ptr() as *const c_char);
let status = unsafe { system("exit 0\0".as_ptr() as *const c_char) };
if status == 0 {
return 1;
} else {
@@ -1551,7 +1576,7 @@ pub unsafe extern "C" fn system(command: *const c_char) -> c_int {
}
}
let child_pid = unistd::fork();
let child_pid = unsafe { unistd::fork() };
if child_pid == 0 {
let command_nonnull = command as *const u8;
@@ -1564,9 +1589,9 @@ pub unsafe extern "C" fn system(command: *const c_char) -> c_int {
ptr::null(),
];
unistd::execv(shell as *const c_char, args.as_ptr() as *const *mut c_char);
unsafe { unistd::execv(shell as *const c_char, args.as_ptr() as *const *mut c_char) };
exit(127);
unsafe { exit(127) };
unreachable!();
} else if child_pid > 0 {
@@ -1597,26 +1622,28 @@ pub extern "C" fn ttyslot() -> c_int {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn unlockpt(fildes: c_int) -> c_int {
let mut u: c_int = 0;
ioctl(fildes, TIOCSPTLCK, &mut u as *mut i32 as *mut c_void)
unsafe { ioctl(fildes, TIOCSPTLCK, &mut u as *mut i32 as *mut c_void) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/unsetenv.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn unsetenv(key: *const c_char) -> c_int {
if let Some((i, _)) = find_env(key) {
if platform::environ == platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() {
if let Some((i, _)) = unsafe { find_env(key) } {
if unsafe { platform::environ }
== unsafe { platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() }
{
// No need to worry about updating the pointer, this does not
// reallocate in any way. And the final null is already shifted back.
{
let mut our_environ = &mut *platform::OUR_ENVIRON.as_mut_ptr();
let mut our_environ = unsafe { &mut *platform::OUR_ENVIRON.as_mut_ptr() };
our_environ.remove(i);
}
// My UB paranoia.
platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr();
unsafe { platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() };
} else {
{
let mut our_environ = &mut *platform::OUR_ENVIRON.as_mut_ptr();
let mut our_environ = unsafe { &mut *platform::OUR_ENVIRON.as_mut_ptr() };
our_environ.clear();
our_environ.extend(
platform::environ_iter()
@@ -1626,7 +1653,7 @@ pub unsafe extern "C" fn unsetenv(key: *const c_char) -> c_int {
);
our_environ.push(core::ptr::null_mut());
}
platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr();
unsafe { platform::environ = platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr() };
}
}
0
@@ -1642,11 +1669,11 @@ pub unsafe extern "C" fn unsetenv(key: *const c_char) -> c_int {
pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void {
/* sysconf(_SC_PAGESIZE) is a c_long and may in principle not
* convert correctly to a size_t. */
match size_t::try_from(sysconf(_SC_PAGESIZE)) {
match size_t::try_from(unsafe { sysconf(_SC_PAGESIZE) }) {
Ok(page_size) => {
/* valloc() is not supposed to be able to set errno to
* EINVAL, hence no call to memalign(). */
let ptr = platform::alloc_align(size, page_size);
let ptr = unsafe { platform::alloc_align(size, page_size) };
if ptr.is_null() {
platform::ERRNO.set(ENOMEM);
}
@@ -1663,14 +1690,14 @@ pub unsafe extern "C" fn valloc(size: size_t) -> *mut c_void {
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wcstombs(s: *mut c_char, mut pwcs: *const wchar_t, n: size_t) -> size_t {
let mut state: mbstate_t = mbstate_t {};
wcsrtombs(s, &mut pwcs, n, &mut state)
unsafe { wcsrtombs(s, &mut pwcs, n, &mut state) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/wctomb.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn wctomb(s: *mut c_char, wc: wchar_t) -> c_int {
let mut state: mbstate_t = mbstate_t {};
let result: usize = wcrtomb(s, wc, &mut state);
let result: usize = unsafe { wcrtomb(s, wc, &mut state) };
if result == -1isize as usize {
return -1;
+13 -10
View File
@@ -1,6 +1,9 @@
//! Helper functions for random() and friends, see https://pubs.opengroup.org/onlinepubs/7908799/xsh/initstate.html
// Ported from musl's implementation (src/prng/random.c)
// TODO: set this for entire crate when possible
#![deny(unsafe_op_in_unsafe_fn)]
use crate::{
platform::types::*,
sync::{Mutex, MutexGuard},
@@ -34,23 +37,23 @@ impl State {
/// To be called in any function that may read from X_PTR
pub unsafe fn ensure_x_ptr_init(&mut self) {
if self.x_ptr.is_null() {
let x_u32_ptr: *mut u32 = DEFAULT_X.get().cast::<u32>().add(1);
let x_u32_ptr: *mut u32 = unsafe { DEFAULT_X.get().cast::<u32>().add(1) };
self.x_ptr = x_u32_ptr.cast::<[u8; 4]>();
}
}
pub unsafe fn save(&mut self) -> *mut [u8; 4] {
self.ensure_x_ptr_init();
unsafe { self.ensure_x_ptr_init() };
let stash_value: u32 =
(u32::from(self.n) << 16) | (u32::from(self.i) << 8) | u32::from(self.j);
*self.x_ptr.offset(-1) = stash_value.to_ne_bytes();
self.x_ptr.offset(-1)
unsafe { *self.x_ptr.offset(-1) = stash_value.to_ne_bytes() };
unsafe { self.x_ptr.offset(-1) }
}
pub unsafe fn load(&mut self, state_ptr: *mut [u8; 4]) {
let stash_value = u32::from_ne_bytes(*state_ptr);
self.x_ptr = state_ptr.offset(1);
let stash_value = u32::from_ne_bytes(unsafe { *state_ptr });
self.x_ptr = unsafe { 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
@@ -63,12 +66,12 @@ impl State {
}
pub unsafe fn seed(&mut self, seed: c_uint) {
self.ensure_x_ptr_init();
unsafe { self.ensure_x_ptr_init() };
let mut s = seed as u64;
if self.n == 0 {
*self.x_ptr = (s as u32).to_ne_bytes();
unsafe { *self.x_ptr = (s as u32).to_ne_bytes() };
} else {
self.i = if self.n == 31 || self.n == 7 { 3 } else { 1 };
@@ -79,11 +82,11 @@ impl State {
// Conversion will always succeed (value is a 32-bit right-
// shift of a 64-bit integer).
*self.x_ptr.add(k) = u32::try_from(s >> 32).unwrap().to_ne_bytes();
unsafe { *self.x_ptr.add(k) = u32::try_from(s >> 32).unwrap().to_ne_bytes() };
}
// ensure X contains at least one odd number
*self.x_ptr = (u32::from_ne_bytes(*self.x_ptr) | 1).to_ne_bytes();
unsafe { *self.x_ptr = (u32::from_ne_bytes(*self.x_ptr) | 1).to_ne_bytes() };
}
}
}
+21 -18
View File
@@ -1,3 +1,6 @@
// TODO: set this for entire crate when possible
#![deny(unsafe_op_in_unsafe_fn)]
use crate::platform::types::*;
pub unsafe fn introsort(
@@ -10,7 +13,7 @@ pub unsafe fn introsort(
let maxdepth = 2 * log2(nel);
introsort_helper(base, nel, width, maxdepth, comp);
*/
insertion_sort(base, nel, width, comp);
unsafe { insertion_sort(base, nel, width, comp) };
}
// NOTE: if num is 0, the result should be considered undefined
@@ -41,23 +44,23 @@ unsafe fn introsort_helper(
// to introsort_helper()
loop {
if nel < THRESHOLD {
insertion_sort(base, nel, width, comp);
unsafe { insertion_sort(base, nel, width, comp) };
break;
} else if nel > 1 {
if maxdepth == 0 {
heapsort(base, nel, width, comp);
unsafe { heapsort(base, nel, width, comp) };
break;
} else {
let (left, right) = partition(base, nel, width, comp);
let (left, right) = unsafe { partition(base, nel, width, comp) };
let right_base = unsafe { base.add((right + 1) * width) };
let right_nel = nel - (right + 1);
maxdepth -= 1;
if left < nel - right {
introsort_helper(base, left, width, maxdepth, comp);
unsafe { introsort_helper(base, left, width, maxdepth, comp) };
base = right_base;
nel = right_nel;
} else {
introsort_helper(right_base, right_nel, width, maxdepth, comp);
unsafe { introsort_helper(right_base, right_nel, width, maxdepth, comp) };
nel = left;
}
}
@@ -76,7 +79,7 @@ unsafe fn insertion_sort(
let current = unsafe { base.add(j * width) };
let prev = unsafe { base.add((j + 1) * width) };
if comp(current as *const c_void, prev as *const c_void) > 0 {
swap(current, prev, width);
unsafe { swap(current, prev, width) };
} else {
break;
}
@@ -90,14 +93,14 @@ unsafe fn heapsort(
width: size_t,
comp: extern "C" fn(*const c_void, *const c_void) -> c_int,
) {
heapify(base, nel, width, comp);
unsafe { heapify(base, nel, width, comp) };
let mut end = nel - 1;
while end > 0 {
let end_ptr = unsafe { base.add(end * width) };
swap(end_ptr, base, width);
unsafe { swap(end_ptr, base, width) };
end -= 1;
heap_sift_down(base, 0, end, width, comp);
unsafe { heap_sift_down(base, 0, end, width, comp) };
}
}
@@ -111,7 +114,7 @@ unsafe fn heapify(
let last_parent = (nel - 2) / 2;
for start in (0..=last_parent).rev() {
heap_sift_down(base, start, nel - 1, width, comp);
unsafe { heap_sift_down(base, start, nel - 1, width, comp) };
}
}
@@ -148,7 +151,7 @@ unsafe fn heap_sift_down(
if swap_idx == root {
break;
} else {
swap(root_ptr, swap_ptr, width);
unsafe { swap(root_ptr, swap_ptr, width) };
root = swap_idx;
}
}
@@ -163,7 +166,7 @@ unsafe fn partition(
) -> (size_t, size_t) {
// calculate the median of the first, middle, and last elements and use it as the pivot
// to do fewer comparisons, also swap the elements into their correct positions
let mut pivot = median_of_three(base, nel, width, comp);
let mut pivot = unsafe { median_of_three(base, nel, width, comp) };
let mut i = 1;
let mut j = 1;
@@ -178,14 +181,14 @@ unsafe fn partition(
let comparison = comp(j_ptr as *const c_void, pivot_ptr as *const c_void);
if comparison < 0 {
swap(i_ptr, j_ptr, width);
unsafe { swap(i_ptr, j_ptr, width) };
if i == pivot {
pivot = j;
}
i += 1;
j += 1;
} else if comparison > 0 {
swap(j_ptr, n_ptr, width);
unsafe { swap(j_ptr, n_ptr, width) };
if n == pivot {
pivot = j;
}
@@ -209,12 +212,12 @@ unsafe fn median_of_three(
let mid = unsafe { base.add(pivot * width) };
let last = unsafe { base.add((nel - 1) * width) };
if comp(mid as *const c_void, base as *const c_void) < 0 {
swap(mid, base, width);
unsafe { swap(mid, base, width) };
}
if comp(last as *const c_void, mid as *const c_void) < 0 {
swap(mid, last, width);
unsafe { swap(mid, last, width) };
if comp(mid as *const c_void, base as *const c_void) < 0 {
swap(mid, base, width);
unsafe { swap(mid, base, width) };
}
}