gh-105927: Add _PyWeakref_GET_REF() internal function (#105929)

Add new pycore_weakref.h internal header file.
This commit is contained in:
Victor Stinner 2023-06-20 08:52:40 +02:00 committed by GitHub
parent 03f1a132ee
commit cb388c9a85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 49 deletions

View File

@ -0,0 +1,40 @@
#ifndef Py_INTERNAL_WEAKREF_H
#define Py_INTERNAL_WEAKREF_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef Py_BUILD_CORE
# error "this header requires Py_BUILD_CORE define"
#endif
static inline PyObject* _PyWeakref_GET_REF(PyObject *ref_obj) {
assert(PyWeakref_Check(ref_obj));
PyWeakReference *ref = _Py_CAST(PyWeakReference*, ref_obj);
PyObject *obj = ref->wr_object;
if (obj == Py_None) {
// clear_weakref() was called
return 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 gh-60806.
Py_ssize_t refcnt = Py_REFCNT(obj);
if (refcnt == 0) {
return NULL;
}
assert(refcnt > 0);
return Py_NewRef(obj);
}
#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_WEAKREF_H */

View File

@ -1801,6 +1801,7 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_unicodeobject.h \ $(srcdir)/Include/internal/pycore_unicodeobject.h \
$(srcdir)/Include/internal/pycore_unicodeobject_generated.h \ $(srcdir)/Include/internal/pycore_unicodeobject_generated.h \
$(srcdir)/Include/internal/pycore_warnings.h \ $(srcdir)/Include/internal/pycore_warnings.h \
$(srcdir)/Include/internal/pycore_weakref.h \
$(DTRACE_HEADERS) \ $(DTRACE_HEADERS) \
@PLATFORM_HEADERS@ \ @PLATFORM_HEADERS@ \
\ \

View File

@ -1,5 +1,6 @@
#include "Python.h" #include "Python.h"
#include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR() #include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR()
#include "pycore_weakref.h" // _PyWeakref_GET_REF()
#include "structmember.h" // PyMemberDef #include "structmember.h" // PyMemberDef
@ -147,12 +148,11 @@ weakref_hash(PyWeakReference *self)
{ {
if (self->hash != -1) if (self->hash != -1)
return self->hash; return self->hash;
PyObject* obj = PyWeakref_GET_OBJECT(self); PyObject* obj = _PyWeakref_GET_REF((PyObject*)self);
if (obj == Py_None) { if (obj == NULL) {
PyErr_SetString(PyExc_TypeError, "weak object has gone away"); PyErr_SetString(PyExc_TypeError, "weak object has gone away");
return -1; return -1;
} }
Py_INCREF(obj);
self->hash = PyObject_Hash(obj); self->hash = PyObject_Hash(obj);
Py_DECREF(obj); Py_DECREF(obj);
return self->hash; return self->hash;
@ -162,15 +162,13 @@ weakref_hash(PyWeakReference *self)
static PyObject * static PyObject *
weakref_repr(PyObject *self) weakref_repr(PyObject *self)
{ {
PyObject *name, *repr; PyObject* obj = _PyWeakref_GET_REF(self);
PyObject* obj = PyWeakref_GET_OBJECT(self); if (obj == NULL) {
if (obj == Py_None) {
return PyUnicode_FromFormat("<weakref at %p; dead>", self); return PyUnicode_FromFormat("<weakref at %p; dead>", self);
} }
Py_INCREF(obj); PyObject *name = _PyObject_LookupSpecial(obj, &_Py_ID(__name__));
name = _PyObject_LookupSpecial(obj, &_Py_ID(__name__)); PyObject *repr;
if (name == NULL || !PyUnicode_Check(name)) { if (name == NULL || !PyUnicode_Check(name)) {
repr = PyUnicode_FromFormat( repr = PyUnicode_FromFormat(
"<weakref at %p; to '%s' at %p>", "<weakref at %p; to '%s' at %p>",
@ -191,16 +189,18 @@ weakref_repr(PyObject *self)
gone away, they are equal if they are identical. */ gone away, they are equal if they are identical. */
static PyObject * static PyObject *
weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op) weakref_richcompare(PyObject* self, PyObject* other, int op)
{ {
if ((op != Py_EQ && op != Py_NE) || if ((op != Py_EQ && op != Py_NE) ||
!PyWeakref_Check(self) || !PyWeakref_Check(self) ||
!PyWeakref_Check(other)) { !PyWeakref_Check(other)) {
Py_RETURN_NOTIMPLEMENTED; Py_RETURN_NOTIMPLEMENTED;
} }
PyObject* obj = PyWeakref_GET_OBJECT(self); PyObject* obj = _PyWeakref_GET_REF(self);
PyObject* other_obj = PyWeakref_GET_OBJECT(other); PyObject* other_obj = _PyWeakref_GET_REF(other);
if (obj == Py_None || other_obj == Py_None) { if (obj == NULL || other_obj == NULL) {
Py_XDECREF(obj);
Py_XDECREF(other_obj);
int res = (self == other); int res = (self == other);
if (op == Py_NE) if (op == Py_NE)
res = !res; res = !res;
@ -209,8 +209,6 @@ weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
else else
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }
Py_INCREF(obj);
Py_INCREF(other_obj);
PyObject* res = PyObject_RichCompare(obj, other_obj, op); PyObject* res = PyObject_RichCompare(obj, other_obj, op);
Py_DECREF(obj); Py_DECREF(obj);
Py_DECREF(other_obj); Py_DECREF(other_obj);
@ -372,7 +370,7 @@ _PyWeakref_RefType = {
Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE, Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_BASETYPE,
.tp_traverse = (traverseproc)gc_traverse, .tp_traverse = (traverseproc)gc_traverse,
.tp_clear = (inquiry)gc_clear, .tp_clear = (inquiry)gc_clear,
.tp_richcompare = (richcmpfunc)weakref_richcompare, .tp_richcompare = weakref_richcompare,
.tp_methods = weakref_methods, .tp_methods = weakref_methods,
.tp_members = weakref_members, .tp_members = weakref_members,
.tp_init = weakref___init__, .tp_init = weakref___init__,
@ -385,7 +383,7 @@ _PyWeakref_RefType = {
static bool static bool
proxy_check_ref(PyObject *obj) proxy_check_ref(PyObject *obj)
{ {
if (obj == Py_None) { if (obj == NULL) {
PyErr_SetString(PyExc_ReferenceError, PyErr_SetString(PyExc_ReferenceError,
"weakly-referenced object no longer exists"); "weakly-referenced object no longer exists");
return false; return false;
@ -400,16 +398,19 @@ proxy_check_ref(PyObject *obj)
*/ */
#define UNWRAP(o) \ #define UNWRAP(o) \
if (PyWeakref_CheckProxy(o)) { \ if (PyWeakref_CheckProxy(o)) { \
o = PyWeakref_GET_OBJECT(o); \ o = _PyWeakref_GET_REF(o); \
if (!proxy_check_ref(o)) \ if (!proxy_check_ref(o)) { \
return NULL; \ return NULL; \
} \
} \
else { \
Py_INCREF(o); \
} }
#define WRAP_UNARY(method, generic) \ #define WRAP_UNARY(method, generic) \
static PyObject * \ static PyObject * \
method(PyObject *proxy) { \ method(PyObject *proxy) { \
UNWRAP(proxy); \ UNWRAP(proxy); \
Py_INCREF(proxy); \
PyObject* res = generic(proxy); \ PyObject* res = generic(proxy); \
Py_DECREF(proxy); \ Py_DECREF(proxy); \
return res; \ return res; \
@ -420,8 +421,6 @@ proxy_check_ref(PyObject *obj)
method(PyObject *x, PyObject *y) { \ method(PyObject *x, PyObject *y) { \
UNWRAP(x); \ UNWRAP(x); \
UNWRAP(y); \ UNWRAP(y); \
Py_INCREF(x); \
Py_INCREF(y); \
PyObject* res = generic(x, y); \ PyObject* res = generic(x, y); \
Py_DECREF(x); \ Py_DECREF(x); \
Py_DECREF(y); \ Py_DECREF(y); \
@ -436,11 +435,9 @@ proxy_check_ref(PyObject *obj)
method(PyObject *proxy, PyObject *v, PyObject *w) { \ method(PyObject *proxy, PyObject *v, PyObject *w) { \
UNWRAP(proxy); \ UNWRAP(proxy); \
UNWRAP(v); \ UNWRAP(v); \
if (w != NULL) \ if (w != NULL) { \
UNWRAP(w); \ UNWRAP(w); \
Py_INCREF(proxy); \ } \
Py_INCREF(v); \
Py_XINCREF(w); \
PyObject* res = generic(proxy, v, w); \ PyObject* res = generic(proxy, v, w); \
Py_DECREF(proxy); \ Py_DECREF(proxy); \
Py_DECREF(v); \ Py_DECREF(v); \
@ -452,7 +449,6 @@ proxy_check_ref(PyObject *obj)
static PyObject * \ static PyObject * \
method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \ method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
UNWRAP(proxy); \ UNWRAP(proxy); \
Py_INCREF(proxy); \
PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \ PyObject* res = PyObject_CallMethodNoArgs(proxy, &_Py_ID(SPECIAL)); \
Py_DECREF(proxy); \ Py_DECREF(proxy); \
return res; \ return res; \
@ -466,24 +462,24 @@ WRAP_UNARY(proxy_str, PyObject_Str)
WRAP_TERNARY(proxy_call, PyObject_Call) WRAP_TERNARY(proxy_call, PyObject_Call)
static PyObject * static PyObject *
proxy_repr(PyWeakReference *proxy) proxy_repr(PyObject *proxy)
{ {
return PyUnicode_FromFormat( PyObject *obj = _PyWeakref_GET_REF(proxy);
PyObject *repr = PyUnicode_FromFormat(
"<weakproxy at %p to %s at %p>", "<weakproxy at %p to %s at %p>",
proxy, proxy, Py_TYPE(obj)->tp_name, obj);
Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name, Py_DECREF(obj);
PyWeakref_GET_OBJECT(proxy)); return repr;
} }
static int static int
proxy_setattr(PyObject *proxy, PyObject *name, PyObject *value) proxy_setattr(PyObject *proxy, PyObject *name, PyObject *value)
{ {
PyObject *obj = PyWeakref_GET_OBJECT(proxy); PyObject *obj = _PyWeakref_GET_REF(proxy);
if (!proxy_check_ref(obj)) { if (!proxy_check_ref(obj)) {
return -1; return -1;
} }
Py_INCREF(obj);
int res = PyObject_SetAttr(obj, name, value); int res = PyObject_SetAttr(obj, name, value);
Py_DECREF(obj); Py_DECREF(obj);
return res; return res;
@ -494,7 +490,10 @@ proxy_richcompare(PyObject *proxy, PyObject *v, int op)
{ {
UNWRAP(proxy); UNWRAP(proxy);
UNWRAP(v); UNWRAP(v);
return PyObject_RichCompare(proxy, v, op); PyObject* res = PyObject_RichCompare(proxy, v, op);
Py_DECREF(proxy);
Py_DECREF(v);
return res;
} }
/* number slots */ /* number slots */
@ -536,11 +535,10 @@ WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
static int static int
proxy_bool(PyObject *proxy) proxy_bool(PyObject *proxy)
{ {
PyObject *o = PyWeakref_GET_OBJECT(proxy); PyObject *o = _PyWeakref_GET_REF(proxy);
if (!proxy_check_ref(o)) { if (!proxy_check_ref(o)) {
return -1; return -1;
} }
Py_INCREF(o);
int res = PyObject_IsTrue(o); int res = PyObject_IsTrue(o);
Py_DECREF(o); Py_DECREF(o);
return res; return res;
@ -561,11 +559,10 @@ proxy_dealloc(PyWeakReference *self)
static int static int
proxy_contains(PyObject *proxy, PyObject *value) proxy_contains(PyObject *proxy, PyObject *value)
{ {
PyObject *obj = PyWeakref_GET_OBJECT(proxy); PyObject *obj = _PyWeakref_GET_REF(proxy);
if (!proxy_check_ref(obj)) { if (!proxy_check_ref(obj)) {
return -1; return -1;
} }
Py_INCREF(obj);
int res = PySequence_Contains(obj, value); int res = PySequence_Contains(obj, value);
Py_DECREF(obj); Py_DECREF(obj);
return res; return res;
@ -576,11 +573,10 @@ proxy_contains(PyObject *proxy, PyObject *value)
static Py_ssize_t static Py_ssize_t
proxy_length(PyObject *proxy) proxy_length(PyObject *proxy)
{ {
PyObject *obj = PyWeakref_GET_OBJECT(proxy); PyObject *obj = _PyWeakref_GET_REF(proxy);
if (!proxy_check_ref(obj)) { if (!proxy_check_ref(obj)) {
return -1; return -1;
} }
Py_INCREF(obj);
Py_ssize_t res = PyObject_Length(obj); Py_ssize_t res = PyObject_Length(obj);
Py_DECREF(obj); Py_DECREF(obj);
return res; return res;
@ -591,11 +587,10 @@ WRAP_BINARY(proxy_getitem, PyObject_GetItem)
static int static int
proxy_setitem(PyObject *proxy, PyObject *key, PyObject *value) proxy_setitem(PyObject *proxy, PyObject *key, PyObject *value)
{ {
PyObject *obj = PyWeakref_GET_OBJECT(proxy); PyObject *obj = _PyWeakref_GET_REF(proxy);
if (!proxy_check_ref(obj)) { if (!proxy_check_ref(obj)) {
return -1; return -1;
} }
Py_INCREF(obj);
int res; int res;
if (value == NULL) { if (value == NULL) {
res = PyObject_DelItem(obj, key); res = PyObject_DelItem(obj, key);
@ -611,11 +606,10 @@ proxy_setitem(PyObject *proxy, PyObject *key, PyObject *value)
static PyObject * static PyObject *
proxy_iter(PyObject *proxy) proxy_iter(PyObject *proxy)
{ {
PyObject *obj = PyWeakref_GET_OBJECT(proxy); PyObject *obj = _PyWeakref_GET_REF(proxy);
if (!proxy_check_ref(obj)) { if (!proxy_check_ref(obj)) {
return NULL; return NULL;
} }
Py_INCREF(obj);
PyObject* res = PyObject_GetIter(obj); PyObject* res = PyObject_GetIter(obj);
Py_DECREF(obj); Py_DECREF(obj);
return res; return res;
@ -624,7 +618,7 @@ proxy_iter(PyObject *proxy)
static PyObject * static PyObject *
proxy_iternext(PyObject *proxy) proxy_iternext(PyObject *proxy)
{ {
PyObject *obj = PyWeakref_GET_OBJECT(proxy); PyObject *obj = _PyWeakref_GET_REF(proxy);
if (!proxy_check_ref(obj)) { if (!proxy_check_ref(obj)) {
return NULL; return NULL;
} }
@ -632,9 +626,9 @@ proxy_iternext(PyObject *proxy)
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Weakref proxy referenced a non-iterator '%.200s' object", "Weakref proxy referenced a non-iterator '%.200s' object",
Py_TYPE(obj)->tp_name); Py_TYPE(obj)->tp_name);
Py_DECREF(obj);
return NULL; return NULL;
} }
Py_INCREF(obj);
PyObject* res = PyIter_Next(obj); PyObject* res = PyIter_Next(obj);
Py_DECREF(obj); Py_DECREF(obj);
return res; return res;
@ -721,7 +715,7 @@ _PyWeakref_ProxyType = {
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_as_async */ 0, /* tp_as_async */
(reprfunc)proxy_repr, /* tp_repr */ proxy_repr, /* tp_repr */
&proxy_as_number, /* tp_as_number */ &proxy_as_number, /* tp_as_number */
&proxy_as_sequence, /* tp_as_sequence */ &proxy_as_sequence, /* tp_as_sequence */
&proxy_as_mapping, /* tp_as_mapping */ &proxy_as_mapping, /* tp_as_mapping */
@ -756,7 +750,7 @@ _PyWeakref_CallableProxyType = {
0, /* tp_getattr */ 0, /* tp_getattr */
0, /* tp_setattr */ 0, /* tp_setattr */
0, /* tp_as_async */ 0, /* tp_as_async */
(unaryfunc)proxy_repr, /* tp_repr */ proxy_repr, /* tp_repr */
&proxy_as_number, /* tp_as_number */ &proxy_as_number, /* tp_as_number */
&proxy_as_sequence, /* tp_as_sequence */ &proxy_as_sequence, /* tp_as_sequence */
&proxy_as_mapping, /* tp_as_mapping */ &proxy_as_mapping, /* tp_as_mapping */

View File

@ -275,6 +275,7 @@
<ClInclude Include="..\Include\internal\pycore_unicodeobject.h" /> <ClInclude Include="..\Include\internal\pycore_unicodeobject.h" />
<ClInclude Include="..\Include\internal\pycore_unicodeobject_generated.h" /> <ClInclude Include="..\Include\internal\pycore_unicodeobject_generated.h" />
<ClInclude Include="..\Include\internal\pycore_warnings.h" /> <ClInclude Include="..\Include\internal\pycore_warnings.h" />
<ClInclude Include="..\Include\internal\pycore_weakref.h" />
<ClInclude Include="..\Include\interpreteridobject.h" /> <ClInclude Include="..\Include\interpreteridobject.h" />
<ClInclude Include="..\Include\intrcheck.h" /> <ClInclude Include="..\Include\intrcheck.h" />
<ClInclude Include="..\Include\iterobject.h" /> <ClInclude Include="..\Include\iterobject.h" />

View File

@ -492,6 +492,9 @@
<ClInclude Include="..\Include\internal\pycore_warnings.h"> <ClInclude Include="..\Include\internal\pycore_warnings.h">
<Filter>Include\internal</Filter> <Filter>Include\internal</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\Include\internal\pycore_weakref.h">
<Filter>Include\internal</Filter>
</ClInclude>
<ClInclude Include="..\Include\internal\pycore_abstract.h"> <ClInclude Include="..\Include\internal\pycore_abstract.h">
<Filter>Include\internal</Filter> <Filter>Include\internal</Filter>
</ClInclude> </ClInclude>