8000 bpo-46417: PyWeakref_GET_OBJECT() uses PyWeakref_CheckRef() by vstinner · Pull Request #30763 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-46417: PyWeakref_GET_OBJECT() uses PyWeakref_CheckRef() #30763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
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
bpo-46417: PyWeakref_GET_OBJECT() uses PyWeakref_CheckRef()
PyWeakref_GET_OBJECT() now ensures that the its argument is valid
using PyWeakref_CheckRef().

* Convert PyWeakref_GET_OBJECT() macro to a static inline function.
* Remove now redundant assert(PyWeakref_CheckRef(ref)) before
  PyWeakref_GET_OBJECT(ref) calls.
* Add proxy_get_object() to proxy functions.
* _ctypes PyDict_GetItemProxy() uses the private
  _PyWeakref_GET_OBJECT() function.
* Cleanup weakrefobject.c.
  • Loading branch information
vstinner committed Jan 21, 2022
commit 6822ad09bbc9c1515d7f0ab7f7552bb0c6529814
4 changes: 2 additions & 2 deletions Doc/c-api/weakref.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,5 @@ as much as it can.

.. c:function:: PyObject* PyWeakref_GET_OBJECT(PyObject *ref)

Similar to :c:func:`PyWeakref_GetObject`, but implemented as a macro that does no
error checking.
Similar to :c:func:`PyWeakref_GetObject`, but implemented as a static inline
function which only check errors with assertions.
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
Original file line number Diff line number Diff line change
Expand Up @@ -131,22 +131,22 @@ static PyObject *
weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
{
static char *kwlist[] = {NULL};

if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
PyObject *object = PyWeakref_GET_OBJECT(self);
Py_INCREF(object);
return (object);
if (!PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
return NULL;
}
return NULL;

return Py_NewRef(PyWeakref_GET_OBJECT(self));
}


