mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
Issue #28427: old keys should not remove new values from
WeakValueDictionary when collecting from another thread.
This commit is contained in:
commit
d741ed492f
7 changed files with 195 additions and 24 deletions
|
@ -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,
|
||||
|
|
|
@ -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]*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue