authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-03-16 15:44:02-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-03-16 15:44:02-07:00
log1b8d1b18c7ec1c8002046d8a7e131bf21ccf92ca
tree11a061057febc1bc32fe580eab2387ff50fb1961
parentdbb11915bd03992ff9b64cd7f373faa428f0cedf
parent67df3ded68a5fda9bdd7ae22d26199ca403409ec
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #19271 from The-King-of-Toasters/falling-metal-pipe

Windows: Replace CreatePipe with ntdll implementation

8 files changed, 244 insertions(+), 53 deletions(-)

lib/std/Thread.zig+1-1
...@@ -208,7 +208,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co...@@ -208,7 +208,7 @@ pub fn getName(self: Thread, buffer_ptr: *[max_name_len:0]u8) GetNameError!?[]co
208 )) {208 )) {
209 .SUCCESS => {209 .SUCCESS => {
210 const string = @as(*const os.windows.UNICODE_STRING, @ptrCast(&buf));210 const string = @as(*const os.windows.UNICODE_STRING, @ptrCast(&buf));
211 const len = std.unicode.wtf16LeToWtf8(buffer, string.Buffer[0 .. string.Length / 2]);211 const len = std.unicode.wtf16LeToWtf8(buffer, string.Buffer.?[0 .. string.Length / 2]);
212 return if (len > 0) buffer[0..len] else null;212 return if (len > 0) buffer[0..len] else null;
213 },213 },
214 .NOT_IMPLEMENTED => return error.Unsupported,214 .NOT_IMPLEMENTED => return error.Unsupported,
lib/std/child_process.zig+1-1
...@@ -1420,7 +1420,7 @@ fn windowsMakeAsyncPipe(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *cons...@@ -1420,7 +1420,7 @@ fn windowsMakeAsyncPipe(rd: *?windows.HANDLE, wr: *?windows.HANDLE, sattr: *cons
1420 const pipe_path = std.fmt.bufPrintZ(1420 const pipe_path = std.fmt.bufPrintZ(
1421 &tmp_buf,1421 &tmp_buf,
1422 "\\\\.\\pipe\\zig-childprocess-{d}-{d}",1422 "\\\\.\\pipe\\zig-childprocess-{d}-{d}",
1423 .{ windows.kernel32.GetCurrentProcessId(), pipe_name_counter.fetchAdd(1, .monotonic) },1423 .{ windows.GetCurrentProcessId(), pipe_name_counter.fetchAdd(1, .monotonic) },
1424 ) catch unreachable;1424 ) catch unreachable;
1425 const len = std.unicode.wtf8ToWtf16Le(&tmp_bufw, pipe_path) catch unreachable;1425 const len = std.unicode.wtf8ToWtf16Le(&tmp_bufw, pipe_path) catch unreachable;
1426 tmp_bufw[len] = 0;1426 tmp_bufw[len] = 0;
lib/std/debug.zig+1-1
...@@ -814,7 +814,7 @@ pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const w...@@ -814,7 +814,7 @@ pub noinline fn walkStackWindows(addresses: []usize, existing_context: ?*const w
814 return windows.ntdll.RtlCaptureStackBackTrace(0, addresses.len, @as(**anyopaque, @ptrCast(addresses.ptr)), null);814 return windows.ntdll.RtlCaptureStackBackTrace(0, addresses.len, @as(**anyopaque, @ptrCast(addresses.ptr)), null);
815 }815 }
816816
817 const tib = @as(*const windows.NT_TIB, @ptrCast(&windows.teb().Reserved1));817 const tib = &windows.teb().NtTib;
818818
819 var context: windows.CONTEXT = undefined;819 var context: windows.CONTEXT = undefined;
820 if (existing_context) |context_ptr| {820 if (existing_context) |context_ptr| {
lib/std/fs.zig+2-2
...@@ -493,7 +493,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {...@@ -493,7 +493,7 @@ pub fn openSelfExe(flags: File.OpenFlags) OpenSelfExeError!File {
493 // not the path that the symlink points to. However, because we are opening493 // not the path that the symlink points to. However, because we are opening
494 // the file, we can let the openFileW call follow the symlink for us.494 // the file, we can let the openFileW call follow the symlink for us.
495 const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName;495 const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName;
496 const image_path_name = image_path_unicode_string.Buffer[0 .. image_path_unicode_string.Length / 2 :0];496 const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
497 const prefixed_path_w = try os.windows.wToPrefixedFileW(null, image_path_name);497 const prefixed_path_w = try os.windows.wToPrefixedFileW(null, image_path_name);
498 return cwd().openFileW(prefixed_path_w.span(), flags);498 return cwd().openFileW(prefixed_path_w.span(), flags);
499 }499 }
...@@ -664,7 +664,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {...@@ -664,7 +664,7 @@ pub fn selfExePath(out_buffer: []u8) SelfExePathError![]u8 {
664 },664 },
665 .windows => {665 .windows => {
666 const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName;666 const image_path_unicode_string = &os.windows.peb().ProcessParameters.ImagePathName;
667 const image_path_name = image_path_unicode_string.Buffer[0 .. image_path_unicode_string.Length / 2 :0];667 const image_path_name = image_path_unicode_string.Buffer.?[0 .. image_path_unicode_string.Length / 2 :0];
668668
669 // If ImagePathName is a symlink, then it will contain the path of the669 // If ImagePathName is a symlink, then it will contain the path of the
670 // symlink, not the path that the symlink points to. We want the path670 // symlink, not the path that the symlink points to. We want the path
lib/std/os/windows.zig+220-46
...@@ -153,14 +153,149 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN...@@ -153,14 +153,149 @@ pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HAN
153 }153 }
154}154}
155155
156pub const CreatePipeError = error{Unexpected};156pub fn GetCurrentProcess() HANDLE {
157 const process_pseudo_handle: usize = @bitCast(@as(isize, -1));
158 return @ptrFromInt(process_pseudo_handle);
159}
160
161pub fn GetCurrentProcessId() DWORD {
162 return @truncate(@intFromPtr(teb().ClientId.UniqueProcess));
163}
164
165pub fn GetCurrentThread() HANDLE {
166 const thread_pseudo_handle: usize = @bitCast(@as(isize, -2));
167 return @ptrFromInt(thread_pseudo_handle);
168}
169
170pub fn GetCurrentThreadId() DWORD {
171 return @truncate(@intFromPtr(teb().ClientId.UniqueThread));
172}
173
174pub const CreatePipeError = error{ Unexpected, SystemResources };
157175
176var npfs: ?HANDLE = null;
177
178/// A Zig wrapper around `NtCreateNamedPipeFile` and `NtCreateFile` syscalls.
179/// It implements similar behavior to `CreatePipe` and is meant to serve
180/// as a direct substitute for that call.
158pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void {181pub fn CreatePipe(rd: *HANDLE, wr: *HANDLE, sattr: *const SECURITY_ATTRIBUTES) CreatePipeError!void {
159 if (kernel32.CreatePipe(rd, wr, sattr, 0) == 0) {182 // Up to NT 5.2 (Windows XP/Server 2003), `CreatePipe` would generate a pipe similar to:
160 switch (kernel32.GetLastError()) {183 //
161 else => |err| return unexpectedError(err),184 // \??\pipe\Win32Pipes.{pid}.{count}
185 //
186 // where `pid` is the process id and count is a incrementing counter.
187 // The implementation was changed after NT 6.0 (Vista) to open a handle to the Named Pipe File System
188 // and use that as the root directory for `NtCreateNamedPipeFile`.
189 // This object is visible under the NPFS but has no filename attached to it.
190 //
191 // This implementation replicates how `CreatePipe` works in modern Windows versions.
192 const opt_dev_handle = @atomicLoad(?HANDLE, &npfs, .seq_cst);
193 const dev_handle = opt_dev_handle orelse blk: {
194 const str = std.unicode.utf8ToUtf16LeStringLiteral("\\Device\\NamedPipe\\");
195 const len: u16 = @truncate(str.len * @sizeOf(u16));
196 const name = UNICODE_STRING{
197 .Length = len,
198 .MaximumLength = len,
199 .Buffer = @constCast(@ptrCast(str)),
200 };
201 const attrs = OBJECT_ATTRIBUTES{
202 .ObjectName = @constCast(&name),
203 .Length = @sizeOf(OBJECT_ATTRIBUTES),
204 .RootDirectory = null,
205 .Attributes = 0,
206 .SecurityDescriptor = null,
207 .SecurityQualityOfService = null,
208 };
209
210 var iosb: IO_STATUS_BLOCK = undefined;
211 var handle: HANDLE = undefined;
212 switch (ntdll.NtCreateFile(
213 &handle,
214 GENERIC_READ | SYNCHRONIZE,
215 @constCast(&attrs),
216 &iosb,
217 null,
218 0,
219 FILE_SHARE_READ | FILE_SHARE_WRITE,
220 FILE_OPEN,
221 FILE_SYNCHRONOUS_IO_NONALERT,
222 null,
223 0,
224 )) {
225 .SUCCESS => {},
226 // Judging from the ReactOS sources this is technically possible.
227 .INSUFFICIENT_RESOURCES => return error.SystemResources,
228 .INVALID_PARAMETER => unreachable,
229 else => |e| return unexpectedStatus(e),
162 }230 }
231 if (@cmpxchgStrong(?HANDLE, &npfs, null, handle, .seq_cst, .seq_cst)) |xchg| {
232 CloseHandle(handle);
233 break :blk xchg.?;
234 } else break :blk handle;
235 };
236
237 const name = UNICODE_STRING{ .Buffer = null, .Length = 0, .MaximumLength = 0 };
238 var attrs = OBJECT_ATTRIBUTES{
239 .ObjectName = @constCast(&name),
240 .Length = @sizeOf(OBJECT_ATTRIBUTES),
241 .RootDirectory = dev_handle,
242 .Attributes = OBJ_CASE_INSENSITIVE,
243 .SecurityDescriptor = sattr.lpSecurityDescriptor,
244 .SecurityQualityOfService = null,
245 };
246 if (sattr.bInheritHandle != 0) attrs.Attributes |= OBJ_INHERIT;
247
248 // 120 second relative timeout in 100ns units.
249 const default_timeout: LARGE_INTEGER = (-120 * std.time.ns_per_s) / 100;
250 var iosb: IO_STATUS_BLOCK = undefined;
251 var read: HANDLE = undefined;
252 switch (ntdll.NtCreateNamedPipeFile(
253 &read,
254 GENERIC_READ | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
255 &attrs,
256 &iosb,
257 FILE_SHARE_READ | FILE_SHARE_WRITE,
258 FILE_CREATE,
259 FILE_SYNCHRONOUS_IO_NONALERT,
260 FILE_PIPE_BYTE_STREAM_TYPE,
261 FILE_PIPE_BYTE_STREAM_MODE,
262 FILE_PIPE_QUEUE_OPERATION,
263 1,
264 4096,
265 4096,
266 @constCast(&default_timeout),
267 )) {
268 .SUCCESS => {},
269 .INVALID_PARAMETER => unreachable,
270 .INSUFFICIENT_RESOURCES => return error.SystemResources,
271 else => |e| return unexpectedStatus(e),
163 }272 }
273 errdefer CloseHandle(read);
274
275 attrs.RootDirectory = read;
276
277 var write: HANDLE = undefined;
278 switch (ntdll.NtCreateFile(
279 &write,
280 GENERIC_WRITE | SYNCHRONIZE | FILE_READ_ATTRIBUTES,
281 &attrs,
282 &iosb,
283 null,
284 0,
285 FILE_SHARE_READ | FILE_SHARE_WRITE,
286 FILE_OPEN,
287 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE,
288 null,
289 0,
290 )) {
291 .SUCCESS => {},
292 .INVALID_PARAMETER => unreachable,
293 .INSUFFICIENT_RESOURCES => return error.SystemResources,
294 else => |e| return unexpectedStatus(e),
295 }
296
297 rd.* = read;
298 wr.* = write;
164}299}
165300
166pub fn CreateEventEx(attributes: ?*SECURITY_ATTRIBUTES, name: []const u8, flags: DWORD, desired_access: DWORD) !HANDLE {301pub fn CreateEventEx(attributes: ?*SECURITY_ATTRIBUTES, name: []const u8, flags: DWORD, desired_access: DWORD) !HANDLE {
...@@ -1050,35 +1185,32 @@ pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {...@@ -1050,35 +1185,32 @@ pub fn SetFilePointerEx_CURRENT_get(handle: HANDLE) SetFilePointerError!u64 {
1050 return @as(u64, @bitCast(result));1185 return @as(u64, @bitCast(result));
1051}1186}
10521187
1053pub fn QueryObjectName(1188pub fn QueryObjectName(handle: HANDLE, out_buffer: []u16) ![]u16 {
1054 handle: HANDLE,
1055 out_buffer: []u16,
1056) ![]u16 {
1057 const out_buffer_aligned = mem.alignInSlice(out_buffer, @alignOf(OBJECT_NAME_INFORMATION)) orelse return error.NameTooLong;1189 const out_buffer_aligned = mem.alignInSlice(out_buffer, @alignOf(OBJECT_NAME_INFORMATION)) orelse return error.NameTooLong;
10581190
1059 const info = @as(*OBJECT_NAME_INFORMATION, @ptrCast(out_buffer_aligned));1191 const info = @as(*OBJECT_NAME_INFORMATION, @ptrCast(out_buffer_aligned));
1060 //buffer size is specified in bytes1192 // buffer size is specified in bytes
1061 const out_buffer_len = std.math.cast(ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(ULONG);1193 const out_buffer_len = std.math.cast(ULONG, out_buffer_aligned.len * 2) orelse std.math.maxInt(ULONG);
1062 //last argument would return the length required for full_buffer, not exposed here1194 // last argument would return the length required for full_buffer, not exposed here
1063 const rc = ntdll.NtQueryObject(handle, .ObjectNameInformation, info, out_buffer_len, null);1195 return switch (ntdll.NtQueryObject(handle, .ObjectNameInformation, info, out_buffer_len, null)) {
1064 switch (rc) {1196 .SUCCESS => blk: {
1065 .SUCCESS => {
1066 // info.Name.Buffer from ObQueryNameString is documented to be null (and MaximumLength == 0)1197 // info.Name.Buffer from ObQueryNameString is documented to be null (and MaximumLength == 0)
1067 // if the object was "unnamed", not sure if this can happen for file handles1198 // if the object was "unnamed", not sure if this can happen for file handles
1068 if (info.Name.MaximumLength == 0) return error.Unexpected;1199 if (info.Name.MaximumLength == 0) break :blk error.Unexpected;
1069 // resulting string length is specified in bytes1200 // resulting string length is specified in bytes
1070 const path_length_unterminated = @divExact(info.Name.Length, 2);1201 const path_length_unterminated = @divExact(info.Name.Length, 2);
1071 return info.Name.Buffer[0..path_length_unterminated];1202 break :blk info.Name.Buffer.?[0..path_length_unterminated];
1072 },1203 },
1073 .ACCESS_DENIED => return error.AccessDenied,1204 .ACCESS_DENIED => error.AccessDenied,
1074 .INVALID_HANDLE => return error.InvalidHandle,1205 .INVALID_HANDLE => error.InvalidHandle,
1075 // triggered when the buffer is too small for the OBJECT_NAME_INFORMATION object (.INFO_LENGTH_MISMATCH),1206 // triggered when the buffer is too small for the OBJECT_NAME_INFORMATION object (.INFO_LENGTH_MISMATCH),
1076 // or if the buffer is too small for the file path returned (.BUFFER_OVERFLOW, .BUFFER_TOO_SMALL)1207 // or if the buffer is too small for the file path returned (.BUFFER_OVERFLOW, .BUFFER_TOO_SMALL)
1077 .INFO_LENGTH_MISMATCH, .BUFFER_OVERFLOW, .BUFFER_TOO_SMALL => return error.NameTooLong,1208 .INFO_LENGTH_MISMATCH, .BUFFER_OVERFLOW, .BUFFER_TOO_SMALL => error.NameTooLong,
1078 else => |e| return unexpectedStatus(e),1209 else => |e| unexpectedStatus(e),
1079 }1210 };
1080}1211}
1081test "QueryObjectName" {1212
1213test QueryObjectName {
1082 if (builtin.os.tag != .windows)1214 if (builtin.os.tag != .windows)
1083 return;1215 return;
10841216
...@@ -3015,29 +3147,29 @@ pub const OVERLAPPED_ENTRY = extern struct {...@@ -3015,29 +3147,29 @@ pub const OVERLAPPED_ENTRY = extern struct {
30153147
3016pub const MAX_PATH = 260;3148pub const MAX_PATH = 260;
30173149
3018// TODO issue #3053150pub const FILE_INFO_BY_HANDLE_CLASS = enum(u32) {
3019pub const FILE_INFO_BY_HANDLE_CLASS = u32;3151 FileBasicInfo = 0,
3020pub const FileBasicInfo = 0;3152 FileStandardInfo = 1,
3021pub const FileStandardInfo = 1;3153 FileNameInfo = 2,
3022pub const FileNameInfo = 2;3154 FileRenameInfo = 3,
3023pub const FileRenameInfo = 3;3155 FileDispositionInfo = 4,
3024pub const FileDispositionInfo = 4;3156 FileAllocationInfo = 5,
3025pub const FileAllocationInfo = 5;3157 FileEndOfFileInfo = 6,
3026pub const FileEndOfFileInfo = 6;3158 FileStreamInfo = 7,
3027pub const FileStreamInfo = 7;3159 FileCompressionInfo = 8,
3028pub const FileCompressionInfo = 8;3160 FileAttributeTagInfo = 9,
3029pub const FileAttributeTagInfo = 9;3161 FileIdBothDirectoryInfo = 10,
3030pub const FileIdBothDirectoryInfo = 10;3162 FileIdBothDirectoryRestartInfo = 11,
3031pub const FileIdBothDirectoryRestartInfo = 11;3163 FileIoPriorityHintInfo = 12,
3032pub const FileIoPriorityHintInfo = 12;3164 FileRemoteProtocolInfo = 13,
3033pub const FileRemoteProtocolInfo = 13;3165 FileFullDirectoryInfo = 14,
3034pub const FileFullDirectoryInfo = 14;3166 FileFullDirectoryRestartInfo = 15,
3035pub const FileFullDirectoryRestartInfo = 15;3167 FileStorageInfo = 16,
3036pub const FileStorageInfo = 16;3168 FileAlignmentInfo = 17,
3037pub const FileAlignmentInfo = 17;3169 FileIdInfo = 18,
3038pub const FileIdInfo = 18;3170 FileIdExtdDirectoryInfo = 19,
3039pub const FileIdExtdDirectoryInfo = 19;3171 FileIdExtdDirectoryRestartInfo = 20,
3040pub const FileIdExtdDirectoryRestartInfo = 20;3172};
30413173
3042pub const BY_HANDLE_FILE_INFORMATION = extern struct {3174pub const BY_HANDLE_FILE_INFORMATION = extern struct {
3043 dwFileAttributes: DWORD,3175 dwFileAttributes: DWORD,
...@@ -3186,6 +3318,25 @@ pub const FILE_ATTRIBUTE_SYSTEM = 0x4;...@@ -3186,6 +3318,25 @@ pub const FILE_ATTRIBUTE_SYSTEM = 0x4;
3186pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;3318pub const FILE_ATTRIBUTE_TEMPORARY = 0x100;
3187pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;3319pub const FILE_ATTRIBUTE_VIRTUAL = 0x10000;
31883320
3321pub const FILE_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1ff;
3322pub const FILE_GENERIC_READ = STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE;
3323pub const FILE_GENERIC_WRITE = STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE;
3324pub const FILE_GENERIC_EXECUTE = STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE;
3325
3326// Flags for NtCreateNamedPipeFile
3327// NamedPipeType
3328pub const FILE_PIPE_BYTE_STREAM_TYPE = 0x0;
3329pub const FILE_PIPE_MESSAGE_TYPE = 0x1;
3330pub const FILE_PIPE_ACCEPT_REMOTE_CLIENTS = 0x0;
3331pub const FILE_PIPE_REJECT_REMOTE_CLIENTS = 0x2;
3332pub const FILE_PIPE_TYPE_VALID_MASK = 0x3;
3333// CompletionMode
3334pub const FILE_PIPE_QUEUE_OPERATION = 0x0;
3335pub const FILE_PIPE_COMPLETE_OPERATION = 0x1;
3336// ReadMode
3337pub const FILE_PIPE_BYTE_STREAM_MODE = 0x0;
3338pub const FILE_PIPE_MESSAGE_MODE = 0x1;
3339
3189// flags for CreateEvent3340// flags for CreateEvent
3190pub const CREATE_EVENT_INITIAL_SET = 0x00000002;3341pub const CREATE_EVENT_INITIAL_SET = 0x00000002;
3191pub const CREATE_EVENT_MANUAL_RESET = 0x00000001;3342pub const CREATE_EVENT_MANUAL_RESET = 0x00000001;
...@@ -4151,7 +4302,7 @@ pub const OBJ_VALID_ATTRIBUTES = 0x000003F2;...@@ -4151,7 +4302,7 @@ pub const OBJ_VALID_ATTRIBUTES = 0x000003F2;
4151pub const UNICODE_STRING = extern struct {4302pub const UNICODE_STRING = extern struct {
4152 Length: c_ushort,4303 Length: c_ushort,
4153 MaximumLength: c_ushort,4304 MaximumLength: c_ushort,
4154 Buffer: [*]WCHAR,4305 Buffer: ?[*]WCHAR,
4155};4306};
41564307
4157pub const ACTIVATION_CONTEXT_DATA = opaque {};4308pub const ACTIVATION_CONTEXT_DATA = opaque {};
...@@ -4176,7 +4327,11 @@ pub const THREAD_BASIC_INFORMATION = extern struct {...@@ -4176,7 +4327,11 @@ pub const THREAD_BASIC_INFORMATION = extern struct {
4176};4327};
41774328
4178pub const TEB = extern struct {4329pub const TEB = extern struct {
4179 Reserved1: [12]PVOID,4330 NtTib: NT_TIB,
4331 EnvironmentPointer: PVOID,
4332 ClientId: CLIENT_ID,
4333 ActiveRpcHandle: PVOID,
4334 ThreadLocalStoragePointer: PVOID,
4180 ProcessEnvironmentBlock: *PEB,4335 ProcessEnvironmentBlock: *PEB,
4181 Reserved2: [399]PVOID,4336 Reserved2: [399]PVOID,
4182 Reserved3: [1952]u8,4337 Reserved3: [1952]u8,
...@@ -4188,6 +4343,25 @@ pub const TEB = extern struct {...@@ -4188,6 +4343,25 @@ pub const TEB = extern struct {
4188 TlsExpansionSlots: PVOID,4343 TlsExpansionSlots: PVOID,
4189};4344};
41904345
4346comptime {
4347 // Offsets taken from WinDbg info and Geoff Chappell[1] (RIP)
4348 // [1]: https://www.geoffchappell.com/studies/windows/km/ntoskrnl/inc/api/pebteb/teb/index.htm
4349 assert(@offsetOf(TEB, "NtTib") == 0x00);
4350 if (@sizeOf(usize) == 4) {
4351 assert(@offsetOf(TEB, "EnvironmentPointer") == 0x1C);
4352 assert(@offsetOf(TEB, "ClientId") == 0x20);
4353 assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x28);
4354 assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x2C);
4355 assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x30);
4356 } else if (@sizeOf(usize) == 8) {
4357 assert(@offsetOf(TEB, "EnvironmentPointer") == 0x38);
4358 assert(@offsetOf(TEB, "ClientId") == 0x40);
4359 assert(@offsetOf(TEB, "ActiveRpcHandle") == 0x50);
4360 assert(@offsetOf(TEB, "ThreadLocalStoragePointer") == 0x58);
4361 assert(@offsetOf(TEB, "ProcessEnvironmentBlock") == 0x60);
4362 }
4363}
4364
4191pub const EXCEPTION_REGISTRATION_RECORD = extern struct {4365pub const EXCEPTION_REGISTRATION_RECORD = extern struct {
4192 Next: ?*EXCEPTION_REGISTRATION_RECORD,4366 Next: ?*EXCEPTION_REGISTRATION_RECORD,
4193 Handler: ?*EXCEPTION_DISPOSITION,4367 Handler: ?*EXCEPTION_DISPOSITION,
lib/std/os/windows/ntdll.zig+17
...@@ -341,3 +341,20 @@ pub extern "ntdll" fn NtProtectVirtualMemory(...@@ -341,3 +341,20 @@ pub extern "ntdll" fn NtProtectVirtualMemory(
341pub extern "ntdll" fn RtlExitUserProcess(341pub extern "ntdll" fn RtlExitUserProcess(
342 ExitStatus: u32,342 ExitStatus: u32,
343) callconv(WINAPI) noreturn;343) callconv(WINAPI) noreturn;
344
345pub extern "ntdll" fn NtCreateNamedPipeFile(
346 FileHandle: *HANDLE,
347 DesiredAccess: ULONG,
348 ObjectAttributes: *OBJECT_ATTRIBUTES,
349 IoStatusBlock: *IO_STATUS_BLOCK,
350 ShareAccess: ULONG,
351 CreateDisposition: ULONG,
352 CreateOptions: ULONG,
353 NamedPipeType: ULONG,
354 ReadMode: ULONG,
355 CompletionMode: ULONG,
356 MaximumInstances: ULONG,
357 InboundQuota: ULONG,
358 OutboundQuota: ULONG,
359 DefaultTimeout: *LARGE_INTEGER,
360) callconv(WINAPI) NTSTATUS;
lib/std/os/windows/test.zig+1-1
...@@ -15,7 +15,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !windows.PathSpace {...@@ -15,7 +15,7 @@ fn RtlDosPathNameToNtPathName_U(path: [:0]const u16) !windows.PathSpace {
15 defer windows.ntdll.RtlFreeUnicodeString(&out);15 defer windows.ntdll.RtlFreeUnicodeString(&out);
1616
17 var path_space: windows.PathSpace = undefined;17 var path_space: windows.PathSpace = undefined;
18 const out_path = out.Buffer[0 .. out.Length / 2];18 const out_path = out.Buffer.?[0 .. out.Length / 2];
19 @memcpy(path_space.data[0..out_path.len], out_path);19 @memcpy(path_space.data[0..out_path.len], out_path);
20 path_space.len = out.Length / 2;20 path_space.len = out.Length / 2;
21 path_space.data[path_space.len] = 0;21 path_space.data[path_space.len] = 0;
lib/std/zig/system/windows.zig+1-1
...@@ -160,7 +160,7 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void {...@@ -160,7 +160,7 @@ fn getCpuInfoFromRegistry(core: usize, args: anytype) !void {
160 => {160 => {
161 var buf = @field(args, field.name).value_buf;161 var buf = @field(args, field.name).value_buf;
162 const entry = @as(*align(1) const std.os.windows.UNICODE_STRING, @ptrCast(table[i + 1].EntryContext));162 const entry = @as(*align(1) const std.os.windows.UNICODE_STRING, @ptrCast(table[i + 1].EntryContext));
163 const len = try std.unicode.utf16LeToUtf8(buf, entry.Buffer[0 .. entry.Length / 2]);163 const len = try std.unicode.utf16LeToUtf8(buf, entry.Buffer.?[0 .. entry.Length / 2]);
164 buf[len] = 0;164 buf[len] = 0;
165 },165 },
166166