{"record":{"id":"2b8bb19554e10603","repo":"can1357/oh-my-pi","slug":"entry-name-contains-nul","errorCode":null,"errorMessage":"entry name contains NUL","messagePattern":"entry name contains NUL","errorType":"error_code","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/pi-walker/src/lib.rs","lineNumber":3839,"sourceCode":"\t\t\t.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, \"path contains NUL\"))?;\n\t\t// SAFETY: `path` is a NUL-terminated C string; flags request a directory\n\t\t// descriptor used only with getdents/statx and do not retain the pointer.\n\t\tlet fd =\n\t\t\tunsafe { libc::open(path.as_ptr(), libc::O_RDONLY | libc::O_DIRECTORY | libc::O_CLOEXEC) };\n\t\tif fd < 0 {\n\t\t\tErr(io::Error::last_os_error())\n\t\t} else {\n\t\t\tOk(FdGuard(fd))\n\t\t}\n\t}\n\n\tfn stat_entry(\n\t\tdirfd: libc::c_int,\n\t\tname: &[u8],\n\t\tdetail: WalkDetail,\n\t) -> io::Result<Option<EntryStat>> {\n\t\tlet name = CString::new(name)\n\t\t\t.map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, \"entry name contains NUL\"))?;\n\t\tmatch statx_entry(dirfd, &name, detail) {\n\t\t\tOk(value) => Ok(value),\n\t\t\tErr(err) if matches!(err.raw_os_error(), Some(libc::ENOSYS | libc::EINVAL)) => {\n\t\t\t\tfstatat_entry(dirfd, &name, detail)\n\t\t\t},\n\t\t\tErr(err) => Err(err),\n\t\t}\n\t}\n\n\tfn statx_entry(\n\t\tdirfd: libc::c_int,\n\t\tname: &CString,\n\t\tdetail: WalkDetail,\n\t) -> io::Result<Option<EntryStat>> {\n\t\t// SAFETY: `Statx` is a plain-old-data buffer whose all-zero value is a\n\t\t// valid initialization before the kernel fills it.\n\t\tlet mut statx = unsafe { zeroed::<Statx>() };\n\t\tlet mask = if detail == WalkDetail::Full {","sourceCodeStart":3821,"sourceCodeEnd":3857,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-walker/src/lib.rs#L3821-L3857","documentation":"stat_entry converts a directory-entry name (raw bytes from getdents) into a CString for statx; an interior NUL makes conversion impossible, so it returns InvalidInput with this message. Entry names should never contain NUL on a healthy filesystem, so this guards against corrupt directory data or memory-safety hazards from passing the name to libc.","triggerScenarios":"A directory stream yields an entry whose raw name bytes include 0x00, then the walker attempts statx/fstatat metadata lookup on that entry.","commonSituations":"Traversing a corrupted or synthetic filesystem, fuzzing the walker, or reading directory data from a misbehaving FUSE/overlay mount.","solutions":["Investigate the filesystem or mount producing entries with NUL in names (corruption, FUSE bug).","Skip or report such entries: catch InvalidInput and continue the walk instead of failing the whole traversal.","If fuzz-testing, treat this as expected validation behavior and assert on it rather than fixing the walker."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// walker callback\nErr(e) if e.kind() == io::ErrorKind::InvalidInput => {\n  // entry name corrupt; skip entry, continue walk\n  ReadDirControl::Continue\n}","preventionTips":["Treat entries with invalid names as filesystem corruption signals.","Check the health of exotic mounts (FUSE/network) before deep walks.","Prefer per-entry error handling so one bad entry doesn't abort traversal."],"tags":["filesystem","invalid-input","nul-byte","corruption"],"backgroundTag":"nul-byte-in-path","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}