Hmbown/CodeWhale · error
Android dladdr could not locate the updater's loaded image
Error message
Android dladdr could not locate the updater's loaded image
What it means
On Android the updater proves which file backs its own executable by calling libc::dladdr on a function marker inside this loaded image. This error is thrown when dladdr returns 0, meaning the dynamic loader could not associate the marker address with any loaded image, so no loaded-image path can be derived for the executable.
Solutions
- Ensure the binary is dynamically linked so dladdr can resolve image paths (avoid static linking for the updater binary on Android).
- Fall back to another proof path for the executable location (e.g. /proc/self/exe style resolution) if the build supports it.
- Verify the Android build/link flags didn't strip the image in a way that breaks dladdr; rebuild normally.
- Skip self-update on this platform and install updates via the app distribution channel instead.
Example fix
// before
let path = android_dladdr_path(marker)?;
// after
let path = match android_dladdr_path(marker) {
Ok(p) => p,
Err(_) => std::fs::read_link("/proc/self/exe")?, // fallback proof
}; Defensive patterns
Strategy: fallback
Validate before calling
// preflight: does dladdr resolve at all in this environment?
let marker = android_dladdr_path as *const _;
let ok = unsafe { libc::dladdr(marker, std::ptr::null_mut()) } != 0; Type guard
fn has_dladdr_proof() -> bool {
android_dladdr_path(android_dladdr_path as *const _).is_ok()
} Try / catch
let proof = android_loaded_executable_proof()
.or_else(|_| std::fs::read_link("/proc/self/exe").context("no dladdr or procfs proof"))?; Prevention
- Keep the Android updater binary dynamically linked.
- Test self-update paths on real Android devices, not only emulators with default loaders.
- Have a /proc/self/exe or /proc/self/maps fallback ready whenever dladdr is used.
When it happens
Trigger: android_dladdr_path invoked on Android (or in unix test harnesses) where dladdr fails for the marker address — e.g. statically linked image, stripped/unusual loader environment, or the marker address not belonging to a registered shared object.
Common situations: Running self-update on an Android build with a nonstandard linker setup; testing dladdr-dependent code in an environment without a normal dynamic loader; custom execve/dlopen environments.
Understand the failure class
Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.
Related errors
- Android dladdr returned an empty loaded-image path
- 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/be1a85ab6ddf704b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/update.rs:303
#[cfg(target_os = "android")]
fn android_loaded_executable_proof() -> Result<AndroidExecutableProof> {
let marker = android_update_image_marker as *const () as usize as u64;
let dladdr_path = android_dladdr_path(android_update_image_marker as *const libc::c_void)?;
let maps = std::fs::read_to_string(ANDROID_PROC_SELF_MAPS)
.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 {View on GitHub (pinned to 73e0f67d83)