Commit 35e1755c99

Sean <69403556+SeanTUT@users.noreply.github.com>
2025-10-28 10:17:09
Fix stale reference bug in `std.zig.system.resolveTargetQuery` (#25713)
Co-authored-by: Alex Rønne Petersen <alex@alexrp.com>
1 parent dba1bf9
Changed files (3)
lib
std
Target
zig
system
darwin
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 {
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;
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 |_| {