static Py_hash_t
weakref_hash(PyWeakReference *self)
{
if (self->hash != -1)
if (self->hash != -1) {
return self->hash;
PyObject* obj = PyWeakref_GET_OBJECT(self);
}

PyObject *obj = PyWeakref_GET_OBJECT(self);
if (obj == Py_None) {
PyErr_SetString(PyExc_TypeError, "weak object has gone away");
return -1;
Expand All @@ -163,7 +163,7 @@ weakref_repr(PyWeakReference *self)
{
PyObject *name, *repr;
_Py_IDENTIFIER(__name__);
PyObject* obj = PyWeakref_GET_OBJECT(self);
PyObject *obj = PyWeakref_GET_OBJECT(self);

if (obj == Py_None) {
return PyUnicode_FromFormat("<weakref at %p; dead>", self);
Expand All @@ -177,17 +177,12 @@ weakref_repr(PyWeakReference *self)
if (name == NULL || !PyUnicode_Check(name)) {
repr = PyUnicode_FromFormat(
"<weakref at %p; to '%s' at %p>",
self,
Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
obj);
self, Py_TYPE(obj)->tp_name, obj);
}
else {
repr = PyUnicode_FromFormat(
"<weakref at %p; to '%s' at %p (%U)>",
self,
Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
obj,
name);
self, Py_TYPE(obj)->tp_name, obj, name);
}
Py_DECREF(obj);
Py_XDECREF(name);
Expand All @@ -206,8 +201,9 @@ weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
!PyWeakref_Check(other)) {
Py_RETURN_NOTIMPLEMENTED;
}
if (PyWeakref_GET_OBJECT(self) == Py_None
|| PyWeakref_GET_OBJECT(other) == Py_None) {
PyObject* obj = PyWeakref_GET_OBJECT(self);
PyObject* other_obj = PyWeakref_GET_OBJECT(other);
if (obj == Py_None || other_obj == Py_None) {
int res = (self == other);
if (op == Py_NE)
res = !res;
Expand All @@ -216,8 +212,6 @@ weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
else
Py_RETURN_FALSE;
}
PyObject* obj = PyWeakref_GET_OBJECT(self);
PyObject* other_obj = PyWeakref_GET_OBJECT(other);
Py_INCREF(obj);
Py_INCREF(other_obj);
PyObject* res = PyObject_RichCompare(obj, other_obj, op);
Expand Down Expand Up @@ -413,10 +407,18 @@ _PyWeakref_RefType = {
};


static inline PyObject*
proxy_get_object(PyWeakReference *ref)
{
assert(PyWeakref_CheckProxy(ref));
return _PyWeakref_GET_OBJECT(ref);
}


static int
proxy_checkref(PyWeakReference *proxy)
{
if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
if (proxy_get_object(proxy) == Py_None) {
PyErr_SetString(PyExc_ReferenceError,
"weakly-referenced object no longer exists");
return 0;
Expand All @@ -431,9 +433,10 @@ proxy_checkref(PyWeakReference *proxy)
*/
#define UNWRAP(o) \
if (PyWeakref_CheckProxy(o)) { \
if (!proxy_checkref((PyWeakReference *)o)) \
PyWeakReference *_proxy = (PyWeakReference *)o; \
if (!proxy_checkref(_proxy)) \
return NULL; \
o = PyWeakref_GET_OBJECT(o); \
o = proxy_get_object(_proxy); \
}

#define WRAP_UNARY(method, generic) \
Expand Down Expand Up @@ -500,20 +503,20 @@ WRAP_TERNARY(proxy_call, PyObject_Call)
static PyObject *
proxy_repr(PyWeakReference *proxy)
{
PyObject *obj = proxy_get_object(proxy);
return PyUnicode_FromFormat(
"<weakproxy at %p to %s at %p>",
proxy,
Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
PyWeakref_GET_OBJECT(proxy));
proxy, Py_TYPE(obj)->tp_name, obj);
}


static int
proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
{
if (!proxy_checkref(proxy))
if (!proxy_checkref(proxy)) {
return -1;
PyObject *obj = PyWeakref_GET_OBJECT(proxy);
}
PyObject *obj = proxy_get_object(proxy);
Py_INCREF(obj);
int res = PyObject_SetAttr(obj, name, value);
Py_DECREF(obj);
Expand Down Expand Up @@ -567,7 +570,7 @@ WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
static int
proxy_bool(PyWeakReference *proxy)
{
PyObject *o = PyWeakref_GET_OBJECT(proxy);
PyObject *o = proxy_get_object(proxy);
if (!proxy_checkref(proxy)) {
return -1;
}
Expand All @@ -594,8 +597,7 @@ proxy_contains(PyWeakReference *proxy, PyObject *value)
if (!proxy_checkref(proxy))
return -1;

PyObject *obj = PyWeakref_GET_OBJECT(proxy);
Py_INCREF(obj);
PyObject *obj = Py_NewRef(proxy_get_object(proxy));
int res = PySequence_Contains(obj, value);
Py_DECREF(obj);
return res;
Expand All @@ -609,8 +611,7 @@ proxy_length(PyWeakReference *proxy)
if (!proxy_checkref(proxy))
return -1;

PyObject *obj = PyWeakref_GET_OBJECT(proxy);
Py_INCREF(obj);
PyObject *obj = Py_NewRef(proxy_get_object(proxy));
Py_ssize_t res = PyObject_Length(obj);
Py_DECREF(obj);
return res;
Expand All @@ -624,8 +625,7 @@ proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
if (!proxy_checkref(proxy))
return -1;

PyObject *obj = PyWeakref_GET_OBJECT(proxy);
Py_INCREF(obj);
PyObject *obj = Py_NewRef(proxy_get_object(proxy));
int res;
if (value == NULL) {
res = PyObject_DelItem(obj, key);
Expand All @@ -643,8 +643,7 @@ proxy_iter(PyWeakReference *proxy)
{
if (!proxy_checkref(proxy))
return NULL;
PyObject *obj = PyWeakref_GET_OBJECT(proxy);
Py_INCREF(obj);
PyObject *obj = Py_NewRef(proxy_get_object(proxy));
PyObject* res = PyObject_GetIter(obj);
Py_DECREF(obj);
return res;
Expand All @@ -656,7 +655,7 @@ proxy_iternext(PyWeakReference *proxy)
if (!proxy_checkref(proxy))
return NULL;

PyObject *obj = PyWeakref_GET_OBJECT(proxy);
PyObject *obj = proxy_get_object(proxy);
if (!PyIter_Check(obj)) {
PyErr_Format(PyExc_TypeError,
"Weakref proxy referenced a non-iterator '%.200s' object",
Expand Down
0