[PATCH v2 1/3] ntdll: Return sufficient info size at once from NtQuerySystemInformation(SystemProcessInformation).
Paul Gofman
pgofman at codeweavers.com
Mon Oct 25 13:46:19 CDT 2021
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
dlls/ntdll/tests/info.c | 43 ++++++++++++++++++++++++++++------------
dlls/ntdll/unix/system.c | 17 ++++++++++++----
server/process.c | 4 ++++
server/protocol.def | 2 ++
4 files changed, 49 insertions(+), 17 deletions(-)
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 6e71f0848ec..635c551383c 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -470,25 +470,30 @@ static void test_query_process(void)
SYSTEM_THREAD_INFORMATION ti[1];
} SYSTEM_PROCESS_INFORMATION_PRIVATE;
- ULONG SystemInformationLength = sizeof(SYSTEM_PROCESS_INFORMATION_PRIVATE);
- SYSTEM_PROCESS_INFORMATION_PRIVATE *spi, *spi_buf = HeapAlloc(GetProcessHeap(), 0, SystemInformationLength);
+ SYSTEM_PROCESS_INFORMATION_PRIVATE *spi, *spi_buf;
+ BOOL current_process_found = FALSE;
/* test ReturnLength */
ReturnLength = 0;
status = pNtQuerySystemInformation(SystemProcessInformation, NULL, 0, &ReturnLength);
ok( status == STATUS_INFO_LENGTH_MISMATCH, "Expected STATUS_INFO_LENGTH_MISMATCH got %08x\n", status);
- ok( ReturnLength > 0, "got 0 length\n");
+ ok( ReturnLength > 0, "got 0 length\n" );
- /* W2K3 and later returns the needed length, the rest returns 0, so we have to loop */
- for (;;)
+ /* W2K3 and later returns the needed length, the rest returns 0. */
+ if (!ReturnLength)
{
- status = pNtQuerySystemInformation(SystemProcessInformation, spi_buf, SystemInformationLength, &ReturnLength);
-
- if (status != STATUS_INFO_LENGTH_MISMATCH) break;
-
- spi_buf = HeapReAlloc(GetProcessHeap(), 0, spi_buf , SystemInformationLength *= 2);
+ win_skip( "Zero return length, skipping tests." );
+ return;
}
- ok( status == STATUS_SUCCESS, "Expected STATUS_SUCCESS, got %08x\n", status);
+
+ spi_buf = HeapAlloc(GetProcessHeap(), 0, ReturnLength);
+ status = pNtQuerySystemInformation(SystemProcessInformation, spi_buf, ReturnLength, &ReturnLength);
+
+ /* Sometimes new process or threads appear between the call and increase the size,
+ * otherwise the previously returned buffer size should be sufficient. */
+ ok( status == STATUS_SUCCESS || status == STATUS_INFO_LENGTH_MISMATCH,
+ "Expected STATUS_SUCCESS, got %08x\n", status );
+
spi = spi_buf;
for (;;)
@@ -496,9 +501,16 @@ static void test_query_process(void)
DWORD_PTR tid;
DWORD j;
+ winetest_push_context( "i %u (%s)", i, debugstr_w(spi->ProcessName.Buffer) );
+
i++;
last_pid = (DWORD_PTR)spi->UniqueProcessId;
+ ok( !(last_pid & 3), "Unexpected PID low bits: %p\n", spi->UniqueProcessId );
+
+ if (last_pid == GetCurrentProcessId())
+ current_process_found = TRUE;
+
ok(!(last_pid & 3), "Unexpected PID low bits: %p\n", spi->UniqueProcessId);
for (j = 0; j < spi->dwThreadCount; j++)
{
@@ -511,12 +523,17 @@ static void test_query_process(void)
ok(!(tid & 3), "Unexpected TID low bits: %p\n", spi->ti[j].ClientId.UniqueThread);
}
- if (!spi->NextEntryOffset) break;
-
+ if (!spi->NextEntryOffset)
+ {
+ winetest_pop_context();
+ break;
+ }
one_before_last_pid = last_pid;
spi = (SYSTEM_PROCESS_INFORMATION_PRIVATE*)((char*)spi + spi->NextEntryOffset);
+ winetest_pop_context();
}
+ ok( current_process_found, "Test process not found.\n" );
if (winetest_debug > 1) trace("%u processes, %u threads\n", i, k);
if (one_before_last_pid == 0) one_before_last_pid = last_pid;
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c
index c6bbabd85c5..33e7083d18b 100644
--- a/dlls/ntdll/unix/system.c
+++ b/dlls/ntdll/unix/system.c
@@ -2446,10 +2446,13 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
case SystemProcessInformation: /* 5 */
{
- unsigned int process_count, i, j;
+ unsigned int process_count, total_thread_count, total_name_len, i, j;
char *buffer = NULL;
unsigned int pos = 0;
+C_ASSERT( sizeof(struct thread_info) <= sizeof(SYSTEM_THREAD_INFORMATION) );
+C_ASSERT( sizeof(struct process_info) <= sizeof(SYSTEM_PROCESS_INFORMATION) );
+
if (size && !(buffer = malloc( size )))
{
ret = STATUS_NO_MEMORY;
@@ -2460,19 +2463,25 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
{
wine_server_set_reply( req, buffer, size );
ret = wine_server_call( req );
- len = reply->info_size;
+ total_thread_count = reply->total_thread_count;
+ total_name_len = reply->total_name_len;
process_count = reply->process_count;
}
SERVER_END_REQ;
+ len = 0;
+
if (ret)
{
+ if (ret == STATUS_INFO_LENGTH_MISMATCH)
+ len = sizeof(SYSTEM_PROCESS_INFORMATION) * process_count
+ + (total_name_len + process_count) * sizeof(WCHAR)
+ + total_thread_count * sizeof(SYSTEM_THREAD_INFORMATION);
+
free( buffer );
break;
}
- len = 0;
-
for (i = 0; i < process_count; i++)
{
SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + len);
diff --git a/server/process.c b/server/process.c
index d8d09698558..b6ad4e47bd4 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1868,6 +1868,8 @@ DECL_HANDLER(list_processes)
char *buffer;
reply->process_count = 0;
+ reply->total_thread_count = 0;
+ reply->total_name_len = 0;
reply->info_size = 0;
LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry )
@@ -1877,6 +1879,8 @@ DECL_HANDLER(list_processes)
reply->info_size = (reply->info_size + 7) & ~7;
reply->info_size += process->running_threads * sizeof(struct thread_info);
reply->process_count++;
+ reply->total_thread_count += process->running_threads;
+ reply->total_name_len += process->imagelen;
}
if (reply->info_size > get_reply_max_size())
diff --git a/server/protocol.def b/server/protocol.def
index 0f58dc7c85a..7d27fa382d2 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1624,6 +1624,8 @@ struct process_info
@REPLY
data_size_t info_size;
int process_count;
+ int total_thread_count;
+ data_size_t total_name_len;
VARARG(data,process_info,info_size);
@END
--
2.31.1
More information about the wine-devel
mailing list