Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2d0a3d6

Browse filesBrowse files
authored
bpo-40609: Add destroy functions to _Py_hashtable (GH-20062)
Add key_destroy_func and value_destroy_func parameters to _Py_hashtable_new_full(). marshal.c and _tracemalloc.c use these destroy functions.
1 parent f9b3b58 commit 2d0a3d6
Copy full SHA for 2d0a3d6

File tree

4 files changed

+73
-52
lines changed
Filter options

4 files changed

+73
-52
lines changed

‎Include/internal/pycore_hashtable.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_hashtable.h
+10-3Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,21 +34,21 @@ typedef struct {
3434
/* data (data_size bytes) follows */
3535
} _Py_hashtable_entry_t;
3636

37-
#define _Py_HASHTABLE_ENTRY_PDATA(TABLE, ENTRY) \
37+
#define _Py_HASHTABLE_ENTRY_PDATA(ENTRY) \
3838
((const void *)((char *)(ENTRY) \
3939
+ sizeof(_Py_hashtable_entry_t)))
4040

4141
#define _Py_HASHTABLE_ENTRY_READ_DATA(TABLE, ENTRY, DATA) \
4242
do { \
4343
assert(sizeof(DATA) == (TABLE)->data_size); \
44-
memcpy(&(DATA), _Py_HASHTABLE_ENTRY_PDATA(TABLE, (ENTRY)), \
44+
memcpy(&(DATA), _Py_HASHTABLE_ENTRY_PDATA((ENTRY)), \
4545
sizeof(DATA)); \
4646
} while (0)
4747

4848
#define _Py_HASHTABLE_ENTRY_WRITE_DATA(TABLE, ENTRY, DATA) \
4949
do { \
5050
assert(sizeof(DATA) == (TABLE)->data_size); \
51-
memcpy((void *)_Py_HASHTABLE_ENTRY_PDATA((TABLE), (ENTRY)), \
51+
memcpy((void *)_Py_HASHTABLE_ENTRY_PDATA(ENTRY), \
5252
&(DATA), sizeof(DATA)); \
5353
} while (0)
5454

@@ -61,6 +61,9 @@ typedef struct _Py_hashtable_t _Py_hashtable_t;
6161

6262
typedef Py_uhash_t (*_Py_hashtable_hash_func) (const void *key);
6363
typedef int (*_Py_hashtable_compare_func) (const void *key1, const void *key2);
64+
typedef void (*_Py_hashtable_destroy_func) (void *key);
65+
typedef void (*_Py_hashtable_value_destroy_func) (_Py_hashtable_t *ht,
66+
_Py_hashtable_entry_t *entry);
6467
typedef _Py_hashtable_entry_t* (*_Py_hashtable_get_entry_func)(_Py_hashtable_t *ht,
6568
const void *key);
6669
typedef int (*_Py_hashtable_get_func) (_Py_hashtable_t *ht,
@@ -86,6 +89,8 @@ struct _Py_hashtable_t {
8689
_Py_hashtable_get_entry_func get_entry_func;
8790
_Py_hashtable_hash_func hash_func;
8891
_Py_hashtable_compare_func compare_func;
92+
_Py_hashtable_destroy_func key_destroy_func;
93+
_Py_hashtable_value_destroy_func value_destroy_func;
8994
_Py_hashtable_allocator_t alloc;
9095
};
9196

@@ -107,6 +112,8 @@ PyAPI_FUNC(_Py_hashtable_t *) _Py_hashtable_new_full(
107112
size_t init_size,
108113
_Py_hashtable_hash_func hash_func,
109114
_Py_hashtable_compare_func compare_func,
115+
_Py_hashtable_destroy_func key_destroy_func,
116+
_Py_hashtable_value_destroy_func value_destroy_func,
110117
_Py_hashtable_allocator_t *allocator);
111118

112119
PyAPI_FUNC(void) _Py_hashtable_destroy(_Py_hashtable_t *ht);

‎Modules/_tracemalloc.c

Copy file name to clipboardExpand all lines: Modules/_tracemalloc.c
+25-26Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,13 @@ hashtable_hash_uint(const void *key_raw)
238238
static _Py_hashtable_t *
239239
hashtable_new(size_t data_size,
240240
_Py_hashtable_hash_func hash_func,
241-
_Py_hashtable_compare_func compare_func)
241+
_Py_hashtable_compare_func compare_func,
242+
_Py_hashtable_value_destroy_func value_destroy_fun)
242243
{
243244
_Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
244245
return _Py_hashtable_new_full(data_size, 0,
245246
hash_func, compare_func,
246-
&hashtable_alloc);
247+
NULL, value_destroy_fun, &hashtable_alloc);
247248
}
248249

249250

@@ -471,35 +472,34 @@ tracemalloc_create_traces_table(void)
471472
{
472473
return hashtable_new(sizeof(trace_t),
473474
_Py_hashtable_hash_ptr,
474-
_Py_hashtable_compare_direct);
475+
_Py_hashtable_compare_direct,
476+
NULL);
475477
}
476478

