mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-27 19:09:47 +03:00
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:
committed by
Andrew Kelley
parent
090ae3042e
commit
5d71e30518
+11
-33
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user