Commit 22334f5730

Andrew Kelley <andrew@ziglang.org>
2025-10-16 20:52:52
std: make IPv6 address parsing system-independent
before, the max length of the host name depended on the target.
1 parent 90fdd21
Changed files (4)
lib/std/Io/net.zig
@@ -447,7 +447,9 @@ pub const Ip6Address = struct {
     pub const Unresolved = struct {
         /// Big endian
         bytes: [16]u8,
-        interface_name: ?Interface.Name,
+        /// Has not been checked to be a valid native interface name.
+        /// Externally managed memory.
+        interface_name: ?[]const u8,
 
         pub const Parsed = union(enum) {
             success: Unresolved,
@@ -536,7 +538,6 @@ pub const Ip6Address = struct {
                         parts_i += 1;
                         text_i += 1;
                         const name = text[text_i..];
-                        if (name.len > Interface.Name.max_len) return .{ .interface_name_oversized = text_i };
                         if (name.len == 0) return .incomplete;
                         interface_name_text = name;
                         text_i = @intCast(text.len);
@@ -563,7 +564,7 @@ pub const Ip6Address = struct {
 
                     return .{ .success = .{
                         .bytes = @bitCast(parts),
-                        .interface_name = if (interface_name_text) |t| .fromSliceUnchecked(t) else null,
+                        .interface_name = interface_name_text,
                     } };
                 },
             }
@@ -646,7 +647,7 @@ pub const Ip6Address = struct {
                     }
                 }
             }
-            if (u.interface_name) |n| try w.print("%{s}", .{n.toSlice()});
+            if (u.interface_name) |n| try w.print("%{s}", .{n});
         }
     };
 
@@ -678,6 +679,8 @@ pub const Ip6Address = struct {
         /// If this is returned, more detailed diagnostics can be obtained by
         /// calling the `Parsed.init` function.
         ParseFailed,
+        /// The interface name is longer than the host operating system supports.
+        NameTooLong,
     } || Interface.Name.ResolveError;
 
     /// This function requires an `Io` parameter because it must query the operating
@@ -689,7 +692,11 @@ pub const Ip6Address = struct {
             .success => |p| return .{
                 .bytes = p.bytes,
                 .port = port,
-                .interface = if (p.interface_name) |n| try n.resolve(io) else .none,
+                .interface = i: {
+                    const text = p.interface_name orelse break :i .none;
+                    const name: Interface.Name = try .fromSlice(text);
+                    break :i try name.resolve(io);
+                },
             },
             else => return error.ParseFailed,
         };
@@ -946,7 +953,7 @@ pub const Interface = struct {
     pub const Name = struct {
         bytes: [max_len:0]u8,
 
-        pub const max_len = std.posix.IFNAMESIZE - 1;
+        pub const max_len = if (@TypeOf(std.posix.IFNAMESIZE) == void) 0 else std.posix.IFNAMESIZE - 1;
 
         pub fn toSlice(n: *const Name) []const u8 {
             return std.mem.sliceTo(&n.bytes, 0);
lib/std/c.zig
@@ -6855,7 +6855,7 @@ pub const IFNAMESIZE = switch (native_os) {
     // https://github.com/SerenityOS/serenity/blob/9882848e0bf783dfc8e8a6d887a848d70d9c58f4/Kernel/API/POSIX/net/if.h#L50
     .openbsd, .dragonfly, .netbsd, .freebsd, .macos, .ios, .tvos, .watchos, .visionos, .serenity => 16,
     .illumos => 32,
-    else => void,
+    else => {},
 };
 
 pub const stack_t = switch (native_os) {
lib/std/os.zig
@@ -201,10 +201,19 @@ pub fn getFdPath(fd: std.posix.fd_t, out_buffer: *[max_path_bytes]u8) std.posix.
     }
 }
 
+pub const FstatatError = error{
+    SystemResources,
+    AccessDenied,
+    NameTooLong,
+    FileNotFound,
+    InvalidUtf8,
+    Unexpected,
+};
+
 /// WASI-only. Same as `fstatat` but targeting WASI.
 /// `pathname` should be encoded as valid UTF-8.
 /// See also `fstatat`.
-pub fn fstatat_wasi(dirfd: posix.fd_t, pathname: []const u8, flags: wasi.lookupflags_t) posix.FStatAtError!wasi.filestat_t {
+pub fn fstatat_wasi(dirfd: posix.fd_t, pathname: []const u8, flags: wasi.lookupflags_t) FstatatError!wasi.filestat_t {
     var stat: wasi.filestat_t = undefined;
     switch (wasi.path_filestat_get(dirfd, flags, pathname.ptr, pathname.len, &stat)) {
         .SUCCESS => return stat,
lib/std/posix.zig
@@ -4945,6 +4945,7 @@ pub const AccessError = error{
     /// Windows-only; file paths provided by the user must be valid WTF-8.
     /// https://wtf-8.codeberg.page/
     InvalidWtf8,
+    Canceled,
 } || UnexpectedError;
 
 /// check user's permissions for a file