Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntdll/tests/pipe.c | 4 ++++ 1 file changed, 4 insertions(+)
diff --git a/dlls/ntdll/tests/pipe.c b/dlls/ntdll/tests/pipe.c index 662dc1d55cb..1118f41f81f 100644 --- a/dlls/ntdll/tests/pipe.c +++ b/dlls/ntdll/tests/pipe.c @@ -1662,8 +1662,10 @@ static void test_volume_info(void) PIPE_TYPE_MESSAGE, 4096 )) return;
memset( buffer, 0xaa, sizeof(buffer) ); + memset( &iosb, 0xaa, sizeof(iosb) ); status = pNtQueryVolumeInformationFile( read, &iosb, buffer, sizeof(buffer), FileFsDeviceInformation ); ok( status == STATUS_SUCCESS, "NtQueryVolumeInformationFile failed: %x\n", status ); + ok( iosb.Status == STATUS_SUCCESS, "got status %#x\n", iosb.Status ); ok( iosb.Information == sizeof(*device_info), "Information = %lu\n", iosb.Information ); device_info = (FILE_FS_DEVICE_INFORMATION*)buffer; ok( device_info->DeviceType == FILE_DEVICE_NAMED_PIPE, "DeviceType = %u\n", device_info->DeviceType ); @@ -1671,8 +1673,10 @@ static void test_volume_info(void) "Characteristics = %x\n", device_info->Characteristics );
memset( buffer, 0xaa, sizeof(buffer) ); + memset( &iosb, 0xaa, sizeof(iosb) ); status = pNtQueryVolumeInformationFile( write, &iosb, buffer, sizeof(buffer), FileFsDeviceInformation ); ok( status == STATUS_SUCCESS, "NtQueryVolumeInformationFile failed: %x\n", status ); + ok( iosb.Status == STATUS_SUCCESS, "got status %#x\n", iosb.Status ); ok( iosb.Information == sizeof(*device_info), "Information = %lu\n", iosb.Information ); device_info = (FILE_FS_DEVICE_INFORMATION*)buffer; ok( device_info->DeviceType == FILE_DEVICE_NAMED_PIPE, "DeviceType = %u\n", device_info->DeviceType );
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/ntoskrnl.exe/tests/driver.c | 99 +++--- dlls/ntoskrnl.exe/tests/driver.h | 40 ++- dlls/ntoskrnl.exe/tests/driver_pnp.c | 6 +- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 439 ++++++++++++++++++++++----- 4 files changed, 454 insertions(+), 130 deletions(-)
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index ce74b9e9512..0d40053b0e6 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -2395,22 +2395,64 @@ static NTSTATUS get_fscontext(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *inf return STATUS_SUCCESS; }
-static NTSTATUS return_status(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) +static NTSTATUS return_status(IRP *irp, IO_STACK_LOCATION *stack, ULONG code) { - char *buffer = irp->AssociatedIrp.SystemBuffer; - NTSTATUS ret; + ULONG input_length = stack->Parameters.DeviceIoControl.InputBufferLength; + ULONG output_length = stack->Parameters.DeviceIoControl.OutputBufferLength; + const struct return_status_params *input_buffer; + struct return_status_params params; + void *output_buffer;
- if (!buffer) + if (code == IOCTL_WINETEST_RETURN_STATUS_NEITHER) + { + input_buffer = stack->Parameters.DeviceIoControl.Type3InputBuffer; + output_buffer = irp->UserBuffer; + } + else if (code == IOCTL_WINETEST_RETURN_STATUS_DIRECT) + { + input_buffer = irp->AssociatedIrp.SystemBuffer; + output_buffer = MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); + } + else + { + input_buffer = irp->AssociatedIrp.SystemBuffer; + output_buffer = irp->AssociatedIrp.SystemBuffer; + } + + if (!input_buffer || !output_buffer) + { + irp->IoStatus.Status = STATUS_ACCESS_VIOLATION; + IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_ACCESS_VIOLATION; + }
- if (stack->Parameters.DeviceIoControl.InputBufferLength < sizeof(DWORD) - || stack->Parameters.DeviceIoControl.OutputBufferLength < 3) + if (input_length < sizeof(params) || output_length < 6) + { + irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; + IoCompleteRequest(irp, IO_NO_INCREMENT); return STATUS_BUFFER_TOO_SMALL; + }
- ret = *(DWORD *)irp->AssociatedIrp.SystemBuffer; - memcpy(buffer, "ghi", 3); - *info = 3; - return ret; + params = *input_buffer; + + if (params.ret_status == STATUS_PENDING && !params.pending) + { + /* this causes kernel hangs under certain conditions */ + irp->IoStatus.Status = STATUS_INVALID_PARAMETER; + IoCompleteRequest(irp, IO_NO_INCREMENT); + return STATUS_INVALID_PARAMETER; + } + + if (params.pending) + IoMarkIrpPending(irp); + + /* intentionally report the wrong information (and status) */ + memcpy(output_buffer, "ghijkl", 6); + irp->IoStatus.Information = 3; + irp->IoStatus.Status = params.iosb_status; + IoCompleteRequest(irp, IO_NO_INCREMENT); + + return params.ret_status; }
static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) @@ -2430,34 +2472,6 @@ static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG return ZwUnloadDriver(&name); }
-static NTSTATUS test_mismatched_status_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) -{ - ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; - char *buffer = irp->UserBuffer; - - if (!buffer) - { - irp->IoStatus.Status = STATUS_ACCESS_VIOLATION; - IoCompleteRequest(irp, IO_NO_INCREMENT); - return STATUS_ACCESS_VIOLATION; - } - - if (length < sizeof(teststr)) - { - irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL; - IoCompleteRequest(irp, IO_NO_INCREMENT); - return STATUS_BUFFER_TOO_SMALL; - } - - memcpy(buffer, teststr, sizeof(teststr)); - - /* This is deliberate; some broken drivers do this */ - *info = 0; - irp->IoStatus.Status = STATUS_UNSUCCESSFUL; - IoCompleteRequest(irp, IO_NO_INCREMENT); - return STATUS_SUCCESS; -} - static NTSTATUS completion_ioctl(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack) { if (device == upper_device) @@ -2564,15 +2578,14 @@ static NTSTATUS WINAPI driver_IoControl(DEVICE_OBJECT *device, IRP *irp) case IOCTL_WINETEST_GET_FSCONTEXT: status = get_fscontext(irp, stack, &irp->IoStatus.Information); break; - case IOCTL_WINETEST_RETURN_STATUS: - status = return_status(irp, stack, &irp->IoStatus.Information); - break; + case IOCTL_WINETEST_RETURN_STATUS_BUFFERED: + case IOCTL_WINETEST_RETURN_STATUS_DIRECT: + case IOCTL_WINETEST_RETURN_STATUS_NEITHER: + return return_status(irp, stack, stack->Parameters.DeviceIoControl.IoControlCode); case IOCTL_WINETEST_DETACH: IoDetachDevice(lower_device); status = STATUS_SUCCESS; break; - case IOCTL_WINETEST_MISMATCHED_STATUS: - return test_mismatched_status_ioctl(irp, stack, &irp->IoStatus.Information); case IOCTL_WINETEST_COMPLETION: return completion_ioctl(device, irp, stack); default: diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h index 8c41010c503..9126e3cf2bf 100644 --- a/dlls/ntoskrnl.exe/tests/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.h @@ -22,21 +22,20 @@
/* All custom IOCTLs need to have a function value >= 0x800. */ -#define IOCTL_WINETEST_BASIC_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_MAIN_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_LOAD_DRIVER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_RESET_CANCEL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_TEST_CANCEL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_GET_CANCEL_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_DETACH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_GET_CREATE_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_GET_CLOSE_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_GET_FSCONTEXT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_RETURN_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_BUFFERED, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_MISMATCHED_STATUS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80b, METHOD_NEITHER, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_COMPLETION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80c, METHOD_NEITHER, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_MARK_PENDING CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80d, METHOD_NEITHER, FILE_ANY_ACCESS) -#define IOCTL_WINETEST_CHECK_REMOVED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80e, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_BASIC_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_MAIN_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_LOAD_DRIVER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_RESET_CANCEL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_TEST_CANCEL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_GET_CANCEL_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_DETACH CTL_CODE(FILE_DEVICE_UNKNOWN, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_GET_CREATE_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x807, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_GET_CLOSE_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_GET_FSCONTEXT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x809, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_RETURN_STATUS_BUFFERED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_RETURN_STATUS_DIRECT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_OUT_DIRECT, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_RETURN_STATUS_NEITHER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80a, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_COMPLETION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x80c, METHOD_NEITHER, FILE_ANY_ACCESS)
#define IOCTL_WINETEST_BUS_MAIN CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WINETEST_BUS_REGISTER_IFACE CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) @@ -45,7 +44,9 @@ #define IOCTL_WINETEST_BUS_ADD_CHILD CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WINETEST_BUS_REMOVE_CHILD CTL_CODE(FILE_DEVICE_BUS_EXTENDER, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)
-#define IOCTL_WINETEST_CHILD_GET_ID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_CHILD_GET_ID CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_CHILD_MARK_PENDING CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_NEITHER, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_CHILD_CHECK_REMOVED CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_NEITHER, FILE_ANY_ACCESS)
static const char teststr[] = "Wine is not an emulator";
@@ -65,6 +66,13 @@ struct main_test_input ULONG64 *modified_value; };
+struct return_status_params +{ + NTSTATUS ret_status; + NTSTATUS iosb_status; + BOOL pending; +}; + static const GUID control_class = {0xdeadbeef, 0x29ef, 0x4538, {0xa5, 0xfd, 0xb6, 0x95, 0x73, 0xa3, 0x62, 0xc0}};
#define SERVER_LISTEN_PORT 9374 diff --git a/dlls/ntoskrnl.exe/tests/driver_pnp.c b/dlls/ntoskrnl.exe/tests/driver_pnp.c index 98ca2ff7961..aa078ab0b2f 100644 --- a/dlls/ntoskrnl.exe/tests/driver_pnp.c +++ b/dlls/ntoskrnl.exe/tests/driver_pnp.c @@ -276,7 +276,7 @@ static NTSTATUS pdo_pnp(DEVICE_OBJECT *device_obj, IRP *irp) }
case IRP_MN_REMOVE_DEVICE: - /* should've been checked and reset by IOCTL_WINETEST_CHECK_REMOVED */ + /* should've been checked and reset by IOCTL_WINETEST_CHILD_CHECK_REMOVED */ ok(remove_device_count == 0, "expected no IRP_MN_REMOVE_DEVICE\n"); todo_wine ok(surprise_removal_count == 0, "expected no IRP_MN_SURPRISE_REMOVAL\n"); ok(query_remove_device_count == 0, "expected no IRP_MN_QUERY_REMOVE_DEVICE\n"); @@ -665,12 +665,12 @@ static NTSTATUS pdo_ioctl(DEVICE_OBJECT *device_obj, IRP *irp, IO_STACK_LOCATION irp->IoStatus.Information = sizeof(device->id); return STATUS_SUCCESS;
- case IOCTL_WINETEST_MARK_PENDING: + case IOCTL_WINETEST_CHILD_MARK_PENDING: IoMarkIrpPending(irp); irp_queue_push(&device->irp_queue, irp); return STATUS_PENDING;
- case IOCTL_WINETEST_CHECK_REMOVED: + case IOCTL_WINETEST_CHILD_CHECK_REMOVED: ok(remove_device_count == 0, "expected IRP_MN_REMOVE_DEVICE\n"); ok(surprise_removal_count == 1, "expected IRP_MN_SURPRISE_REMOVAL\n"); ok(query_remove_device_count == 0, "expected no IRP_MN_QUERY_REMOVE_DEVICE\n"); diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index 774021c5ba2..b1fc73fb773 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -430,18 +430,6 @@ static void test_basic_ioctl(void) ok(!strcmp(buf, "Wine is no"), "got '%s'\n", buf); }
-static void test_mismatched_status_ioctl(void) -{ - DWORD written; - char buf[32]; - BOOL res; - - res = DeviceIoControl(device, IOCTL_WINETEST_MISMATCHED_STATUS, NULL, 0, buf, - sizeof(buf), &written, NULL); - todo_wine ok(res, "DeviceIoControl failed: %u\n", GetLastError()); - todo_wine ok(!strcmp(buf, teststr), "got '%s'\n", buf); -} - static void test_overlapped(void) { OVERLAPPED overlapped, overlapped2, *o; @@ -631,72 +619,376 @@ static void test_file_handles(void) ok(count == 3, "got %u\n", count); }
-static void test_return_status(void) +static unsigned int got_return_status_apc; + +static void WINAPI return_status_apc(void *apc_user, IO_STATUS_BLOCK *io, ULONG reserved) { - NTSTATUS status; + ++got_return_status_apc; + ok(apc_user == (void *)456, "got %p\n", apc_user); + ok(!reserved, "got reserved %#x\n", reserved); +} + +static void do_return_status(ULONG ioctl, struct return_status_params *params) +{ + const char *expect_buffer; + LARGE_INTEGER zero = {0}; + HANDLE file, port, event; + NTSTATUS expect_status; + ULONG_PTR key, value; + IO_STATUS_BLOCK io; char buffer[7]; - DWORD ret_size; + DWORD size; BOOL ret;
- strcpy(buffer, "abcdef"); - status = STATUS_SUCCESS; - SetLastError(0xdeadbeef); - ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status, - sizeof(status), buffer, sizeof(buffer), &ret_size, NULL); - ok(ret, "ioctl failed\n"); - ok(GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError()); - ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer); - ok(ret_size == 3, "got size %u\n", ret_size); + if (params->ret_status == STATUS_PENDING && !params->pending) + { + /* this causes kernel hangs under certain conditions */ + return; + } + + event = CreateEventW(NULL, TRUE, FALSE, NULL); + + if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) + expect_buffer = "ghijkl"; + else if (NT_ERROR(params->iosb_status)) + expect_buffer = "abcdef"; + else + expect_buffer = "ghidef"; + + /* Test the non-overlapped case. */ + + expect_status = (params->ret_status == STATUS_PENDING ? params->iosb_status : params->ret_status);
strcpy(buffer, "abcdef"); - status = STATUS_TIMEOUT; - SetLastError(0xdeadbeef); - ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status, - sizeof(status), buffer, sizeof(buffer), &ret_size, NULL); - todo_wine ok(ret, "ioctl failed\n"); - todo_wine ok(GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError()); - ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer); - ok(ret_size == 3, "got size %u\n", ret_size); + size = 0xdeadf00d; + SetLastError(0xdeadf00d); + ret = DeviceIoControl(device, ioctl, params, sizeof(*params), buffer, sizeof(buffer), &size, NULL); + todo_wine_if (NT_SUCCESS(expect_status) != !params->iosb_status) + ok(ret == NT_SUCCESS(expect_status), "got %d\n", ret); + if (NT_SUCCESS(expect_status)) + { + todo_wine_if (params->iosb_status) + ok(GetLastError() == 0xdeadf00d, "got error %u\n", GetLastError()); + } + else + { + todo_wine_if (RtlNtStatusToDosError(expect_status) != RtlNtStatusToDosError(params->iosb_status) + || params->iosb_status == STATUS_PENDING) + ok(GetLastError() == RtlNtStatusToDosError(expect_status), "got error %u\n", GetLastError()); + } + if (NT_ERROR(expect_status)) + todo_wine ok(size == 0xdeadf00d, "got size %u\n", size); + else if (!NT_ERROR(params->iosb_status)) + ok(size == 3, "got size %u\n", size); + /* size is garbage if !NT_ERROR(expect_status) && NT_ERROR(iosb_status) */ + todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) + ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
strcpy(buffer, "abcdef"); - status = 0x0eadbeef; - SetLastError(0xdeadbeef); - ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status, - sizeof(status), buffer, sizeof(buffer), &ret_size, NULL); - todo_wine ok(ret, "ioctl failed\n"); - todo_wine ok(GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError()); - ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer); - ok(ret_size == 3, "got size %u\n", ret_size); + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + ret = NtDeviceIoControlFile(device, NULL, NULL, NULL, &io, + ioctl, params, sizeof(*params), buffer, sizeof(buffer)); + todo_wine_if ((params->ret_status != params->iosb_status && params->ret_status != STATUS_PENDING) + || params->iosb_status == STATUS_PENDING) + ok(ret == expect_status, "got %#x\n", ret); + if (NT_ERROR(params->iosb_status)) + { + todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status); + todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information); + } + else + { + todo_wine_if (params->iosb_status == STATUS_PENDING) + ok(io.Status == params->iosb_status, "got %#x\n", io.Status); + ok(io.Information == 3, "got size %Iu\n", io.Information); + } + todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) + ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer); + + /* Test the overlapped case. */ + + file = CreateFileA("\\.\WineTestDriver", FILE_ALL_ACCESS, + 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + ok(file != INVALID_HANDLE_VALUE, "failed to open device, error %u\n", GetLastError()); + port = CreateIoCompletionPort(file, NULL, 123, 0); + ok(port != NULL, "failed to create port, error %u\n", GetLastError()); + + ret = WaitForSingleObject(file, 0); + todo_wine ok(!ret, "got %d\n", ret); + + ResetEvent(event); + strcpy(buffer, "abcdef"); + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + ret = NtDeviceIoControlFile(file, event, NULL, (void *)456, &io, + ioctl, params, sizeof(*params), buffer, sizeof(buffer)); + todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + ok(ret == params->ret_status + || broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */ + "got %#x\n", ret); + if (!params->pending && NT_ERROR(params->iosb_status)) + { + todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status); + todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information); + ret = WaitForSingleObject(event, 0); + todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + } + else + { + todo_wine_if (params->iosb_status == STATUS_PENDING) + ok(io.Status == params->iosb_status, "got %#x\n", io.Status); + ok(io.Information == 3, "got size %Iu\n", io.Information); + ret = WaitForSingleObject(event, 0); + ok(!ret, "got %d\n", ret); + } + todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) + ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer); + + ret = WaitForSingleObject(file, 0); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + + key = 0xdeadf00d; + value = 0xdeadf00d; + memset(&io, 0xcc, sizeof(io)); + ret = NtRemoveIoCompletion(port, &key, &value, &io, &zero); + if (!params->pending && NT_ERROR(params->iosb_status)) + { + todo_wine ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + } + else + { + ok(!ret, "got %#x\n", ret); + ok(key == 123, "got key %Iu\n", key); + ok(value == 456, "got value %Iu\n", value); + todo_wine_if (params->iosb_status == STATUS_PENDING) + ok(io.Status == params->iosb_status, "got iosb status %#x\n", io.Status); + ok(io.Information == 3, "got information %Iu\n", io.Information); + } + + /* As above, but set the event first, to show that the event is always + * reset. */ + ResetEvent(event); + strcpy(buffer, "abcdef"); + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + ret = NtDeviceIoControlFile(file, event, NULL, NULL, &io, + ioctl, params, sizeof(*params), buffer, sizeof(buffer)); + todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + ok(ret == params->ret_status + || broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */ + "got %#x\n", ret); + if (!params->pending && NT_ERROR(params->iosb_status)) + { + todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status); + todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information); + ret = WaitForSingleObject(event, 0); + todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + } + else + { + todo_wine_if (params->iosb_status == STATUS_PENDING) + ok(io.Status == params->iosb_status, "got %#x\n", io.Status); + ok(io.Information == 3, "got size %Iu\n", io.Information); + ret = WaitForSingleObject(event, 0); + ok(!ret, "got %d\n", ret); + } + todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) + ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer); + + /* As above, but use the file handle instead of an event. */ + ret = WaitForSingleObject(file, 0); + ok(ret == WAIT_TIMEOUT, "got %d\n", ret);
strcpy(buffer, "abcdef"); - status = 0x4eadbeef; - SetLastError(0xdeadbeef); - ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status, - sizeof(status), buffer, sizeof(buffer), &ret_size, NULL); - todo_wine ok(ret, "ioctl failed\n"); - todo_wine ok(GetLastError() == 0xdeadbeef, "got error %u\n", GetLastError()); - ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer); - ok(ret_size == 3, "got size %u\n", ret_size); + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + ret = NtDeviceIoControlFile(file, NULL, NULL, NULL, &io, + ioctl, params, sizeof(*params), buffer, sizeof(buffer)); + todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + ok(ret == params->ret_status + || broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */ + "got %#x\n", ret); + if (!params->pending && NT_ERROR(params->iosb_status)) + { + todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status); + todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information); + ret = WaitForSingleObject(file, 0); + todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + } + else + { + todo_wine_if (params->iosb_status == STATUS_PENDING) + ok(io.Status == params->iosb_status, "got %#x\n", io.Status); + ok(io.Information == 3, "got size %Iu\n", io.Information); + ret = WaitForSingleObject(file, 0); + ok(!ret, "got %d\n", ret); + } + todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) + ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer); + + /* Test FILE_SKIP_COMPLETION_PORT_ON_SUCCESS. */ + + if (pSetFileCompletionNotificationModes) + { + ret = pSetFileCompletionNotificationModes(file, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS); + ok(ret, "got error %u\n", GetLastError()); + + SetEvent(event); + strcpy(buffer, "abcdef"); + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + ret = NtDeviceIoControlFile(file, event, NULL, (void *)456, &io, + ioctl, params, sizeof(*params), buffer, sizeof(buffer)); + todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + ok(ret == params->ret_status + || broken(NT_WARNING(params->ret_status) && ret == STATUS_PENDING), /* win10 */ + "got %#x\n", ret); + if (!params->pending && NT_ERROR(params->iosb_status)) + { + todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status); + todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information); + ret = WaitForSingleObject(event, 0); + todo_wine ok(ret == WAIT_TIMEOUT, "got %d\n", ret); + } + else + { + todo_wine_if (params->iosb_status == STATUS_PENDING) + ok(io.Status == params->iosb_status, "got %#x\n", io.Status); + ok(io.Information == 3, "got size %Iu\n", io.Information); + ret = WaitForSingleObject(event, 0); + ok(!ret, "got %d\n", ret); + } + todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) + ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer); + + key = 0xdeadf00d; + value = 0xdeadf00d; + memset(&io, 0xcc, sizeof(io)); + ret = NtRemoveIoCompletion(port, &key, &value, &io, &zero); + if (!params->pending) + { + /* Completion is skipped on non-pending NT_ERROR regardless of file + * options. Windows < 8 interprets + * FILE_SKIP_COMPLETION_PORT_ON_SUCCESS to mean that !NT_ERROR + * should also be skipped. Windows >= 8 restricts this to + * NT_SUCCESS, which has the weird effect that non-pending + * NT_WARNING does *not* skip completion. It's not clear whether + * this is a bug or not—it looks like one, but on the other hand it + * arguably follows the letter of the documentation more closely. */ + ok(ret == STATUS_TIMEOUT || (NT_WARNING(params->iosb_status) && !ret), "got %#x\n", ret); + } + else + { + todo_wine ok(!ret, "got %#x\n", ret); + } + if (!ret) + { + ok(key == 123, "got key %Iu\n", key); + ok(value == 456, "got value %Iu\n", value); + ok(io.Status == params->iosb_status, "got iosb status %#x\n", io.Status); + ok(io.Information == 3, "got information %Iu\n", io.Information); + } + } + + ret = CloseHandle(file); + ok(ret, "failed to close file, error %u\n", GetLastError()); + ret = CloseHandle(port); + ok(ret, "failed to close port, error %u\n", GetLastError()); + + /* Test with an APC. */ + + got_return_status_apc = 0; + + file = CreateFileA("\\.\WineTestDriver", FILE_ALL_ACCESS, + 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + ok(file != INVALID_HANDLE_VALUE, "failed to open device, error %u\n", GetLastError());
strcpy(buffer, "abcdef"); - status = 0x8eadbeef; - SetLastError(0xdeadbeef); - ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status, - sizeof(status), buffer, sizeof(buffer), &ret_size, NULL); - ok(!ret, "ioctl succeeded\n"); - ok(GetLastError() == ERROR_MR_MID_NOT_FOUND, "got error %u\n", GetLastError()); - ok(!strcmp(buffer, "ghidef"), "got buffer %s\n", buffer); - ok(ret_size == 3, "got size %u\n", ret_size); + io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + ret = NtDeviceIoControlFile(file, NULL, return_status_apc, (void *)456, &io, + ioctl, params, sizeof(*params), buffer, sizeof(buffer)); + todo_wine_if (params->ret_status != params->iosb_status || params->ret_status == STATUS_PENDING) + ok(ret == params->ret_status, "got %#x\n", ret); + if (!params->pending && NT_ERROR(params->iosb_status)) + { + todo_wine ok(io.Status == 0xdeadf00d, "got %#x\n", io.Status); + todo_wine ok(io.Information == 0xdeadf00d, "got size %Iu\n", io.Information); + } + else + { + todo_wine_if (params->iosb_status == STATUS_PENDING) + ok(io.Status == params->iosb_status, "got %#x\n", io.Status); + ok(io.Information == 3, "got size %Iu\n", io.Information); + } + todo_wine_if (ioctl != IOCTL_WINETEST_RETURN_STATUS_BUFFERED) + ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
- strcpy(buffer, "abcdef"); - status = 0xceadbeef; - SetLastError(0xdeadbeef); - ret = DeviceIoControl(device, IOCTL_WINETEST_RETURN_STATUS, &status, - sizeof(status), buffer, sizeof(buffer), &ret_size, NULL); - ok(!ret, "ioctl succeeded\n"); - ok(GetLastError() == ERROR_MR_MID_NOT_FOUND, "got error %u\n", GetLastError()); - ok(!strcmp(buffer, "abcdef"), "got buffer %s\n", buffer); - ok(ret_size == 3, "got size %u\n", ret_size); + ret = SleepEx(0, TRUE); + if (!params->pending && NT_ERROR(params->iosb_status)) + { + todo_wine ok(!ret, "got %d\n", ret); + todo_wine ok(!got_return_status_apc, "got %u APC calls\n", got_return_status_apc); + } + else + { + ok(ret == WAIT_IO_COMPLETION, "got %d\n", ret); + ok(got_return_status_apc == 1, "got %u APC calls\n", got_return_status_apc); + } + + ret = CloseHandle(file); + ok(ret, "failed to close file, error %u\n", GetLastError()); + + CloseHandle(event); +} + +static void test_return_status(void) +{ + struct return_status_params params; + unsigned int i, j, k; + + static const ULONG method_tests[] = + { + IOCTL_WINETEST_RETURN_STATUS_BUFFERED, + IOCTL_WINETEST_RETURN_STATUS_DIRECT, + IOCTL_WINETEST_RETURN_STATUS_NEITHER, + }; + + static const NTSTATUS status_tests[] = + { + STATUS_SUCCESS, + STATUS_PENDING, + STATUS_TIMEOUT, + 0x0eadbeef, + 0x4eadbeef, + STATUS_BUFFER_OVERFLOW, + 0x8eadbeef, + STATUS_NOT_IMPLEMENTED, + 0xceadbeef, + }; + + for (i = 0; i < ARRAY_SIZE(status_tests); ++i) + { + for (j = 0; j < ARRAY_SIZE(status_tests); ++j) + { + for (params.pending = 0; params.pending <= 1; ++params.pending) + { + for (k = 0; k < ARRAY_SIZE(method_tests); ++k) + { + params.ret_status = status_tests[i]; + params.iosb_status = status_tests[j]; + + winetest_push_context("return 0x%08x, iosb 0x%08x, pending %d, method %u", + params.ret_status, params.iosb_status, params.pending, method_tests[k] & 3); + + do_return_status(method_tests[k], ¶ms); + + winetest_pop_context(); + } + } + } + } }
static BOOL compare_unicode_string(const WCHAR *buffer, ULONG len, const WCHAR *expect) @@ -765,13 +1057,25 @@ static void test_object_info(void) ok(compare_unicode_string(file_info->FileName, file_info->FileNameLength, L"\subfile"), "wrong name %s\n", debugstr_wn(file_info->FileName, file_info->FileNameLength / sizeof(WCHAR)));
+ io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; status = NtQueryVolumeInformationFile(file, &io, buffer, sizeof(buffer), FileFsVolumeInformation); ok(!status, "got %#x\n", status); + ok(!io.Status, "got status %#x\n", io.Status); + size = offsetof(FILE_FS_VOLUME_INFORMATION, VolumeLabel) + volume_info->VolumeLabelLength; + ok(io.Information == size, "expected information %Iu, got %Iu\n", size, io.Information); ok(volume_info->VolumeSerialNumber == 0xdeadbeef, "wrong serial number 0x%08x\n", volume_info->VolumeSerialNumber); ok(compare_unicode_string(volume_info->VolumeLabel, volume_info->VolumeLabelLength, L"WineTestDriver"), "wrong name %s\n", debugstr_wn(volume_info->VolumeLabel, volume_info->VolumeLabelLength / sizeof(WCHAR)));
+ io.Status = 0xdeadf00d; + io.Information = 0xdeadf00d; + status = NtQueryVolumeInformationFile(file, &io, buffer, sizeof(buffer), FileFsAttributeInformation); + ok(status == STATUS_NOT_IMPLEMENTED, "got %#x\n", status); + ok(io.Status == 0xdeadf00d, "got status %#x\n", io.Status); + ok(io.Information == 0xdeadf00d, "got information %Iu\n", io.Information); + CloseHandle(file);
file = CreateFileA("\\.\WineTestDriver\notimpl", 0, 0, NULL, OPEN_EXISTING, 0, NULL); @@ -1354,7 +1658,7 @@ static void test_pnp_devices(void) ret = NtOpenFile(&child, SYNCHRONIZE, &attr, &io, 0, 0); ok(!ret, "failed to open child: %#x\n", ret);
- ret = DeviceIoControl(child, IOCTL_WINETEST_MARK_PENDING, NULL, 0, NULL, 0, &size, &ovl); + ret = DeviceIoControl(child, IOCTL_WINETEST_CHILD_MARK_PENDING, NULL, 0, NULL, 0, &size, &ovl); ok(!ret, "DeviceIoControl succeeded\n"); ok(GetLastError() == ERROR_IO_PENDING, "got error %u\n", GetLastError()); ok(size == 0, "got size %u\n", size); @@ -1367,7 +1671,7 @@ static void test_pnp_devices(void) ok(got_child_arrival == 1, "got %u child arrival messages\n", got_child_arrival); ok(got_child_removal == 1, "got %u child removal messages\n", got_child_removal);
- ret = DeviceIoControl(child, IOCTL_WINETEST_CHECK_REMOVED, NULL, 0, NULL, 0, &size, NULL); + ret = DeviceIoControl(child, IOCTL_WINETEST_CHILD_CHECK_REMOVED, NULL, 0, NULL, 0, &size, NULL); todo_wine ok(ret, "got error %u\n", GetLastError());
ret = NtOpenFile(&tmp, SYNCHRONIZE, &attr, &io, 0, FILE_SYNCHRONOUS_IO_NONALERT); @@ -3162,7 +3466,6 @@ START_TEST(ntoskrnl) ok(device != INVALID_HANDLE_VALUE, "failed to open device: %u\n", GetLastError());
test_basic_ioctl(); - test_mismatched_status_ioctl();
main_test(); todo_wine ok(modified_value == 0xdeadbeeffeedcafe, "Got unexpected value %#I64x.\n", modified_value);
This patch introduces too many failed todos, more than 200kB worth of them:
https://testbot.winehq.org/JobDetails.pl?Key=96439#k401 https://bugs.winehq.org/show_bug.cgi?id=51696
That pushes the WineTest reports over the 1.5MB limit so that we no longer get the daily test results in Wine:
https://test.winehq.org/data/patterns-tb-wine.html https://test.winehq.org/data/errors.html
On 8/28/21 2:08 PM, Francois Gouget wrote:
This patch introduces too many failed todos, more than 200kB worth of them:
https://testbot.winehq.org/JobDetails.pl?Key=96439#k401 https://bugs.winehq.org/show_bug.cgi?id=51696
That pushes the WineTest reports over the 1.5MB limit so that we no longer get the daily test results in Wine:
https://test.winehq.org/data/patterns-tb-wine.html https://test.winehq.org/data/errors.html
Ugh, sorry about that. I usually use 'make test' so the todo messages aren't printed.
I have patches to solve all of these already written, but there's about 40 of them so it may take a while to get them all upstream. I don't know if there's a nice way to suppress messages until then. The best thing that comes to mind is to temporarily hack winetest_mute_threshold in that test to something much lower.
On Sat, 28 Aug 2021, Zebediah Figura (she/her) wrote: [...]
I have patches to solve all of these already written, but there's about 40 of them so it may take a while to get them all upstream. I don't know if there's a nice way to suppress messages until then. The best thing that comes to mind is to temporarily hack winetest_mute_threshold in that test to something much lower.
I modified the configuration of the wt-daily machines (cw-gtx560, cw-rx460 and fg-deb64) to skip the ntoskrnl.exe:ntoskrnl test so that got test results in.
I also hacked the script that runs the tests on the debiant2 VM to do the same but due to a missing space typo it instead only ran ntoskrnl.exe:ntoskrnl. I would have expected the corresponding report to be rejected but it was not so now test.winehq.org shows 726 failures for these and 480 tests with recent failures. So I need to figure out why these reports were not rejected.
A rerun sent proper results but they are hidden by default and the test.winehq.org pages are still messed up anyway. This will require more manual cleanup :-(
Anyway. Skipping ntoskrnl.exe:ntoskrnl can probably let us keep going for a few weeks until the patches fixing the todos are in.
On Sun, 29 Aug 2021, Francois Gouget wrote: [...]
I also hacked the script that runs the tests on the debiant2 VM to do the same but due to a missing space typo it instead only ran ntoskrnl.exe:ntoskrnl. I would have expected the corresponding report to be rejected but it was not so now test.winehq.org shows 726 failures for these and 480 tests with recent failures. So I need to figure out why these reports were not rejected.
With some path adjustments the following commands should clean things up:
grep -L activeds:activeds data/8e2df64cf897*/linux_*/report | \ while read f; do d=`dirname $f`; \ rm -rf "$d"; \ test -d "${d}_1" && mv "${d}_1" "$d"; \ done
gather --update data/8e2df64cf897* build-index build-patterns
* "grep -L" selects all the report files that don't contain the activeds:activeds results which Wine should always run.
* And the mv ensures that the results that are currently tagged as reruns take the place of the broken reports.
* I tested the commands here and they cleaned up my test.winehq.org mirror. To be safe one could insert echo before the rm and mv commands to make sure they do the right thing.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/kernel32/file.c | 57 ++++++------------------------------- dlls/kernel32/kernel32.spec | 2 +- 2 files changed, 10 insertions(+), 49 deletions(-)
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c index 92022063ecc..4d6f893c92d 100644 --- a/dlls/kernel32/file.c +++ b/dlls/kernel32/file.c @@ -389,21 +389,16 @@ HANDLE WINAPI OpenVxDHandle(HANDLE hHandleRing3) /**************************************************************************** * DeviceIoControl (KERNEL32.@) */ -BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, - LPVOID lpvInBuffer, DWORD cbInBuffer, - LPVOID lpvOutBuffer, DWORD cbOutBuffer, - LPDWORD lpcbBytesReturned, - LPOVERLAPPED lpOverlapped) +BOOL WINAPI KERNEL32_DeviceIoControl( HANDLE handle, DWORD code, void *in_buff, DWORD in_count, + void *out_buff, DWORD out_count, DWORD *returned, + OVERLAPPED *overlapped ) { - NTSTATUS status; - - TRACE( "(%p,%x,%p,%d,%p,%d,%p,%p)\n", - hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer, - lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped ); + TRACE( "(%p,%#x,%p,%d,%p,%d,%p,%p)\n", + handle, code, in_buff, in_count, out_buff, out_count, returned, overlapped );
/* Check if this is a user defined control code for a VxD */
- if (HIWORD( dwIoControlCode ) == 0 && (GetVersion() & 0x80000000)) + if (HIWORD( code ) == 0 && (GetVersion() & 0x80000000)) { typedef BOOL (WINAPI *DeviceIoProc)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); static DeviceIoProc (*vxd_get_proc)(HANDLE); @@ -411,45 +406,11 @@ BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
if (!vxd_get_proc) vxd_get_proc = (void *)GetProcAddress( GetModuleHandleW(L"krnl386.exe16"), "__wine_vxd_get_proc" ); - if (vxd_get_proc) proc = vxd_get_proc( hDevice ); - if (proc) return proc( dwIoControlCode, lpvInBuffer, cbInBuffer, - lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, lpOverlapped ); + if (vxd_get_proc) proc = vxd_get_proc( handle ); + if (proc) return proc( code, in_buff, in_count, out_buff, out_count, returned, overlapped ); }
- /* Not a VxD, let ntdll handle it */ - - if (lpOverlapped) - { - LPVOID cvalue = ((ULONG_PTR)lpOverlapped->hEvent & 1) ? NULL : lpOverlapped; - lpOverlapped->Internal = STATUS_PENDING; - lpOverlapped->InternalHigh = 0; - if (HIWORD(dwIoControlCode) == FILE_DEVICE_FILE_SYSTEM) - status = NtFsControlFile(hDevice, lpOverlapped->hEvent, - NULL, cvalue, (PIO_STATUS_BLOCK)lpOverlapped, - dwIoControlCode, lpvInBuffer, cbInBuffer, - lpvOutBuffer, cbOutBuffer); - else - status = NtDeviceIoControlFile(hDevice, lpOverlapped->hEvent, - NULL, cvalue, (PIO_STATUS_BLOCK)lpOverlapped, - dwIoControlCode, lpvInBuffer, cbInBuffer, - lpvOutBuffer, cbOutBuffer); - if (lpcbBytesReturned) *lpcbBytesReturned = lpOverlapped->InternalHigh; - } - else - { - IO_STATUS_BLOCK iosb; - - if (HIWORD(dwIoControlCode) == FILE_DEVICE_FILE_SYSTEM) - status = NtFsControlFile(hDevice, NULL, NULL, NULL, &iosb, - dwIoControlCode, lpvInBuffer, cbInBuffer, - lpvOutBuffer, cbOutBuffer); - else - status = NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb, - dwIoControlCode, lpvInBuffer, cbInBuffer, - lpvOutBuffer, cbOutBuffer); - if (lpcbBytesReturned) *lpcbBytesReturned = iosb.Information; - } - return set_ntstatus( status ); + return DeviceIoControl( handle, code, in_buff, in_count, out_buff, out_count, returned, overlapped ); }
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 6c02b17c7cf..90b503af19f 100644 --- a/dlls/kernel32/kernel32.spec +++ b/dlls/kernel32/kernel32.spec @@ -377,7 +377,7 @@ @ stdcall DeleteVolumeMountPointA(str) @ stdcall -import DeleteVolumeMountPointW(wstr) @ stdcall -arch=x86_64 DequeueUmsCompletionListItems(ptr long ptr) -@ stdcall DeviceIoControl(long long ptr long ptr long ptr ptr) +@ stdcall DeviceIoControl(long long ptr long ptr long ptr ptr) KERNEL32_DeviceIoControl @ stdcall -import DisableThreadLibraryCalls(long) @ stdcall -import DisconnectNamedPipe(long) @ stdcall DnsHostnameToComputerNameA (str ptr ptr)
Likely a similar treatment should be given to other kernelbase APIs, but it's not immediately clear which.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/kernelbase/file.c | 7 ++++++- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c index d21ad299d1f..74e713b7593 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c @@ -4116,7 +4116,12 @@ BOOL WINAPI DECLSPEC_HOTPATCH DeviceIoControl( HANDLE handle, DWORD code, void * in_buff, in_count, out_buff, out_count );
if (returned) *returned = piosb->Information; - return set_ntstatus( status ); + if (status == STATUS_PENDING || !NT_SUCCESS( status )) + { + SetLastError( RtlNtStatusToDosError( status )); + return FALSE; + } + return TRUE; }
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index b1fc73fb773..99f161e141c 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -663,17 +663,17 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params) size = 0xdeadf00d; SetLastError(0xdeadf00d); ret = DeviceIoControl(device, ioctl, params, sizeof(*params), buffer, sizeof(buffer), &size, NULL); - todo_wine_if (NT_SUCCESS(expect_status) != !params->iosb_status) + todo_wine_if (NT_SUCCESS(expect_status) != NT_SUCCESS(params->iosb_status)) ok(ret == NT_SUCCESS(expect_status), "got %d\n", ret); if (NT_SUCCESS(expect_status)) { - todo_wine_if (params->iosb_status) + todo_wine_if (!NT_SUCCESS(params->iosb_status)) ok(GetLastError() == 0xdeadf00d, "got error %u\n", GetLastError()); } else { todo_wine_if (RtlNtStatusToDosError(expect_status) != RtlNtStatusToDosError(params->iosb_status) - || params->iosb_status == STATUS_PENDING) + || NT_SUCCESS(params->iosb_status)) ok(GetLastError() == RtlNtStatusToDosError(expect_status), "got error %u\n", GetLastError()); } if (NT_ERROR(expect_status))
Zebediah Figura zfigura@codeweavers.com writes:
Likely a similar treatment should be given to other kernelbase APIs, but it's not immediately clear which.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
dlls/kernelbase/file.c | 7 ++++++- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-)
This breaks the tests:
tools/runtest -q -P wine -T . -M kernel32.dll -p dlls/kernel32/tests/kernel32_test.exe volume && touch dlls/kernel32/tests/volume.ok wine: Unhandled page fault on read access to 013539BB at address 7BC51E77 (thread 0024), starting debugger... Unhandled exception: page fault on read access to 0x013539bb in 32-bit code (0x7bc51e77). Register dump: CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b EIP:7bc51e77 ESP:0031fc14 EBP:0031fc18 EFLAGS:00010216( R- -- I -A-P- ) EAX:013539bb EBX:0000005c ECX:013539d1 EDX:7b09c41c ESI:00fb3998 EDI:013539bb Stack dump: 0x0031fc14: 00000002 0031fc78 7b07f615 013539bb 0x0031fc24: 7b09c41c 00000016 7b01719e 7b09c140 0x0031fc34: 00000000 00000003 00000400 00fb3978 0x0031fc44: 00000018 0031fcc8 00fb2b68 00000000 0x0031fc54: 008e02c8 00fb3978 0000005c 00000064 0x0031fc64: 00000285 0031fc90 00000064 7ffc2000 Backtrace: =>0 0x7bc51e77 memcmp+0x27(ptr2=0x7b09c41c, n=0x16) [Z:\home\julliard\wine\wine\dlls\ntdll\string.c:89] in ntdll (0x0031fc18) 1 0x7b07f615 FindNextVolumeW+0x6f(volume=<couldn't compute location>, len=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\kernelbase\volume.c:1105] in kernelbase (0x0031fc78) 2 0x7b07f90f FindFirstVolumeW+0x189(len=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\kernelbase\volume.c:1079] in kernelbase (0x0031fcf8) 3 0x7b632080 FindFirstVolumeA+0x4f(len=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\kernel32\volume.c:474] in kernel32 (0x0031fd58) 4 0x00566ed6 func_volume+0x135() [Z:\home\julliard\wine\wine\dlls\kernel32\tests\volume.c:198] in kernel32_test (0x0031fe08) 5 0x0056998b main+0x26a(argv=<is not available>) [Z:\home\julliard\wine\wine\include\wine\test.h:612] in kernel32_test (0x0031fee8) 6 0x00568bef mainCRTStartup+0x7e() [Z:\home\julliard\wine\wine\dlls\msvcrt\crt_main.c:58] in kernel32_test (0x0031ff30) 7 0x7b62e010 WriteTapemark+0xff(type=<is not available>, count=<is not available>, immediate=<is not available>) [Z:\home\julliard\wine\wine\dlls\kernel32\tape.c:317] in kernel32 (0x0031ff48) 8 0x7bc54bf7 RtlSleepConditionVariableSRW+0x226(lock=<is not available>, timeout=<is not available>, flags=<is not available>) [Z:\home\julliard\wine\wine\dlls\ntdll\sync.c:556] in ntdll (0x0031ff5c) 9 0x7bc552b0 call_thread_func+0xaf(arg=0x7ffd1000) [Z:\home\julliard\wine\wine\dlls\ntdll\thread.c:225] in ntdll (0x0031ffec) 0x7bc51e77 memcmp+0x27 [Z:\home\julliard\wine\wine\dlls\ntdll\string.c:89] in ntdll: cmpb %bl,0x0(%eax) 89 if (*p1 < *p2) return -1;
On 8/27/21 11:22 AM, Alexandre Julliard wrote:
Zebediah Figura zfigura@codeweavers.com writes:
Likely a similar treatment should be given to other kernelbase APIs, but it's not immediately clear which.
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
dlls/kernelbase/file.c | 7 ++++++- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-)
This breaks the tests:
tools/runtest -q -P wine -T . -M kernel32.dll -p dlls/kernel32/tests/kernel32_test.exe volume && touch dlls/kernel32/tests/volume.ok wine: Unhandled page fault on read access to 013539BB at address 7BC51E77 (thread 0024), starting debugger... Unhandled exception: page fault on read access to 0x013539bb in 32-bit code (0x7bc51e77). Register dump: CS:0023 SS:002b DS:002b ES:002b FS:0063 GS:006b EIP:7bc51e77 ESP:0031fc14 EBP:0031fc18 EFLAGS:00010216( R- -- I -A-P- ) EAX:013539bb EBX:0000005c ECX:013539d1 EDX:7b09c41c ESI:00fb3998 EDI:013539bb Stack dump: 0x0031fc14: 00000002 0031fc78 7b07f615 013539bb 0x0031fc24: 7b09c41c 00000016 7b01719e 7b09c140 0x0031fc34: 00000000 00000003 00000400 00fb3978 0x0031fc44: 00000018 0031fcc8 00fb2b68 00000000 0x0031fc54: 008e02c8 00fb3978 0000005c 00000064 0x0031fc64: 00000285 0031fc90 00000064 7ffc2000 Backtrace: =>0 0x7bc51e77 memcmp+0x27(ptr2=0x7b09c41c, n=0x16) [Z:\home\julliard\wine\wine\dlls\ntdll\string.c:89] in ntdll (0x0031fc18) 1 0x7b07f615 FindNextVolumeW+0x6f(volume=<couldn't compute location>, len=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\kernelbase\volume.c:1105] in kernelbase (0x0031fc78) 2 0x7b07f90f FindFirstVolumeW+0x189(len=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\kernelbase\volume.c:1079] in kernelbase (0x0031fcf8) 3 0x7b632080 FindFirstVolumeA+0x4f(len=<couldn't compute location>) [Z:\home\julliard\wine\wine\dlls\kernel32\volume.c:474] in kernel32 (0x0031fd58) 4 0x00566ed6 func_volume+0x135() [Z:\home\julliard\wine\wine\dlls\kernel32\tests\volume.c:198] in kernel32_test (0x0031fe08) 5 0x0056998b main+0x26a(argv=<is not available>) [Z:\home\julliard\wine\wine\include\wine\test.h:612] in kernel32_test (0x0031fee8) 6 0x00568bef mainCRTStartup+0x7e() [Z:\home\julliard\wine\wine\dlls\msvcrt\crt_main.c:58] in kernel32_test (0x0031ff30) 7 0x7b62e010 WriteTapemark+0xff(type=<is not available>, count=<is not available>, immediate=<is not available>) [Z:\home\julliard\wine\wine\dlls\kernel32\tape.c:317] in kernel32 (0x0031ff48) 8 0x7bc54bf7 RtlSleepConditionVariableSRW+0x226(lock=<is not available>, timeout=<is not available>, flags=<is not available>) [Z:\home\julliard\wine\wine\dlls\ntdll\sync.c:556] in ntdll (0x0031ff5c) 9 0x7bc552b0 call_thread_func+0xaf(arg=0x7ffd1000) [Z:\home\julliard\wine\wine\dlls\ntdll\thread.c:225] in ntdll (0x0031ffec) 0x7bc51e77 memcmp+0x27 [Z:\home\julliard\wine\wine\dlls\ntdll\string.c:89] in ntdll: cmpb %bl,0x0(%eax) 89 if (*p1 < *p2) return -1;
Thanks, I don't get that test failure, but I think I see the bug regardless.