From 631633b25253201968b97cf129d986def37eed4a Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Fri, 27 Mar 2020 14:28:48 -0500 Subject: [PATCH 1/5] Document and reduce usage of MAX_PATH_BYTES, lifting arbitrary buffer size requirements --- lib/std/debug.zig | 3 +++ lib/std/fs.zig | 38 ++++++++++++++++++++++++++++---------- lib/std/os.zig | 2 ++ lib/std/process.zig | 4 +++- 4 files changed, 36 insertions(+), 11 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 3e52770932..aea9bcef51 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1283,6 +1283,9 @@ pub const DebugInfo = struct { const elf_path = if (ctx.name.len > 0) ctx.name else blk: { + // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately + // opened with no modification. TODO: Use openSelfExe instead to avoid path + // length limitations var buf: [fs.MAX_PATH_BYTES]u8 = undefined; break :blk try fs.selfExePath(&buf); }; diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 99383277a7..31953a805b 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -33,8 +33,11 @@ pub const GetAppDataDirError = @import("fs/get_app_data_dir.zig").GetAppDataDirE pub const Watch = @import("fs/watch.zig").Watch; -/// This represents the maximum size of a UTF-8 encoded file path. -/// All file system operations which return a path are guaranteed to +/// This represents the maximum size of a UTF-8 encoded file path that the +/// operating system will accept. Paths, including those returned from file +/// system operations, may be longer than this length, but such paths cannot +/// be successfully passed back in other file system operations. However, +/// all path components returned by file system operations are assumed to /// fit into a UTF-8 encoded array of this length. /// The byte count includes room for a null sentinel byte. pub const MAX_PATH_BYTES = switch (builtin.os.tag) { @@ -1194,7 +1197,7 @@ pub const Dir = struct { /// Read value of a symbolic link. /// The return value is a slice of `buffer`, from index `0`. /// Asserts that the path parameter has no null bytes. - pub fn readLink(self: Dir, sub_path: []const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { + pub fn readLink(self: Dir, sub_path: []const u8, buffer: []u8) ![]u8 { const sub_path_c = try os.toPosixPath(sub_path); return self.readLinkZ(&sub_path_c, buffer); } @@ -1202,7 +1205,7 @@ pub const Dir = struct { pub const readLinkC = @compileError("deprecated: renamed to readLinkZ"); /// Same as `readLink`, except the `pathname` parameter is null-terminated. - pub fn readLinkZ(self: Dir, sub_path_c: [*:0]const u8, buffer: *[MAX_PATH_BYTES]u8) ![]u8 { + pub fn readLinkZ(self: Dir, sub_path_c: [*:0]const u8, buffer: []u8) ![]u8 { return os.readlinkatZ(self.fd, sub_path_c, buffer); } @@ -1320,6 +1323,9 @@ pub const Dir = struct { var cleanup_dir = true; defer if (cleanup_dir) dir.close(); + // Likely valid use of MAX_PATH_BYTES, as dir_name_buf will only + // ever store a single path component that was returned from the + // filesystem. var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined; var dir_name: []const u8 = sub_path; @@ -1781,6 +1787,8 @@ pub fn openSelfExe() OpenSelfExeError!File { const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); return cwd().openFileW(prefixed_path_w.span(), .{}); } + // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately + // opened with no modification. var buf: [MAX_PATH_BYTES]u8 = undefined; const self_exe_path = try selfExePath(&buf); buf[self_exe_path.len] = 0; @@ -1792,6 +1800,8 @@ pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; /// `selfExePath` except allocates the result on the heap. /// Caller owns returned memory. pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 { + // TODO(#4812): Consider looping with larger and larger buffers to handle + // overlong paths. var buf: [MAX_PATH_BYTES]u8 = undefined; return mem.dupe(allocator, u8, try selfExePath(&buf)); } @@ -1806,10 +1816,10 @@ pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 { /// On Linux, depends on procfs being mounted. If the currently executing binary has /// been deleted, the file path looks something like `/a/b/c/exe (deleted)`. /// TODO make the return type of this a null terminated pointer -pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { +pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 { if (is_darwin) { - var u32_len: u32 = out_buffer.len; - const rc = std.c._NSGetExecutablePath(out_buffer, &u32_len); + var u32_len: u32 = @intCast(u32, math.min(out_buffer.len, math.maxInt(u32))); + const rc = std.c._NSGetExecutablePath(out_buffer.ptr, &u32_len); if (rc != 0) return error.NameTooLong; return mem.spanZ(@ptrCast([*:0]u8, out_buffer)); } @@ -1818,14 +1828,14 @@ pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]u8 { .freebsd, .dragonfly => { var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC, os.KERN_PROC_PATHNAME, -1 }; var out_len: usize = out_buffer.len; - try os.sysctl(&mib, out_buffer, &out_len, null, 0); + try os.sysctl(&mib, out_buffer.ptr, &out_len, null, 0); // TODO could this slice from 0 to out_len instead? return mem.spanZ(@ptrCast([*:0]u8, out_buffer)); }, .netbsd => { var mib = [4]c_int{ os.CTL_KERN, os.KERN_PROC_ARGS, -1, os.KERN_PROC_PATHNAME }; var out_len: usize = out_buffer.len; - try os.sysctl(&mib, out_buffer, &out_len, null, 0); + try os.sysctl(&mib, out_buffer.ptr, &out_len, null, 0); // TODO could this slice from 0 to out_len instead? return mem.spanZ(@ptrCast([*:0]u8, out_buffer)); }, @@ -1848,13 +1858,15 @@ pub fn selfExePathW() [:0]const u16 { /// `selfExeDirPath` except allocates the result on the heap. /// Caller owns returned memory. pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 { + // TODO(#4812): Consider looping with larger and larger buffers to handle + // overlong paths. var buf: [MAX_PATH_BYTES]u8 = undefined; return mem.dupe(allocator, u8, try selfExeDirPath(&buf)); } /// Get the directory path that contains the current executable. /// Returned value is a slice of out_buffer. -pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const u8 { +pub fn selfExeDirPath(out_buffer: []u8) SelfExePathError![]const u8 { const self_exe_path = try selfExePath(out_buffer); // Assume that the OS APIs return absolute paths, and therefore dirname // will not return null. @@ -1864,6 +1876,12 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) SelfExePathError![]const /// `realpath`, except caller must free the returned memory. /// TODO integrate with `Dir` pub fn realpathAlloc(allocator: *Allocator, pathname: []const u8) ![]u8 { + // Use of MAX_PATH_BYTES here is valid as the realpath function does not + // have a variant that takes an arbitrary-size buffer. + // TODO(#4812): Consider reimplementing realpath or using the POSIX.1-2008 + // NULL out parameter (GNU's canonicalize_file_name) to handle overelong + // paths. musl supports passing NULL but restricts the output to PATH_MAX + // anyway. var buf: [MAX_PATH_BYTES]u8 = undefined; return mem.dupe(allocator, u8, try os.realpath(pathname, &buf)); } diff --git a/lib/std/os.zig b/lib/std/os.zig index 22c884fce8..0fbffc822e 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -1236,6 +1236,8 @@ pub fn execvpeZ_expandArg0( if (mem.indexOfScalar(u8, file_slice, '/') != null) return execveZ(file, child_argv, envp); const PATH = getenvZ("PATH") orelse "/usr/local/bin:/bin/:/usr/bin"; + // Use of MAX_PATH_BYTES here is valid as the path_buf will be passed + // directly to the operating system in execveZ. var path_buf: [MAX_PATH_BYTES]u8 = undefined; var it = mem.tokenize(PATH, ":"); var seen_eacces = false; diff --git a/lib/std/process.zig b/lib/std/process.zig index a9400e8ce1..4e602a63cb 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -15,12 +15,14 @@ pub const changeCurDir = os.chdir; pub const changeCurDirC = os.chdirC; /// The result is a slice of `out_buffer`, from index `0`. -pub fn getCwd(out_buffer: *[fs.MAX_PATH_BYTES]u8) ![]u8 { +pub fn getCwd(out_buffer: []u8) ![]u8 { return os.getcwd(out_buffer); } /// Caller must free the returned memory. pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { + // TODO(#4812): Consider looping with larger and larger buffers to handle + // overlong paths. var buf: [fs.MAX_PATH_BYTES]u8 = undefined; return mem.dupe(allocator, u8, try os.getcwd(&buf)); } From ab3931fa9581776ef3654b9b55ff447ad91e7949 Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Fri, 27 Mar 2020 15:13:26 -0500 Subject: [PATCH 2/5] Prefer Files to paths in std.debug. Additionally [breaking] add a flags parameter to openSelfExe and stop exporting openElfDebugInfo. This should save a call to readlink in openSelfDebugInfo and support executables in overlong paths on Linux. --- lib/std/debug.zig | 46 +++++++++++++++++++++++---------------------- lib/std/fs.zig | 8 ++++---- lib/std/fs/test.zig | 2 +- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index aea9bcef51..462f4def1b 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -670,10 +670,11 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { } } +/// This takes ownership of coff_file: users of this function should not close +/// it themselves, even on error. /// TODO resources https://github.com/ziglang/zig/issues/4353 -fn openCoffDebugInfo(allocator: *mem.Allocator, coff_file_path: [:0]const u16) !ModuleDebugInfo { +fn readCoffDebugInfo(allocator: *mem.Allocator, coff_file: File) !ModuleDebugInfo { nosuspend { - const coff_file = try std.fs.openFileAbsoluteW(coff_file_path, .{ .intended_io_mode = .blocking }); errdefer coff_file.close(); const coff_obj = try allocator.create(coff.Coff); @@ -851,10 +852,12 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 { return ptr[start..end]; } +/// This takes ownership of elf_file: users of this function should not close +/// it themselves, even on error. /// TODO resources https://github.com/ziglang/zig/issues/4353 -pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !ModuleDebugInfo { +pub fn readElfDebugInfo(allocator: *mem.Allocator, elf_file: File) !ModuleDebugInfo { nosuspend { - const mapped_mem = try mapWholeFile(elf_file_path); + const mapped_mem = try mapWholeFile(elf_file); const hdr = @ptrCast(*const elf.Ehdr, &mapped_mem[0]); if (!mem.eql(u8, hdr.e_ident[0..4], "\x7fELF")) return error.InvalidElfMagic; if (hdr.e_ident[elf.EI_VERSION] != 1) return error.InvalidElfVersion; @@ -921,8 +924,10 @@ pub fn openElfDebugInfo(allocator: *mem.Allocator, elf_file_path: []const u8) !M } /// TODO resources https://github.com/ziglang/zig/issues/4353 -fn openMachODebugInfo(allocator: *mem.Allocator, macho_file_path: []const u8) !ModuleDebugInfo { - const mapped_mem = try mapWholeFile(macho_file_path); +/// This takes ownership of coff_file: users of this function should not close +/// it themselves, even on error. +fn readMachODebugInfo(allocator: *mem.Allocator, macho_file: File) !ModuleDebugInfo { + const mapped_mem = try mapWholeFile(macho_file); const hdr = @ptrCast( *const macho.mach_header_64, @@ -1055,9 +1060,8 @@ const MachoSymbol = struct { } }; -fn mapWholeFile(path: []const u8) ![]align(mem.page_size) const u8 { +fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 { nosuspend { - const file = try fs.cwd().openFile(path, .{ .intended_io_mode = .blocking }); defer file.close(); const file_len = try math.cast(usize, try file.getEndPos()); @@ -1140,10 +1144,11 @@ pub const DebugInfo = struct { errdefer self.allocator.destroy(obj_di); const macho_path = mem.spanZ(std.c._dyld_get_image_name(i)); - obj_di.* = openMachODebugInfo(self.allocator, macho_path) catch |err| switch (err) { + const macho_file = fs.cwd().openFile(macho_path, .{ .always_blocking = true }) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; + obj_di.* = try readMachODebugInfo(self.allocator, macho_file); obj_di.base_address = base_address; try self.address_map.putNoClobber(base_address, obj_di); @@ -1221,10 +1226,11 @@ pub const DebugInfo = struct { const obj_di = try self.allocator.create(ModuleDebugInfo); errdefer self.allocator.destroy(obj_di); - obj_di.* = openCoffDebugInfo(self.allocator, name_buffer[0 .. len + 4 :0]) catch |err| switch (err) { + const coff_file = fs.openFileAbsoluteW(name_buffer[0 .. len + 4 :0], .{}) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; + obj_di.* = try readCoffDebugInfo(self.allocator, coff_file); obj_di.base_address = seg_start; try self.address_map.putNoClobber(seg_start, obj_di); @@ -1280,23 +1286,18 @@ pub const DebugInfo = struct { return obj_di; } - const elf_path = if (ctx.name.len > 0) - ctx.name - else blk: { - // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately - // opened with no modification. TODO: Use openSelfExe instead to avoid path - // length limitations - var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - break :blk try fs.selfExePath(&buf); - }; - const obj_di = try self.allocator.create(ModuleDebugInfo); errdefer self.allocator.destroy(obj_di); - obj_di.* = openElfDebugInfo(self.allocator, elf_path) catch |err| switch (err) { + const elf_file = (if (ctx.name.len > 0) + fs.cwd().openFile(ctx.name, .{ .always_blocking = true }) + else + fs.openSelfExe(.{ .always_blocking = true })) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; + + obj_di.* = try readElfDebugInfo(self.allocator, elf_file); obj_di.base_address = ctx.base_address; try self.address_map.putNoClobber(ctx.base_address, obj_di); @@ -1332,7 +1333,8 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) { } fn loadOFile(self: *@This(), o_file_path: []const u8) !DW.DwarfInfo { - const mapped_mem = try mapWholeFile(o_file_path); + const o_file = try fs.cwd().openFile(o_file_path, .{ .always_blocking = true }); + const mapped_mem = try mapWholeFile(o_file); const hdr = @ptrCast( *const macho.mach_header_64, diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 31953a805b..9e86d6a2fe 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1778,21 +1778,21 @@ pub fn walkPath(allocator: *Allocator, dir_path: []const u8) !Walker { pub const OpenSelfExeError = os.OpenError || os.windows.CreateFileError || SelfExePathError || os.FlockError; -pub fn openSelfExe() OpenSelfExeError!File { +pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { if (builtin.os.tag == .linux) { - return openFileAbsoluteZ("/proc/self/exe", .{}); + return openFileAbsoluteZ("/proc/self/exe", flags); } if (builtin.os.tag == .windows) { const wide_slice = selfExePathW(); const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); - return cwd().openFileW(prefixed_path_w.span(), .{}); + return cwd().openFileW(prefix_path_w.span(), flags); } // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately // opened with no modification. var buf: [MAX_PATH_BYTES]u8 = undefined; const self_exe_path = try selfExePath(&buf); buf[self_exe_path.len] = 0; - return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, .{}); + return openFileAbsoluteZ(self_exe_path[0..self_exe_path.len :0].ptr, flags); } pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; diff --git a/lib/std/fs/test.zig b/lib/std/fs/test.zig index 2d979f5690..875565fc54 100644 --- a/lib/std/fs/test.zig +++ b/lib/std/fs/test.zig @@ -6,7 +6,7 @@ const File = std.fs.File; test "openSelfExe" { if (builtin.os.tag == .wasi) return error.SkipZigTest; - const self_exe_file = try std.fs.openSelfExe(); + const self_exe_file = try std.fs.openSelfExe(.{}); self_exe_file.close(); } From 0674b51453d5631f400936b4da7c74788f745e90 Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Sat, 28 Mar 2020 00:12:40 -0500 Subject: [PATCH 3/5] In getCwdAlloc, geometrically allocate larger buffers to find an appropriate size. --- lib/std/process.zig | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/lib/std/process.zig b/lib/std/process.zig index 4e602a63cb..85d3ae2ecb 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -21,10 +21,28 @@ pub fn getCwd(out_buffer: []u8) ![]u8 { /// Caller must free the returned memory. pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { - // TODO(#4812): Consider looping with larger and larger buffers to handle - // overlong paths. - var buf: [fs.MAX_PATH_BYTES]u8 = undefined; - return mem.dupe(allocator, u8, try os.getcwd(&buf)); + // The use of MAX_PATH_BYTES here is just a heuristic: most paths will fit + // in stack_buf, avoiding an extra allocation in the common case. + var stack_buf: [fs.MAX_PATH_BYTES]u8 = undefined; + var heap_buf: ?[]u8 = null; + defer if (heap_buf) |buf| allocator.free(buf); + + var current_buf: []u8 = &stack_buf; + while (true) { + if (os.getcwd(current_buf)) |slice| { + return mem.dupe(allocator, u8, slice); + } else |err| switch(err) { + error.NameTooLong => { + // The path is too long to fit in stack_buf. Allocate geometrically + // increasing buffers until we find one that works + const new_capacity = current_buf.len * 2; + if (heap_buf) |buf| allocator.free(buf); + current_buf = try allocator.alloc(u8, new_capacity); + heap_buf = current_buf; + }, + else => return err, + } + } } test "getCwdAlloc" { From c209da1589f50dee9e961f64cb389d0b4e485aba Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Sat, 28 Mar 2020 00:33:12 -0500 Subject: [PATCH 4/5] Document the failure to improve selfExe{,Dir}PathAlloc --- lib/std/fs.zig | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 9e86d6a2fe..311bfa5faf 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1800,8 +1800,13 @@ pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; /// `selfExePath` except allocates the result on the heap. /// Caller owns returned memory. pub fn selfExePathAlloc(allocator: *Allocator) ![]u8 { - // TODO(#4812): Consider looping with larger and larger buffers to handle - // overlong paths. + // Use of MAX_PATH_BYTES here is justified as, at least on one tested Linux + // system, readlink will completely fail to return a result larger than + // PATH_MAX even if given a sufficiently large buffer. This makes it + // fundamentally impossible to get the selfExePath of a program running in + // a very deeply nested directory chain in this way. + // TODO(#4812): Investigate other systems and whether it is possible to get + // this path by trying larger and larger buffers until one succeeds. var buf: [MAX_PATH_BYTES]u8 = undefined; return mem.dupe(allocator, u8, try selfExePath(&buf)); } @@ -1858,8 +1863,13 @@ pub fn selfExePathW() [:0]const u16 { /// `selfExeDirPath` except allocates the result on the heap. /// Caller owns returned memory. pub fn selfExeDirPathAlloc(allocator: *Allocator) ![]u8 { - // TODO(#4812): Consider looping with larger and larger buffers to handle - // overlong paths. + // Use of MAX_PATH_BYTES here is justified as, at least on one tested Linux + // system, readlink will completely fail to return a result larger than + // PATH_MAX even if given a sufficiently large buffer. This makes it + // fundamentally impossible to get the selfExeDirPath of a program running + // in a very deeply nested directory chain in this way. + // TODO(#4812): Investigate other systems and whether it is possible to get + // this path by trying larger and larger buffers until one succeeds. var buf: [MAX_PATH_BYTES]u8 = undefined; return mem.dupe(allocator, u8, try selfExeDirPath(&buf)); } From 89a97a7a278e69a440fd35665d4f1af864d023d9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 29 May 2020 16:39:47 -0400 Subject: [PATCH 5/5] cleanups --- lib/std/debug.zig | 14 ++++++++++---- lib/std/fs.zig | 6 +++--- lib/std/process.zig | 4 ++-- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 462f4def1b..bf82dab49c 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -673,6 +673,7 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { /// This takes ownership of coff_file: users of this function should not close /// it themselves, even on error. /// TODO resources https://github.com/ziglang/zig/issues/4353 +/// TODO it's weird to take ownership even on error, rework this code. fn readCoffDebugInfo(allocator: *mem.Allocator, coff_file: File) !ModuleDebugInfo { nosuspend { errdefer coff_file.close(); @@ -855,6 +856,7 @@ fn chopSlice(ptr: []const u8, offset: u64, size: u64) ![]const u8 { /// This takes ownership of elf_file: users of this function should not close /// it themselves, even on error. /// TODO resources https://github.com/ziglang/zig/issues/4353 +/// TODO it's weird to take ownership even on error, rework this code. pub fn readElfDebugInfo(allocator: *mem.Allocator, elf_file: File) !ModuleDebugInfo { nosuspend { const mapped_mem = try mapWholeFile(elf_file); @@ -926,6 +928,7 @@ pub fn readElfDebugInfo(allocator: *mem.Allocator, elf_file: File) !ModuleDebugI /// TODO resources https://github.com/ziglang/zig/issues/4353 /// This takes ownership of coff_file: users of this function should not close /// it themselves, even on error. +/// TODO it's weird to take ownership even on error, rework this code. fn readMachODebugInfo(allocator: *mem.Allocator, macho_file: File) !ModuleDebugInfo { const mapped_mem = try mapWholeFile(macho_file); @@ -1060,6 +1063,9 @@ const MachoSymbol = struct { } }; +/// `file` is expected to have been opened with .intended_io_mode == .blocking. +/// Takes ownership of file, even on error. +/// TODO it's weird to take ownership even on error, rework this code. fn mapWholeFile(file: File) ![]align(mem.page_size) const u8 { nosuspend { defer file.close(); @@ -1144,7 +1150,7 @@ pub const DebugInfo = struct { errdefer self.allocator.destroy(obj_di); const macho_path = mem.spanZ(std.c._dyld_get_image_name(i)); - const macho_file = fs.cwd().openFile(macho_path, .{ .always_blocking = true }) catch |err| switch (err) { + const macho_file = fs.cwd().openFile(macho_path, .{ .intended_io_mode = .blocking }) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; @@ -1290,9 +1296,9 @@ pub const DebugInfo = struct { errdefer self.allocator.destroy(obj_di); const elf_file = (if (ctx.name.len > 0) - fs.cwd().openFile(ctx.name, .{ .always_blocking = true }) + fs.cwd().openFile(ctx.name, .{ .intended_io_mode = .blocking }) else - fs.openSelfExe(.{ .always_blocking = true })) catch |err| switch (err) { + fs.openSelfExe(.{ .intended_io_mode = .blocking })) catch |err| switch (err) { error.FileNotFound => return error.MissingDebugInfo, else => return err, }; @@ -1333,7 +1339,7 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) { } fn loadOFile(self: *@This(), o_file_path: []const u8) !DW.DwarfInfo { - const o_file = try fs.cwd().openFile(o_file_path, .{ .always_blocking = true }); + const o_file = try fs.cwd().openFile(o_file_path, .{ .intended_io_mode = .blocking }); const mapped_mem = try mapWholeFile(o_file); const hdr = @ptrCast( diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 311bfa5faf..262aa4872d 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -1323,7 +1323,7 @@ pub const Dir = struct { var cleanup_dir = true; defer if (cleanup_dir) dir.close(); - // Likely valid use of MAX_PATH_BYTES, as dir_name_buf will only + // Valid use of MAX_PATH_BYTES because dir_name_buf will only // ever store a single path component that was returned from the // filesystem. var dir_name_buf: [MAX_PATH_BYTES]u8 = undefined; @@ -1785,14 +1785,14 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File { if (builtin.os.tag == .windows) { const wide_slice = selfExePathW(); const prefixed_path_w = try os.windows.wToPrefixedFileW(wide_slice); - return cwd().openFileW(prefix_path_w.span(), flags); + return cwd().openFileW(prefixed_path_w.span(), flags); } // Use of MAX_PATH_BYTES here is valid as the resulting path is immediately // opened with no modification. var buf: [MAX_PATH_BYTES]u8 = undefined; const self_exe_path = try selfExePath(&buf); buf[self_exe_path.len] = 0; - return openFileAbsoluteZ(self_exe_path[0..self_exe_path.len :0].ptr, flags); + return openFileAbsoluteZ(buf[0..self_exe_path.len :0].ptr, flags); } pub const SelfExePathError = os.ReadLinkError || os.SysCtlError; diff --git a/lib/std/process.zig b/lib/std/process.zig index 85d3ae2ecb..6ffb7bc1bc 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -31,7 +31,7 @@ pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { while (true) { if (os.getcwd(current_buf)) |slice| { return mem.dupe(allocator, u8, slice); - } else |err| switch(err) { + } else |err| switch (err) { error.NameTooLong => { // The path is too long to fit in stack_buf. Allocate geometrically // increasing buffers until we find one that works @@ -40,7 +40,7 @@ pub fn getCwdAlloc(allocator: *Allocator) ![]u8 { current_buf = try allocator.alloc(u8, new_capacity); heap_buf = current_buf; }, - else => return err, + else => |e| return e, } } }