gh-125434: Display thread name in faulthandler on Windows (#140675)

This commit is contained in:
Victor Stinner 2025-10-27 18:41:18 +01:00 committed by GitHub
parent 1753ccb432
commit 313145eab5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 80 additions and 14 deletions

View file

@ -506,6 +506,7 @@ pycore_init_runtime(_PyRuntimeState *runtime,
_PyRuntimeState_SetFinalizing(runtime, NULL);
_Py_InitVersion();
_Py_DumpTraceback_Init();
status = _Py_HashRandomization_Init(config);
if (_PyStatus_EXCEPTION(status)) {

View file

@ -69,6 +69,13 @@ class traceback "PyTracebackObject *" "&PyTraceback_Type"
#include "clinic/traceback.c.h"
#ifdef MS_WINDOWS
typedef HRESULT (WINAPI *PF_GET_THREAD_DESCRIPTION)(HANDLE, PCWSTR*);
static PF_GET_THREAD_DESCRIPTION pGetThreadDescription = NULL;
#endif
static PyObject *
tb_create_raw(PyTracebackObject *next, PyFrameObject *frame, int lasti,
int lineno)
@ -1107,23 +1114,12 @@ _Py_DumpTraceback(int fd, PyThreadState *tstate)
# endif
#endif
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
is_current is true, "Thread 0xHHHH:\n" otherwise.
This function is signal safe. */
// Write the thread name
static void
write_thread_id(int fd, PyThreadState *tstate, int is_current)
write_thread_name(int fd, PyThreadState *tstate)
{
if (is_current)
PUTS(fd, "Current thread 0x");
else
PUTS(fd, "Thread 0x");
_Py_DumpHexadecimal(fd,
tstate->thread_id,
sizeof(unsigned long) * 2);
// Write the thread name
#ifndef MS_WINDOWS
#if defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
char name[100];
pthread_t thread = (pthread_t)tstate->thread_id;
@ -1142,6 +1138,54 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
}
}
#endif
#else
// Windows implementation
if (pGetThreadDescription == NULL) {
return;
}
HANDLE thread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, tstate->thread_id);
if (thread == NULL) {
return;
}
wchar_t *wname;
HRESULT hr = pGetThreadDescription(thread, &wname);
if (!FAILED(hr)) {
char *name = _Py_EncodeLocaleRaw(wname, NULL);
if (name != NULL) {
size_t len = strlen(name);
if (len) {
PUTS(fd, " [");
(void)_Py_write_noraise(fd, name, len);
PUTS(fd, "]");
}
PyMem_RawFree(name);
}
LocalFree(wname);
}
CloseHandle(thread);
#endif
}
/* Write the thread identifier into the file 'fd': "Current thread 0xHHHH:\" if
is_current is true, "Thread 0xHHHH:\n" otherwise.
This function is signal safe (except on Windows). */
static void
write_thread_id(int fd, PyThreadState *tstate, int is_current)
{
if (is_current)
PUTS(fd, "Current thread 0x");
else
PUTS(fd, "Thread 0x");
_Py_DumpHexadecimal(fd,
tstate->thread_id,
sizeof(unsigned long) * 2);
write_thread_name(fd, tstate);
PUTS(fd, " (most recent call first):\n");
}
@ -1336,3 +1380,20 @@ _Py_InitDumpStack(void)
(void)backtrace(callstack, 1);
#endif
}
void
_Py_DumpTraceback_Init(void)
{
#ifdef MS_WINDOWS
if (pGetThreadDescription != NULL) {
return;
}
HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
if (kernelbase != NULL) {
pGetThreadDescription = (PF_GET_THREAD_DESCRIPTION)GetProcAddress(
kernelbase, "GetThreadDescription");
}
#endif
}