mirror of
https://github.com/python/cpython.git
synced 2025-12-23 09:19:18 +00:00
[3.13] gh-128679: Fix tracemalloc.stop() race conditions (#128897)
tracemalloc_alloc(), tracemalloc_realloc(), PyTraceMalloc_Track(),
PyTraceMalloc_Untrack() and _PyTraceMalloc_TraceRef() now check
tracemalloc_config.tracing after calling TABLES_LOCK().
_PyTraceMalloc_Stop() now protects more code with TABLES_LOCK(),
especially setting tracemalloc_config.tracing to 1.
Add a test using PyTraceMalloc_Track() to test tracemalloc.stop()
race condition.
Call _PyTraceMalloc_Init() at Python startup.
(cherry picked from commit 6b47499510)
This commit is contained in:
parent
83de72e5ec
commit
6df22cbf60
7 changed files with 250 additions and 116 deletions
|
|
@ -3238,6 +3238,105 @@ test_atexit(PyObject *self, PyObject *Py_UNUSED(args))
|
|||
|
||||
static PyObject *test_buildvalue_issue38913(PyObject *, PyObject *);
|
||||
|
||||
|
||||
static void
|
||||
tracemalloc_track_race_thread(void *data)
|
||||
{
|
||||
PyTraceMalloc_Track(123, 10, 1);
|
||||
|
||||
PyThread_type_lock lock = (PyThread_type_lock)data;
|
||||
PyThread_release_lock(lock);
|
||||
}
|
||||
|
||||
// gh-128679: Test fix for tracemalloc.stop() race condition
|
||||
static PyObject *
|
||||
tracemalloc_track_race(PyObject *self, PyObject *args)
|
||||
{
|
||||
#define NTHREAD 50
|
||||
PyObject *tracemalloc = NULL;
|
||||
PyObject *stop = NULL;
|
||||
PyThread_type_lock locks[NTHREAD];
|
||||
memset(locks, 0, sizeof(locks));
|
||||
|
||||
// Call tracemalloc.start()
|
||||
tracemalloc = PyImport_ImportModule("tracemalloc");
|
||||
if (tracemalloc == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *start = PyObject_GetAttrString(tracemalloc, "start");
|
||||
if (start == NULL) {
|
||||
goto error;
|
||||
}
|
||||
PyObject *res = PyObject_CallNoArgs(start);
|
||||
Py_DECREF(start);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
|
||||
stop = PyObject_GetAttrString(tracemalloc, "stop");
|
||||
Py_CLEAR(tracemalloc);
|
||||
if (stop == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Start threads
|
||||
for (size_t i = 0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = PyThread_allocate_lock();
|
||||
if (!lock) {
|
||||
PyErr_NoMemory();
|
||||
goto error;
|
||||
}
|
||||
locks[i] = lock;
|
||||
PyThread_acquire_lock(lock, 1);
|
||||
|
||||
unsigned long thread;
|
||||
thread = PyThread_start_new_thread(tracemalloc_track_race_thread,
|
||||
(void*)lock);
|
||||
if (thread == (unsigned long)-1) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "can't start new thread");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// Call tracemalloc.stop() while threads are running
|
||||
res = PyObject_CallNoArgs(stop);
|
||||
Py_CLEAR(stop);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
|
||||
// Wait until threads complete with the GIL released
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
for (size_t i = 0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
PyThread_acquire_lock(lock, 1);
|
||||
PyThread_release_lock(lock);
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
// Free threads locks
|
||||
for (size_t i=0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
PyThread_free_lock(lock);
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
Py_CLEAR(tracemalloc);
|
||||
Py_CLEAR(stop);
|
||||
for (size_t i=0; i < NTHREAD; i++) {
|
||||
PyThread_type_lock lock = locks[i];
|
||||
if (lock) {
|
||||
PyThread_free_lock(lock);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
#undef NTHREAD
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef TestMethods[] = {
|
||||
{"set_errno", set_errno, METH_VARARGS},
|
||||
{"test_config", test_config, METH_NOARGS},
|
||||
|
|
@ -3378,6 +3477,7 @@ static PyMethodDef TestMethods[] = {
|
|||
{"function_get_kw_defaults", function_get_kw_defaults, METH_O, NULL},
|
||||
{"function_set_kw_defaults", function_set_kw_defaults, METH_VARARGS, NULL},
|
||||
{"test_atexit", test_atexit, METH_NOARGS},
|
||||
{"tracemalloc_track_race", tracemalloc_track_race, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -219,10 +219,5 @@ PyInit__tracemalloc(void)
|
|||
if (m == NULL)
|
||||
return NULL;
|
||||
|
||||
if (_PyTraceMalloc_Init() < 0) {
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue