Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 88c2987

Browse files
committed
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.
1 parent 1511680 commit 88c2987

1 file changed

Lines changed: 26 additions & 10 deletions

File tree

Modules/_tracemalloc.c

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -456,15 +456,13 @@ tracemalloc_add_trace(void *ptr, size_t size)
456456
trace.size = size;
457457
trace.traceback = traceback;
458458

459-
TABLES_LOCK();
460459
res = _Py_HASHTABLE_SET(tracemalloc_traces, ptr, trace);
461460
if (res == 0) {
462461
assert(tracemalloc_traced_memory <= PY_SIZE_MAX - size);
463462
tracemalloc_traced_memory += size;
464463
if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory)
465464
tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
466465
}
467-
TABLES_UNLOCK();
468466

469467
return res;
470468
}
@@ -474,12 +472,10 @@ tracemalloc_remove_trace(void *ptr)
474472
{
475473
trace_t trace;
476474

477-
TABLES_LOCK();
478475
if (_Py_hashtable_pop(tracemalloc_traces, ptr, &trace, sizeof(trace))) {
479476
assert(tracemalloc_traced_memory >= trace.size);
480477
tracemalloc_traced_memory -= trace.size;
481478
}
482-
TABLES_UNLOCK();
483479
}
484480

485481
static void*
@@ -492,11 +488,14 @@ tracemalloc_malloc(void *ctx, size_t size)
492488
if (ptr == NULL)
493489
return NULL;
494490

491+
TABLES_LOCK();
495492
if (tracemalloc_add_trace(ptr, size) < 0) {
496493
/* Failed to allocate a trace for the new memory block */
494+
TABLES_UNLOCK();
497495
alloc->free(alloc->ctx, ptr);
498496
return NULL;
499497
}
498+
TABLES_UNLOCK();
500499
return ptr;
501500
}
502501

@@ -513,26 +512,34 @@ tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
513512
if (ptr != NULL) {
514513
/* an existing memory block has been resized */
515514

515+
TABLES_LOCK();
516516
tracemalloc_remove_trace(ptr);
517517

518518
if (tracemalloc_add_trace(ptr2, new_size) < 0) {
519519
/* Memory allocation failed. The error cannot be reported to
520520
the caller, because realloc() may already have shrinked the
521521
memory block and so removed bytes.
522522
523-
This case is very unlikely since we just released an hash
524-
entry, so we have enough free bytes to allocate the new
525-
entry. */
523+
This case is very unlikely: an hash entry has just been
524+
released, so the hash table should have at least one free entry.
525+
526+
The GIL and the table lock ensures that only one thread is
527+
allocating memory. */
528+
assert(0 && "should never happen");
526529
}
530+
TABLES_UNLOCK();
527531
}
528532
else {
529533
/* new allocation */
530534

535+
TABLES_LOCK();
531536
if (tracemalloc_add_trace(ptr2, new_size) < 0) {
532537
/* Failed to allocate a trace for the new memory block */
538+
TABLES_UNLOCK();
533539
alloc->free(alloc->ctx, ptr2);
534540
return NULL;
535541
}
542+
TABLES_UNLOCK();
536543
}
537544
return ptr2;
538545
}
@@ -549,7 +556,10 @@ tracemalloc_free(void *ctx, void *ptr)
549556
a deadlock in PyThreadState_DeleteCurrent(). */
550557

551558
alloc->free(alloc->ctx, ptr);
559+
560+
TABLES_LOCK();
552561
tracemalloc_remove_trace(ptr);
562+
TABLES_UNLOCK();
553563
}
554564

555565
static void*
@@ -586,8 +596,11 @@ tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
586596
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
587597

588598
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
589-
if (ptr2 != NULL && ptr != NULL)
599+
if (ptr2 != NULL && ptr != NULL) {
600+
TABLES_LOCK();
590601
tracemalloc_remove_trace(ptr);
602+
TABLES_UNLOCK();
603+
}
591604
return ptr2;
592605
}
593606

@@ -646,9 +659,12 @@ tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
646659
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
647660

648661
ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
649-
if (ptr2 != NULL && ptr != NULL)
650-
tracemalloc_remove_trace(ptr);
651662

663+
if (ptr2 != NULL && ptr != NULL) {
664+
TABLES_LOCK();
665+
tracemalloc_remove_trace(ptr);
666+
TABLES_UNLOCK();
667+
}
652668
return ptr2;
653669
}
654670

0 commit comments

Comments
 (0)