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.
This commit is contained in:
Andrew Kelley 2026-01-05 00:36:11 -08:00
parent 36044a0e81
commit 60e2ea0bfb
7 changed files with 6 additions and 36 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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