Support nightly-2025-10-03

This commit is contained in:
Jeremy Soller
2025-10-03 12:11:12 -06:00
parent f3f37c3176
commit 82084440ad
188 changed files with 1440 additions and 1574 deletions
+57 -161
View File
@@ -3,7 +3,7 @@
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/string.h.html>.
use core::{
iter::{once, zip},
iter::once,
mem::{self, MaybeUninit},
ptr, slice, usize,
};
@@ -14,10 +14,11 @@ use crate::{
header::{errno::*, signal},
iter::{NulTerminated, NulTerminatedInclusive, SrcDstPtrIter},
platform::{self, types::*},
raw_cell::RawCell,
};
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/memccpy.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memccpy(
dest: *mut c_void,
src: *const c_void,
@@ -36,7 +37,7 @@ pub unsafe extern "C" fn memccpy(
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/memchr.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memchr(
haystack: *const c_void,
needle: c_int,
@@ -51,8 +52,8 @@ pub unsafe extern "C" fn memchr(
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/memcmp.html>.
#[no_mangle]
#[no_mangle]
#[unsafe(no_mangle)]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize) -> c_int {
let (div, rem) = (n / mem::size_of::<usize>(), n % mem::size_of::<usize>());
let mut a = s1 as *const usize;
@@ -92,114 +93,11 @@ pub unsafe extern "C" fn memcmp(s1: *const c_void, s2: *const c_void, n: usize)
/// - `s1` is convertible to a `&mut [MaybeUninit<u8>]` with length `n`,
/// and
/// - `s2` is convertible to a `&[MaybeUninit<u8>]` with length `n`.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memcpy(s1: *mut c_void, s2: *const c_void, n: size_t) -> *mut c_void {
// Avoid creating slices for n == 0. This is because we are required to
// avoid UB for n == 0, even if either s1 or s2 is null, to comply with the
// expectations of Rust's core library, as well as C2y (N3322).
// See https://doc.rust-lang.org/core/index.html for details.
if n != 0 {
// SAFETY: the caller is required to ensure that the provided pointers
// are valid. The slices are required to have a length of at most
// isize::MAX; this implicitly ensured by requiring valid pointers to
// two nonoverlapping slices.
let s1_slice = unsafe { slice::from_raw_parts_mut(s1.cast::<MaybeUninit<u8>>(), n) };
let s2_slice = unsafe { slice::from_raw_parts(s2.cast::<MaybeUninit<u8>>(), n) };
// At this point, it may seem tempting to use
// s1_slice.copy_from_slice(s2_slice) here, but memcpy is one of the
// handful of symbols whose existence is assumed by Rust's core
// library, and thus we need to be careful here not to rely on any
// function that calls memcpy internally.
// See https://doc.rust-lang.org/core/index.html for details.
//
// Instead, we check the alignment of the two slices and try to
// identify the largest Rust primitive type that is well-aligned for
// copying in chunks. s1_slice and s2_slice will be divided into
// (prefix, middle, suffix), where only the "middle" part is copyable
// using the larger primitive type.
let s1_addr = s1.addr();
let s2_addr = s2.addr();
// Find the number of similar trailing bits in the two addresses to let
// us find the largest possible chunk size
let equal_trailing_bits_count = (s1_addr ^ s2_addr).trailing_zeros();
let chunk_size = match equal_trailing_bits_count {
0 => 1,
1 => 2,
2 => 4,
3 => 8,
_ => 16, // use u128 chunks for any higher alignments
};
let chunk_align_offset = s1.align_offset(chunk_size);
let prefix_len = chunk_align_offset.min(n);
// Copy "prefix" bytes
for (s1_elem, s2_elem) in zip(&mut s1_slice[..prefix_len], &s2_slice[..prefix_len]) {
*s1_elem = *s2_elem;
}
if chunk_align_offset < n {
fn copy_chunks_and_remainder<const N: usize, T: Copy>(
dst: &mut [MaybeUninit<u8>],
src: &[MaybeUninit<u8>],
) {
// Check sanity
assert_eq!(N, mem::size_of::<T>());
assert_eq!(0, N % mem::align_of::<T>());
assert!(dst.as_mut_ptr().is_aligned_to(N));
assert!(src.as_ptr().is_aligned_to(N));
// Split into "middle" and "suffix"
let (dst_chunks, dst_remainder) = dst.as_chunks_mut::<N>();
let (src_chunks, src_remainder) = src.as_chunks::<N>();
// Copy "middle"
for (dst_chunk, src_chunk) in zip(dst_chunks, src_chunks) {
// SAFETY: the chunks are safely subsliced from s1 and
// s2. Alignment is ensured through the use of
// "align_offset", while the size of the chunks is
// explicitly taken to match the primitive size.
let dst_chunk_primitive: &mut MaybeUninit<T> =
unsafe { &mut *dst_chunk.as_mut_ptr().cast() };
let src_chunk_primitive: &MaybeUninit<T> =
unsafe { &*src_chunk.as_ptr().cast() };
*dst_chunk_primitive = *src_chunk_primitive;
}
// Copy "suffix"
for (dst_elem, src_elem) in zip(dst_remainder, src_remainder) {
*dst_elem = *src_elem;
}
}
// Copy "middle" bytes (if length is sufficient) and any remaining
// "suffix" bytes.
let s1_middle_and_suffix = &mut s1_slice[prefix_len..];
let s2_middle_and_suffix = &s2_slice[prefix_len..];
match chunk_size {
1 => {
for (s1_elem, s2_elem) in zip(s1_middle_and_suffix, s2_middle_and_suffix) {
*s1_elem = *s2_elem;
}
}
2 => {
copy_chunks_and_remainder::<2, u16>(s1_middle_and_suffix, s2_middle_and_suffix)
}
4 => {
copy_chunks_and_remainder::<4, u32>(s1_middle_and_suffix, s2_middle_and_suffix)
}
8 => {
copy_chunks_and_remainder::<8, u64>(s1_middle_and_suffix, s2_middle_and_suffix)
}
16 => copy_chunks_and_remainder::<16, u128>(
s1_middle_and_suffix,
s2_middle_and_suffix,
),
_ => unreachable!(),
}
}
for i in 0..n {
*(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i);
}
s1
}
@@ -209,7 +107,7 @@ pub unsafe extern "C" fn memcpy(s1: *mut c_void, s2: *const c_void, n: size_t) -
/// The caller must ensure that:
/// - `haystack` is convertible to a `&[u8]` with length `haystacklen`, and
/// - `needle` is convertible to a `&[u8]` with length `needlelen`.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memmem(
haystack: *const c_void,
haystacklen: size_t,
@@ -241,7 +139,7 @@ pub unsafe extern "C" fn memmem(
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/memmove.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memmove(s1: *mut c_void, s2: *const c_void, n: size_t) -> *mut c_void {
if s2 < s1 as *const c_void {
// copy from end
@@ -262,7 +160,7 @@ pub unsafe extern "C" fn memmove(s1: *mut c_void, s2: *const c_void, n: size_t)
}
/// Non-POSIX, see <https://www.man7.org/linux/man-pages/man3/memchr.3.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memrchr(
haystack: *const c_void,
needle: c_int,
@@ -277,7 +175,7 @@ pub unsafe extern "C" fn memrchr(
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/memset.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: size_t) -> *mut c_void {
for i in 0..n {
*(s as *mut u8).add(i) = c as u8;
@@ -286,7 +184,7 @@ pub unsafe extern "C" fn memset(s: *mut c_void, c: c_int, n: size_t) -> *mut c_v
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcpy.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn stpcpy(mut s1: *mut c_char, mut s2: *const c_char) -> *mut c_char {
loop {
*s1 = *s2;
@@ -303,7 +201,7 @@ pub unsafe extern "C" fn stpcpy(mut s1: *mut c_char, mut s2: *const c_char) -> *
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strncpy.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn stpncpy(
mut s1: *mut c_char,
mut s2: *const c_char,
@@ -327,13 +225,13 @@ pub unsafe extern "C" fn stpncpy(
}
/// Non-POSIX, see <https://www.man7.org/linux/man-pages/man3/strstr.3.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strcasestr(haystack: *const c_char, needle: *const c_char) -> *mut c_char {
inner_strstr(haystack, needle, !32)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcat.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_char {
strncat(s1, s2, usize::MAX)
}
@@ -344,7 +242,7 @@ pub unsafe extern "C" fn strcat(s1: *mut c_char, s2: *const c_char) -> *mut c_ch
/// The caller is required to ensure that `s` is a valid pointer to a buffer
/// containing at least one nul value. The pointed-to buffer must not be
/// modified for the duration of the call.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
let c_as_c_char = c as c_char;
@@ -361,7 +259,7 @@ pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
}
/// Non-POSIX, see <https://man7.org/linux/man-pages/man3/strchr.3.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strchrnul(s: *const c_char, c: c_int) -> *mut c_char {
let mut s = s.cast_mut();
loop {
@@ -377,13 +275,13 @@ pub unsafe extern "C" fn strchrnul(s: *const c_char, c: c_int) -> *mut c_char {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcmp.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int {
strncmp(s1, s2, usize::MAX)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcoll.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int {
// relibc has no locale stuff (yet)
strcmp(s1, s2)
@@ -392,7 +290,7 @@ pub unsafe extern "C" fn strcoll(s1: *const c_char, s2: *const c_char) -> c_int
// TODO: strcoll_l
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcpy.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char {
let src_iter = unsafe { NulTerminated::new(src).unwrap() };
let src_dest_iter = unsafe { SrcDstPtrIter::new(src_iter.chain(once(&0)), dst) };
@@ -431,37 +329,40 @@ pub unsafe fn inner_strspn(s1: *const c_char, s2: *const c_char, cmp: bool) -> s
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strcspn.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strcspn(s1: *const c_char, s2: *const c_char) -> size_t {
inner_strspn(s1, s2, false)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strdup.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strdup(s1: *const c_char) -> *mut c_char {
strndup(s1, usize::MAX)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strerror.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strerror(errnum: c_int) -> *mut c_char {
use core::fmt::Write;
static mut strerror_buf: [u8; STRERROR_MAX] = [0; STRERROR_MAX];
let mut w = platform::StringWriter(strerror_buf.as_mut_ptr(), strerror_buf.len());
static strerror_buf: RawCell<[u8; STRERROR_MAX]> = RawCell::new([0; STRERROR_MAX]);
let mut w = platform::StringWriter(
strerror_buf.unsafe_mut().as_mut_ptr(),
strerror_buf.unsafe_ref().len(),
);
let _ = match STR_ERROR.get(errnum as usize) {
Some(e) => w.write_str(e),
None => w.write_fmt(format_args!("Unknown error {}", errnum)),
};
strerror_buf.as_mut_ptr() as *mut c_char
strerror_buf.unsafe_mut().as_mut_ptr() as *mut c_char
}
// TODO: strerror_l
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strerror.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
let msg = strerror(errnum);
let len = strlen(msg);
@@ -479,7 +380,7 @@ pub unsafe extern "C" fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: siz
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strlcat.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strlcat(dst: *mut c_char, src: *const c_char, n: size_t) -> size_t {
let len = strlen(dst) as isize;
let d = dst.offset(len);
@@ -487,7 +388,7 @@ pub unsafe extern "C" fn strlcat(dst: *mut c_char, src: *const c_char, n: size_t
strlcpy(d, src, n)
}
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strsep(str_: *mut *mut c_char, sep: *const c_char) -> *mut c_char {
let s = *str_;
if s.is_null() {
@@ -505,7 +406,7 @@ pub unsafe extern "C" fn strsep(str_: *mut *mut c_char, sep: *const c_char) -> *
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strlcat.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strlcpy(dst: *mut c_char, src: *const c_char, n: size_t) -> size_t {
let mut i = 0;
@@ -520,13 +421,13 @@ pub unsafe extern "C" fn strlcpy(dst: *mut c_char, src: *const c_char, n: size_t
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strlen.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strlen(s: *const c_char) -> size_t {
unsafe { NulTerminated::new(s).unwrap() }.count()
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strncat.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char {
let len = strlen(s1.cast());
let mut i = 0;
@@ -545,15 +446,14 @@ pub unsafe extern "C" fn strncat(s1: *mut c_char, s2: *const c_char, n: size_t)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strncmp.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: size_t) -> c_int {
let s1 = slice::from_raw_parts(s1 as *const c_uchar, n);
let s2 = slice::from_raw_parts(s2 as *const c_uchar, n);
for (&a, &b) in s1.iter().zip(s2.iter()) {
let val = (a as c_int) - (b as c_int);
for i in 0..n {
// These must be cast as u8 to have correct comparisons
let a = *s1.add(i) as u8;
let b = *s2.add(i) as u8;
if a != b || a == 0 {
return val;
return (a as c_int) - (b as c_int);
}
}
@@ -561,14 +461,14 @@ pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: size_t
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strncpy.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strncpy(s1: *mut c_char, s2: *const c_char, n: size_t) -> *mut c_char {
stpncpy(s1, s2, n);
s1
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strdup.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strndup(s1: *const c_char, size: size_t) -> *mut c_char {
let len = strnlen(s1, size);
@@ -588,23 +488,19 @@ pub unsafe extern "C" fn strndup(s1: *const c_char, size: size_t) -> *mut c_char
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strlen.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strnlen(s: *const c_char, size: size_t) -> size_t {
unsafe { NulTerminated::new(s).unwrap() }.take(size).count()
}
/// Non-POSIX, see <https://en.cppreference.com/w/c/string/byte/strlen>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strnlen_s(s: *const c_char, size: size_t) -> size_t {
if s.is_null() {
0
} else {
strnlen(s, size)
}
if s.is_null() { 0 } else { strnlen(s, size) }
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strpbrk.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strpbrk(s1: *const c_char, s2: *const c_char) -> *mut c_char {
let p = s1.add(strcspn(s1, s2));
if *p != 0 {
@@ -615,7 +511,7 @@ pub unsafe extern "C" fn strpbrk(s1: *const c_char, s2: *const c_char) -> *mut c
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strrchr.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strrchr(s: *const c_char, c: c_int) -> *mut c_char {
let len = strlen(s) as isize;
let c = c as c_char;
@@ -630,7 +526,7 @@ pub unsafe extern "C" fn strrchr(s: *const c_char, c: c_int) -> *mut c_char {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strsignal.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strsignal(sig: c_int) -> *mut c_char {
signal::SIGNAL_STRINGS
.get(sig as usize)
@@ -639,7 +535,7 @@ pub unsafe extern "C" fn strsignal(sig: c_int) -> *mut c_char {
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strspn.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strspn(s1: *const c_char, s2: *const c_char) -> size_t {
inner_strspn(s1, s2, true)
}
@@ -669,20 +565,20 @@ unsafe fn inner_strstr(
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strstr.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strstr(haystack: *const c_char, needle: *const c_char) -> *mut c_char {
inner_strstr(haystack, needle, !0)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strtok.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strtok(s1: *mut c_char, delimiter: *const c_char) -> *mut c_char {
static mut HAYSTACK: *mut c_char = ptr::null_mut();
strtok_r(s1, delimiter, &mut HAYSTACK)
strtok_r(s1, delimiter, &raw mut HAYSTACK)
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strtok.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strtok_r(
s: *mut c_char,
delimiter: *const c_char,
@@ -719,7 +615,7 @@ pub unsafe extern "C" fn strtok_r(
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/strxfrm.html>.
#[no_mangle]
#[unsafe(no_mangle)]
pub unsafe extern "C" fn strxfrm(s1: *mut c_char, s2: *const c_char, n: size_t) -> size_t {
// relibc has no locale stuff (yet)
let len = strlen(s2);