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

  1. 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.
  2. 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.
  3. Report the environment details (Android version, linker, sandbox) upstream; the parser could be taught to disambiguate rows with identical device/inode/path.
  4. 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

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


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)