Skip to content

Commit ecbd4a5

Browse files
committed
don't call dict watcher callback with dead dict
1 parent 71db5db commit ecbd4a5

File tree

3 files changed

+10
-0
lines changed

3 files changed

+10
-0
lines changed

Include/internal/pycore_dict.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ _PyDict_NotifyEvent(PyDict_WatchEvent event,
164164
PyObject *key,
165165
PyObject *value)
166166
{
167+
assert(Py_REFCNT((PyObject*)mp) > 0);
167168
int watcher_bits = mp->ma_version_tag & DICT_VERSION_MASK;
168169
if (watcher_bits) {
169170
_PyDict_SendEvent(watcher_bits, event, mp, key, value);

Lib/test/test_capi/test_watchers.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,12 @@ def test_error(self):
113113
self.assertEqual(str(cm.unraisable.exc_value), "boom!")
114114
self.assert_events([])
115115

116+
def test_dealloc_error(self):
117+
d = {}
118+
with self.watcher(kind=self.ERROR) as wid:
119+
self.watch(wid, d)
120+
del d
121+
116122
def test_two_watchers(self):
117123
d1 = {}
118124
d2 = {}

Objects/dictobject.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,7 +2308,10 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value)
23082308
static void
23092309
dict_dealloc(PyDictObject *mp)
23102310
{
2311+
Py_INCREF(mp);
23112312
_PyDict_NotifyEvent(PyDict_EVENT_DEALLOCATED, mp, NULL, NULL);
2313+
assert(Py_REFCNT(mp) == 1);
2314+
Py_SET_REFCNT(mp, 0);
23122315
PyDictValues *values = mp->ma_values;
23132316
PyDictKeysObject *keys = mp->ma_keys;
23142317
Py_ssize_t i, n;

0 commit comments

Comments
 (0)