fix(ld_so): page faulting when library not found

The error handling was already in place. The reason it was page faulting
is that, on failure, the function exits as soon as it encounters an
`Err` variant. When that happens, the DSO object for which the
dependency was being loaded is dropped. Dropping it calls `munmap` to
unload the executable and also runs the functions in `.fini`. However,
`run_fini` should only be called if the `DSO` is being unloaded after it
has been successfully loaded (i.e. all dependencies were satisfied and
all init functions had run).

Closes #1599

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2025-12-10 13:18:21 +11:00
parent 7d6296f29d
commit 64d3793190
2 changed files with 16 additions and 1 deletions
+15 -1
View File
@@ -30,6 +30,7 @@ use core::{
mem::{offset_of, size_of},
ptr::{self, NonNull},
slice,
sync::atomic::{AtomicBool, Ordering},
};
pub const CHAR_BITS: usize = size_of::<c_char>() * 8;
@@ -334,6 +335,9 @@ pub struct DSO {
pub scope: spin::Once<Scope>,
/// Position Independent Executable.
pub pie: bool,
/// Whether this DSO *and* its dependencies have been successfully loaded.
is_ready: AtomicBool,
}
impl DSO {
@@ -380,11 +384,17 @@ impl DSO {
pie: is_pie_enabled(&elf),
dynamic,
scope: spin::Once::new(),
is_ready: AtomicBool::new(false),
};
Ok((dso, tcb_master, elf.elf_program_headers().to_vec()))
}
#[inline]
pub fn mark_ready(&self) {
self.is_ready.store(true, Ordering::SeqCst);
}
#[inline]
pub fn scope(&self) -> &Scope {
self.scope.get().expect("scope not initialized")
@@ -1120,7 +1130,11 @@ impl DSO {
impl Drop for DSO {
fn drop(&mut self) {
self.run_fini();
if self.is_ready.load(Ordering::SeqCst) {
// `run_fini` should not be called if we are being prematurely
// dropped (e.g. failed to satisfy dependencies).
self.run_fini();
}
unsafe { Sys::munmap(self.mmap.as_ptr() as *mut c_void, self.mmap.len()).unwrap() };
}
}
+1
View File
@@ -715,6 +715,7 @@ impl Linker {
}
for obj in new_objects.into_iter() {
obj.mark_ready();
self.run_init(&obj);
self.register_object(obj);
}