From 60e2ea0bfbb8a8ae2df31a8e45ef8c416a9ff77e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Jan 2026 00:36:11 -0800 Subject: [PATCH] windows: use ProcessPrng from bcryptprimitives.dll rather than SystemFunction036 from advapi32. This has the advantage that the code is loaded preemptively, preventing random numbers from failing when they are needed for the first time on a system under heavy load. --- lib/std/os/windows.zig | 28 +-------------------- lib/std/os/windows/advapi32.zig | 5 ---- lib/std/os/windows/bcryptprimitives.zig | 4 +++ lib/std/posix.zig | 2 +- test/standalone/issue_5825/build.zig | 1 - test/standalone/test_obj_link_run/build.zig | 1 - test/standalone/windows_argv/build.zig | 1 - 7 files changed, 6 insertions(+), 36 deletions(-) create mode 100644 lib/std/os/windows/bcryptprimitives.zig diff --git a/lib/std/os/windows.zig b/lib/std/os/windows.zig index c041293e2f..03a12e4e72 100644 --- a/lib/std/os/windows.zig +++ b/lib/std/os/windows.zig @@ -22,6 +22,7 @@ test { } pub const advapi32 = @import("windows/advapi32.zig"); +pub const bcryptprimitives = @import("windows/bcryptprimitives.zig"); pub const kernel32 = @import("windows/kernel32.zig"); pub const ntdll = @import("windows/ntdll.zig"); pub const ws2_32 = @import("windows/ws2_32.zig"); @@ -2644,33 +2645,6 @@ pub fn SetHandleInformation(h: HANDLE, mask: DWORD, flags: DWORD) SetHandleInfor } } -pub const RtlGenRandomError = error{ - /// `RtlGenRandom` has been known to fail in situations where the system is under heavy load. - /// Unfortunately, it does not call `SetLastError`, so it is not possible to get more specific - /// error information; it could actually be due to an out-of-memory condition, for example. - SystemResources, -}; - -/// Call RtlGenRandom() instead of CryptGetRandom() on Windows -/// https://github.com/rust-lang-nursery/rand/issues/111 -/// https://bugzilla.mozilla.org/show_bug.cgi?id=504270 -pub fn RtlGenRandom(output: []u8) RtlGenRandomError!void { - var total_read: usize = 0; - var buff: []u8 = output[0..]; - const max_read_size: ULONG = maxInt(ULONG); - - while (total_read < output.len) { - const to_read: ULONG = @min(buff.len, max_read_size); - - if (advapi32.RtlGenRandom(buff.ptr, to_read) == 0) { - return error.SystemResources; - } - - total_read += to_read; - buff = buff[to_read..]; - } -} - pub const WaitForSingleObjectError = error{ WaitAbandoned, WaitTimeOut, diff --git a/lib/std/os/windows/advapi32.zig b/lib/std/os/windows/advapi32.zig index bf438e2776..90f16b1ec9 100644 --- a/lib/std/os/windows/advapi32.zig +++ b/lib/std/os/windows/advapi32.zig @@ -28,11 +28,6 @@ pub extern "advapi32" fn RegQueryValueExW( pub extern "advapi32" fn RegCloseKey(hKey: HKEY) callconv(.winapi) LSTATUS; -// RtlGenRandom is known as SystemFunction036 under advapi32 -// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */ -pub extern "advapi32" fn SystemFunction036(output: [*]u8, length: ULONG) callconv(.winapi) BOOL; -pub const RtlGenRandom = SystemFunction036; - pub const RRF = struct { pub const RT_ANY: DWORD = 0x0000ffff; diff --git a/lib/std/os/windows/bcryptprimitives.zig b/lib/std/os/windows/bcryptprimitives.zig new file mode 100644 index 0000000000..a38171c6d6 --- /dev/null +++ b/lib/std/os/windows/bcryptprimitives.zig @@ -0,0 +1,4 @@ +const std = @import("../../std.zig"); +const windows = std.os.windows; + +pub extern "bcryptprimitives" fn ProcessPrng(pbData: [*]u8, cbData: usize) callconv(.winapi) c_int; diff --git a/lib/std/posix.zig b/lib/std/posix.zig index 736dcf824f..d9e2772795 100644 --- a/lib/std/posix.zig +++ b/lib/std/posix.zig @@ -370,7 +370,7 @@ pub const GetRandomError = OpenError; /// library implementation. pub fn getrandom(buffer: []u8) GetRandomError!void { if (native_os == .windows) { - return windows.RtlGenRandom(buffer); + return assert(windows.bcryptprimitives.ProcessPrng(buffer.ptr, buffer.len) == 1); } if (builtin.link_libc and @TypeOf(system.arc4random_buf) != void) { system.arc4random_buf(buffer.ptr, buffer.len); diff --git a/test/standalone/issue_5825/build.zig b/test/standalone/issue_5825/build.zig index e5ac02f85e..e102febe2d 100644 --- a/test/standalone/issue_5825/build.zig +++ b/test/standalone/issue_5825/build.zig @@ -32,7 +32,6 @@ pub fn build(b: *std.Build) void { }), }); exe.subsystem = .console; - exe.root_module.linkSystemLibrary("advapi32", .{}); // for RtlGenRandom exe.root_module.linkSystemLibrary("kernel32", .{}); exe.root_module.linkSystemLibrary("ntdll", .{}); exe.root_module.addObject(obj); diff --git a/test/standalone/test_obj_link_run/build.zig b/test/standalone/test_obj_link_run/build.zig index c0ba0bc22e..24e0e961e7 100644 --- a/test/standalone/test_obj_link_run/build.zig +++ b/test/standalone/test_obj_link_run/build.zig @@ -12,7 +12,6 @@ pub fn build(b: *std.Build) void { test_obj.root_module.linkSystemLibrary("ntdll", .{}); test_obj.root_module.linkSystemLibrary("kernel32", .{}); test_obj.root_module.linkSystemLibrary("ws2_32", .{}); - test_obj.root_module.linkSystemLibrary("advapi32", .{}); // for RtlGenRandom } const test_exe_mod = b.createModule(.{ diff --git a/test/standalone/windows_argv/build.zig b/test/standalone/windows_argv/build.zig index b76fd33a2d..9b507e978a 100644 --- a/test/standalone/windows_argv/build.zig +++ b/test/standalone/windows_argv/build.zig @@ -86,7 +86,6 @@ pub fn build(b: *std.Build) !void { .optimize = optimize, }), }); - lib_msvc.root_module.linkSystemLibrary("advapi32", .{}); // for RtlGenRandom const verify_msvc = b.addExecutable(.{ .name = "verify-msvc", .root_module = b.createModule(.{