{"record":{"id":"be1a85ab6ddf704b","repo":"Hmbown/CodeWhale","slug":"android-dladdr-could-not-locate-the-updater-s-load","errorCode":null,"errorMessage":"Android dladdr could not locate the updater's loaded image","messagePattern":"Android dladdr could not locate the updater's loaded image","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/update.rs","lineNumber":303,"sourceCode":"#[cfg(target_os = \"android\")]\nfn android_loaded_executable_proof() -> Result<AndroidExecutableProof> {\n    let marker = android_update_image_marker as *const () as usize as u64;\n    let dladdr_path = android_dladdr_path(android_update_image_marker as *const libc::c_void)?;\n    let maps = std::fs::read_to_string(ANDROID_PROC_SELF_MAPS)\n        .context(\"failed to read Android executable mappings from /proc/self/maps\")?;\n    android_loaded_executable_proof_report(&maps, marker, &dladdr_path)\n}\n\n#[cfg(target_os = \"android\")]\nfn android_dladdr_path(marker: *const libc::c_void) -> Result<PathBuf> {\n    use std::os::unix::ffi::OsStrExt;\n\n    let mut info = std::mem::MaybeUninit::<libc::Dl_info>::zeroed();\n    // SAFETY: `marker` points to a function in this loaded image and `info`\n    // points to writable storage for the duration of the call.\n    let found = unsafe { libc::dladdr(marker, info.as_mut_ptr()) };\n    if found == 0 {\n        bail!(\"Android dladdr could not locate the updater's loaded image\");\n    }\n    // SAFETY: A non-zero dladdr result initializes `info`.\n    let info = unsafe { info.assume_init() };\n    if info.dli_fname.is_null() {\n        bail!(\"Android dladdr returned an empty loaded-image path\");\n    }\n    // SAFETY: `dli_fname` is a NUL-terminated string owned by the dynamic\n    // loader and remains valid while this image is loaded.\n    let bytes = unsafe { CStr::from_ptr(info.dli_fname) }.to_bytes();\n    if bytes.is_empty() {\n        bail!(\"Android dladdr returned an empty loaded-image path\");\n    }\n    Ok(PathBuf::from(OsStr::from_bytes(bytes)))\n}\n\n#[cfg(any(target_os = \"android\", all(test, unix)))]\n#[derive(Debug, Clone, PartialEq, Eq)]\nstruct AndroidImageMapping {","sourceCodeStart":285,"sourceCodeEnd":321,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/update.rs#L285-L321","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nlet path = android_dladdr_path(marker)?;\n// after\nlet path = match android_dladdr_path(marker) {\n    Ok(p) => p,\n    Err(_) => std::fs::read_link(\"/proc/self/exe\")?, // fallback proof\n};","handlingStrategy":"fallback","validationCode":"// preflight: does dladdr resolve at all in this environment?\nlet marker = android_dladdr_path as *const _;\nlet ok = unsafe { libc::dladdr(marker, std::ptr::null_mut()) } != 0;","typeGuard":"fn has_dladdr_proof() -> bool {\n    android_dladdr_path(android_dladdr_path as *const _).is_ok()\n}","tryCatchPattern":"let proof = android_loaded_executable_proof()\n    .or_else(|_| std::fs::read_link(\"/proc/self/exe\").context(\"no dladdr or procfs proof\"))?;","preventionTips":["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."],"tags":["android","dladdr","self-update","platform"],"backgroundTag":"unsupported-platform","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}