From f072b0c056768648eb56230036dc8c973116d066 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 29 Feb 2020 12:00:58 +0100 Subject: [PATCH 1/3] target: Implement OS version detection for Windows Closes #4581 --- lib/std/os/windows/bits.zig | 13 ++++++++++++ lib/std/os/windows/ntdll.zig | 10 ++++++++- lib/std/zig/system.zig | 40 +++++++++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 2 deletions(-) diff --git a/lib/std/os/windows/bits.zig b/lib/std/os/windows/bits.zig index 4e153d40e..761b50837 100644 --- a/lib/std/os/windows/bits.zig +++ b/lib/std/os/windows/bits.zig @@ -1321,3 +1321,16 @@ pub const PSAPI_WS_WATCH_INFORMATION_EX = extern struct { Flags: ULONG_PTR, }; pub const PPSAPI_WS_WATCH_INFORMATION_EX = *PSAPI_WS_WATCH_INFORMATION_EX; + +pub const OSVERSIONINFOW = extern struct { + dwOSVersionInfoSize: ULONG, + dwMajorVersion: ULONG, + dwMinorVersion: ULONG, + dwBuildNumber: ULONG, + dwPlatformId: ULONG, + szCSDVersion: [128]WCHAR, +}; +pub const POSVERSIONINFOW = *OSVERSIONINFOW; +pub const LPOSVERSIONINFOW = *OSVERSIONINFOW; +pub const RTL_OSVERSIONINFOW = OSVERSIONINFOW; +pub const PRTL_OSVERSIONINFOW = *RTL_OSVERSIONINFOW; diff --git a/lib/std/os/windows/ntdll.zig b/lib/std/os/windows/ntdll.zig index e98a2e6a8..49e60803b 100644 --- a/lib/std/os/windows/ntdll.zig +++ b/lib/std/os/windows/ntdll.zig @@ -1,6 +1,14 @@ usingnamespace @import("bits.zig"); -pub extern "NtDll" fn RtlCaptureStackBackTrace(FramesToSkip: DWORD, FramesToCapture: DWORD, BackTrace: **c_void, BackTraceHash: ?*DWORD) callconv(.Stdcall) WORD; +pub extern "NtDll" fn RtlGetVersion( + lpVersionInformation: PRTL_OSVERSIONINFOW, +) callconv(.Stdcall) NTSTATUS; +pub extern "NtDll" fn RtlCaptureStackBackTrace( + FramesToSkip: DWORD, + FramesToCapture: DWORD, + BackTrace: **c_void, + BackTraceHash: ?*DWORD, +) callconv(.Stdcall) WORD; pub extern "NtDll" fn NtQueryInformationFile( FileHandle: HANDLE, IoStatusBlock: *IO_STATUS_BLOCK, diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index aa8def32a..333a5c395 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -181,6 +181,7 @@ pub const NativeTargetInfo = struct { ProcessFdQuotaExceeded, SystemFdQuotaExceeded, DeviceBusy, + Unexpected, }; /// Given a `CrossTarget`, which specifies in detail which parts of the target should be detected @@ -221,7 +222,44 @@ pub const NativeTargetInfo = struct { } }, .windows => { - // TODO Detect native operating system version. + var version_info: std.os.windows.RTL_OSVERSIONINFOW = undefined; + version_info.dwOSVersionInfoSize = @sizeOf(@TypeOf(version_info)); + + const rc = std.os.windows.ntdll.RtlGetVersion(&version_info); + switch (rc) { + .SUCCESS => {}, + else => return std.os.windows.unexpectedStatus(rc), + } + + // Starting from the system infos build a NTDDI-like version + // constant whose format is: + // B0 B1 B2 B3 + // `---` `` ``--> Sub-version (Starting from Windows 10 onwards) + // \ `--> Service pack (Always zero in the constants defined) + // `--> OS version (Major & minor) + const os_ver: u16 = // + @intCast(u16, version_info.dwMajorVersion & 0xff) << 8 | + @intCast(u16, version_info.dwMinorVersion & 0xff); + const sp_ver: u8 = 0; + const sub_ver: u8 = if (os_ver >= 0xA000) subver: { + // There's no other way to obtain this info beside + // checking the build number against a known set of + // values + for ([_]u32{ + 10240, 10586, 14393, 15063, 16299, 17134, 17763, + 18362, 18363, + }) |build, i| { + if (version_info.dwBuildNumber < build) + break :subver @truncate(u8, i); + } + // Unknown subversion, the OS is too new... + break :subver 0; + } else 0; + + const version: u32 = @as(u32, os_ver) << 16 | @as(u32, sp_ver) << 8 | sub_ver; + + os.version_range.windows.max = @intToEnum(Target.Os.WindowsVersion, version); + os.version_range.windows.min = @intToEnum(Target.Os.WindowsVersion, version); }, .macosx => { // TODO Detect native operating system version. From 58222204353c052a62f3723f879dc16f2d608f8b Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 29 Feb 2020 14:19:13 +0100 Subject: [PATCH 2/3] Address review comments --- lib/std/zig/system.zig | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 333a5c395..b04fb1288 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -181,7 +181,6 @@ pub const NativeTargetInfo = struct { ProcessFdQuotaExceeded, SystemFdQuotaExceeded, DeviceBusy, - Unexpected, }; /// Given a `CrossTarget`, which specifies in detail which parts of the target should be detected @@ -225,10 +224,9 @@ pub const NativeTargetInfo = struct { var version_info: std.os.windows.RTL_OSVERSIONINFOW = undefined; version_info.dwOSVersionInfoSize = @sizeOf(@TypeOf(version_info)); - const rc = std.os.windows.ntdll.RtlGetVersion(&version_info); - switch (rc) { + switch (std.os.windows.ntdll.RtlGetVersion(&version_info)) { .SUCCESS => {}, - else => return std.os.windows.unexpectedStatus(rc), + else => unreachable, } // Starting from the system infos build a NTDDI-like version @@ -245,15 +243,16 @@ pub const NativeTargetInfo = struct { // There's no other way to obtain this info beside // checking the build number against a known set of // values - for ([_]u32{ + const known_build_numbers = [_]u32{ 10240, 10586, 14393, 15063, 16299, 17134, 17763, 18362, 18363, - }) |build, i| { + }; + for (known_build_numbers) |build, i| { if (version_info.dwBuildNumber < build) break :subver @truncate(u8, i); } // Unknown subversion, the OS is too new... - break :subver 0; + break :subver @truncate(u8, known_build_numbers.len); } else 0; const version: u32 = @as(u32, os_ver) << 16 | @as(u32, sp_ver) << 8 | sub_ver; From 278f0f8fa97610589dfb28c8fffedca7298e6715 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sat, 29 Feb 2020 18:31:03 +0100 Subject: [PATCH 3/3] Change how the build-id is checked Address review comment by @rocksnest --- lib/std/zig/system.zig | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index b04fb1288..e76d2eaca 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -239,7 +239,7 @@ pub const NativeTargetInfo = struct { @intCast(u16, version_info.dwMajorVersion & 0xff) << 8 | @intCast(u16, version_info.dwMinorVersion & 0xff); const sp_ver: u8 = 0; - const sub_ver: u8 = if (os_ver >= 0xA000) subver: { + const sub_ver: u8 = if (os_ver >= 0x0A00) subver: { // There's no other way to obtain this info beside // checking the build number against a known set of // values @@ -247,12 +247,12 @@ pub const NativeTargetInfo = struct { 10240, 10586, 14393, 15063, 16299, 17134, 17763, 18362, 18363, }; + var last_idx: usize = 0; for (known_build_numbers) |build, i| { - if (version_info.dwBuildNumber < build) - break :subver @truncate(u8, i); + if (version_info.dwBuildNumber >= build) + last_idx = i; } - // Unknown subversion, the OS is too new... - break :subver @truncate(u8, known_build_numbers.len); + break :subver @truncate(u8, last_idx); } else 0; const version: u32 = @as(u32, os_ver) << 16 | @as(u32, sp_ver) << 8 | sub_ver;