{"record":{"id":"a82368f7341a0c05","repo":"xai-org/grok-build","slug":"path-contains-nul","errorCode":null,"errorMessage":"path contains NUL","messagePattern":"path contains NUL","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-grok-tools/src/persistence.rs","lineNumber":380,"sourceCode":"                PCWSTR(from.as_ptr()),\n                PCWSTR(to.as_ptr()),\n                Self::WINDOWS_MOVE_FLAGS,\n            )\n        }\n        .map_err(io::Error::other)\n    }\n\n    #[cfg(windows)]\n    const WINDOWS_MOVE_FLAGS: windows::Win32::Storage::FileSystem::MOVE_FILE_FLAGS =\n        windows::Win32::Storage::FileSystem::MOVE_FILE_FLAGS(1 | 8);\n\n    #[cfg(windows)]\n    fn windows_extended_path(path: &Path) -> io::Result<Vec<u16>> {\n        use std::os::windows::ffi::OsStrExt;\n        let path = std::path::absolute(path)?;\n        let mut wide = path.as_os_str().encode_wide().collect::<Vec<_>>();\n        if wide.contains(&0) {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                \"path contains NUL\",\n            ));\n        }\n        let unc = wide.starts_with(&[92, 92]);\n        let mut result = if unc { r\"\\\\?\\UNC\\\" } else { r\"\\\\?\\\" }\n            .encode_utf16()\n            .collect::<Vec<_>>();\n        if unc {\n            wide.drain(..2);\n        }\n        result.extend(wide);\n        result.push(0);\n        Ok(result)\n    }\n}\n\n// Old `PersistenceLayer` / `PersistenceRunner` deleted.","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-grok-tools/src/persistence.rs#L362-L398","documentation":"windows_extended_path converts a path to a Windows extended-length (\\\\?\\ or \\\\?\\UNC\\) wide-string path for Win32 APIs that take UTF-16 paths. Windows cannot accept embedded NUL characters in path strings, so if the encoded wide string contains a 0 code unit the function refuses to build the extended path and throws io::ErrorKind::InvalidInput with 'path contains NUL'.","triggerScenarios":"Calling any persistence API on Windows whose path argument (after std::path::absolute) encodes to a wide string containing a NUL code unit — practically only when a Rust OsStr was constructed from raw bytes containing interior NULs, or a path was built from a buffer/string that includes '\\0'.","commonSituations":"Paths read from binary data, fixed-size C buffers, or legacy configs that include a trailing or interior NUL byte; converting C FFI strings to PathBuf without trimming the terminator.","solutions":["Trim or strip NUL bytes from the path string before constructing the PathBuf (e.g. split at the first '\\0').","Validate the path with path.as_os_str().to_string_lossy().contains('\\0') before calling the API and sanitize it.","Log the offending path bytes to find where the NUL is being introduced upstream."],"exampleFix":"// before\nlet path = PathBuf::from(c_string_buf); // may contain '\\0'\n// after\nlet cleaned: &str = c_string_buf.split('\\0').next().unwrap();\nlet path = PathBuf::from(cleaned);","handlingStrategy":"validation","validationCode":"fn path_has_nul(p: &std::path::Path) -> bool {\n    #[cfg(windows)]\n    { use std::os::windows::ffi::OsStrExt; p.as_os_str().encode_wide().any(|c| c == 0) }\n    #[cfg(not(windows))]\n    { false }\n}\n// if path_has_nul(&p) { sanitize before calling }","typeGuard":"fn is_safe_path(p: &std::path::Path) -> bool {\n    p.as_os_str().to_str().map(|s| !s.contains('\\0')).unwrap_or(false)\n}","tryCatchPattern":"match persistence::save(&path) {\n    Ok(v) => v,\n    Err(e) if e.kind() == std::io::ErrorKind::InvalidInput && e.to_string().contains(\"NUL\") => {\n        let clean = sanitize_nul(&path);\n        persistence::save(&clean)?\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Never build PathBuf from raw C/F buffers without trimming at the first NUL","Sanitize paths read from binary configs or network payloads","Validate paths contain no '\\0' at the boundary where they enter your code"],"tags":["windows","filesystem","path","invalid-input"],"backgroundTag":"path-contains-nul","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}