Commit 0b3508073c
lib/std/fs/Dir.zig
@@ -1786,6 +1786,9 @@ pub fn symLink(
// when converting to an NT namespaced path. CreateSymbolicLink in
// symLinkW will handle the necessary conversion.
var target_path_w: windows.PathSpace = undefined;
+ if (try std.unicode.checkWtf8ToWtf16LeOverflow(target_path, &target_path_w.data)) {
+ return error.NameTooLong;
+ }
target_path_w.len = try std.unicode.wtf8ToWtf16Le(&target_path_w.data, target_path);
target_path_w.data[target_path_w.len] = 0;
// However, we need to canonicalize any path separators to `\`, since if
lib/std/posix/test.zig
@@ -22,6 +22,15 @@ const tmpDir = std.testing.tmpDir;
const Dir = std.fs.Dir;
const ArenaAllocator = std.heap.ArenaAllocator;
+// https://github.com/ziglang/zig/issues/20288
+test "WTF-8 to WTF-16 conversion buffer overflows" {
+ if (native_os != .windows) return error.SkipZigTest;
+
+ const input_wtf8 = "\u{10FFFF}" ** 16385;
+ try expectError(error.NameTooLong, posix.chdir(input_wtf8));
+ try expectError(error.NameTooLong, posix.chdirZ(input_wtf8));
+}
+
test "chdir smoke test" {
if (native_os == .wasi) return error.SkipZigTest;
lib/std/posix.zig
@@ -3111,8 +3111,10 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
@compileError("WASI does not support os.chdir");
} else if (native_os == .windows) {
var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
- const len = try std.unicode.wtf8ToWtf16Le(wtf16_dir_path[0..], dir_path);
- if (len > wtf16_dir_path.len) return error.NameTooLong;
+ if (try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path, &wtf16_dir_path)) {
+ return error.NameTooLong;
+ }
+ const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path);
return chdirW(wtf16_dir_path[0..len]);
} else {
const dir_path_c = try toPosixPath(dir_path);
@@ -3126,9 +3128,12 @@ pub fn chdir(dir_path: []const u8) ChangeCurDirError!void {
/// On other platforms, `dir_path` is an opaque sequence of bytes with no particular encoding.
pub fn chdirZ(dir_path: [*:0]const u8) ChangeCurDirError!void {
if (native_os == .windows) {
+ const dir_path_span = mem.span(dir_path);
var wtf16_dir_path: [windows.PATH_MAX_WIDE]u16 = undefined;
- const len = try std.unicode.wtf8ToWtf16Le(wtf16_dir_path[0..], mem.span(dir_path));
- if (len > wtf16_dir_path.len) return error.NameTooLong;
+ if (try std.unicode.checkWtf8ToWtf16LeOverflow(dir_path_span, &wtf16_dir_path)) {
+ return error.NameTooLong;
+ }
+ const len = try std.unicode.wtf8ToWtf16Le(&wtf16_dir_path, dir_path_span);
return chdirW(wtf16_dir_path[0..len]);
} else if (native_os == .wasi and !builtin.link_libc) {
return chdir(mem.span(dir_path));