diff options
author | Antoine Pitrou <solipsis@pitrou.net> | 2016-12-27 13:23:43 (GMT) |
---|---|---|
committer | Antoine Pitrou <solipsis@pitrou.net> | 2016-12-27 13:23:43 (GMT) |
commit | d741ed492f17609109432f1bccac0c019a05471b (patch) | |
tree | 5b4425dfb7360f55993971d1b2fc9ebe7d1f00fa /Modules | |
parent | 34d0ac8027e23609e24588735b37b8d5a55f7223 (diff) | |
parent | e10ca3a0fe10d825689179e9958c70aef01f4230 (diff) | |
download | cpython-d741ed492f17609109432f1bccac0c019a05471b.zip cpython-d741ed492f17609109432f1bccac0c019a05471b.tar.gz cpython-d741ed492f17609109432f1bccac0c019a05471b.tar.bz2 |
Issue #28427: old keys should not remove new values from
WeakValueDictionary when collecting from another thread.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_weakref.c | 41 | ||||
-rw-r--r-- | Modules/clinic/_weakref.c.h | 32 |
2 files changed, 72 insertions, 1 deletions
diff --git a/Modules/_weakref.c b/Modules/_weakref.c index 805d6d0..f9c68d6 100644 --- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -35,6 +35,46 @@ _weakref_getweakrefcount_impl(PyObject *module, PyObject *object) } +static int +is_dead_weakref(PyObject *value) +{ + if (!PyWeakref_Check(value)) { + PyErr_SetString(PyExc_TypeError, "not a weakref"); + return -1; + } + return PyWeakref_GET_OBJECT(value) == Py_None; +} + +/*[clinic input] + +_weakref._remove_dead_weakref -> object + + dct: object(subclass_of='&PyDict_Type') + key: object + / + +Atomically remove key from dict if it points to a dead weakref. +[clinic start generated code]*/ + +static PyObject * +_weakref__remove_dead_weakref_impl(PyObject *module, PyObject *dct, + PyObject *key) +/*[clinic end generated code: output=d9ff53061fcb875c input=19fc91f257f96a1d]*/ +{ + if (_PyDict_DelItemIf(dct, key, is_dead_weakref) < 0) { + if (PyErr_ExceptionMatches(PyExc_KeyError)) + /* This function is meant to allow safe weak-value dicts + with GC in another thread (see issue #28427), so it's + ok if the key doesn't exist anymore. + */ + PyErr_Clear(); + else + return NULL; + } + Py_RETURN_NONE; +} + + PyDoc_STRVAR(weakref_getweakrefs__doc__, "getweakrefs(object) -- return a list of all weak reference objects\n" "that point to 'object'."); @@ -88,6 +128,7 @@ weakref_proxy(PyObject *self, PyObject *args) static PyMethodDef weakref_functions[] = { _WEAKREF_GETWEAKREFCOUNT_METHODDEF + _WEAKREF__REMOVE_DEAD_WEAKREF_METHODDEF {"getweakrefs", weakref_getweakrefs, METH_O, weakref_getweakrefs__doc__}, {"proxy", weakref_proxy, METH_VARARGS, diff --git a/Modules/clinic/_weakref.c.h b/Modules/clinic/_weakref.c.h index c192e72..ab84c30 100644 --- a/Modules/clinic/_weakref.c.h +++ b/Modules/clinic/_weakref.c.h @@ -29,4 +29,34 @@ _weakref_getweakrefcount(PyObject *module, PyObject *object) exit: return return_value; } -/*[clinic end generated code: output=e1ad587147323e19 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(_weakref__remove_dead_weakref__doc__, +"_remove_dead_weakref($module, dct, key, /)\n" +"--\n" +"\n" +"Atomically remove key from dict if it points to a dead weakref."); + +#define _WEAKREF__REMOVE_DEAD_WEAKREF_METHODDEF \ + {"_remove_dead_weakref", (PyCFunction)_weakref__remove_dead_weakref, METH_VARARGS, _weakref__remove_dead_weakref__doc__}, + +static PyObject * +_weakref__remove_dead_weakref_impl(PyObject *module, PyObject *dct, + PyObject *key); + +static PyObject * +_weakref__remove_dead_weakref(PyObject *module, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *dct; + PyObject *key; + + if (!PyArg_ParseTuple(args, "O!O:_remove_dead_weakref", + &PyDict_Type, &dct, &key)) { + goto exit; + } + return_value = _weakref__remove_dead_weakref_impl(module, dct, key); + +exit: + return return_value; +} +/*[clinic end generated code: output=e860dd818a44bc9b input=a9049054013a1b77]*/ |