std: remove another kernel32 dependency

We can directly access this path string from the PEB (albeit with some
weirdness around addressing) and that ends up making the downstream code
simpler and more efficient. (Almost like the kernel32 API isn't very
good!)
This commit is contained in:
Matthew Lugg
2026-03-13 01:06:47 +00:00
committed by Andrew Kelley
parent 090ae3042e
commit 5d71e30518
3 changed files with 61 additions and 42 deletions
+11 -33
View File
@@ -16602,43 +16602,21 @@ const WindowsCommandLineCache = struct {
return self.script_cmd_line.?;
}
fn cmdExePath(self: *WindowsCommandLineCache) ![:0]u16 {
fn cmdExePath(self: *WindowsCommandLineCache) Allocator.Error![:0]u16 {
if (self.cmd_exe_path == null) {
self.cmd_exe_path = try windowsCmdExePath(self.allocator);
// Remove trailing slash from system directory path; we'll re-add it below
const system_dir = std.mem.trimEnd(u16, windows.getSystemDirectoryWtf16Le(), &.{ '/', '\\' });
const suffix = std.unicode.utf8ToUtf16LeStringLiteral("\\cmd.exe");
const buf = try self.allocator.allocSentinel(u16, system_dir.len + suffix.len, 0);
errdefer comptime unreachable;
@memcpy(buf[0..system_dir.len], system_dir);
@memcpy(buf[system_dir.len..], suffix);
self.cmd_exe_path = buf;
}
return self.cmd_exe_path.?;
}
};
/// Returns the absolute path of `cmd.exe` within the Windows system directory.
/// The caller owns the returned slice.
fn windowsCmdExePath(allocator: Allocator) error{ OutOfMemory, Unexpected }![:0]u16 {
var buf = try std.ArrayList(u16).initCapacity(allocator, 128);
errdefer buf.deinit(allocator);
while (true) {
const unused_slice = buf.unusedCapacitySlice();
// TODO: Get the system directory from PEB.ReadOnlyStaticServerData
const len = windows.kernel32.GetSystemDirectoryW(@ptrCast(unused_slice), @intCast(unused_slice.len));
if (len == 0) {
switch (windows.GetLastError()) {
else => |err| return windows.unexpectedError(err),
}
}
if (len > unused_slice.len) {
try buf.ensureUnusedCapacity(allocator, len);
} else {
buf.items.len = len;
break;
}
}
switch (buf.items[buf.items.len - 1]) {
'/', '\\' => {},
else => try buf.append(allocator, Dir.path.sep),
}
try buf.appendSlice(allocator, std.unicode.utf8ToUtf16LeStringLiteral("cmd.exe"));
return try buf.toOwnedSliceSentinel(allocator, 0);
}
const ArgvToScriptCommandLineError = error{
OutOfMemory,
InvalidWtf8,
@@ -16659,8 +16637,8 @@ const ArgvToScriptCommandLineError = error{
///
/// The return of this function will look like
/// `cmd.exe /d /e:ON /v:OFF /c "<escaped command line>"`
/// and should be used as the `lpCommandLine` of `CreateProcessW`, while the
/// return of `windowsCmdExePath` should be used as `lpApplicationName`.
/// and should be used as the `lpCommandLine` of `CreateProcessW`, while the return of
/// `WindowsCommandLineCache.cmdExePath` should be used as `lpApplicationName`.
///
/// Should only be used when spawning `.bat`/`.cmd` scripts, see `argvToCommandLineWindows` otherwise.
/// The `.bat`/`.cmd` file must be known to both have the `.bat`/`.cmd` extension and exist on the filesystem.
+50 -1
View File
@@ -4408,13 +4408,14 @@ pub const PEB = extern struct {
// note: there is padding here on 64 bit
TlsBitmap: *RTL_BITMAP,
TlsBitmapBits: [2]ULONG,
/// Our base address of the memory region shared with the CSR server.
ReadOnlySharedMemoryBase: PVOID,
// Versions: 1703+
SharedData: PVOID,
// Versions: all
ReadOnlyStaticServerData: *PVOID,
ReadOnlyStaticServerData: *UnknownStaticServerDataIndirection,
AnsiCodePageData: PVOID,
OemCodePageData: PVOID,
UnicodeCaseTableData: PVOID,
@@ -4501,6 +4502,7 @@ pub const PEB = extern struct {
TracingFlags: ULONG,
// Fields appended in 6.2 (Windows 8):
/// Base address in the CSRSS address space of the memory region shared with the CSR server.
CsrServerReadOnlySharedMemoryBase: ULONGLONG,
// Fields appended in 1511:
@@ -4511,6 +4513,14 @@ pub const PEB = extern struct {
// Fields appended in 1709:
TelemetryCoverageHeader: PVOID,
CloudFileFlags: ULONG,
/// Details of this structure are unknown, but the existence of the field at offset 8 is known
/// from experimentation and from reverse-engineering kernelbase.dll.
const UnknownStaticServerDataIndirection = extern struct {
unknown: u64,
/// In the CSRSS address space.
base_static_server_data_addr: u64,
};
};
/// The `PEB_LDR_DATA` structure is the main record of what modules are loaded in a process.
@@ -5139,3 +5149,42 @@ pub fn wtf8ToWtf16Le(wtf16le: []u16, wtf8: []const u8) error{ BadPathName, NameT
error.InvalidWtf8 => return error.BadPathName,
};
}
/// Returns the path to the system directory, typically "C:\\WINDOWS\\System32".
///
/// Equivalent to `GetSystemDirectoryW` in kernel32.
pub fn getSystemDirectoryWtf16Le() [:0]const u16 {
const ssd: *const BASE_STATIC_SERVER_DATA = @ptrCast(@alignCast(relocateCsrssAddress(
peb().ReadOnlyStaticServerData.base_static_server_data_addr,
)));
return ssd.windows_system_directory.relocate().sliceZ();
}
// https://github.com/reactos/reactos/blob/4b75ec5508d47b726d1210e24f5a849dae4e3bda/sdk/include/reactos/subsys/win/base.h#L119
const BASE_STATIC_SERVER_DATA = extern struct {
windows_directory: ForeignString,
windows_system_directory: ForeignString,
named_object_directory: ForeignString,
/// This matches the 64-bit version of `UNICODE_STRING`---even on 32-bit targets, this string is
/// from 64-bit code (since it comes from CSRSS which is running outside of WOW64).
const ForeignString = extern struct {
length: u16,
maximum_length: u16,
/// Address in the CSRSS address space. To convert this to a valid pointer in *our* address
/// space, see `relocateCsrssAddress` (or the `ForeignString.relocate` wrapper function).
buffer_address: u64,
fn relocate(str: ForeignString) UNICODE_STRING {
return .{
.Length = str.length,
.MaximumLength = str.maximum_length,
.Buffer = @ptrCast(@alignCast(@constCast(relocateCsrssAddress(str.buffer_address)))),
};
}
};
};
/// Takes an address in the CSRSS address space's mapped view of the shared memory region, and
/// returns the corresponding address in *our* mapped view of the shared memory region.
fn relocateCsrssAddress(addr: u64) *const anyopaque {
const base: [*]const u8 = @ptrCast(peb().ReadOnlySharedMemoryBase);
const offset: usize = @intCast(addr - peb().CsrServerReadOnlySharedMemoryBase);
return base + offset;
}
-8
View File
@@ -13,17 +13,9 @@ const THREAD_START_ROUTINE = windows.THREAD_START_ROUTINE;
const SECURITY_ATTRIBUTES = windows.SECURITY_ATTRIBUTES;
const SIZE_T = windows.SIZE_T;
const STARTUPINFOW = windows.STARTUPINFOW;
const UINT = windows.UINT;
const va_list = windows.va_list;
const Win32Error = windows.Win32Error;
// I/O - Filesystem
pub extern "kernel32" fn GetSystemDirectoryW(
lpBuffer: LPWSTR,
uSize: UINT,
) callconv(.winapi) UINT;
// Process Management
pub extern "kernel32" fn CreateProcessW(