Close #19741: tracemalloc_realloc() does not release the table lock anymore
between tracemalloc_remove_trace() and tracemalloc_add_trace() to reduce the risk of race condition. tracemalloc_add_trace() cannot fail anymore in tracemalloc_realloc() when tracemalloc_realloc() resizes a memory block.
This commit is contained in:
parent
1511680b79
commit
88c29877c7
|
@ -456,7 +456,6 @@ tracemalloc_add_trace(void *ptr, size_t size)
|
||||||
trace.size = size;
|
trace.size = size;
|
||||||
trace.traceback = traceback;
|
trace.traceback = traceback;
|
||||||
|
|
||||||
TABLES_LOCK();
|
|
||||||
res = _Py_HASHTABLE_SET(tracemalloc_traces, ptr, trace);
|
res = _Py_HASHTABLE_SET(tracemalloc_traces, ptr, trace);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
assert(tracemalloc_traced_memory <= PY_SIZE_MAX - size);
|
assert(tracemalloc_traced_memory <= PY_SIZE_MAX - size);
|
||||||
|
@ -464,7 +463,6 @@ tracemalloc_add_trace(void *ptr, size_t size)
|
||||||
if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory)
|
if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory)
|
||||||
tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
|
tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
|
||||||
}
|
}
|
||||||
TABLES_UNLOCK();
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -474,12 +472,10 @@ tracemalloc_remove_trace(void *ptr)
|
||||||
{
|
{
|
||||||
trace_t trace;
|
trace_t trace;
|
||||||
|
|
||||||
TABLES_LOCK();
|
|
||||||
if (_Py_hashtable_pop(tracemalloc_traces, ptr, &trace, sizeof(trace))) {
|
if (_Py_hashtable_pop(tracemalloc_traces, ptr, &trace, sizeof(trace))) {
|
||||||
assert(tracemalloc_traced_memory >= trace.size);
|
assert(tracemalloc_traced_memory >= trace.size);
|
||||||
tracemalloc_traced_memory -= trace.size;
|
tracemalloc_traced_memory -= trace.size;
|
||||||
}
|
}
|
||||||
TABLES_UNLOCK();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
|
@ -492,11 +488,14 @@ tracemalloc_malloc(void *ctx, size_t size)
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
TABLES_LOCK();
|
||||||
if (tracemalloc_add_trace(ptr, size) < 0) {
|
if (tracemalloc_add_trace(ptr, size) < 0) {
|
||||||
/* Failed to allocate a trace for the new memory block */
|
/* Failed to allocate a trace for the new memory block */
|
||||||
|
TABLES_UNLOCK();
|
||||||
alloc->free(alloc->ctx, ptr);
|
alloc->free(alloc->ctx, ptr);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
TABLES_UNLOCK();
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,6 +512,7 @@ tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
|
||||||
if (ptr != NULL) {
|
if (ptr != NULL) {
|
||||||
/* an existing memory block has been resized */
|
/* an existing memory block has been resized */
|
||||||
|
|
||||||
|
TABLES_LOCK();
|
||||||
tracemalloc_remove_trace(ptr);
|
tracemalloc_remove_trace(ptr);
|
||||||
|
|
||||||
if (tracemalloc_add_trace(ptr2, new_size) < 0) {
|
if (tracemalloc_add_trace(ptr2, new_size) < 0) {
|
||||||
|
@ -520,19 +520,26 @@ tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
|
||||||
the caller, because realloc() may already have shrinked the
|
the caller, because realloc() may already have shrinked the
|
||||||
memory block and so removed bytes.
|
memory block and so removed bytes.
|
||||||
|
|
||||||
This case is very unlikely since we just released an hash
|
This case is very unlikely: an hash entry has just been
|
||||||
entry, so we have enough free bytes to allocate the new
|
released, so the hash table should have at least one free entry.
|
||||||
entry. */
|
|
||||||
|
The GIL and the table lock ensures that only one thread is
|
||||||
|
allocating memory. */
|
||||||
|
assert(0 && "should never happen");
|
||||||
}
|
}
|
||||||
|
TABLES_UNLOCK();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* new allocation */
|
/* new allocation */
|
||||||
|
|
||||||
|
TABLES_LOCK();
|
||||||
if (tracemalloc_add_trace(ptr2, new_size) < 0) {
|
if (tracemalloc_add_trace(ptr2, new_size) < 0) {
|
||||||
/* Failed to allocate a trace for the new memory block */
|
/* Failed to allocate a trace for the new memory block */
|
||||||
|
TABLES_UNLOCK();
|
||||||
alloc->free(alloc->ctx, ptr2);
|
alloc->free(alloc->ctx, ptr2);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
TABLES_UNLOCK();
|
||||||
}
|
}
|
||||||
return ptr2;
|
return ptr2;
|
||||||
}
|
}
|
||||||
|
@ -549,7 +556,10 @@ tracemalloc_free(void *ctx, void *ptr)
|
||||||
a deadlock in PyThreadState_DeleteCurrent(). */
|
a deadlock in PyThreadState_DeleteCurrent(). */
|
||||||
|
|
||||||
alloc->free(alloc->ctx, ptr);
|
alloc->free(alloc->ctx, ptr);
|
||||||
|
|
||||||
|
TABLES_LOCK();
|
||||||
tracemalloc_remove_trace(ptr);
|
tracemalloc_remove_trace(ptr);
|
||||||
|
TABLES_UNLOCK();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static void*
|
||||||
|
@ -586,8 +596,11 @@ tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
|
||||||
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
|
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
|
||||||
|
|
||||||
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
|
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
|
||||||
if (ptr2 != NULL && ptr != NULL)
|
if (ptr2 != NULL && ptr != NULL) {
|
||||||
|
TABLES_LOCK();
|
||||||
tracemalloc_remove_trace(ptr);
|
tracemalloc_remove_trace(ptr);
|
||||||
|
TABLES_UNLOCK();
|
||||||
|
}
|
||||||
return ptr2;
|
return ptr2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -646,9 +659,12 @@ tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
|
||||||
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
|
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
|
||||||
|
|
||||||
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
|
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
|
||||||
if (ptr2 != NULL && ptr != NULL)
|
|
||||||
tracemalloc_remove_trace(ptr);
|
|
||||||
|
|
||||||
|
if (ptr2 != NULL && ptr != NULL) {
|
||||||
|
TABLES_LOCK();
|
||||||
|
tracemalloc_remove_trace(ptr);
|
||||||
|
TABLES_UNLOCK();
|
||||||
|
}
|
||||||
return ptr2;
|
return ptr2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue