From 399c428cb0dfa45fe840315a04526d3794622662 Mon Sep 17 00:00:00 2001 From: Vincent Rischmann Date: Mon, 28 Dec 2020 17:50:29 +0100 Subject: [PATCH 1/2] fs: add a test for the walker Written like this it triggers the segfault reported in #7560 --- lib/std/fs/test.zig | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index f4d50ca958..3f83f7886b 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -794,3 +794,42 @@ test "open file with exclusive nonblocking lock twice (absolute paths)" { try fs.deleteFileAbsolute(filename); } + +test "walker" { + if (builtin.os.tag == .wasi) return error.SkipZigTest; + + var arena = ArenaAllocator.init(testing.allocator); + defer arena.deinit(); + var allocator = &arena.allocator; + + var tmp = tmpDir(.{}); + defer tmp.cleanup(); + + const nb_dirs = 8; + + var i: usize = 0; + var sub_dir = tmp.dir; + while (i < nb_dirs) : (i += 1) { + const dir_name = try std.fmt.allocPrint(allocator, "{}", .{i}); + try sub_dir.makeDir(dir_name); + sub_dir = try sub_dir.openDir(dir_name, .{}); + } + + const tmp_path = try fs.path.join(allocator, &[_][]const u8{ "zig-cache", "tmp", tmp.sub_path[0..] }); + + var walker = try fs.walkPath(testing.allocator, tmp_path); + defer walker.deinit(); + + i = 0; + var expected_dir_name: []const u8 = ""; + while (i < nb_dirs) : (i += 1) { + const name = try std.fmt.allocPrint(allocator, "{}", .{i}); + expected_dir_name = if (expected_dir_name.len == 0) + name + else + try fs.path.join(allocator, &[_][]const u8{ expected_dir_name, name }); + + var entry = (try walker.next()).?; + testing.expectEqualStrings(expected_dir_name, try fs.path.relative(allocator, tmp_path, entry.path)); + } +} From 9c53564af1e00486218a5d345744273ad242ea33 Mon Sep 17 00:00:00 2001 From: Vincent Rischmann Date: Mon, 28 Dec 2020 17:53:52 +0100 Subject: [PATCH 2/2] fs: fix segfault in Walker.next `top` might point to invalid memory after a call to self.stack.append which causes a segfault. Prevent this by recomputing `top`. Fixes #7560 --- lib/std/fs.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 6880940c03..026bf21c5c 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -2183,7 +2183,7 @@ pub const Walker = struct { while (true) { if (self.stack.items.len == 0) return null; // `top` becomes invalid after appending to `self.stack`. - const top = &self.stack.items[self.stack.items.len - 1]; + var top = &self.stack.items[self.stack.items.len - 1]; const dirname_len = top.dirname_len; if (try top.dir_it.next()) |base| { self.name_buffer.shrink(dirname_len); @@ -2200,6 +2200,7 @@ pub const Walker = struct { .dir_it = new_dir.iterate(), .dirname_len = self.name_buffer.items.len, }); + top = &self.stack.items[self.stack.items.len - 1]; } } return Entry{