cpython: e5ce7bdf9e99 (original) (raw)

Mercurial > cpython

changeset 105853:e5ce7bdf9e99

Issue #28427: old keys should not remove new values from WeakValueDictionary when collecting from another thread. [#28427]

Antoine Pitrou solipsis@pitrou.net
date Tue, 27 Dec 2016 14:34:54 +0100
parents 77f5f31bf699(current diff)97d6616b2d22(diff)
children 3a2595f82447
files Include/dictobject.h Misc/NEWS Objects/dictobject.c
diffstat 7 files changed, 194 insertions(+), 22 deletions(-)[+] [-] Include/dictobject.h 2 Lib/test/test_weakref.py 12 Lib/weakref.py 34 Misc/NEWS 3 Modules/_weakref.c 41 Modules/clinic/_weakref.c.h 32 Objects/dictobject.c 92

line wrap: on

line diff

--- a/Include/dictobject.h +++ b/Include/dictobject.h @@ -88,6 +88,8 @@ PyAPI_FUNC(int) PyDict_DelItem(PyObject #ifndef Py_LIMITED_API PyAPI_FUNC(int) _PyDict_DelItem_KnownHash(PyObject *mp, PyObject *key, Py_hash_t hash); +PyAPI_FUNC(int) _PyDict_DelItemIf(PyObject *mp, PyObject *key,

#endif PyAPI_FUNC(void) PyDict_Clear(PyObject *mp); PyAPI_FUNC(int) PyDict_Next(

--- a/Lib/test/test_weakref.py +++ b/Lib/test/test_weakref.py @@ -1676,6 +1676,18 @@ class MappingTestCase(TestBase): x = d.pop(10, 10) self.assertIsNot(x, None) # we never put None in there

+ from test import mapping_tests

--- a/Lib/weakref.py +++ b/Lib/weakref.py @@ -16,7 +16,8 @@ from _weakref import ( proxy, CallableProxyType, ProxyType,

from _weakrefset import WeakSet, _IterationGuard @@ -111,7 +112,9 @@ class WeakValueDictionary(collections.Mu if self._iterating: self._pending_removals.append(wr.key) else:

@@ -125,9 +128,12 @@ class WeakValueDictionary(collections.Mu # We shouldn't encounter any KeyError, because this method should # always be called before mutating the dict. while l:

def getitem(self, key):

@@ -140,9 +146,13 @@ class WeakValueDictionary(collections.Mu del self.data[key] def len(self):

def contains(self, key):

@@ -158,6 +168,8 @@ class WeakValueDictionary(collections.Mu self.data[key] = KeyedRef(value, self._remove, key) def copy(self):

@@ -169,6 +181,8 @@ class WeakValueDictionary(collections.Mu def deepcopy(self, memo): from copy import deepcopy

@@ -177,6 +191,8 @@ class WeakValueDictionary(collections.Mu return new def get(self, key, default=None):

@@ -190,6 +206,8 @@ class WeakValueDictionary(collections.Mu return o def items(self):

@@ -197,6 +215,8 @@ class WeakValueDictionary(collections.Mu yield k, v def keys(self):

@@ -214,10 +234,14 @@ class WeakValueDictionary(collections.Mu keep the values around longer than needed. """

def values(self):

@@ -290,6 +314,8 @@ class WeakValueDictionary(collections.Mu keep the values around longer than needed. """

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -208,6 +208,9 @@ Core and Builtins Library ------- +- Issue #28427: old keys should not remove new values from

--- a/Modules/_weakref.c +++ b/Modules/_weakref.c @@ -35,6 +35,46 @@ static Py_ssize_t } +static int +is_dead_weakref(PyObject *value) +{

+} + +/*[clinic input] + +_weakref._remove_dead_weakref -> object +

+/[clinic end generated code: output=d9ff53061fcb875c input=19fc91f257f96a1d]/ +{

+} + + 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 * static PyMethodDef weakref_functions[] = { _WEAKREF_GETWEAKREFCOUNT_METHODDEF

--- a/Modules/clinic/_weakref.c.h +++ b/Modules/clinic/weakref.c.h @@ -29,4 +29,34 @@ static PyObject 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 [](#l6.15)

+ +static PyObject * +_weakref__remove_dead_weakref_impl(PyObject *module, PyObject *dct,

+ +static PyObject * +_weakref__remove_dead_weakref(PyObject *module, PyObject *args) +{

+

+ +exit:

+} +/[clinic end generated code: output=e860dd818a44bc9b input=a9049054013a1b77]/

--- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1583,11 +1583,32 @@ int return insertdict(mp, key, hash, value); } +static int +delitem_common(PyDictObject *mp, Py_ssize_t hashpos, Py_ssize_t ix,

+{

+

+

+} + int PyDict_DelItem(PyObject *op, PyObject *key) { Py_hash_t hash; - assert(key); if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { @@ -1604,8 +1625,7 @@ int { Py_ssize_t hashpos, ix; PyDictObject *mp;

if (!PyDict_Check(op)) { PyErr_BadInternalCall(); @@ -1632,22 +1652,60 @@ int assert(ix >= 0); }

-

} +/* This function promises that the predicate -> deletion sequence is atomic

+{

+

+

+

+} + + void PyDict_Clear(PyObject *op) {