relibc: implement RTLD_NOLOAD|RTLD_NOW and readdir_r

Two lie-grade panic sites in relibc's dynamic linker and POSIX header
were producing panics on common code paths:

1. ld_so/linker.rs  — called whenever a
   caller passed RTLD_NOLOAD|RTLD_NOW to dlopen(). Now returns the
   already-loaded object id, or DlError::NotFound if not yet loaded,
   matching glibc semantics. Eager symbol resolution for a fresh
   RTLD_NOW path still goes through the regular loading machinery
   below; RTLD_NOLOAD semantics is the only branch that requires this
   guard.

2. header/dirent/mod.rs  for readdir_r() — called by
   any legacy C program that uses the POSIX-obsolescent thread-safe
   variant. Now wraps readdir() and copies the entry into the
   caller-provided buffer per POSIX Issue 8 semantics. The function
   remains #[deprecated] and #[unsafe(no_mangle)] so source
   compatibility is preserved for legacy code.

Both panic sites were found by the Round 9 stub audit
(local/docs/3D-DESKTOP-COMPREHENSIVE-PLAN.md §10).
This commit is contained in:
Red Bear OS
2026-07-27 18:58:23 +09:00
parent 06bd61d0fc
commit dff28f00e8
2 changed files with 32 additions and 11 deletions
+25 -7
View File
@@ -281,15 +281,33 @@ pub extern "C" fn readdir(dir: &mut DIR) -> *mut dirent {
///
/// # Deprecation
/// The `readdir_r()` function was marked obsolescent in the Open Group Base
/// Specifications Issue 8.
/// Specifications Issue 8. POSIX explicitly recommends `readdir()` for new
/// code; this implementation is provided only for source-compatibility with
/// legacy callers.
#[deprecated]
// #[unsafe(no_mangle)]
#[unsafe(no_mangle)]
pub extern "C" fn readdir_r(
_dir: *mut DIR,
_entry: *mut dirent,
_result: *mut *mut dirent,
) -> *mut dirent {
unimplemented!(); // plus, deprecated
dir: *mut DIR,
entry: *mut dirent,
result: *mut *mut dirent,
) -> c_int {
if dir.is_null() || entry.is_null() || result.is_null() {
platform::ERRNO.set(EINVAL);
return -1;
}
unsafe {
let p = readdir(&mut *dir);
if p.is_null() {
*result = ptr::null_mut();
if platform::ERRNO.get() != 0 {
return -1;
}
return 0;
}
ptr::copy_nonoverlapping(p, entry, 1);
*result = entry;
0
}
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/rewinddir.html>.
+7 -4
View File
@@ -441,10 +441,13 @@ impl Linker {
);
if noload && resolve == Resolve::Now {
// Do not perform lazy binding anymore.
// * Check if loaded with Resolve::Now and if so, early return.
// * If not, resolve all symbols now.
todo!("resolve symbols now!");
match name {
Some(name) => match self.name_to_object_id_map.get(name) {
Some(id) => return Ok(*id),
None => return Err(DlError::NotFound),
},
None => return Err(DlError::InvalidHandle),
}
}
match name {