From dfaac47afc3df529d920f40c0c0ffdd59f0ef7f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 23 Nov 2025 22:18:39 +0100 Subject: [PATCH] [KERNEL32_VISTA] Reimplement [Get|Set]ThreadDescription() (#8484) - `GetThreadDescription()`: since there may be concurrent `SetThreadDescription()` invocations being executed, we need to loop over the buffer allocation size until we can successfully capture the thread name. Also, we can directly re-use the temporary buffer, after resizing, for the output description buffer. - `SetThreadDescription()`: Use `RtlInitUnicodeStringEx()` instead of reimplementing its internal logic. --- .../kernel32/kernel32_vista/CMakeLists.txt | 4 +- .../kernel32_vista/SetThreadDescription.c | 28 ------ .../kernel32_vista/ThreadDescription.c | 93 +++++++++++++++++++ .../kernel32_vista/kernel32_vista.spec | 1 + 4 files changed, 96 insertions(+), 30 deletions(-) delete mode 100644 dll/win32/kernel32/kernel32_vista/SetThreadDescription.c create mode 100644 dll/win32/kernel32/kernel32_vista/ThreadDescription.c diff --git a/dll/win32/kernel32/kernel32_vista/CMakeLists.txt b/dll/win32/kernel32/kernel32_vista/CMakeLists.txt index 28ba7f5a3ab..a53bd7a324e 100644 --- a/dll/win32/kernel32/kernel32_vista/CMakeLists.txt +++ b/dll/win32/kernel32/kernel32_vista/CMakeLists.txt @@ -7,8 +7,8 @@ include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/subsys ..) spec2def(kernel32_vista.dll kernel32_vista.spec ADD_IMPORTLIB) list(APPEND SOURCE - firmware.c EnumSystemLocalesEx.c + firmware.c GetLocaleInfoEx.c GetFileInformationByHandleEx.c GetFinalPathNameByHandle.c @@ -19,8 +19,8 @@ list(APPEND SOURCE IsValidLocaleName.c LCIDToLocaleName.c LocaleNameToLCID.c - SetThreadDescription.c sync.c + ThreadDescription.c threadpool.c vista.c) diff --git a/dll/win32/kernel32/kernel32_vista/SetThreadDescription.c b/dll/win32/kernel32/kernel32_vista/SetThreadDescription.c deleted file mode 100644 index 35ead9efd61..00000000000 --- a/dll/win32/kernel32/kernel32_vista/SetThreadDescription.c +++ /dev/null @@ -1,28 +0,0 @@ - -#include "k32_vista.h" -#define NDEBUG -#include - -#undef TRACE -#define TRACE DPRINT - -/*********************************************************************** - * SetThreadDescription (kernelbase.@) - */ -HRESULT WINAPI DECLSPEC_HOTPATCH SetThreadDescription( HANDLE thread, PCWSTR description ) -{ - THREAD_NAME_INFORMATION info; - int length; - - TRACE( "(%p, %s)\n", thread, debugstr_w( description )); - - length = description ? lstrlenW( description ) * sizeof(WCHAR) : 0; - - if (length > USHRT_MAX) - return HRESULT_FROM_NT(STATUS_INVALID_PARAMETER); - - info.ThreadName.Length = info.ThreadName.MaximumLength = length; - info.ThreadName.Buffer = (WCHAR *)description; - - return HRESULT_FROM_NT(NtSetInformationThread( thread, ThreadNameInformation, &info, sizeof(info) )); -} diff --git a/dll/win32/kernel32/kernel32_vista/ThreadDescription.c b/dll/win32/kernel32/kernel32_vista/ThreadDescription.c new file mode 100644 index 00000000000..5425022de8f --- /dev/null +++ b/dll/win32/kernel32/kernel32_vista/ThreadDescription.c @@ -0,0 +1,93 @@ +/* + * PROJECT: ReactOS Win32 Base API + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: NT10+ Thread Description helpers + * COPYRIGHT: Copyright 2025-2026 Hermès Bélusca-Maïto + */ + +#include "k32_vista.h" + +HRESULT +WINAPI +DECLSPEC_HOTPATCH +GetThreadDescription( + _In_ HANDLE hThread, + _Outptr_result_z_ PWSTR* ppszThreadDescription) +{ + PTHREAD_NAME_INFORMATION NameInfo = NULL; + PVOID ptr; + NTSTATUS Status; + ULONG Length; + + *ppszThreadDescription = NULL; + + /* Since there may be concurrent SetThreadDescription() invocations being + * executed, we need to loop over the buffer allocation size until we can + * successfully capture the thread name. */ + Length = 0; + Status = NtQueryInformationThread(hThread, ThreadNameInformation, NULL, 0, &Length); + if (Status != STATUS_BUFFER_TOO_SMALL) + return HRESULT_FROM_NT(Status); + + /* Loop again only if we get buffer-too-small types of errors; + * otherwise, break the loop: any error will be handled below. */ + while (Status == STATUS_INFO_LENGTH_MISMATCH || + Status == STATUS_BUFFER_TOO_SMALL) + { + /* (Re-)allocate the information buffer */ + ptr = (NameInfo ? LocalReAlloc(NameInfo, Length, LMEM_MOVEABLE) + : LocalAlloc(LMEM_FIXED, Length)); + if (!ptr) + { + Status = STATUS_NO_MEMORY; + break; + } + NameInfo = ptr; + Status = NtQueryInformationThread(hThread, ThreadNameInformation, + NameInfo, Length, &Length); + } + if (!NT_SUCCESS(Status)) + { + LocalFree(NameInfo); + return HRESULT_FROM_NT(Status); + } + + /* + * We already have a suitable memory buffer, containing a UNICODE_STRING + * followed by the actual string data. Just move the string back to the + * beginning of the buffer and resize it down. Since sizeof(UNICODE_STRING) + * is larger than sizeof(WCHAR), we also have space for the NUL-terminator. + */ + *ppszThreadDescription = (PWSTR)NameInfo; + Length = NameInfo->ThreadName.Length; + if (Length) + RtlMoveMemory(*ppszThreadDescription, NameInfo->ThreadName.Buffer, Length); + (*ppszThreadDescription)[Length / sizeof(WCHAR)] = UNICODE_NULL; + + /* Resize down the buffer. If the call fails, the old buffer + * is still valid, but is larger than what is necessary. */ + ptr = LocalReAlloc(*ppszThreadDescription, Length + sizeof(WCHAR), LMEM_FIXED); + if (ptr) + *ppszThreadDescription = ptr; + + return HRESULT_FROM_NT(Status); +} + +HRESULT +WINAPI +DECLSPEC_HOTPATCH +SetThreadDescription( + _In_ HANDLE hThread, + _In_ PCWSTR lpThreadDescription) +{ + THREAD_NAME_INFORMATION NameInfo; + NTSTATUS Status; + + Status = RtlInitUnicodeStringEx(&NameInfo.ThreadName, lpThreadDescription); + if (NT_SUCCESS(Status)) + { + Status = NtSetInformationThread(hThread, ThreadNameInformation, + &NameInfo, sizeof(NameInfo)); + } + return HRESULT_FROM_NT(Status); +} diff --git a/dll/win32/kernel32/kernel32_vista/kernel32_vista.spec b/dll/win32/kernel32/kernel32_vista/kernel32_vista.spec index c5b35d49ce6..1835aa6c176 100644 --- a/dll/win32/kernel32/kernel32_vista/kernel32_vista.spec +++ b/dll/win32/kernel32/kernel32_vista/kernel32_vista.spec @@ -59,6 +59,7 @@ @ stdcall CompareStringOrdinal(ptr long ptr long long) @ stdcall GetNamedPipeClientProcessId(ptr ptr) +@ stdcall GetThreadDescription(ptr ptr) # Win 10 @ stdcall SetThreadDescription(ptr wstr) # Win 10 @ stdcall GetSystemTimePreciseAsFileTime(ptr) kernel32.GetSystemTimeAsFileTime @ stdcall TrySubmitThreadpoolCallback(ptr ptr ptr)