Compare commits

...

2 Commits

Author SHA1 Message Date
Claude Bot
e1f3200fc4 fix: validate u32 range before casting RtlNtStatusToDosError result to u16
Replace @truncate with an explicit range check (raw > maxInt(u16)) before
@intCast to avoid silently wrapping out-of-range values from the u32
return of RtlNtStatusToDosError.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-01 05:26:48 +00:00
Claude Bot
e7e719cfcf fix(windows): prevent panic from unmapped Win32 error codes in enum conversion
RtlNtStatusToDosError returns a u32 Win32 error code, but was declared
as returning Win32Error enum(u16) directly. When the API returns an
error code not in Bun's Win32Error subset, Zig panics with "invalid
enum value". Use std.meta.intToEnum for safe conversion, falling back
to MR_MID_NOT_FOUND for unmapped codes. Also hardens Win32Error.get()
and SystemErrno.init() against the same class of invalid enum panics.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-01 05:17:21 +00:00
2 changed files with 11 additions and 5 deletions

View File

@@ -968,7 +968,7 @@ pub const SystemErrno = enum(u16) {
if (@TypeOf(code) == u16 or (@TypeOf(code) == c_int and code > 0)) {
// Win32Error and WSA Error codes
if (code <= @intFromEnum(Win32Error.IO_REISSUE_AS_CACHED) or (code >= @intFromEnum(Win32Error.WSAEINTR) and code <= @intFromEnum(Win32Error.WSA_QOS_RESERVED_PETYPE))) {
return init(@as(Win32Error, @enumFromInt(code)));
return init(std.meta.intToEnum(Win32Error, code) catch return null);
} else {
// uv error codes
inline for (@typeInfo(SystemErrno).@"enum".fields) |field| {
@@ -988,7 +988,7 @@ pub const SystemErrno = enum(u16) {
}
if (comptime @TypeOf(code) == Win32Error or @TypeOf(code) == std.os.windows.Win32Error) {
return switch (@as(Win32Error, @enumFromInt(@intFromEnum(code)))) {
return switch (std.meta.intToEnum(Win32Error, @intFromEnum(code)) catch return null) {
Win32Error.NOACCESS => SystemErrno.EACCES,
Win32Error.WSAEACCES => SystemErrno.EACCES,
Win32Error.ELEVATION_REQUIRED => SystemErrno.EACCES,

View File

@@ -149,7 +149,7 @@ pub extern "kernel32" fn SetCurrentDirectoryW(
lpPathName: win32.LPCWSTR,
) callconv(.winapi) win32.BOOL;
pub const SetCurrentDirectory = SetCurrentDirectoryW;
pub extern "ntdll" fn RtlNtStatusToDosError(win32.NTSTATUS) callconv(.winapi) Win32Error;
pub extern "ntdll" fn RtlNtStatusToDosError(win32.NTSTATUS) callconv(.winapi) u32;
pub extern "advapi32" fn SaferiIsExecutableFileType(szFullPathname: win32.LPCWSTR, bFromShellExecute: win32.BOOLEAN) callconv(.winapi) win32.BOOL;
// This was originally copied from Zig's standard library
/// Codes are from https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/18d8fbe8-a967-4f1c-ae50-99ca8e491d2d
@@ -2952,7 +2952,8 @@ pub const Win32Error = enum(u16) {
pub const WSA_QOS_RESERVED_PETYPE: Win32Error = @enumFromInt(11031);
pub fn get() Win32Error {
return @enumFromInt(@intFromEnum(bun.windows.kernel32.GetLastError()));
const raw: u16 = @intFromEnum(bun.windows.kernel32.GetLastError());
return std.meta.intToEnum(Win32Error, raw) catch .MR_MID_NOT_FOUND;
}
pub fn int(this: Win32Error) u16 {
@@ -2971,7 +2972,12 @@ pub const Win32Error = enum(u16) {
}
pub fn fromNTStatus(status: win32.NTSTATUS) Win32Error {
return RtlNtStatusToDosError(status);
// RtlNtStatusToDosError returns a u32 Win32 error code that may not be
// in our Win32Error enum subset. Safely convert to avoid panic on
// invalid enum values.
const raw = RtlNtStatusToDosError(status);
if (raw > std.math.maxInt(u16)) return .MR_MID_NOT_FOUND;
return std.meta.intToEnum(Win32Error, @as(u16, @intCast(raw))) catch .MR_MID_NOT_FOUND;
}
};