Hmbown/CodeWhale · error
Android dladdr returned an empty loaded-image path
Error message
Android dladdr returned an empty loaded-image path
What it means
After a successful dladdr call on Android, the updater reads info.dli_fname, the loaded-image path. This error is thrown when dli_fname is a NULL pointer — dladdr resolved the image but supplied no filename, so the updater cannot determine which file backs its executable.
Solutions
- Fall back to /proc/self/maps scanning (android_loaded_executable_proof_report / parse_android_image_mapping) to locate the backing file.
- Launch the binary from a real filesystem path rather than a memfd/anonymous mapping so the loader records a filename.
- Skip in-place self-update and obtain updates through the platform's distribution mechanism.
Example fix
// before
let info = unsafe { info.assume_init() };
if info.dli_fname.is_null() { bail!(...) }
// after (caller-level guard)
let proof = android_loaded_executable_proof().or_else(|_| proof_from_proc_maps())?; Defensive patterns
Strategy: fallback
Validate before calling
// only trust dladdr when it yields a filename
let proof_ok = android_dladdr_path(marker)
.map(|p| !p.as_os_str().is_empty())
.unwrap_or(false); Try / catch
match android_dladdr_path(marker) {
Ok(p) => p,
Err(_) => proof_from_proc_maps(marker)?, // scan /proc/self/maps
} Prevention
- Avoid executing the updater from memfd/anonymous mappings on Android.
- Always pair dladdr-based resolution with a /proc/self/maps fallback.
- Test on hardened Android runtimes, not just stock shells.
When it happens
Trigger: android_dladdr_path on Android where dladdr returns nonzero but dli_fname == NULL — occurs when the loader has no file path recorded for the mapping (e.g. anonymous or memfd-backed image).
Common situations: Executing from an in-memory/memfd image or unpacked loader that maps the code without a filesystem path; heavily hardened Android runtimes.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Android dladdr could not locate the updater's loaded image
- Android loaded-image authorities disagree: dladdr resolved…
- loaded-image mapping for updater marker has no file inode
- loaded-image mapping for updater marker has no pathname
- loaded-image mapping for updater marker is not executable
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/5447bbe938fd45ea.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/update.rs:308
.context("failed to read Android executable mappings from /proc/self/maps")?;
android_loaded_executable_proof_report(&maps, marker, &dladdr_path)
}
#[cfg(target_os = "android")]
fn android_dladdr_path(marker: *const libc::c_void) -> Result<PathBuf> {
use std::os::unix::ffi::OsStrExt;
let mut info = std::mem::MaybeUninit::<libc::Dl_info>::zeroed();
// SAFETY: `marker` points to a function in this loaded image and `info`
// points to writable storage for the duration of the call.
let found = unsafe { libc::dladdr(marker, info.as_mut_ptr()) };
if found == 0 {
bail!("Android dladdr could not locate the updater's loaded image");
}
// SAFETY: A non-zero dladdr result initializes `info`.
let info = unsafe { info.assume_init() };
if info.dli_fname.is_null() {
bail!("Android dladdr returned an empty loaded-image path");
}
// SAFETY: `dli_fname` is a NUL-terminated string owned by the dynamic
// loader and remains valid while this image is loaded.
let bytes = unsafe { CStr::from_ptr(info.dli_fname) }.to_bytes();
if bytes.is_empty() {
bail!("Android dladdr returned an empty loaded-image path");
}
Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(any(target_os = "android", all(test, unix)))]
#[derive(Debug, Clone, PartialEq, Eq)]
struct AndroidImageMapping {
start: u64,
end: u64,
device_major: u32,
device_minor: u32,
inode: u64,View on GitHub (pinned to 73e0f67d83)