@@ -141,7 +141,7 @@ static traceback_t *tracemalloc_traceback = NULL;
141
141
Protected by the GIL */
142
142
static _Py_hashtable_t * tracemalloc_tracebacks = NULL ;
143
143
144
- /* pointer (void*) => trace (trace_t).
144
+ /* pointer (void*) => trace (trace_t* ).
145
145
Protected by TABLES_LOCK(). */
146
146
static _Py_hashtable_t * tracemalloc_traces = NULL ;
147
147
@@ -516,14 +516,23 @@ traceback_new(void)
516
516
}
517
517
518
518
519
- static int
520
- tracemalloc_use_domain_cb (_Py_hashtable_t * old_traces ,
521
- _Py_hashtable_entry_t * entry , void * user_data )
519
+ static void
520
+ tracemalloc_destroy_trace_cb (_Py_hashtable_t * traces ,
521
+ _Py_hashtable_entry_t * entry )
522
522
{
523
- return hashtable_new (sizeof (trace_t ),
523
+ trace_t * trace ;
524
+ _Py_HASHTABLE_ENTRY_READ_DATA (traces , entry , trace );
525
+ raw_free (trace );
526
+ }
527
+
528
+
529
+ static _Py_hashtable_t *
530
+ tracemalloc_create_traces_table (void )
531
+ {
532
+ return hashtable_new (sizeof (trace_t * ),
524
533
_Py_hashtable_hash_ptr ,
525
534
_Py_hashtable_compare_direct ,
526
- NULL );
535
+ tracemalloc_destroy_trace_cb );
527
536
}
528
537
529
538
_Py_HASHTABLE_ENTRY_READ_KEY (old_traces , entry , ptr );
@@ -569,8 +578,13 @@ tracemalloc_remove_trace(_PyTraceMalloc_domain_t domain, uintptr_t ptr)
569
578
return ;
570
579
}
571
580
572
- assert (tracemalloc_traced_memory >= trace .size );
573
- tracemalloc_traced_memory -= trace .size ;
581
+ trace_t * trace ;
582
+ if (!_Py_HASHTABLE_POP (traces , TO_PTR (ptr ), trace )) {
583
+ return ;
584
+ }
585
+ assert (tracemalloc_traced_memory >= trace -> size );
586
+ tracemalloc_traced_memory -= trace -> size ;
587
+ raw_free (trace );
574
588
}
575
589
576
590
#define REMOVE_TRACE (ptr ) \
@@ -609,19 +623,24 @@ tracemalloc_add_trace(_PyTraceMalloc_domain_t domain, uintptr_t ptr,
609
623
entry = _Py_HASHTABLE_GET_ENTRY (tracemalloc_traces , ptr );
610
624
}
611
625
626
+ _Py_hashtable_entry_t * entry = _Py_HASHTABLE_GET_ENTRY (traces , ptr );
612
627
if (entry != NULL ) {
613
628
/* the memory block is already tracked */
614
- _Py_HASHTABLE_ENTRY_READ_DATA (tracemalloc_traces , entry , trace );
615
- assert (tracemalloc_traced_memory >= trace .size );
616
- tracemalloc_traced_memory -= trace .size ;
629
+ trace_t * trace ;
630
+ _Py_HASHTABLE_ENTRY_READ_DATA (traces , entry , trace );
631
+ assert (tracemalloc_traced_memory >= trace -> size );
632
+ tracemalloc_traced_memory -= trace -> size ;
617
633
618
- trace .size = size ;
619
- trace .traceback = traceback ;
620
- _Py_HASHTABLE_ENTRY_WRITE_DATA (tracemalloc_traces , entry , trace );
634
+ trace -> size = size ;
635
+ trace -> traceback = traceback ;
621
636
}
622
637
else {
623
- trace .size = size ;
624
- trace .traceback = traceback ;
638
+ trace_t * trace = raw_malloc (sizeof (trace_t ));
639
+ if (trace == NULL ) {
640
+ return -1 ;
641
+ }
642
+ trace -> size = size ;
643
+ trace -> traceback = traceback ;
625
644
626
645
if (tracemalloc_config .use_domain ) {
627
646
res = _Py_HASHTABLE_SET (tracemalloc_traces , key , trace );
@@ -630,6 +649,7 @@ tracemalloc_add_trace(_PyTraceMalloc_domain_t domain, uintptr_t ptr,
630
649
res = _Py_HASHTABLE_SET (tracemalloc_traces , ptr , trace );
631
650
}
632
651
if (res != 0 ) {
652
+ raw_free (trace );
633
653
return res ;
634
654
}
635
655
}
@@ -1275,13 +1295,94 @@ typedef struct {
1275
1295
PyObject * list ;
1276
1296
} get_traces_t ;
1277
1297
1298
+
1299
+ static int
1300
+ tracemalloc_copy_trace (_Py_hashtable_t * traces ,
1301
+ _Py_hashtable_entry_t * entry ,
1302
+ void * traces2_raw )
1303
+ {
1304
+ _Py_hashtable_t * traces2 = (_Py_hashtable_t * )traces2_raw ;
1305
+
1306
+ trace_t * trace ;
1307
+ _Py_HASHTABLE_ENTRY_READ_DATA (traces , entry , trace );
1308
+
1309
+ trace_t * trace2 = raw_malloc (sizeof (trace_t ));
1310
+ if (traces2 == NULL ) {
1311
+ return -1 ;
1312
+ }
1313
+ * trace2 = * trace ;
1314
+ if (_Py_HASHTABLE_SET (traces2 , entry -> key , trace2 ) < 0 ) {
1315
+ raw_free (trace2 );
1316
+ return -1 ;
1317
+ }
1318
+ return 0 ;
1319
+ }
1320
+
1321
+
1322
+ static _Py_hashtable_t *
1323
+ tracemalloc_copy_traces (_Py_hashtable_t * traces )
1324
+ {
1325
+ _Py_hashtable_t * traces2 = tracemalloc_create_traces_table ();
1326
+ if (traces2 == NULL ) {
1327
+ return NULL ;
1328
+ }
1329
+
1330
+ int err = _Py_hashtable_foreach (traces ,
1331
+ tracemalloc_copy_trace ,
1332
+ traces2 );
1333
+ if (err ) {
1334
+ _Py_hashtable_destroy (traces2 );
1335
+ return NULL ;
1336
+ }
1337
+ return traces2 ;
1338
+ }
1339
+
1340
+
1341
+ static int
1342
+ tracemalloc_copy_domain (_Py_hashtable_t * domains ,
1343
+ _Py_hashtable_entry_t * entry ,
1344
+ void * domains2_raw )
1345
+ {
1346
+ _Py_hashtable_t * domains2 = (_Py_hashtable_t * )domains2_raw ;
1347
+
1348
+ unsigned int domain = (unsigned int )FROM_PTR (entry -> key );
1349
+ _Py_hashtable_t * traces ;
1350
+ _Py_HASHTABLE_ENTRY_READ_DATA (domains , entry , traces );
1351
+
1352
+ _Py_hashtable_t * traces2 = tracemalloc_copy_traces (traces );
1353
+ if (_Py_HASHTABLE_SET (domains2 , TO_PTR (domain ), traces2 ) < 0 ) {
1354
+ _Py_hashtable_destroy (traces2 );
1355
+ return -1 ;
1356
+ }
1357
+ return 0 ;
1358
+ }
1359
+
1360
+
1361
+ static _Py_hashtable_t *
1362
+ tracemalloc_copy_domains (_Py_hashtable_t * domains )
1363
+ {
1364
+ _Py_hashtable_t * domains2 = tracemalloc_create_domains_table ();
1365
+ if (domains2 == NULL ) {
1366
+ return NULL ;
1367
+ }
1368
+
1369
+ int err = _Py_hashtable_foreach (domains ,
1370
+ tracemalloc_copy_domain ,
1371
+ domains2 );
1372
+ if (err ) {
1373
+ _Py_hashtable_destroy (domains2 );
1374
+ return NULL ;
1375
+ }
1376
+ return domains2 ;
1377
+ }
1378
+
1379
+
1278
1380
static int
1279
1381
tracemalloc_get_traces_fill (_Py_hashtable_t * traces , _Py_hashtable_entry_t * entry ,
1280
1382
void * user_data )
1281
1383
{
1282
1384
get_traces_t * get_traces = user_data ;
1283
- _PyTraceMalloc_domain_t domain ;
1284
- trace_t trace ;
1385
+ trace_t * trace ;
1285
1386
PyObject * tracemalloc_obj ;
1286
1387
int res ;
1287
1388
@@ -1295,7 +1396,7 @@ tracemalloc_get_traces_fill(_Py_hashtable_t *traces, _Py_hashtable_entry_t *entr
1295
1396
}
1296
1397
_Py_HASHTABLE_ENTRY_READ_DATA (traces , entry , trace );
1297
1398
1298
- tracemalloc_obj = trace_to_pyobject (domain , & trace , get_traces -> tracebacks );
1399
+ tracemalloc_obj = trace_to_pyobject (get_traces -> domain , trace , get_traces -> tracebacks );
1299
1400
if (tracemalloc_obj == NULL )
1300
1401
return 1 ;
1301
1402
@@ -1368,22 +1469,37 @@ py_tracemalloc_get_traces(PyObject *self, PyObject *obj)
1368
1469
_Py_hashtable_compare_direct ,
1369
1470
tracemalloc_pyobject_decref_cb );
1370
1471
if (get_traces .tracebacks == NULL ) {
1371
- PyErr_NoMemory ();
1372
- goto error ;
1472
+ goto no_memory ;
1373
1473
}
1374
1474
1475
+ // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable
1476
+ // temporarily tracemalloc which would impact other threads and so would
1477
+ // miss allocations while get_traces() is called.
1375
1478
TABLES_LOCK ();
1376
- get_traces .traces = _Py_hashtable_copy (tracemalloc_traces );
1479
+ get_traces .traces = tracemalloc_copy_traces (tracemalloc_traces );
1377
1480
TABLES_UNLOCK ();
1378
1481
1379
1482
if (get_traces .traces == NULL ) {
1380
- PyErr_NoMemory ();
1381
- goto error ;
1483
+ goto no_memory ;
1484
+ }
1485
+
1486
+ TABLES_LOCK ();
1487
+ get_traces .domains = tracemalloc_copy_domains (tracemalloc_domains );
1488
+ TABLES_UNLOCK ();
1489
+
1490
+ if (get_traces .domains == NULL ) {
1491
+ goto no_memory ;
1382
1492
}
1383
1493
1384
1494
set_reentrant (1 );
1385
- err = _Py_hashtable_foreach (get_traces .traces ,
1386
- tracemalloc_get_traces_fill , & get_traces );
1495
+ int err = _Py_hashtable_foreach (get_traces .traces ,
1496
+ tracemalloc_get_traces_fill ,
1497
+ & get_traces );
1498
+ if (!err ) {
1499
+ err = _Py_hashtable_foreach (get_traces .domains ,
1500
+ tracemalloc_get_traces_domain ,
1501
+ & get_traces );
1502
+ }
1387
1503
set_reentrant (0 );
1388
1504
if (err )
1389
1505
goto error ;
@@ -1408,7 +1524,7 @@ py_tracemalloc_get_traces(PyObject *self, PyObject *obj)
1408
1524
static traceback_t *
1409
1525
tracemalloc_get_traceback (_PyTraceMalloc_domain_t domain , uintptr_t ptr )
1410
1526
{
1411
- trace_t trace ;
1527
+ trace_t * trace ;
1412
1528
int found ;
1413
1529
1414
1530
if (!tracemalloc_config .tracing )
@@ -1424,10 +1540,11 @@ tracemalloc_get_traceback(_PyTraceMalloc_domain_t domain, uintptr_t ptr)
1424
1540
}
1425
1541
TABLES_UNLOCK ();
1426
1542
1427
- if (!found )
1543
+ if (!found ) {
1428
1544
return NULL ;
1545
+ }
1429
1546
1430
- return trace . traceback ;
1547
+ return trace -> traceback ;
1431
1548
}
1432
1549
1433
1550
@@ -1803,6 +1920,52 @@ _PyTraceMalloc_Untrack(_PyTraceMalloc_domain_t domain, uintptr_t ptr)
1803
1920
}
1804
1921
1805
1922
1923
+ /* If the object memory block is already traced, update its trace
1924
+ with the current Python traceback.
1925
+
1926
+ Do nothing if tracemalloc is not tracing memory allocations
1927
+ or if the object memory block is not already traced. */
1928
+ int
1929
+ _PyTraceMalloc_NewReference (PyObject * op )
1930
+ {
1931
+ assert (PyGILState_Check ());
1932
+
1933
+ if (!_Py_tracemalloc_config .tracing ) {
1934
+ /* tracemalloc is not tracing: do nothing */
1935
+ return -1 ;
1936
+ }
1937
+
1938
+ uintptr_t ptr ;
1939
+ PyTypeObject * type = Py_TYPE (op );
1940
+ if (PyType_IS_GC (type )) {
1941
+ ptr = (uintptr_t )((char * )op - sizeof (PyGC_Head ));
1942
+ }
1943
+ else {
1944
+ ptr = (uintptr_t )op ;
1945
+ }
1946
+
1947
+ int res = -1 ;
1948
+
1949
+ TABLES_LOCK ();
1950
+ _Py_hashtable_entry_t * entry ;
1951
+ entry = _Py_HASHTABLE_GET_ENTRY (tracemalloc_traces , ptr );
1952
+ if (entry != NULL ) {
1953
+ /* update the traceback of the memory block */
1954
+ traceback_t * traceback = traceback_new ();
1955
+ if (traceback != NULL ) {
1956
+ trace_t * trace ;
1957
+ _Py_HASHTABLE_ENTRY_READ_DATA (tracemalloc_traces , entry , trace );
1958
+ trace -> traceback = traceback ;
1959
+ res = 0 ;
1960
+ }
1961
+ }
1962
+ /* else: cannot track the object, its memory block size is unknown */
1963
+ TABLES_UNLOCK ();
1964
+
1965
+ return res ;
1966
+ }
1967
+
1968
+
1806
1969
PyObject *
1807
1970
_PyTraceMalloc_GetTraceback (_PyTraceMalloc_domain_t domain , uintptr_t ptr )
1808
1971
{
0 commit comments