mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-116008: Detect freed thread state in faulthandler (#141988)
Add _PyMem_IsULongFreed() function.
This commit is contained in:
parent
83d8134c5b
commit
d5d9e89dde
2 changed files with 40 additions and 4 deletions
|
|
@ -70,6 +70,27 @@ static inline int _PyMem_IsPtrFreed(const void *ptr)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Similar to _PyMem_IsPtrFreed() but expects an 'unsigned long' instead of a
|
||||||
|
// pointer.
|
||||||
|
static inline int _PyMem_IsULongFreed(unsigned long value)
|
||||||
|
{
|
||||||
|
#if SIZEOF_LONG == 8
|
||||||
|
return (value == 0
|
||||||
|
|| value == (unsigned long)0xCDCDCDCDCDCDCDCD
|
||||||
|
|| value == (unsigned long)0xDDDDDDDDDDDDDDDD
|
||||||
|
|| value == (unsigned long)0xFDFDFDFDFDFDFDFD
|
||||||
|
|| value == (unsigned long)0xFFFFFFFFFFFFFFFF);
|
||||||
|
#elif SIZEOF_LONG == 4
|
||||||
|
return (value == 0
|
||||||
|
|| value == (unsigned long)0xCDCDCDCD
|
||||||
|
|| value == (unsigned long)0xDDDDDDDD
|
||||||
|
|| value == (unsigned long)0xFDFDFDFD
|
||||||
|
|| value == (unsigned long)0xFFFFFFFF);
|
||||||
|
#else
|
||||||
|
# error "unknown long size"
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
extern int _PyMem_GetAllocatorName(
|
extern int _PyMem_GetAllocatorName(
|
||||||
const char *name,
|
const char *name,
|
||||||
PyMemAllocatorName *allocator);
|
PyMemAllocatorName *allocator);
|
||||||
|
|
|
||||||
|
|
@ -1094,6 +1094,9 @@ tstate_is_freed(PyThreadState *tstate)
|
||||||
if (_PyMem_IsPtrFreed(tstate->interp)) {
|
if (_PyMem_IsPtrFreed(tstate->interp)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
if (_PyMem_IsULongFreed(tstate->thread_id)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1113,7 +1116,7 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tstate_is_freed(tstate)) {
|
if (tstate_is_freed(tstate)) {
|
||||||
PUTS(fd, " <tstate is freed>\n");
|
PUTS(fd, " <freed thread state>\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1138,12 +1141,16 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
||||||
PUTS(fd, " <freed frame>\n");
|
PUTS(fd, " <freed frame>\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Read frame->previous early since memory can be freed during
|
||||||
|
// dump_frame()
|
||||||
|
_PyInterpreterFrame *previous = frame->previous;
|
||||||
|
|
||||||
if (dump_frame(fd, frame) < 0) {
|
if (dump_frame(fd, frame) < 0) {
|
||||||
PUTS(fd, " <invalid frame>\n");
|
PUTS(fd, " <invalid frame>\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = frame->previous;
|
frame = previous;
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -1240,7 +1247,9 @@ write_thread_id(int fd, PyThreadState *tstate, int is_current)
|
||||||
tstate->thread_id,
|
tstate->thread_id,
|
||||||
sizeof(unsigned long) * 2);
|
sizeof(unsigned long) * 2);
|
||||||
|
|
||||||
write_thread_name(fd, tstate);
|
if (!_PyMem_IsULongFreed(tstate->thread_id)) {
|
||||||
|
write_thread_name(fd, tstate);
|
||||||
|
}
|
||||||
|
|
||||||
PUTS(fd, " (most recent call first):\n");
|
PUTS(fd, " (most recent call first):\n");
|
||||||
}
|
}
|
||||||
|
|
@ -1298,7 +1307,6 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
||||||
return "unable to get the thread head state";
|
return "unable to get the thread head state";
|
||||||
|
|
||||||
/* Dump the traceback of each thread */
|
/* Dump the traceback of each thread */
|
||||||
tstate = PyInterpreterState_ThreadHead(interp);
|
|
||||||
unsigned int nthreads = 0;
|
unsigned int nthreads = 0;
|
||||||
_Py_BEGIN_SUPPRESS_IPH
|
_Py_BEGIN_SUPPRESS_IPH
|
||||||
do
|
do
|
||||||
|
|
@ -1309,11 +1317,18 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp,
|
||||||
PUTS(fd, "...\n");
|
PUTS(fd, "...\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tstate_is_freed(tstate)) {
|
||||||
|
PUTS(fd, "<freed thread state>\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
write_thread_id(fd, tstate, tstate == current_tstate);
|
write_thread_id(fd, tstate, tstate == current_tstate);
|
||||||
if (tstate == current_tstate && tstate->interp->gc.collecting) {
|
if (tstate == current_tstate && tstate->interp->gc.collecting) {
|
||||||
PUTS(fd, " Garbage-collecting\n");
|
PUTS(fd, " Garbage-collecting\n");
|
||||||
}
|
}
|
||||||
dump_traceback(fd, tstate, 0);
|
dump_traceback(fd, tstate, 0);
|
||||||
|
|
||||||
tstate = PyThreadState_Next(tstate);
|
tstate = PyThreadState_Next(tstate);
|
||||||
nthreads++;
|
nthreads++;
|
||||||
} while (tstate != NULL);
|
} while (tstate != NULL);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue