Fix stale reference bug in std.zig.system.resolveTargetQuery (#25713)

Co-authored-by: Alex Rønne Petersen <alex@alexrp.com>
This commit is contained in:
Sean 2025-10-28 05:17:09 -04:00 committed by GitHub
parent dba1bf9353
commit 35e1755c99
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 20 additions and 24 deletions

View File

@ -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 {

View File

@ -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 |_| {

View File

@ -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;