{"record":{"id":"5447bbe938fd45ea","repo":"Hmbown/CodeWhale","slug":"android-dladdr-returned-an-empty-loaded-image-path","errorCode":null,"errorMessage":"Android dladdr returned an empty loaded-image path","messagePattern":"Android dladdr returned an empty loaded-image path","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/update.rs","lineNumber":308,"sourceCode":"        .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 {\n    start: u64,\n    end: u64,\n    device_major: u32,\n    device_minor: u32,\n    inode: u64,","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/update.rs#L290-L326","documentation":"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.","triggerScenarios":"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).","commonSituations":"Executing from an in-memory/memfd image or unpacked loader that maps the code without a filesystem path; heavily hardened Android runtimes.","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."],"exampleFix":"// before\nlet info = unsafe { info.assume_init() };\nif info.dli_fname.is_null() { bail!(...) }\n// after (caller-level guard)\nlet proof = android_loaded_executable_proof().or_else(|_| proof_from_proc_maps())?;","handlingStrategy":"fallback","validationCode":"// only trust dladdr when it yields a filename\nlet proof_ok = android_dladdr_path(marker)\n    .map(|p| !p.as_os_str().is_empty())\n    .unwrap_or(false);","typeGuard":null,"tryCatchPattern":"match android_dladdr_path(marker) {\n    Ok(p) => p,\n    Err(_) => proof_from_proc_maps(marker)?, // scan /proc/self/maps\n}","preventionTips":["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."],"tags":["android","dladdr","self-update","platform"],"backgroundTag":"resource-not-found","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"}