477479

478-
static _Py_hashtable_t*
479-
tracemalloc_create_domains_table(void)
480+
static void
481+
tracemalloc_destroy_domain_table(_Py_hashtable_t *domains,
482+
_Py_hashtable_entry_t *entry)
480483
{
481-
return hashtable_new(sizeof(_Py_hashtable_t *),
482-
hashtable_hash_uint,
483-
_Py_hashtable_compare_direct);
484+
_Py_hashtable_t *traces;
485+
_Py_HASHTABLE_ENTRY_READ_DATA(domains, entry, traces);
486+
_Py_hashtable_destroy(traces);
484487
}
485488

486489

487-
static int
488-
tracemalloc_destroy_domains_cb(_Py_hashtable_t *domains,
489-
_Py_hashtable_entry_t *entry,
490-
void *user_data)
490+
static _Py_hashtable_t*
491+
tracemalloc_create_domains_table(void)
491492
{
492-
_Py_hashtable_t *traces;
493-
_Py_HASHTABLE_ENTRY_READ_DATA(domains, entry, traces);
494-
_Py_hashtable_destroy(traces);
495-
return 0;
493+
return hashtable_new(sizeof(_Py_hashtable_t *),
494+
hashtable_hash_uint,
495+
_Py_hashtable_compare_direct,
496+
tracemalloc_destroy_domain_table);
496497
}
497498

498499

499500
static void
500501
tracemalloc_destroy_domains(_Py_hashtable_t *domains)
501502
{
502-
_Py_hashtable_foreach(domains, tracemalloc_destroy_domains_cb, NULL);
503503
_Py_hashtable_destroy(domains);
504504
}
505505

@@ -924,11 +924,13 @@ tracemalloc_init(void)
924924

925925
tracemalloc_filenames = hashtable_new(0,
926926
hashtable_hash_pyobject,
927-
hashtable_compare_unicode);
927+
hashtable_compare_unicode,
928+
NULL);
928929

929930
tracemalloc_tracebacks = hashtable_new(0,
930931
hashtable_hash_traceback,
931-
hashtable_compare_traceback);
932+
hashtable_compare_traceback,
933+
NULL);
932934

933935
tracemalloc_traces = tracemalloc_create_traces_table();
934936
tracemalloc_domains = tracemalloc_create_domains_table();
@@ -1285,15 +1287,13 @@ tracemalloc_get_traces_domain(_Py_hashtable_t *domains,
12851287
}
12861288

12871289

