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:
@@ -281,15 +281,33 @@ pub extern "C" fn readdir(dir: &mut DIR) -> *mut dirent {
|
|||||||
///
|
///
|
||||||
/// # Deprecation
|
/// # Deprecation
|
||||||
/// The `readdir_r()` function was marked obsolescent in the Open Group Base
|
/// 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]
|
#[deprecated]
|
||||||
// #[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
pub extern "C" fn readdir_r(
|
pub extern "C" fn readdir_r(
|
||||||
_dir: *mut DIR,
|
dir: *mut DIR,
|
||||||
_entry: *mut dirent,
|
entry: *mut dirent,
|
||||||
_result: *mut *mut dirent,
|
result: *mut *mut dirent,
|
||||||
) -> *mut dirent {
|
) -> c_int {
|
||||||
unimplemented!(); // plus, deprecated
|
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>.
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/rewinddir.html>.
|
||||||
|
|||||||
+7
-4
@@ -441,10 +441,13 @@ impl Linker {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if noload && resolve == Resolve::Now {
|
if noload && resolve == Resolve::Now {
|
||||||
// Do not perform lazy binding anymore.
|
match name {
|
||||||
// * Check if loaded with Resolve::Now and if so, early return.
|
Some(name) => match self.name_to_object_id_map.get(name) {
|
||||||
// * If not, resolve all symbols now.
|
Some(id) => return Ok(*id),
|
||||||
todo!("resolve symbols now!");
|
None => return Err(DlError::NotFound),
|
||||||
|
},
|
||||||
|
None => return Err(DlError::InvalidHandle),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match name {
|
match name {
|
||||||
|
|||||||
Reference in New Issue
Block a user