authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-03-17 00:01:28+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2024-03-17 01:20:08+02:00
logec2465542cd7bfd58f7bf72552b6f332af2c03f9
tree79bd54aaf995afd85655d500e9172f6a7e392bd0
parent7628785983486c612bcadc9a14bd784b627a5d21

std: adjust DynLib API

The cross-platform functions now use an error set that contains all possible errors on every platform.

2 files changed, 63 insertions(+), 17 deletions(-)

lib/std/c.zig+1
...@@ -1881,6 +1881,7 @@ pub const FILE = opaque {};...@@ -1881,6 +1881,7 @@ pub const FILE = opaque {};
1881pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*anyopaque;1881pub extern "c" fn dlopen(path: [*:0]const u8, mode: c_int) ?*anyopaque;
1882pub extern "c" fn dlclose(handle: *anyopaque) c_int;1882pub extern "c" fn dlclose(handle: *anyopaque) c_int;
1883pub extern "c" fn dlsym(handle: ?*anyopaque, symbol: [*:0]const u8) ?*anyopaque;1883pub extern "c" fn dlsym(handle: ?*anyopaque, symbol: [*:0]const u8) ?*anyopaque;
1884pub extern "c" fn dlerror() ?[*:0]u8;
18841885
1885pub extern "c" fn sync() void;1886pub extern "c" fn sync() void;
1886pub extern "c" fn syncfs(fd: c_int) c_int;1887pub extern "c" fn syncfs(fd: c_int) c_int;
lib/std/dynamic_library.zig+62-17
...@@ -7,14 +7,41 @@ const elf = std.elf;...@@ -7,14 +7,41 @@ const elf = std.elf;
7const windows = std.os.windows;7const windows = std.os.windows;
8const system = std.os.system;8const system = std.os.system;
99
10pub const DynLib = switch (builtin.os.tag) {10/// Cross-platform dynamic library loading and symbol lookup.
11 .linux => if (!builtin.link_libc or builtin.abi == .musl and builtin.link_mode == .static)11/// Platform-specific functionality is available through the `inner` field.
12 ElfDynLib12pub const DynLib = struct {
13 else13 const InnerType = switch (builtin.os.tag) {
14 DlDynLib,14 .linux => if (!builtin.link_libc or builtin.abi == .musl and builtin.link_mode == .static)
15 .windows => WindowsDynLib,15 ElfDynLib
16 .macos, .tvos, .watchos, .ios, .freebsd, .netbsd, .openbsd, .dragonfly, .solaris, .illumos => DlDynLib,16 else
17 else => void,17 DlDynLib,
18 .windows => WindowsDynLib,
19 .macos, .tvos, .watchos, .ios, .freebsd, .netbsd, .openbsd, .dragonfly, .solaris, .illumos => DlDynLib,
20 else => @compileError("unsupported platform"),
21 };
22
23 inner: InnerType,
24
25 pub const Error = ElfDynLib.Error || DlDynLib.Error || WindowsDynLib.Error;
26
27 /// Trusts the file. Malicious file will be able to execute arbitrary code.
28 pub fn open(path: []const u8) Error!DynLib {
29 return .{ .inner = try InnerType.open(path) };
30 }
31
32 /// Trusts the file. Malicious file will be able to execute arbitrary code.
33 pub fn openZ(path_c: [*:0]const u8) Error!DynLib {
34 return .{ .inner = try InnerType.open(path_c) };
35 }
36
37 /// Trusts the file.
38 pub fn close(self: *DynLib) void {
39 return self.inner.close();
40 }
41
42 pub fn lookup(self: *DynLib, comptime T: type, name: [:0]const u8) ?T {
43 return self.inner.lookup(T, name);
44 }
18};45};
1946
20// The link_map structure is not completely specified beside the fields47// The link_map structure is not completely specified beside the fields
...@@ -59,12 +86,12 @@ pub fn get_DYNAMIC() ?[*]elf.Dyn {...@@ -59,12 +86,12 @@ pub fn get_DYNAMIC() ?[*]elf.Dyn {
59 return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak });86 return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak });
60}87}
6188
62pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {89pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
63 _ = phdrs;90 _ = phdrs;
64 const _DYNAMIC = get_DYNAMIC() orelse {91 const _DYNAMIC = get_DYNAMIC() orelse {
65 // No PT_DYNAMIC means this is either a statically-linked program or a92 // No PT_DYNAMIC means this is either a statically-linked program or a
66 // badly corrupted dynamically-linked one.93 // badly corrupted dynamically-linked one.
67 return LinkMap.Iterator{ .current = null };94 return .{ .current = null };
68 };95 };
6996
70 const link_map_ptr = init: {97 const link_map_ptr = init: {
...@@ -89,10 +116,10 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {...@@ -89,10 +116,10 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
89 else => {},116 else => {},
90 }117 }
91 }118 }
92 return LinkMap.Iterator{ .current = null };119 return .{ .current = null };
93 };120 };
94121
95 return LinkMap.Iterator{ .current = link_map_ptr };122 return .{ .current = link_map_ptr };
96}123}
97124
98pub const ElfDynLib = struct {125pub const ElfDynLib = struct {
...@@ -239,7 +266,7 @@ pub const ElfDynLib = struct {...@@ -239,7 +266,7 @@ pub const ElfDynLib = struct {
239 }266 }
240 }267 }
241268
242 return ElfDynLib{269 return .{
243 .memory = all_loaded_mem,270 .memory = all_loaded_mem,
244 .strings = maybe_strings orelse return error.ElfStringSectionNotFound,271 .strings = maybe_strings orelse return error.ElfStringSectionNotFound,
245 .syms = maybe_syms orelse return error.ElfSymSectionNotFound,272 .syms = maybe_syms orelse return error.ElfSymSectionNotFound,
...@@ -260,7 +287,7 @@ pub const ElfDynLib = struct {...@@ -260,7 +287,7 @@ pub const ElfDynLib = struct {
260 self.* = undefined;287 self.* = undefined;
261 }288 }
262289
263 pub fn lookup(self: *ElfDynLib, comptime T: type, name: [:0]const u8) ?T {290 pub fn lookup(self: *const ElfDynLib, comptime T: type, name: [:0]const u8) ?T {
264 if (self.lookupAddress("", name)) |symbol| {291 if (self.lookupAddress("", name)) |symbol| {
265 return @as(T, @ptrFromInt(symbol));292 return @as(T, @ptrFromInt(symbol));
266 } else {293 } else {
...@@ -268,6 +295,7 @@ pub const ElfDynLib = struct {...@@ -268,6 +295,7 @@ pub const ElfDynLib = struct {
268 }295 }
269 }296 }
270297
298 /// ElfDynLib specific
271 /// Returns the address of the symbol299 /// Returns the address of the symbol
272 pub fn lookupAddress(self: *const ElfDynLib, vername: []const u8, name: []const u8) ?usize {300 pub fn lookupAddress(self: *const ElfDynLib, vername: []const u8, name: []const u8) ?usize {
273 const maybe_versym = if (self.verdef == null) null else self.versym;301 const maybe_versym = if (self.verdef == null) null else self.versym;
...@@ -334,6 +362,8 @@ pub const WindowsDynLib = struct {...@@ -334,6 +362,8 @@ pub const WindowsDynLib = struct {
334 return openEx(path, .none);362 return openEx(path, .none);
335 }363 }
336364
365 /// WindowsDynLib specific
366 /// Opens dynamic library with specified library loading flags.
337 pub fn openEx(path: []const u8, flags: windows.LoadLibraryFlags) Error!WindowsDynLib {367 pub fn openEx(path: []const u8, flags: windows.LoadLibraryFlags) Error!WindowsDynLib {
338 const path_w = windows.sliceToPrefixedFileW(null, path) catch return error.InvalidPath;368 const path_w = windows.sliceToPrefixedFileW(null, path) catch return error.InvalidPath;
339 return openExW(path_w.span().ptr, flags);369 return openExW(path_w.span().ptr, flags);
...@@ -343,15 +373,20 @@ pub const WindowsDynLib = struct {...@@ -343,15 +373,20 @@ pub const WindowsDynLib = struct {
343 return openExZ(path_c, .none);373 return openExZ(path_c, .none);
344 }374 }
345375
376 /// WindowsDynLib specific
377 /// Opens dynamic library with specified library loading flags.
346 pub fn openExZ(path_c: [*:0]const u8, flags: windows.LoadLibraryFlags) Error!WindowsDynLib {378 pub fn openExZ(path_c: [*:0]const u8, flags: windows.LoadLibraryFlags) Error!WindowsDynLib {
347 const path_w = try windows.cStrToPrefixedFileW(null, path_c);379 const path_w = try windows.cStrToPrefixedFileW(null, path_c);
348 return openExW(path_w.span().ptr, flags);380 return openExW(path_w.span().ptr, flags);
349 }381 }
350382
383 /// WindowsDynLib specific
351 pub fn openW(path_w: [*:0]const u16) Error!WindowsDynLib {384 pub fn openW(path_w: [*:0]const u16) Error!WindowsDynLib {
352 return openExW(path_w, .none);385 return openExW(path_w, .none);
353 }386 }
354387
388 /// WindowsDynLib specific
389 /// Opens dynamic library with specified library loading flags.
355 pub fn openExW(path_w: [*:0]const u16, flags: windows.LoadLibraryFlags) Error!WindowsDynLib {390 pub fn openExW(path_w: [*:0]const u16, flags: windows.LoadLibraryFlags) Error!WindowsDynLib {
356 var offset: usize = 0;391 var offset: usize = 0;
357 if (path_w[0] == '\\' and path_w[1] == '?' and path_w[2] == '?' and path_w[3] == '\\') {392 if (path_w[0] == '\\' and path_w[1] == '?' and path_w[2] == '?' and path_w[3] == '\\') {
...@@ -359,7 +394,7 @@ pub const WindowsDynLib = struct {...@@ -359,7 +394,7 @@ pub const WindowsDynLib = struct {
359 offset = 4;394 offset = 4;
360 }395 }
361396
362 return WindowsDynLib{397 return .{
363 .dll = try windows.LoadLibraryExW(path_w + offset, flags),398 .dll = try windows.LoadLibraryExW(path_w + offset, flags),
364 };399 };
365 }400 }
...@@ -389,7 +424,7 @@ pub const DlDynLib = struct {...@@ -389,7 +424,7 @@ pub const DlDynLib = struct {
389 }424 }
390425
391 pub fn openZ(path_c: [*:0]const u8) Error!DlDynLib {426 pub fn openZ(path_c: [*:0]const u8) Error!DlDynLib {
392 return DlDynLib{427 return .{
393 .handle = system.dlopen(path_c, system.RTLD.LAZY) orelse {428 .handle = system.dlopen(path_c, system.RTLD.LAZY) orelse {
394 return error.FileNotFound;429 return error.FileNotFound;
395 },430 },
...@@ -397,7 +432,10 @@ pub const DlDynLib = struct {...@@ -397,7 +432,10 @@ pub const DlDynLib = struct {
397 }432 }
398433
399 pub fn close(self: *DlDynLib) void {434 pub fn close(self: *DlDynLib) void {
400 _ = system.dlclose(self.handle);435 switch (std.os.errno(system.dlclose(self.handle))) {
436 .SUCCESS => return,
437 else => unreachable,
438 }
401 self.* = undefined;439 self.* = undefined;
402 }440 }
403441
...@@ -410,6 +448,13 @@ pub const DlDynLib = struct {...@@ -410,6 +448,13 @@ pub const DlDynLib = struct {
410 return null;448 return null;
411 }449 }
412 }450 }
451
452 /// DlDynLib specific
453 /// Returns human readable string describing most recent error than occurred from `lookup`
454 /// or `null` if no error has occurred since initialization or when `getError` was last called.
455 pub fn getError() ?[:0]const u8 {
456 return mem.span(system.dlerror());
457 }
413};458};
414459
415test "dynamic_library" {460test "dynamic_library" {