Skip to content

Commit 932eb3f

Browse files
fix: avoid use after free in Counter.update
1 parent d986124 commit 932eb3f

1 file changed

Lines changed: 29 additions & 17 deletions

File tree

Modules/_collectionsmodule.c

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include "Python.h"
22
#include "pycore_call.h" // _PyObject_CallNoArgs()
3-
#include "pycore_dict.h" // _PyDict_GetItem_KnownHash()
3+
#include "pycore_dict.h" // _PyDict_GetItemRef_KnownHash_LockHeld()
44
#include "pycore_long.h" // _PyLong_GetZero()
55
#include "pycore_moduleobject.h" // _PyModule_GetState()
66
#include "pycore_pyatomic_ft_wrappers.h"
@@ -2595,24 +2595,36 @@ _collections__count_elements_impl(PyObject *module, PyObject *mapping,
25952595
goto done;
25962596
}
25972597

2598-
oldval = _PyDict_GetItem_KnownHash(mapping, key, hash);
2599-
if (oldval == NULL) {
2600-
if (PyErr_Occurred())
2601-
goto done;
2602-
if (_PyDict_SetItem_KnownHash(mapping, key, one, hash) < 0)
2603-
goto done;
2604-
} else {
2605-
/* oldval is a borrowed reference. Keep it alive across
2606-
PyNumber_Add(), which can execute arbitrary user code and
2607-
mutate (or even clear) the underlying dict. */
2608-
Py_INCREF(oldval);
2598+
int found;
2599+
int cs_err = 0;
2600+
Py_BEGIN_CRITICAL_SECTION(mapping);
2601+
found = _PyDict_GetItemRef_KnownHash_LockHeld(
2602+
(PyDictObject *)mapping, key, hash, &oldval);
2603+
if (found < 0) {
2604+
cs_err = -1;
2605+
}
2606+
else if (found == 0) {
2607+
if (_PyDict_SetItem_KnownHash_LockHeld(
2608+
(PyDictObject *)mapping, key, one, hash) < 0) {
2609+
cs_err = -1;
2610+
}
2611+
}
2612+
else {
26092613
newval = PyNumber_Add(oldval, one);
26102614
Py_DECREF(oldval);
2611-
if (newval == NULL)
2612-
goto done;
2613-
if (_PyDict_SetItem_KnownHash(mapping, key, newval, hash) < 0)
2614-
goto done;
2615-
Py_CLEAR(newval);
2615+
oldval = NULL;
2616+
if (newval == NULL) {
2617+
cs_err = -1;
2618+
}
2619+
else if (_PyDict_SetItem_KnownHash_LockHeld(
2620+
(PyDictObject *)mapping, key, newval, hash) < 0) {
2621+
cs_err = -1;
2622+
}
2623+
}
2624+
Py_END_CRITICAL_SECTION();
2625+
Py_CLEAR(newval);
2626+
if (cs_err < 0) {
2627+
goto done;
26162628
}
26172629
Py_DECREF(key);
26182630
}

0 commit comments

Comments
 (0)