can1357/oh-my-pi · error · io::Error
path contains NUL
Error message
path contains NUL
What it means
pi-walker's directory-descriptor helper converts a Path's bytes to a CString before calling libc::open, and conversion fails if the path embeds a NUL byte (0x00). Rust Paths can contain interior NULs; libc APIs are NUL-terminated C strings, so such a path can never be opened. The walker maps the failure to io::ErrorKind::InvalidInput with this message.
Source
Thrown at crates/pi-walker/src/lib.rs:3567
},
Err(err) if is_skippable_entry_error(&err) => continue,
Err(err) => return Err(err.into()),
}
}
let raw_entry =
RawDirEntry { name: Cow::Owned(entry.file_name()), file_type, mtime, size };
if emit(raw_entry).map_err(ReadDirError::Walk)? == ReadDirControl::Stop {
return Ok(ReadDirControl::Stop);
}
}
Ok(ReadDirControl::Continue)
}
fn open_dir(path: &Path) -> io::Result<FdGuard> {
let path = CString::new(path.as_os_str().as_bytes())
.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "path contains NUL"))?;
// SAFETY: `path` is a NUL-terminated C string; flags open the directory for
// metadata traversal only and do not transfer ownership of the string.
let fd =
unsafe { libc::open(path.as_ptr(), libc::O_RDONLY | libc::O_DIRECTORY | libc::O_CLOEXEC) };
if fd < 0 {
Err(io::Error::last_os_error())
} else {
Ok(FdGuard(fd))
}
}
fn parse_record(record: &[u8], detail: WalkDetail) -> io::Result<Option<RawDirEntry<'_>>> {
let mut cursor = size_of::<u32>();
let name_ref_start = cursor;
let name_ref = read_value::<libc::attrreference_t>(record, &mut cursor)?;
let obj_type = read_value::<u32>(record, &mut cursor)?;
let (mtime, data_length) = if detail == WalkDetail::Full {
let modified = read_value::<libc::timespec>(record, &mut cursor)?;View on GitHub (pinned to 9690622007)
Solutions
- Sanitize or reject paths containing interior NUL bytes before passing them to the walker.
- Find the source of the malformed path (decoded buffer, binary format, database) and fix the producer.
- Catch io::ErrorKind::InvalidInput with this message and surface a user-facing validation error instead of walking.
Example fix
// before
walker.walk(untrustedPath);
// after
if (untrustedPath.as_os_str().as_bytes().contains(&0)) {
return Err("path contains NUL byte");
}
walker.walk(untrustedPath); Defensive patterns
Strategy: validation
Validate before calling
if (path.as_os_str().as_bytes().contains(&0)) {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "rejecting path with NUL"));
} Try / catch
match walker.walk(path) {
Err(e) if e.kind() == io::ErrorKind::InvalidInput => eprintln!("invalid path: {e}"),
Err(e) => return Err(e),
Ok(()) => {},
} Prevention
- Validate paths from untrusted/binary sources before walking.
- Never build Paths from raw byte buffers without a NUL check.
- Log and skip invalid paths instead of aborting the whole walk.
When it happens
Trigger: Calling open_dir with a Path whose OS bytes contain an interior 0x00 byte; typically reached via walk/read_dir APIs when the filesystem tree (or a crafted path input) contains NUL in a component.
Common situations: Paths sourced from binary data, corrupted filesystem entries, or user/network input that was not sanitized; rare on normal trees since most filesystems forbid NUL in names.
Related errors
- entry name contains NUL
- unknown filetype: {ft_debug}
- Is a directory
- Too many levels of symbolic links
- {}: {error}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/c756e06213270262.
Report an issue: GitHub.