authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-18 21:32:34-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:10-08:00
log21d0264c61ac29724b98187aa87d192f97b52425
tree4c6a174456c70245d4a5b98ea02c8fcf0512379b
parent8632a28ca95a5a491bde57fdc45d9a0ce3cf597e

std.dynamic_library: use a global static single threaded Io

See #30150

7 files changed, 41 insertions(+), 41 deletions(-)

lib/std/Build/Watch.zig+1-1
......@@ -684,7 +684,7 @@ const Os = switch (builtin.os.tag) {
684684 path.root_dir.handle.handle
685685 else
686686 posix.openat(path.root_dir.handle.handle, path.sub_path, dir_open_flags, 0) catch |err| {
687 fatal("failed to open directory {f}: {s}", .{ path, @errorName(err) });
687 fatal("failed to open directory {f}: {t}", .{ path, err });
688688 };
689689 // Empirically the dir has to stay open or else no events are triggered.
690690 errdefer if (!skip_open_dir) posix.close(dir_fd);
lib/std/Io/File/Reader.zig+3-1
......@@ -43,7 +43,9 @@ pub const Error = error{
4343 /// In WASI, this error occurs when the file descriptor does
4444 /// not hold the required rights to read from it.
4545 AccessDenied,
46 /// Unable to read file due to lock.
46 /// Unable to read file due to lock. Depending on the `Io` implementation,
47 /// reading from a locked file may return this error, or may ignore the
48 /// lock.
4749 LockViolation,
4850} || Io.Cancelable || Io.UnexpectedError;
4951
lib/std/Io/Writer.zig+3-3
......@@ -2838,7 +2838,7 @@ test "discarding sendFile" {
28382838 const file = try tmp_dir.dir.createFile(io, "input.txt", .{ .read = true });
28392839 defer file.close(io);
28402840 var r_buffer: [256]u8 = undefined;
2841 var file_writer: File.Writer = .init(file, &r_buffer);
2841 var file_writer: File.Writer = .init(file, io, &r_buffer);
28422842 try file_writer.interface.writeByte('h');
28432843 try file_writer.interface.flush();
28442844
......@@ -2860,7 +2860,7 @@ test "allocating sendFile" {
28602860 const file = try tmp_dir.dir.createFile(io, "input.txt", .{ .read = true });
28612861 defer file.close(io);
28622862 var r_buffer: [2]u8 = undefined;
2863 var file_writer: File.Writer = .init(file, &r_buffer);
2863 var file_writer: File.Writer = .init(file, io, &r_buffer);
28642864 try file_writer.interface.writeAll("abcd");
28652865 try file_writer.interface.flush();
28662866
......@@ -2884,7 +2884,7 @@ test sendFileReading {
28842884 const file = try tmp_dir.dir.createFile(io, "input.txt", .{ .read = true });
28852885 defer file.close(io);
28862886 var r_buffer: [2]u8 = undefined;
2887 var file_writer: File.Writer = .init(file, &r_buffer);
2887 var file_writer: File.Writer = .init(file, io, &r_buffer);
28882888 try file_writer.interface.writeAll("abcd");
28892889 try file_writer.interface.flush();
28902890
lib/std/debug.zig+2-8
......@@ -1610,14 +1610,8 @@ test "manage resources correctly" {
16101610 var discarding: Writer.Discarding = .init(&.{});
16111611 var di: SelfInfo = .init;
16121612 defer di.deinit(gpa);
1613 try printSourceAtAddress(
1614 gpa,
1615 io,
1616 &di,
1617 &discarding.writer,
1618 S.showMyTrace(),
1619 .no_color,
1620 );
1613 const t: Io.Terminal = .{ .writer = &discarding.writer, .mode = .no_color };
1614 try printSourceAtAddress(gpa, io, &di, t, S.showMyTrace());
16211615}
16221616
16231617/// This API helps you track where a value originated and where it was mutated,
lib/std/dynamic_library.zig+21-19
......@@ -55,11 +55,11 @@ pub const DynLib = struct {
5555// An iterator is provided in order to traverse the linked list in a idiomatic
5656// fashion.
5757const LinkMap = extern struct {
58 l_addr: usize,
59 l_name: [*:0]const u8,
60 l_ld: ?*elf.Dyn,
61 l_next: ?*LinkMap,
62 l_prev: ?*LinkMap,
58 addr: usize,
59 name: [*:0]const u8,
60 ld: ?*elf.Dyn,
61 next: ?*LinkMap,
62 prev: ?*LinkMap,
6363
6464 pub const Iterator = struct {
6565 current: ?*LinkMap,
......@@ -70,7 +70,7 @@ const LinkMap = extern struct {
7070
7171 pub fn next(self: *Iterator) ?*LinkMap {
7272 if (self.current) |it| {
73 self.current = it.l_next;
73 self.current = it.next;
7474 return it;
7575 }
7676 return null;
......@@ -79,10 +79,10 @@ const LinkMap = extern struct {
7979};
8080
8181const RDebug = extern struct {
82 r_version: i32,
83 r_map: ?*LinkMap,
84 r_brk: usize,
85 r_ldbase: usize,
82 version: i32,
83 map: ?*LinkMap,
84 brk: usize,
85 ldbase: usize,
8686};
8787
8888/// TODO fix comparisons of extern symbol pointers so we don't need this helper function.
......@@ -107,8 +107,8 @@ pub fn linkmap_iterator() error{InvalidExe}!LinkMap.Iterator {
107107 elf.DT_DEBUG => {
108108 const ptr = @as(?*RDebug, @ptrFromInt(_DYNAMIC[i].d_val));
109109 if (ptr) |r_debug| {
110 if (r_debug.r_version != 1) return error.InvalidExe;
111 break :init r_debug.r_map;
110 if (r_debug.version != 1) return error.InvalidExe;
111 break :init r_debug.map;
112112 }
113113 },
114114 elf.DT_PLTGOT => {
......@@ -142,6 +142,8 @@ const ElfDynLibError = error{
142142 Streaming,
143143} || posix.OpenError || posix.MMapError;
144144
145var static_single_threaded_io: Io.Threaded = .init_single_threaded;
146
145147pub const ElfDynLib = struct {
146148 strings: [*:0]u8,
147149 syms: [*]elf.Sym,
......@@ -157,7 +159,7 @@ pub const ElfDynLib = struct {
157159 dt_gnu_hash: *elf.gnu_hash.Header,
158160 };
159161
160 fn openPath(path: []const u8, io: Io) !Io.Dir {
162 fn openPath(io: Io, path: []const u8) !Io.Dir {
161163 if (path.len == 0) return error.NotDir;
162164 var parts = std.mem.tokenizeScalar(u8, path, '/');
163165 var parent = if (path[0] == '/') try Io.Dir.cwd().openDir(io, "/", .{}) else Io.Dir.cwd();
......@@ -172,7 +174,7 @@ pub const ElfDynLib = struct {
172174 fn resolveFromSearchPath(io: Io, search_path: []const u8, file_name: []const u8, delim: u8) ?posix.fd_t {
173175 var paths = std.mem.tokenizeScalar(u8, search_path, delim);
174176 while (paths.next()) |p| {
175 var dir = openPath(p) catch continue;
177 var dir = openPath(io, p) catch continue;
176178 defer dir.close(io);
177179 const fd = posix.openat(dir.handle, file_name, .{
178180 .ACCMODE = .RDONLY,
......@@ -221,7 +223,9 @@ pub const ElfDynLib = struct {
221223 }
222224
223225 /// Trusts the file. Malicious file will be able to execute arbitrary code.
224 pub fn open(io: Io, path: []const u8) Error!ElfDynLib {
226 pub fn open(path: []const u8) Error!ElfDynLib {
227 const io = static_single_threaded_io.ioBasic();
228
225229 const fd = try resolveFromName(io, path);
226230 defer posix.close(fd);
227231
......@@ -551,11 +555,9 @@ fn checkver(def_arg: *elf.Verdef, vsym_arg: elf.Versym, vername: []const u8, str
551555}
552556
553557test "ElfDynLib" {
554 if (native_os != .linux) {
555 return error.SkipZigTest;
556 }
557
558 if (native_os != .linux) return error.SkipZigTest;
558559 try testing.expectError(error.FileNotFound, ElfDynLib.open("invalid_so.so"));
560 try testing.expectError(error.FileNotFound, ElfDynLib.openZ("invalid_so.so"));
559561}
560562
561563/// Separated to avoid referencing `WindowsDynLib`, because its field types may not
lib/std/fs/test.zig+5-3
......@@ -1796,7 +1796,7 @@ test "read from locked file" {
17961796 const f = try ctx.dir.createFile(io, filename, .{ .read = true });
17971797 defer f.close(io);
17981798 var buffer: [1]u8 = undefined;
1799 _ = try f.read(&buffer);
1799 _ = try f.readPositional(io, &.{&buffer}, 0);
18001800 }
18011801 {
18021802 const f = try ctx.dir.createFile(io, filename, .{
......@@ -1806,11 +1806,13 @@ test "read from locked file" {
18061806 defer f.close(io);
18071807 const f2 = try ctx.dir.openFile(io, filename, .{});
18081808 defer f2.close(io);
1809 // On POSIX locks may be ignored, however on Windows they cause
1810 // LockViolation.
18091811 var buffer: [1]u8 = undefined;
18101812 if (builtin.os.tag == .windows) {
1811 try expectError(error.LockViolation, f2.read(&buffer));
1813 try expectError(error.LockViolation, f2.readPositional(io, &.{&buffer}, 0));
18121814 } else {
1813 try expectEqual(0, f2.read(&buffer));
1815 try expectEqual(0, f2.readPositional(io, &.{&buffer}, 0));
18141816 }
18151817 }
18161818 }
lib/std/posix.zig+6-6
......@@ -777,7 +777,7 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: O, mode: mode_t) O
777777 .NFILE => return error.SystemFdQuotaExceeded,
778778 .NODEV => return error.NoDevice,
779779 .NOENT => return error.FileNotFound,
780 .SRCH => return error.ProcessNotFound,
780 .SRCH => return error.FileNotFound,
781781 .NOMEM => return error.SystemResources,
782782 .NOSPC => return error.NoSpaceLeft,
783783 .NOTDIR => return error.NotDir,
......@@ -2759,16 +2759,16 @@ pub fn dl_iterate_phdr(
27592759
27602760 // Last return value from the callback function.
27612761 while (it.next()) |entry| {
2762 const phdrs: []elf.ElfN.Phdr = if (entry.l_addr != 0) phdrs: {
2763 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.l_addr);
2762 const phdrs: []elf.ElfN.Phdr = if (entry.addr != 0) phdrs: {
2763 const ehdr: *elf.ElfN.Ehdr = @ptrFromInt(entry.addr);
27642764 assert(mem.eql(u8, ehdr.ident[0..4], elf.MAGIC));
2765 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.l_addr + ehdr.phoff);
2765 const phdrs: [*]elf.ElfN.Phdr = @ptrFromInt(entry.addr + ehdr.phoff);
27662766 break :phdrs phdrs[0..ehdr.phnum];
27672767 } else getSelfPhdrs();
27682768
27692769 var info: dl_phdr_info = .{
2770 .addr = entry.l_addr,
2771 .name = entry.l_name,
2770 .addr = entry.addr,
2771 .name = entry.name,
27722772 .phdr = phdrs.ptr,
27732773 .phnum = @intCast(phdrs.len),
27742774 };