bpo-46417: PyWeakref_GET_OBJECT() uses PyWeakref_CheckRef() by vstinner · Pull Request #30763 · python/cpython · GitHub
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Doc/c-api/weakref.rst
35 changes: 25 additions & 10 deletions Include/cpython/weakrefobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,28 @@ PyAPI_FUNC(Py_ssize_t) _PyWeakref_GetWeakrefCount(PyWeakReference *head);

PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);

/* Explanation for the Py_REFCNT() check: when a weakref's target is part
of a long chain of deallocations which triggers the trashcan mechanism,
clearing the weakrefs can be delayed long after the target's refcount
has dropped to zero. In the meantime, code accessing the weakref will
be able to "see" the target object even though it is supposed to be
unreachable. See issue #16602. */
#define PyWeakref_GET_OBJECT(ref) \
(Py_REFCNT(((PyWeakReference *)(ref))->wr_object) > 0 \
? ((PyWeakReference *)(ref))->wr_object \
: Py_None)

static inline PyObject* _PyWeakref_GET_OBJECT(PyWeakReference *ref)
{
PyObject *obj = ref->wr_object;
assert(obj != NULL);
/* Explanation for the Py_REFCNT() check: when a weakref's target is part
of a long chain of deallocations which triggers the trashcan mechanism,
clearing the weakrefs can be delayed long after the target's refcount
has dropped to zero. In the meantime, code accessing the weakref will
be able to "see" the target object even though it is supposed to be
unreachable. See issue #16602. */
if (Py_REFCNT(obj) > 0) {
return obj;
}
else {
return Py_None;
}
}

static inline PyObject* PyWeakref_GET_OBJECT(PyWeakReference *ref)
{
assert(PyWeakref_CheckRef(ref));
return _PyWeakref_GET_OBJECT(ref);
}
#define PyWeakref_GET_OBJECT(ref) PyWeakref_GET_OBJECT((PyWeakReference*)(ref))
4 changes: 1 addition & 3 deletions Modules/_abc.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,7 @@ _in_weak_set(PyObject *set, PyObject *obj)
static PyObject *
_destroy(PyObject *setweakref, PyObject *objweakref)
{
PyObject *set;
set = PyWeakref_GET_OBJECT(setweakref);
PyObject *set = PyWeakref_GET_OBJECT(setweakref);
if (set == Py_None) {
Py_RETURN_NONE;
}
Expand Down Expand Up @@ -502,7 +501,6 @@ set_collection_flag_recursive(PyTypeObject *child, unsigned long flag)
assert(PyDict_CheckExact(grandchildren));
Py_ssize_t i = 0;
while (PyDict_Next(grandchildren, &i, NULL, &grandchildren)) {
assert(PyWeakref_CheckRef(grandchildren));
PyObject *grandchild = PyWeakref_GET_OBJECT(grandchildren);
if (PyType_Check(grandchild)) {
set_collection_flag_recursive((PyTypeObject *)grandchild, flag);
Expand Down
4 changes: 2 additions & 2 deletions Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ PyDict_SetItemProxy(PyObject *dict, PyObject *key, PyObject *item)
return result;
}

PyObject *
static PyObject *
PyDict_GetItemProxy(PyObject *dict, PyObject *key)
{
PyObject *result;
Expand All @@ -256,7 +256,7 @@ PyDict_GetItemProxy(PyObject *dict, PyObject *key)
return NULL;
if (!PyWeakref_CheckProxy(item))
return item;
result = PyWeakref_GET_OBJECT(item);
result = _PyWeakref_GET_OBJECT((PyWeakReference*)item);
if (result == Py_None)
return NULL;
return result;
Expand Down
1 change: 0 additions & 1 deletion Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,6 @@ local_getattro(localobject *self, PyObject *name)
static PyObject *
_localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref)
{
assert(PyWeakref_CheckRef(localweakref));
PyObject *obj = PyWeakref_GET_OBJECT(localweakref);
if (obj == Py_None) {
Py_RETURN_NONE;
Expand Down
4 changes: 0 additions & 4 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,6 @@ PyType_Modified(PyTypeObject *type)
assert(PyDict_CheckExact(raw));
i = 0;
while (PyDict_Next(raw, &i, NULL, &ref)) {
assert(PyWeakref_CheckRef(ref));
ref = PyWeakref_GET_OBJECT(ref);
if (ref != Py_None) {
PyType_Modified(_PyType_CAST(ref));
Expand Down Expand Up @@ -4146,7 +4145,6 @@ type___subclasses___impl(PyTypeObject *self)
assert(PyDict_CheckExact(raw));
i = 0;
while (PyDict_Next(raw, &i, NULL, &ref)) {
assert(PyWeakref_CheckRef(ref));
ref = PyWeakref_GET_OBJECT(ref);
if (ref != Py_None) {
if (PyList_Append(list, ref) < 0) {
Expand Down Expand Up @@ -8647,9 +8645,7 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *name,
assert(PyDict_CheckExact(subclasses));
i = 0;
while (PyDict_Next(subclasses, &i, NULL, &ref)) {
assert(PyWeakref_CheckRef(ref));
PyObject *obj = PyWeakref_GET_OBJECT(ref);
assert(obj != NULL);
if (obj == Py_None) {
continue;
}
Expand Down
75 changes: 37 additions & 38 deletions Objects/weakrefobject.c