astrid-runtime/astrid · error

umount target has NUL

Error message

umount target has NUL

What it means

umount converts the mountpoint path to a CString for umount2(2) with MNT_DETACH. If the target path contains an embedded NUL byte, CString::new fails and the function returns InvalidInput 'umount target has NUL' rather than calling the syscall with a truncated path.

Solutions

  1. Validate the stored mountpoint for NUL bytes before calling unmount_path
  2. Ensure paths are truncated at the first NUL when converted from byte buffers
  3. Prefer paths sourced from Rust std APIs, which forbid interior NULs
  4. Fix the record-keeping that saved the corrupted mountpoint path

Example fix

// before
let mp = Path::new(std::ffi::OsStr::from_bytes(&padded_buf));
unmount_path(mp)?;
// after
let trimmed: &[u8] = padded_buf.split(|b| *b == 0).next().unwrap();
let mp = Path::new(std::ffi::OsStr::from_bytes(trimmed));
unmount_path(mp)?;
Defensive patterns

Strategy: validation

Validate before calling

fn assert_umount_target(p: &Path) -> io::Result<()> { if p.as_os_str().as_bytes().contains(&0) { Err(io::Error::new(io::ErrorKind::InvalidInput, "mountpoint contains NUL")) } else { Ok(()) } }

Type guard

fn mountpoint_ok(p: &Path) -> bool { !p.as_os_str().as_bytes().contains(&0) }

Try / catch

if let Err(e) = unmount_path(mp) { if e.kind() == io::ErrorKind::InvalidInput { /* repair/re-derive the stored mountpoint */ } return Err(e.into()); }

Prevention

When it happens

Trigger: Calling unmount_path (→ umount) with a mountpoint Path whose OsStr bytes contain an interior '\0', typically from untrimmed byte buffers or FFI-derived data.

Common situations: Mountpoint paths reconstructed from binary IPC or config blobs; bookkeeping bugs where a stored path kept trailing NUL padding.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/dfd5543db40c949b. Report an issue: GitHub.

Appendix: source

Thrown at crates/astrid-vfs/src/workspace_cow/overlayfs.rs:523

        libc::mount(
            src.as_ptr(),
            target_c.as_ptr(),
            fstype.as_ptr(),
            0,
            data_c.as_ptr().cast(),
        )
    };
    if rc != 0 {
        return Err(io::Error::last_os_error());
    }
    Ok(())
}

/// `umount2(target, MNT_DETACH)` — lazy unmount so a busy mountpoint still
/// detaches.
fn umount(target: &Path) -> io::Result<()> {
    let target_c = CString::new(target.as_os_str().as_bytes())
        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "umount target has NUL"))?;
    // SAFETY: `target_c` is a valid, NUL-terminated C string outliving the call.
    let rc = unsafe { libc::umount2(target_c.as_ptr(), libc::MNT_DETACH) };
    if rc != 0 {
        return Err(io::Error::last_os_error());
    }
    Ok(())
}

View on GitHub (pinned to affd8760f4)