Based on a patch by Qian Hong.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44812
-- v2: ntdll: Add NtQueryInformationProcess(ProcessQuotaLimits) tests. ntdll: Add NtQueryInformationProcess(ProcessQuotaLimits) stub.
From: Vijay Kiran Kamuju infyquest@gmail.com
Based on a patch by Qian Hong.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44812 Signed-off-by: Gijs Vermeulen gijsvrm@gmail.com --- dlls/ntdll/unix/process.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index 2c6dc1b43cc..b4ff3ea7fef 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -1124,7 +1124,6 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class
switch (class) { - UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits); UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority); UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority); UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort); @@ -1580,6 +1579,36 @@ NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class else ret = STATUS_INVALID_PARAMETER; break;
+ case ProcessQuotaLimits: + { + QUOTA_LIMITS qlimits; + + FIXME( "ProcessQuotaLimits (%p,%p,0x%08x,%p) stub\n", handle, info, (int)size, ret_len ); + + len = sizeof(QUOTA_LIMITS); + if (size == len) + { + if (!info) ret = STATUS_ACCESS_VIOLATION; + else if (!handle) ret = STATUS_INVALID_HANDLE; + else + { + /* FIXME: SetProcessWorkingSetSize can also set the quota values. + Quota Limits should be stored inside the process. */ + qlimits.PagedPoolLimit = (SIZE_T)-1; + qlimits.NonPagedPoolLimit = (SIZE_T)-1; + /* Default minimum working set size is 204800 bytes (50 Pages) */ + qlimits.MinimumWorkingSetSize = 204800; + /* Default maximum working set size is 1413120 bytes (345 Pages) */ + qlimits.MaximumWorkingSetSize = 1413120; + qlimits.PagefileLimit = (SIZE_T)-1; + qlimits.TimeLimit.QuadPart = -1; + memcpy(info, &qlimits, len); + } + } + else ret = STATUS_INFO_LENGTH_MISMATCH; + break; + } + default: FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n", handle, class, info, (int)size, ret_len );
From: Vijay Kiran Kamuju infyquest@gmail.com
Signed-off-by: Gijs Vermeulen gijsvrm@gmail.com --- dlls/ntdll/tests/info.c | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c index 6771bbe4e3f..26e01f0e252 100644 --- a/dlls/ntdll/tests/info.c +++ b/dlls/ntdll/tests/info.c @@ -2677,6 +2677,60 @@ static void test_query_process_debug_flags(int argc, char **argv) } }
+static void test_query_process_quota_limits(void) +{ + QUOTA_LIMITS qlimits; + NTSTATUS status; + HANDLE process; + ULONG ret_len; + + status = NtQueryInformationProcess(NULL, ProcessQuotaLimits, NULL, sizeof(qlimits), NULL); + ok(status == STATUS_ACCESS_VIOLATION || status == STATUS_INVALID_HANDLE, + "NtQueryInformationProcess failed, status %#lx.\n", status); + + status = NtQueryInformationProcess(NULL, ProcessQuotaLimits, &qlimits, sizeof(qlimits), NULL); + ok(status == STATUS_INVALID_HANDLE, "NtQueryInformationProcess failed, status %#lx.\n", status); + + process = GetCurrentProcess(); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, 2, &ret_len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationProcess failed, status %#lx.\n", status); + + memset(&qlimits, 0, sizeof(qlimits)); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, sizeof(qlimits), &ret_len); + ok(status == STATUS_SUCCESS, "NtQueryInformationProcess failed, status %#lx.\n", status); + ok(sizeof(qlimits) == ret_len, "len set to %lx\n", ret_len); + ok(qlimits.MinimumWorkingSetSize == 204800,"Expected MinimumWorkingSetSize = 204800, got %s\n", + wine_dbgstr_longlong(qlimits.MinimumWorkingSetSize)); + ok(qlimits.MaximumWorkingSetSize == 1413120,"Expected MaximumWorkingSetSize = 1413120, got %s\n", + wine_dbgstr_longlong(qlimits.MaximumWorkingSetSize)); + ok(qlimits.PagefileLimit == ~0,"Expected PagefileLimit = ~0, got %s\n", + wine_dbgstr_longlong(qlimits.PagefileLimit)); + ok(qlimits.TimeLimit.QuadPart == ~0,"Expected TimeLimit = ~0, got %s\n", + wine_dbgstr_longlong(qlimits.TimeLimit.QuadPart)); + + if (winetest_debug > 1) + { + trace("Quota Limits:\n"); + trace("PagedPoolLimit: %s\n", wine_dbgstr_longlong(qlimits.PagedPoolLimit)); + trace("NonPagedPoolLimit: %s\n", wine_dbgstr_longlong(qlimits.NonPagedPoolLimit)); + } + + memset(&qlimits, 0, sizeof(qlimits)); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, sizeof(qlimits) * 2, &ret_len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationProcess failed, status %#lx.\n", status); + ok(sizeof(qlimits) == ret_len, "len set to %lx\n", ret_len); + + memset(&qlimits, 0, sizeof(qlimits)); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, sizeof(qlimits) - 1, &ret_len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationProcess failed, status %#lx.\n", status); + ok(sizeof(qlimits) == ret_len, "len set to %lx\n", ret_len); + + memset(&qlimits, 0, sizeof(qlimits)); + status = NtQueryInformationProcess( process, ProcessQuotaLimits, &qlimits, sizeof(qlimits) + 1, &ret_len); + ok(status == STATUS_INFO_LENGTH_MISMATCH, "NtQueryInformationProcess failed, status %#lx.\n", status); + ok(sizeof(qlimits) == ret_len, "len set to %lx\n", ret_len); +} + static void test_readvirtualmemory(void) { HANDLE process; @@ -3886,6 +3940,7 @@ START_TEST(info) test_query_process_debug_object_handle(argc, argv); test_query_process_debug_flags(argc, argv); test_query_process_image_info(); + test_query_process_quota_limits(); test_mapprotection(); test_threadstack();
On Tue Mar 19 12:39:20 2024 +0000, Gijs Vermeulen wrote:
Everything after WinXP seems to return `STATUS_INVALID_HANDLE`. Wine, however, still returns STATUS_ACCESS_VIOLATION consistently in this case for other classes. It's also done like this in other tests in this file, so maybe we should leave it as-is?
We no longer test on WinXP reguarly. It doesn't make sense to allow behavior not exhibited by any actively tested Windows version. I'd suggest we leave this as todo_wine.
```suggestion:-0+0 todo_wine ok(status == STATUS_INVALID_HANDLE, ```
Other classes would need similar treatment (but not in this MR).
On Tue Mar 19 13:03:32 2024 +0000, Jinoh Kang wrote:
We no longer test on WinXP reguarly. It doesn't make sense to allow behavior not exhibited by any actively tested Windows version. I'd suggest we leave this as todo_wine.
todo_wine ok(status == STATUS_INVALID_HANDLE,
Other classes would need similar treatment (but not in this MR).
If we're "breaking consistency" anyway, wouldn't it make more sense to just return the correct value for this class?
On Tue Mar 19 13:12:32 2024 +0000, Gijs Vermeulen wrote:
If we're "breaking consistency" anyway, wouldn't it make more sense to just return the correct value for this class?
My impression is that `STATUS_ACCESS_VIOLATION` is not necessarily something you'll return after explicit check, it might come from syscall exception handling. That means that after winxp there is an invalid handle check that wasn't there before.