Merge upstream/master into submodule/relibc

Sync the relibc fork with 50 upstream commits (socket layer rework,
exec/signal/ptrace/path/timer updates, pthread cleanup, ld_so lifecycle
work bringing mark_ready/run_fini into the tree, dynamically-linked
init support, start.rs allocator-model rewrite, test harness updates).
Satisfies the verify-fork-functions gate (2 previously-missing ld_so
functions now present).

Conflicts resolved (4 files; 46 auto-merged):

- src/start.rs: took upstream's version wholesale. Upstream moved
  allocator/linker initialization into ld_so's new lifecycle (the
  mark_ready/run_fini work this merge brings in), superseding the RB
  alloc_init cluster; the old model's function was already merged out
  and its lone call would not compile.

- redox-rt/src/sys.rs: kept the RB refresh flow with the non-fatal
  lseek fallback (upstream adopted the refresh as a fatal '?' —
  RB's conservative fallback protects spawn for uid-dropped /
  namespace-restricted exec where the kernel cannot refresh).

- src/platform/redox/exec.rs: kept the RB root exec-permission bypass
  (ruid/euid != 0 gate, Linux-matching behavior).

- Cargo.lock: syn 2.0.118 -> 2.0.119 (upstream).

Verified: repo cook relibc --force-rebuild successful;
verify-fork-functions.sh --no-fetch relibc passes;
all 9 forks now pass the gate.
This commit is contained in:
Red Bear OS
2026-07-19 07:12:56 +09:00
54 changed files with 745 additions and 2333 deletions
+2 -1
View File
@@ -76,7 +76,7 @@ macro_rules! pthread_assert_equal_size(
// Fail at compile-time if alignments differ.
let a = [0_u8; core::mem::align_of::<$export>()];
#[allow(clippy::useless_transmute)]
#[expect(clippy::useless_transmute)]
let b: [u8; core::mem::align_of::<Wrapped>()] = core::mem::transmute(a);
};
// TODO: Turn into a macro?
@@ -88,6 +88,7 @@ macro_rules! pthread_assert_equal_size(
let _: libc::$export = core::mem::transmute(export.__relibc_internal_size);
let a = [0_u8; core::mem::align_of::<$export>()];
#[expect(clippy::useless_transmute)]
let b: [u8; core::mem::align_of::<libc::$export>()] = core::mem::transmute(a);
};
+2 -2
View File
@@ -68,13 +68,13 @@ impl<'a> From<&'a syscall::TimeSpec> for timespec {
fn from(value: &'a syscall::TimeSpec) -> Self {
Self {
tv_sec: value.tv_sec as _,
tv_nsec: value.tv_nsec as _,
tv_nsec: value.tv_nsec.into(),
}
}
}
#[cfg(target_os = "redox")]
impl<'a> From<&'a timespec> for syscall::TimeSpec {
impl From<&timespec> for syscall::TimeSpec {
fn from(tp: &timespec) -> Self {
Self {
tv_sec: tp.tv_sec as _,
+13 -15
View File
@@ -11,10 +11,13 @@ use core::{
sync::atomic::{AtomicUsize, Ordering},
};
use alloc::sync::Arc;
use crate::{
c_str::CStr,
ld_so::{
linker::{DlError, ObjectHandle, Resolve, ScopeKind},
dso::DSO,
linker::{DlError, Resolve, ScopeKind},
tcb::Tcb,
},
platform::types::{c_char, c_int, c_void},
@@ -123,11 +126,8 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
let mut linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone();
let cbs = cbs_c.borrow();
match (cbs.load_library)(&mut linker, filename, resolve, scope, noload) {
Ok(handle) => handle.as_ptr().cast_mut(),
match linker.load_library(filename, resolve, scope, noload) {
Ok(handle) => Arc::into_raw(handle).cast::<c_void>().cast_mut(),
Err(error) => {
set_last_error(error);
ptr::null_mut()
@@ -138,7 +138,7 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/dlsym.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void {
let handle = ObjectHandle::from_ptr(handle);
let handle = unsafe { handle.cast::<DSO>().as_ref() };
if symbol.is_null() {
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
@@ -161,9 +161,8 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
}
let linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone();
let cbs = cbs_c.borrow();
match (cbs.get_sym)(&linker, handle, symbol_str) {
match linker.get_sym(handle, symbol_str) {
Some(sym) => sym,
_ => {
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
@@ -185,15 +184,14 @@ pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
return -1;
};
let Some(handle) = ObjectHandle::from_ptr(handle) else {
if handle.is_null() {
set_last_error(DlError::InvalidHandle);
return -1;
};
}
let mut linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone();
let cbs = cbs_c.borrow();
(cbs.unload)(&mut linker, handle);
let obj = unsafe { Arc::from_raw(handle.cast::<DSO>()) };
linker.unload(obj);
0
}
+7 -2
View File
@@ -98,11 +98,16 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig
continue;
}
#[expect(clippy::needless_update)]
#[cfg(target_os = "redox")]
let mut event = epoll_event {
events: 0,
data: epoll_data { u64: i as u64 },
..Default::default()
};
#[cfg(target_os = "linux")]
let mut event = epoll_event {
events: 0,
data: epoll_data { u64: i as u64 },
..Default::default() // needed only on redox for _pad field
};
for (p, ep) in event_map.iter() {
+1 -1
View File
@@ -5,7 +5,7 @@ pub fn split(line: &mut [u8]) -> Option<passwd> {
let mut parts = line.split_mut(|&c| c == b'\0');
Some(passwd {
pw_name: parts.next()?.as_mut_ptr().cast::<c_char>(),
pw_passwd: c"x".as_ptr() as *const c_char as *mut c_char,
pw_passwd: c"x".as_ptr().cast::<c_char>().cast_mut(),
pw_uid: parsed(parts.next())?,
pw_gid: parsed(parts.next())?,
pw_gecos: parts.next()?.as_mut_ptr().cast::<c_char>(),
+16 -16
View File
@@ -22,7 +22,9 @@ fn dup_read<T>(fd: c_int, name: &str, t: &mut T) -> syscall::Result<usize> {
let size = mem::size_of::<T>();
let bytes = dup.read(unsafe { slice::from_raw_parts_mut(t as *mut T as *mut u8, size) })?;
let bytes = dup.read(unsafe {
slice::from_raw_parts_mut(core::ptr::from_mut::<T>(t).cast::<u8>(), size)
})?;
Ok(bytes / size)
}
@@ -33,7 +35,8 @@ fn dup_write<T>(fd: c_int, name: &str, t: &T) -> Result<usize> {
let size = mem::size_of::<T>();
let bytes = dup.write(unsafe { slice::from_raw_parts(t as *const T as *const u8, size) })?;
let bytes = dup
.write(unsafe { slice::from_raw_parts(core::ptr::from_ref::<T>(t).cast::<u8>(), size) })?;
Ok(bytes / size)
}
@@ -50,13 +53,13 @@ impl IoctlBuffer {
unsafe fn read<T>(&self) -> Result<T> {
let (ptr, size) = match *self {
Self::Write(ptr, size) => (ptr, size),
Self::ReadWrite(ptr, size) => (ptr as *const c_void, size),
Self::ReadWrite(ptr, size) => (ptr.cast_const(), size),
_ => {
return Err(Errno(EINVAL));
}
};
if size == mem::size_of::<T>() {
let value = unsafe { ptr::read(ptr as *const T) };
let value = unsafe { ptr::read(ptr.cast::<T>()) };
Ok(value)
} else {
Err(Errno(EINVAL))
@@ -64,14 +67,11 @@ impl IoctlBuffer {
}
unsafe fn write<T>(&mut self, value: T) -> Result<()> {
let (ptr, size) = match *self {
Self::Read(ptr, size) | Self::ReadWrite(ptr, size) => (ptr, size),
_ => {
return Err(Errno(EINVAL));
}
let (Self::Read(ptr, size) | Self::ReadWrite(ptr, size)) = *self else {
return Err(Errno(EINVAL));
};
if size == mem::size_of::<T>() {
unsafe { ptr::write(ptr as *mut T, value) };
unsafe { ptr::write(ptr.cast::<T>(), value) };
Ok(())
} else {
Err(Errno(EINVAL))
@@ -83,7 +83,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
match request {
FIONBIO => {
let mut flags = Sys::fcntl(fd, fcntl::F_GETFL, 0)?;
flags = if unsafe { *(out as *mut c_int) } == 0 {
flags = if unsafe { *out.cast::<c_int>() } == 0 {
flags & !fcntl::O_NONBLOCK
} else {
flags | fcntl::O_NONBLOCK
@@ -91,7 +91,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
Sys::fcntl(fd, fcntl::F_SETFL, flags as c_ulonglong)?;
}
TCGETS => {
let termios = unsafe { &mut *(out as *mut termios::termios) };
let termios = unsafe { &mut *out.cast::<termios::termios>() };
dup_read(fd, "termios", termios)?;
}
// TODO: give these different behaviors
@@ -119,7 +119,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
todo_skip!(0, "ioctl TIOCSCTTY");
}
TIOCGPGRP => {
let pgrp = unsafe { &mut *(out as *mut pid_t) };
let pgrp = unsafe { &mut *out.cast::<pid_t>() };
dup_read(fd, "pgrp", pgrp)?;
}
TIOCSPGRP => {
@@ -127,7 +127,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
dup_write(fd, "pgrp", pgrp)?;
}
TIOCGWINSZ => {
let winsize = unsafe { &mut *(out as *mut winsize) };
let winsize = unsafe { &mut *out.cast::<winsize>() };
dup_read(fd, "winsize", winsize)?;
}
TIOCSWINSZ => {
@@ -135,7 +135,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
dup_write(fd, "winsize", winsize)?;
}
TIOCGPTLCK => {
let lock = unsafe { &mut *(out as *mut c_int) };
let lock = unsafe { &mut *out.cast::<c_int>() };
dup_read(fd, "ptlock", lock)?;
}
TIOCSPTLCK => {
@@ -143,7 +143,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
dup_write(fd, "ptlock", lock)?;
}
TIOCGPTN => {
let name = unsafe { &mut *(out as *mut c_int) };
let name = unsafe { &mut *out.cast::<c_int>() };
dup_read(fd, "ptsname", name)?;
}
SIOCATMARK => {
+1 -1
View File
@@ -72,7 +72,7 @@ pub(crate) struct timer_internal_t {
#[cfg(target_os = "redox")]
impl timer_internal_t {
pub unsafe fn from_raw(timerid: timer_t) -> &'static mut Self {
unsafe { &mut *(timerid as *mut Self) }
unsafe { &mut *timerid.cast::<Self>() }
}
}
+3 -1
View File
@@ -1,4 +1,6 @@
/// sysconf.h: <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sysconf.html>.
//! `sysconf.h` implementation.
//!
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sysconf.html>.
#[cfg(target_os = "redox")]
#[path = "sysconf/redox.rs"]
+3 -3
View File
@@ -40,7 +40,7 @@ pub(super) fn sysconf_impl(name: c_int) -> c_long {
_SC_TIMEOUTS => 202405,
_SC_TIMERS => 202405,
_SC_SYMLOOP_MAX => -1,
_SC_HOST_NAME_MAX => limits::HOST_NAME_MAX.try_into().unwrap_or(-1),
_SC_HOST_NAME_MAX => limits::HOST_NAME_MAX,
_SC_NPROCESSORS_CONF => get_cpu_count().unwrap_or(None).unwrap_or(1),
_SC_NPROCESSORS_ONLN => get_cpu_count().unwrap_or(None).unwrap_or(1),
_SC_PHYS_PAGES => get_mem_stat().map(|s| s.f_blocks as c_long).unwrap_or(-1),
@@ -77,6 +77,6 @@ pub fn get_mem_stat() -> Result<sys_statvfs::statvfs, Errno> {
let mut buf = sys_statvfs::statvfs::default();
let res = Sys::fstatvfs(fd, Out::from_mut(&mut buf));
if let Ok(()) = Sys::close(fd) {}; // TODO handle error
let _ = res?;
return Ok(buf);
res?;
Ok(buf)
}