1288-
static int
1290+
static void
12891291
tracemalloc_pyobject_decref_cb(_Py_hashtable_t *tracebacks,
1290-
_Py_hashtable_entry_t *entry,
1291-
void *user_data)
1292+
_Py_hashtable_entry_t *entry)
12921293
{
12931294
PyObject *obj;
12941295
_Py_HASHTABLE_ENTRY_READ_DATA(tracebacks, entry, obj);
12951296
Py_DECREF(obj);
1296-
return 0;
12971297
}
12981298

12991299

@@ -1329,7 +1329,8 @@ _tracemalloc__get_traces_impl(PyObject *module)
13291329
of (filename, lineno) tuples */
13301330
get_traces.tracebacks = hashtable_new(sizeof(PyObject *),
13311331
_Py_hashtable_hash_ptr,
1332-
_Py_hashtable_compare_direct);
1332+
_Py_hashtable_compare_direct,
1333+
tracemalloc_pyobject_decref_cb);
13331334
if (get_traces.tracebacks == NULL) {
13341335
goto no_memory;
13351336
}
@@ -1381,8 +1382,6 @@ _tracemalloc__get_traces_impl(PyObject *module)
13811382

13821383
finally:
13831384
if (get_traces.tracebacks != NULL) {
1384-
_Py_hashtable_foreach(get_traces.tracebacks,
1385-
tracemalloc_pyobject_decref_cb, NULL);
13861385
_Py_hashtable_destroy(get_traces.tracebacks);
13871386
}
13881387
if (get_traces.traces != NULL) {

‎Python/hashtable.c

Copy file name to clipboardExpand all lines: Python/hashtable.c
+27-10Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,14 @@
6464
#define ENTRY_READ_PDATA(TABLE, ENTRY, DATA_SIZE, PDATA) \
6565
do { \
6666
assert((DATA_SIZE) == (TABLE)->data_size); \
67-
memcpy((PDATA), _Py_HASHTABLE_ENTRY_PDATA(TABLE, (ENTRY)), \
67+
memcpy((PDATA), _Py_HASHTABLE_ENTRY_PDATA(ENTRY), \
6868
(DATA_SIZE)); \
6969
} while (0)
7070

7171
#define ENTRY_WRITE_PDATA(TABLE, ENTRY, DATA_SIZE, PDATA) \
7272
do { \
7373
assert((DATA_SIZE) == (TABLE)->data_size); \
74-
memcpy((void *)_Py_HASHTABLE_ENTRY_PDATA((TABLE), (ENTRY)), \
74+
memcpy((void *)_Py_HASHTABLE_ENTRY_PDATA(ENTRY), \
7575
(PDATA), (DATA_SIZE)); \
7676
} while (0)
7777

@@ -432,6 +432,8 @@ _Py_hashtable_t *
432432
_Py_hashtable_new_full(size_t data_size, size_t init_size,
433433
_Py_hashtable_hash_func hash_func,
434434
_Py_hashtable_compare_func compare_func,
435+
_Py_hashtable_destroy_func key_destroy_func,
436+
_Py_hashtable_value_destroy_func value_destroy_func,
435437
_Py_hashtable_allocator_t *allocator)
436438
{
437439
_Py_hashtable_t *ht;
@@ -466,6 +468,8 @@ _Py_hashtable_new_full(size_t data_size, size_t init_size,
466468
ht->get_entry_func = _Py_hashtable_get_entry_generic;
467469
ht->hash_func = hash_func;
468470
ht->compare_func = compare_func;
471+
ht->key_destroy_func = key_destroy_func;
472+
ht->value_destroy_func = value_destroy_func;
469473
ht->alloc = alloc;
470474
if (ht->hash_func == _Py_hashtable_hash_ptr
471475
&& ht->compare_func == _Py_hashtable_compare_direct)
@@ -484,7 +488,7 @@ _Py_hashtable_new(size_t data_size,
484488
{
485489
return _Py_hashtable_new_full(data_size, HASHTABLE_MIN_SIZE,
486490
hash_func, compare_func,
487-
NULL);
491+
NULL, NULL, NULL);
488492
}
489493

490494

@@ -506,16 +510,27 @@ _Py_hashtable_clear(_Py_hashtable_t *ht)
506510
}
507511

508512

513+
static void
514+
_Py_hashtable_destroy_entry(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry)
515+
{
516+
if (ht->key_destroy_func) {
517+
ht->key_destroy_func(entry->key);
518+
}
519+
if (ht->value_destroy_func) {
520+
ht->value_destroy_func(ht, entry);
521+
}
522+
ht->alloc.free(entry);
523+
}
524+
525+
509526
void
510527
_Py_hashtable_destroy(_Py_hashtable_t *ht)
511528
{
512-
size_t i;
513-
514-
for (i = 0; i < ht->num_buckets; i++) {
515-
_Py_slist_item_t *entry = ht->buckets[i].head;
529+
for (size_t i = 0; i < ht->num_buckets; i++) {
530+
_Py_hashtable_entry_t *entry = TABLE_HEAD(ht, i);
516531
while (entry) {
517-
_Py_slist_item_t *entry_next = entry->next;
518-
ht->alloc.free(entry);
532+
_Py_hashtable_entry_t *entry_next = ENTRY_NEXT(entry);
533+
_Py_hashtable_destroy_entry(ht, entry);
519534
entry = entry_next;
520535
}
521536
}
@@ -537,6 +552,8 @@ _Py_hashtable_copy(_Py_hashtable_t *src)
537552
dst = _Py_hashtable_new_full(data_size, src->num_buckets,
538553
src->hash_func,
539554
src->compare_func,
555+
src->key_destroy_func,
556+
src->value_destroy_func,
540557
&src->alloc);
541558
if (dst == NULL)
542559
return NULL;
@@ -545,7 +562,7 @@ _Py_hashtable_copy(_Py_hashtable_t *src)
545562
entry = TABLE_HEAD(src, bucket);
546563
for (; entry; entry = ENTRY_NEXT(entry)) {
547564
const void *key = entry->key;
548-
const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(src, entry);
565+
const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(entry);
549566
err = _Py_hashtable_set(dst, key, data_size, pdata);
550567
if (err) {
551568
_Py_hashtable_destroy(dst);

‎Python/marshal.c

Copy file name to clipboardExpand all lines: Python/marshal.c
+11-13Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -545,13 +545,21 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
545545
}
546546
}
547547

548+
static void
549+
w_decref_entry(void *key)
550+
{
551+
PyObject *entry_key = (PyObject *)key;
552+
Py_XDECREF(entry_key);
553+
}
554+
548555
static int
549556
w_init_refs(WFILE *wf, int version)
550557
{
551558
if (version >= 3) {
552-
wf->hashtable = _Py_hashtable_new(sizeof(int),
553-
_Py_hashtable_hash_ptr,
554-
_Py_hashtable_compare_direct);
559+
wf->hashtable = _Py_hashtable_new_full(sizeof(int), 0,
560+
_Py_hashtable_hash_ptr,
561+
_Py_hashtable_compare_direct,
562+
w_decref_entry, NULL, NULL);
555563
if (wf->hashtable == NULL) {
556564
PyErr_NoMemory();
557565
return -1;
@@ -560,20 +568,10 @@ w_init_refs(WFILE *wf, int version)
560568
return 0;
561569
}
562570

563-
static int
564-
w_decref_entry(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry,
565-
void *Py_UNUSED(data))
566-
{
567-
PyObject *entry_key = (PyObject *)entry->key;
568-
Py_XDECREF(entry_key);
569-
return 0;
570-
}
571-
572571
static void
573572
w_clear_refs(WFILE *wf)
574573
{
575574
if (wf->hashtable != NULL) {
576-
_Py_hashtable_foreach(wf->hashtable, w_decref_entry, NULL);
577575
_Py_hashtable_destroy(wf->hashtable);
578576
}
579577
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.