[PATCH 0/2] MR127: ws2_32: Make wait in select alertable
Jinoh Kang
jinoh.kang.kr at gmail.com
Wed May 25 10:46:52 CDT 2022
On 5/25/22 22:30, Alexandre Julliard wrote:
>> We can wrap the IOSB writes in `set_async_iosb` inside a `__TRY` block from `wine/unixlib.h`.
>
> That would only be hiding the bug.
>
Handling the exception does not necessarily mean silencing the bug; we can flag the error condition via ERR().
Also, letting the IOSB leak won't make debugging much more pleasurable either IMHO:
1. There's no way to detect pulling the rug out under a pending I/O operation.
2. It causes hard-to-trace memory leak.
---
As a side note, Windows does ignore invalid memory accesses when writing IOSB. On Windows, running the test program below results in the following:
Test 1. Valid Status, Valid Information
iosb->Status = 0
iosb->Information = 0x1
Test 2. Valid Status, Faulting Information
iosb->Status = 0xcccccccc
iosb->Information = 0xcccccccccccccccc
Test 3. Faulting Status, Valid Information
iosb->Status = 0xcccccccc
iosb->Information = 0x1
Test 4. Faulting Status, Faulting Information
iosb->Status = 0xcccccccc
iosb->Information = 0xcccccccccccccccc
>From the output above, we can infer two things:
1. Windows gives up writing IOSB and let the program continue as usual when it encounters invalid memory accesses.
2. Even if the Status field is invalid, Windows still successfully writes the Information field.
---
#define WIN32_LEAN_AND_MEAN
#define _UNICODE
#include <windows.h>
#include <winternl.h>
#include <stdio.h>
#include <stdlib.h>
NTSYSAPI NTSTATUS WINAPI NtReadFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,PVOID,ULONG,PLARGE_INTEGER,PULONG);;
void die_(int line, unsigned int errcode)
{
fprintf(stderr, "error @ %d: %u (%#x)\n", line, errcode, errcode);
exit(EXIT_FAILURE);
}
#define die() die_(__LINE__, GetLastError())
static void subtest(HANDLE read_pipe, HANDLE write_pipe, IO_STATUS_BLOCK *iosb, void *fault_page);
int wmain(void)
{
HANDLE read_pipe, write_pipe;
void *page_0, *page_1, *fault_page;
const WCHAR pipe_name[] = L"\\\\.\\PIPE\\LOCAL\\faulty-iosb-test";
IO_STATUS_BLOCK *iosb;
read_pipe = CreateNamedPipeW(
pipe_name,
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_ACCEPT_REMOTE_CLIENTS,
1,
4096,
4096,
0,
NULL
);
if (read_pipe == INVALID_HANDLE_VALUE) die();
write_pipe = CreateFile(
pipe_name,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (write_pipe == INVALID_HANDLE_VALUE) die();
page_0 = VirtualAlloc(NULL, 4096 * 2, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!page_0) die();
page_1 = (char *)page_0 + 4096;
puts("Test 1. Valid Status, Valid Information");
iosb = (IO_STATUS_BLOCK *)page_0;
fault_page = page_1;
subtest(read_pipe, write_pipe, iosb, fault_page);
puts("Test 2. Valid Status, Faulting Information");
iosb = CONTAINING_RECORD((ULONG_PTR *)page_1, IO_STATUS_BLOCK, Information);
fault_page = page_1;
subtest(read_pipe, write_pipe, iosb, fault_page);
puts("Test 3. Faulting Status, Valid Information");
iosb = CONTAINING_RECORD((ULONG_PTR *)page_1, IO_STATUS_BLOCK, Information);
fault_page = page_0;
subtest(read_pipe, write_pipe, iosb, fault_page);
puts("Test 4. Faulting Status, Faulting Information");
iosb = (IO_STATUS_BLOCK *)page_0;
fault_page = page_0;
subtest(read_pipe, write_pipe, iosb, fault_page);
return 0;
}
static void subtest(HANDLE read_pipe, HANDLE write_pipe, IO_STATUS_BLOCK *iosb, void *fault_page)
{
DWORD old_prot;
DWORD result;
NTSTATUS status;
char buffer[1];
memset(iosb, 0xcc, sizeof(*iosb));
status = NtReadFile(read_pipe, NULL, NULL, NULL, iosb, buffer, sizeof(buffer), NULL, NULL);
if (status != STATUS_PENDING) die_(__LINE__, status);
if (!VirtualProtect(fault_page, 4096, PAGE_NOACCESS, &old_prot)) die();
if (!WriteFile(write_pipe, "", 1, &result, NULL)) die();
if (WaitForSingleObject(read_pipe, INFINITE) != WAIT_OBJECT_0) die();
if (!VirtualProtect(fault_page, 4096, old_prot, &old_prot)) die();
printf("iosb->Status = %#lx\n", (unsigned long)iosb->Status);
printf("iosb->Information = %#Ix\n", iosb->Information);
puts("");
}
--
Sincerely,
Jinoh Kang
More information about the wine-devel
mailing list