Paul Gofman : ntdll: Return sufficient info size at once from NtQuerySystemInformation(SystemProcessInformation).
Alexandre Julliard
julliard at winehq.org
Wed Oct 27 16:26:04 CDT 2021
Module: wine
Branch: master
Commit: b5f3ddd185808e45e702490348493919dac95ad2
URL: https://source.winehq.org/git/wine.git/?a=commit;h=b5f3ddd185808e45e702490348493919dac95ad2
Author: Paul Gofman <pgofman at codeweavers.com>
Date: Mon Oct 25 21:46:19 2021 +0300
ntdll: Return sufficient info size at once from NtQuerySystemInformation(SystemProcessInformation).
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntdll/tests/info.c | 43 +++++++++++++++++++++++++++++-------------
dlls/ntdll/unix/system.c | 17 +++++++++++++----
include/wine/server_protocol.h | 4 +++-
server/process.c | 4 ++++
server/protocol.def | 2 ++
server/request.h | 4 +++-
server/trace.c | 2 ++
7 files changed, 57 insertions(+), 19 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/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 8a85e0bc4ff..6e38d0b075d 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -2029,6 +2029,8 @@ struct list_processes_reply
struct reply_header __header;
data_size_t info_size;
int process_count;
+ int total_thread_count;
+ data_size_t total_name_len;
/* VARARG(data,process_info,info_size); */
};
@@ -6259,7 +6261,7 @@ union generic_reply
/* ### protocol_version begin ### */
-#define SERVER_PROTOCOL_VERSION 733
+#define SERVER_PROTOCOL_VERSION 734
/* ### protocol_version end ### */
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
diff --git a/server/request.h b/server/request.h
index 778e7272bf5..33d4237f49f 100644
--- a/server/request.h
+++ b/server/request.h
@@ -1127,7 +1127,9 @@ C_ASSERT( sizeof(struct get_mapping_filename_reply) == 16 );
C_ASSERT( sizeof(struct list_processes_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct list_processes_reply, info_size) == 8 );
C_ASSERT( FIELD_OFFSET(struct list_processes_reply, process_count) == 12 );
-C_ASSERT( sizeof(struct list_processes_reply) == 16 );
+C_ASSERT( FIELD_OFFSET(struct list_processes_reply, total_thread_count) == 16 );
+C_ASSERT( FIELD_OFFSET(struct list_processes_reply, total_name_len) == 20 );
+C_ASSERT( sizeof(struct list_processes_reply) == 24 );
C_ASSERT( FIELD_OFFSET(struct create_debug_obj_request, access) == 12 );
C_ASSERT( FIELD_OFFSET(struct create_debug_obj_request, flags) == 16 );
C_ASSERT( sizeof(struct create_debug_obj_request) == 24 );
diff --git a/server/trace.c b/server/trace.c
index 5a2afac504a..6e78f8281f0 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2287,6 +2287,8 @@ static void dump_list_processes_reply( const struct list_processes_reply *req )
{
fprintf( stderr, " info_size=%u", req->info_size );
fprintf( stderr, ", process_count=%d", req->process_count );
+ fprintf( stderr, ", total_thread_count=%d", req->total_thread_count );
+ fprintf( stderr, ", total_name_len=%u", req->total_name_len );
dump_varargs_process_info( ", data=", min(cur_size,req->info_size) );
}
More information about the wine-cvs
mailing list