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 c041293e2f8f7ad1d3233aa71f7b52067223e63d..03a12e4e72e8e9618c5041d54595eb0f1633fea0 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 bf438e2776726631787f7c0f52a7ded760638e36..90f16b1ec9d03a62e85005bc24c081caa3278774 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 0000000000000000000000000000000000000000..a38171c6d6e5ca4e8e43ee702932581343df8364 --- /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 736dcf824f50a4b89ab63d15079702725828f828..d9e2772795c98eb7f9ef4c1be1d2d2d7bcdf1642 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 e5ac02f85e1001634e9216f5c4083d471de64cd6..e102febe2dcb702f7df29a6a0b95b8f36d2d096f 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 c0ba0bc22e5ea8985089664066b5c762d745b13d..24e0e961e7e0ee5aa262aab2f108ce9d906e21d8 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 b76fd33a2d558ce9ab8b13dad9411008cf85146d..9b507e978a1d53665800f9c89830690943c26270 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(.{ -- 2.54.0