From 35e1755c996eb1cff77ff262d93302e5d6f16f9a Mon Sep 17 00:00:00 2001 From: Sean <69403556+SeanTUT@users.noreply.github.com> Date: Tue, 28 Oct 2025 05:17:09 -0400 Subject: [PATCH] Fix stale reference bug in `std.zig.system.resolveTargetQuery` (#25713) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Alex Rønne Petersen --- lib/std/Target/Query.zig | 8 ++++++- lib/std/zig/system.zig | 34 ++++++++++------------------- lib/std/zig/system/darwin/macos.zig | 2 ++ 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/lib/std/Target/Query.zig b/lib/std/Target/Query.zig index aa6671b65f..90c127d800 100644 --- a/lib/std/Target/Query.zig +++ b/lib/std/Target/Query.zig @@ -339,6 +339,7 @@ pub fn parseCpuArch(args: ParseOptions) ?Target.Cpu.Arch { /// Similar to `SemanticVersion.parse`, but with following changes: /// * Leading zeroes are allowed. /// * Supports only 2 or 3 version components (major, minor, [patch]). If 3-rd component is omitted, it will be 0. +/// * Prerelease and build components are disallowed. pub fn parseVersion(ver: []const u8) error{ InvalidVersion, Overflow }!SemanticVersion { const parseVersionComponentFn = (struct { fn parseVersionComponentInner(component: []const u8) error{ InvalidVersion, Overflow }!usize { @@ -348,11 +349,14 @@ pub fn parseVersion(ver: []const u8) error{ InvalidVersion, Overflow }!SemanticV }; } }).parseVersionComponentInner; + var version_components = mem.splitScalar(u8, ver, '.'); + const major = version_components.first(); const minor = version_components.next() orelse return error.InvalidVersion; const patch = version_components.next() orelse "0"; if (version_components.next() != null) return error.InvalidVersion; + return .{ .major = try parseVersionComponentFn(major), .minor = try parseVersionComponentFn(minor), @@ -361,10 +365,12 @@ pub fn parseVersion(ver: []const u8) error{ InvalidVersion, Overflow }!SemanticV } test parseVersion { - try std.testing.expectError(error.InvalidVersion, parseVersion("1")); try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 0 }, try parseVersion("1.2")); try std.testing.expectEqual(SemanticVersion{ .major = 1, .minor = 2, .patch = 3 }, try parseVersion("1.2.3")); + + try std.testing.expectError(error.InvalidVersion, parseVersion("1")); try std.testing.expectError(error.InvalidVersion, parseVersion("1.2.3.4")); + try std.testing.expectError(error.InvalidVersion, parseVersion("1.2.3-dev")); } pub fn isNativeCpu(self: Query) bool { diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 0324e7670f..bc44bbdd46 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -215,25 +215,17 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target { var os = query_os_tag.defaultVersionRange(query_cpu_arch, query_abi); if (query.os_tag == null) { switch (builtin.target.os.tag) { - .linux => { + .linux, .illumos => { const uts = posix.uname(); const release = mem.sliceTo(&uts.release, 0); // The release field sometimes has a weird format, // `Version.parse` will attempt to find some meaningful interpretation. if (std.SemanticVersion.parse(release)) |ver| { - os.version_range.linux.range.min = ver; - os.version_range.linux.range.max = ver; - } else |err| switch (err) { - error.Overflow => {}, - error.InvalidVersion => {}, - } - }, - .illumos => { - const uts = posix.uname(); - const release = mem.sliceTo(&uts.release, 0); - if (std.SemanticVersion.parse(release)) |ver| { - os.version_range.semver.min = ver; - os.version_range.semver.max = ver; + var stripped = ver; + stripped.pre = null; + stripped.build = null; + os.version_range.linux.range.min = stripped; + os.version_range.linux.range.max = stripped; } else |err| switch (err) { error.Overflow => {}, error.InvalidVersion => {}, @@ -307,10 +299,9 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target { posix.CTL.KERN, posix.KERN.OSRELEASE, }; - var buf: [64]u8 = undefined; + var buf: [64:0]u8 = undefined; // consider that sysctl result includes null-termination - // reserve 1 byte to ensure we never overflow when appending ".0" - var len: usize = buf.len - 1; + var len: usize = buf.len + 1; posix.sysctl(&mib, &buf, &len, null, 0) catch |err| switch (err) { error.NameTooLong => unreachable, // constant, known good value @@ -320,12 +311,9 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target { error.Unexpected => return error.OSVersionDetectionFail, }; - // append ".0" to satisfy semver - buf[len - 1] = '.'; - buf[len] = '0'; - len += 1; - - if (std.SemanticVersion.parse(buf[0..len])) |ver| { + if (Target.Query.parseVersion(buf[0..len :0])) |ver| { + assert(ver.build == null); + assert(ver.pre == null); os.version_range.semver.min = ver; os.version_range.semver.max = ver; } else |_| { diff --git a/lib/std/zig/system/darwin/macos.zig b/lib/std/zig/system/darwin/macos.zig index eecb857465..9bb4e34e3b 100644 --- a/lib/std/zig/system/darwin/macos.zig +++ b/lib/std/zig/system/darwin/macos.zig @@ -58,6 +58,8 @@ pub fn detect(target_os: *Target.Os) !void { if (parseSystemVersion(bytes)) |ver| { // never return non-canonical `10.(16+)` if (!(ver.major == 10 and ver.minor >= 16)) { + assert(ver.pre == null); + assert(ver.build == null); target_os.version_range.semver.min = ver; target_os.version_range.semver.max = ver; return;