Hmbown/CodeWhale · error
multiple /proc/self/maps rows contain the updater marker
Error message
multiple /proc/self/maps rows contain the updater marker
What it means
During a self-update on Android, the updater locates its own loaded executable image by finding the /proc/self/maps row that contains the address of a function inside the updater (the marker address). parse_android_image_mapping scans the maps text and keeps at most one matching executable row; if more than one maps row spans the marker address it refuses to guess and throws this error. It is a deliberate ambiguity guard so the updater never replaces the wrong file.
Solutions
- Inspect `cat /proc/self/maps` in the failing environment and identify why more than one executable row spans the updater's address; fix the duplication at the container/emulation level.
- Retry the update by running the installed binary directly from a normal filesystem path (e.g. /data/app/... or $PREFIX/bin) instead of under the unusual environment.
- Report the environment details (Android version, linker, sandbox) upstream; the parser could be taught to disambiguate rows with identical device/inode/path.
- As a workaround, replace the binary manually (download the new release and copy it over the installed path) rather than using in-place self-update.
Defensive patterns
Strategy: validation
Validate before calling
fn maps_rows_for_marker(maps: &str, marker: u64) -> usize {
maps.lines().filter(|l| {
l.split_whitespace().next()
.and_then(|r| r.split_once('-'))
.and_then(|(s, e)| Some(u64::from_str_radix(s,16).ok()? <= marker && marker < u64::from_str_radix(e,16).ok()?))
.unwrap_or(false)
}).count()
}
// call before update; if > 1, do not attempt in-place self-update Prevention
- Inspect /proc/self/maps in your target environment before shipping self-update there.
- Run updates from a normally loaded binary on a standard filesystem.
- Avoid sandboxes/emulators that split executable mappings.
- Prefer manual replacement over in-place self-update in exotic environments.
When it happens
Trigger: Calling the Android self-update path when /proc/self/maps contains two or more rows whose [start,end) address range contains the updater's marker address (e.g. duplicated or overlapping mappings of the binary).
Common situations: Kernel/linker producing overlapping executable mappings of the same image (e.g. unusual hugepage or shared mapping setups), custom or modified map entries, or running under emulation/sandboxes that split the text segment into multiple maps rows.
Related errors
- Android reported deleted loaded image
- Android loaded-image authorities disagree: dladdr resolved…
- Android identifies runtime linker ` `; refusing to use the…
- Android reported non-absolute loaded-image path
- Android dladdr could not locate the updater's loaded image
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/44c9b65273b391ea.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/update.rs:410
.context("loaded-image mapping has an invalid device")?;
let device_major = u32::from_str_radix(device_major, 16)
.context("loaded-image mapping has an invalid device major number")?;
let device_minor = u32::from_str_radix(device_minor, 16)
.context("loaded-image mapping has an invalid device minor number")?;
if path.is_empty() {
bail!("loaded-image mapping for updater marker has no pathname");
}
let mapping = AndroidImageMapping {
start,
end,
device_major,
device_minor,
inode,
path: PathBuf::from(path),
};
if matching.replace(mapping).is_some() {
bail!("multiple /proc/self/maps rows contain the updater marker");
}
}
matching.ok_or_else(|| anyhow!("no /proc/self/maps row contains the updater marker"))
}
#[cfg(all(test, unix))]
fn resolve_android_loaded_executable_report(
maps: &str,
marker: u64,
dladdr_path: &Path,
) -> Result<PathBuf> {
Ok(android_loaded_executable_proof_report(maps, marker, dladdr_path)?.path)
}
#[cfg(any(target_os = "android", all(test, unix)))]
fn android_loaded_executable_proof_report(
maps: &str,View on GitHub (pinned to 73e0f67d83)