blob: bb56c7dbdb8322915f1da039a9fe933124c3bc3d [file] [log] [blame]
Fred Drake8844d522001-10-05 21:52:26 +00001#include "Python.h"
Victor Stinner4a21e572020-04-15 02:35:41 +02002#include "pycore_object.h" // _PyObject_GET_WEAKREFS_LISTPTR()
3#include "structmember.h" // PyMemberDef
Fred Drake8844d522001-10-05 21:52:26 +00004
5
6#define GET_WEAKREFS_LISTPTR(o) \
Victor Stinner38aefc52020-04-06 14:07:02 +02007 ((PyWeakReference **) _PyObject_GET_WEAKREFS_LISTPTR(o))
Fred Drake8844d522001-10-05 21:52:26 +00008
Fred Drake8844d522001-10-05 21:52:26 +00009
Thomas Wouters0e3f5912006-08-11 14:57:12 +000010Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +000011_PyWeakref_GetWeakrefCount(PyWeakReference *head)
12{
Thomas Wouters0e3f5912006-08-11 14:57:12 +000013 Py_ssize_t count = 0;
Fred Drake8844d522001-10-05 21:52:26 +000014
15 while (head != NULL) {
16 ++count;
17 head = head->wr_next;
18 }
19 return count;
20}
21
22
Fred Drake0a4dd392004-07-02 18:57:45 +000023static void
24init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
25{
26 self->hash = -1;
27 self->wr_object = ob;
Xiang Zhangd0e82122017-02-20 12:25:16 +080028 self->wr_prev = NULL;
29 self->wr_next = NULL;
Fred Drake0a4dd392004-07-02 18:57:45 +000030 Py_XINCREF(callback);
31 self->wr_callback = callback;
32}
33
Fred Drake8844d522001-10-05 21:52:26 +000034static PyWeakReference *
Neil Schemenauer38a89162002-03-27 15:18:21 +000035new_weakref(PyObject *ob, PyObject *callback)
Fred Drake8844d522001-10-05 21:52:26 +000036{
37 PyWeakReference *result;
38
Neil Schemenauer38a89162002-03-27 15:18:21 +000039 result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
40 if (result) {
Fred Drake0a4dd392004-07-02 18:57:45 +000041 init_weakref(result, ob, callback);
Neil Schemenauer38a89162002-03-27 15:18:21 +000042 PyObject_GC_Track(result);
43 }
Fred Drake8844d522001-10-05 21:52:26 +000044 return result;
45}
46
47
48/* This function clears the passed-in reference and removes it from the
49 * list of weak references for the referent. This is the only code that
50 * removes an item from the doubly-linked list of weak references for an
51 * object; it is also responsible for clearing the callback slot.
52 */
53static void
54clear_weakref(PyWeakReference *self)
55{
56 PyObject *callback = self->wr_callback;
57
Antoine Pitrou62a0d6e2012-12-08 21:15:26 +010058 if (self->wr_object != Py_None) {
59 PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
Fred Drake8844d522001-10-05 21:52:26 +000060
61 if (*list == self)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000062 /* If 'self' is the end of the list (and thus self->wr_next == NULL)
63 then the weakref list itself (and thus the value of *list) will
64 end up being set to NULL. */
Fred Drake8844d522001-10-05 21:52:26 +000065 *list = self->wr_next;
66 self->wr_object = Py_None;
Fred Drake8844d522001-10-05 21:52:26 +000067 if (self->wr_prev != NULL)
68 self->wr_prev->wr_next = self->wr_next;
69 if (self->wr_next != NULL)
70 self->wr_next->wr_prev = self->wr_prev;
71 self->wr_prev = NULL;
72 self->wr_next = NULL;
Tim Peters403a2032003-11-20 21:21:46 +000073 }
74 if (callback != NULL) {
75 Py_DECREF(callback);
76 self->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +000077 }
78}
79
Tim Peters403a2032003-11-20 21:21:46 +000080/* Cyclic gc uses this to *just* clear the passed-in reference, leaving
81 * the callback intact and uncalled. It must be possible to call self's
82 * tp_dealloc() after calling this, so self has to be left in a sane enough
83 * state for that to work. We expect tp_dealloc to decref the callback
84 * then. The reason for not letting clear_weakref() decref the callback
85 * right now is that if the callback goes away, that may in turn trigger
86 * another callback (if a weak reference to the callback exists) -- running
87 * arbitrary Python code in the middle of gc is a disaster. The convolution
88 * here allows gc to delay triggering such callbacks until the world is in
89 * a sane state again.
90 */
91void
92_PyWeakref_ClearRef(PyWeakReference *self)
93{
94 PyObject *callback;
95
96 assert(self != NULL);
97 assert(PyWeakref_Check(self));
98 /* Preserve and restore the callback around clear_weakref. */
99 callback = self->wr_callback;
100 self->wr_callback = NULL;
101 clear_weakref(self);
102 self->wr_callback = callback;
103}
Fred Drake8844d522001-10-05 21:52:26 +0000104
105static void
Fred Drake0a4dd392004-07-02 18:57:45 +0000106weakref_dealloc(PyObject *self)
Fred Drake8844d522001-10-05 21:52:26 +0000107{
Fred Drake0a4dd392004-07-02 18:57:45 +0000108 PyObject_GC_UnTrack(self);
109 clear_weakref((PyWeakReference *) self);
Christian Heimes90aa7642007-12-19 02:45:37 +0000110 Py_TYPE(self)->tp_free(self);
Fred Drake8844d522001-10-05 21:52:26 +0000111}
112
113
114static int
115gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
116{
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000117 Py_VISIT(self->wr_callback);
Fred Drake8844d522001-10-05 21:52:26 +0000118 return 0;
119}
120
121
122static int
123gc_clear(PyWeakReference *self)
124{
125 clear_weakref(self);
126 return 0;
127}
128
129
130static PyObject *
131weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
132{
Martin v. Löwis15e62742006-02-27 16:46:16 +0000133 static char *kwlist[] = {NULL};
Fred Drake8844d522001-10-05 21:52:26 +0000134
Martin v. Löwis15e62742006-02-27 16:46:16 +0000135 if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
Fred Drake8844d522001-10-05 21:52:26 +0000136 PyObject *object = PyWeakref_GET_OBJECT(self);
137 Py_INCREF(object);
138 return (object);
139 }
140 return NULL;
141}
142
143
Benjamin Peterson8f67d082010-10-17 20:54:53 +0000144static Py_hash_t
Fred Drake8844d522001-10-05 21:52:26 +0000145weakref_hash(PyWeakReference *self)
146{
147 if (self->hash != -1)
148 return self->hash;
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100149 PyObject* obj = PyWeakref_GET_OBJECT(self);
150 if (obj == Py_None) {
Fred Drake8844d522001-10-05 21:52:26 +0000151 PyErr_SetString(PyExc_TypeError, "weak object has gone away");
152 return -1;
153 }
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100154 Py_INCREF(obj);
155 self->hash = PyObject_Hash(obj);
156 Py_DECREF(obj);
Fred Drake8844d522001-10-05 21:52:26 +0000157 return self->hash;
158}
Tim Peters403a2032003-11-20 21:21:46 +0000159
Fred Drake8844d522001-10-05 21:52:26 +0000160
161static PyObject *
162weakref_repr(PyWeakReference *self)
163{
Victor Stinner499dfcf2011-03-21 13:26:24 +0100164 PyObject *name, *repr;
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200165 _Py_IDENTIFIER(__name__);
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100166 PyObject* obj = PyWeakref_GET_OBJECT(self);
Victor Stinner499dfcf2011-03-21 13:26:24 +0100167
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100168 if (obj == Py_None) {
Victor Stinner499dfcf2011-03-21 13:26:24 +0100169 return PyUnicode_FromFormat("<weakref at %p; dead>", self);
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100170 }
Victor Stinner499dfcf2011-03-21 13:26:24 +0100171
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100172 Py_INCREF(obj);
173 if (_PyObject_LookupAttrId(obj, &PyId___name__, &name) < 0) {
174 Py_DECREF(obj);
Serhiy Storchaka41c57b32019-09-01 12:03:39 +0300175 return NULL;
176 }
Victor Stinner499dfcf2011-03-21 13:26:24 +0100177 if (name == NULL || !PyUnicode_Check(name)) {
Victor Stinner499dfcf2011-03-21 13:26:24 +0100178 repr = PyUnicode_FromFormat(
179 "<weakref at %p; to '%s' at %p>",
180 self,
181 Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100182 obj);
Fred Drake8844d522001-10-05 21:52:26 +0000183 }
184 else {
Victor Stinner499dfcf2011-03-21 13:26:24 +0100185 repr = PyUnicode_FromFormat(
186 "<weakref at %p; to '%s' at %p (%U)>",
187 self,
188 Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100189 obj,
Victor Stinner499dfcf2011-03-21 13:26:24 +0100190 name);
Fred Drake8844d522001-10-05 21:52:26 +0000191 }
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100192 Py_DECREF(obj);
Victor Stinner499dfcf2011-03-21 13:26:24 +0100193 Py_XDECREF(name);
194 return repr;
Fred Drake8844d522001-10-05 21:52:26 +0000195}
196
197/* Weak references only support equality, not ordering. Two weak references
198 are equal if the underlying objects are equal. If the underlying object has
199 gone away, they are equal if they are identical. */
200
201static PyObject *
202weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
203{
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000204 if ((op != Py_EQ && op != Py_NE) ||
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000205 !PyWeakref_Check(self) ||
206 !PyWeakref_Check(other)) {
Brian Curtindfc80e32011-08-10 20:28:54 -0500207 Py_RETURN_NOTIMPLEMENTED;
Fred Drake8844d522001-10-05 21:52:26 +0000208 }
209 if (PyWeakref_GET_OBJECT(self) == Py_None
210 || PyWeakref_GET_OBJECT(other) == Py_None) {
Antoine Pitroue11fecb2012-11-11 19:36:51 +0100211 int res = (self == other);
212 if (op == Py_NE)
213 res = !res;
214 if (res)
215 Py_RETURN_TRUE;
216 else
217 Py_RETURN_FALSE;
Fred Drake8844d522001-10-05 21:52:26 +0000218 }
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100219 PyObject* obj = PyWeakref_GET_OBJECT(self);
220 PyObject* other_obj = PyWeakref_GET_OBJECT(other);
221 Py_INCREF(obj);
222 Py_INCREF(other_obj);
223 PyObject* res = PyObject_RichCompare(obj, other_obj, op);
224 Py_DECREF(obj);
225 Py_DECREF(other_obj);
226 return res;
Fred Drake8844d522001-10-05 21:52:26 +0000227}
228
Fred Drake0a4dd392004-07-02 18:57:45 +0000229/* Given the head of an object's list of weak references, extract the
230 * two callback-less refs (ref and proxy). Used to determine if the
231 * shared references exist and to determine the back link for newly
232 * inserted references.
233 */
234static void
235get_basic_refs(PyWeakReference *head,
236 PyWeakReference **refp, PyWeakReference **proxyp)
237{
238 *refp = NULL;
239 *proxyp = NULL;
240
241 if (head != NULL && head->wr_callback == NULL) {
242 /* We need to be careful that the "basic refs" aren't
243 subclasses of the main types. That complicates this a
244 little. */
245 if (PyWeakref_CheckRefExact(head)) {
246 *refp = head;
247 head = head->wr_next;
248 }
249 if (head != NULL
250 && head->wr_callback == NULL
251 && PyWeakref_CheckProxy(head)) {
252 *proxyp = head;
253 /* head = head->wr_next; */
254 }
255 }
256}
257
258/* Insert 'newref' in the list after 'prev'. Both must be non-NULL. */
259static void
260insert_after(PyWeakReference *newref, PyWeakReference *prev)
261{
262 newref->wr_prev = prev;
263 newref->wr_next = prev->wr_next;
264 if (prev->wr_next != NULL)
265 prev->wr_next->wr_prev = newref;
266 prev->wr_next = newref;
267}
268
269/* Insert 'newref' at the head of the list; 'list' points to the variable
270 * that stores the head.
271 */
272static void
273insert_head(PyWeakReference *newref, PyWeakReference **list)
274{
275 PyWeakReference *next = *list;
276
277 newref->wr_prev = NULL;
278 newref->wr_next = next;
279 if (next != NULL)
280 next->wr_prev = newref;
281 *list = newref;
282}
283
284static int
Serhiy Storchakaef1585e2015-12-25 20:01:53 +0200285parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs,
Fred Drake0a4dd392004-07-02 18:57:45 +0000286 PyObject **obp, PyObject **callbackp)
287{
Fred Drake0a4dd392004-07-02 18:57:45 +0000288 return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
289}
290
291static PyObject *
292weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
293{
294 PyWeakReference *self = NULL;
295 PyObject *ob, *callback = NULL;
296
297 if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
298 PyWeakReference *ref, *proxy;
299 PyWeakReference **list;
300
Christian Heimes90aa7642007-12-19 02:45:37 +0000301 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
Fred Drake0a4dd392004-07-02 18:57:45 +0000302 PyErr_Format(PyExc_TypeError,
303 "cannot create weak reference to '%s' object",
Christian Heimes90aa7642007-12-19 02:45:37 +0000304 Py_TYPE(ob)->tp_name);
Fred Drake0a4dd392004-07-02 18:57:45 +0000305 return NULL;
306 }
307 if (callback == Py_None)
308 callback = NULL;
309 list = GET_WEAKREFS_LISTPTR(ob);
310 get_basic_refs(*list, &ref, &proxy);
311 if (callback == NULL && type == &_PyWeakref_RefType) {
312 if (ref != NULL) {
313 /* We can re-use an existing reference. */
314 Py_INCREF(ref);
315 return (PyObject *)ref;
316 }
317 }
318 /* We have to create a new reference. */
319 /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
320 list on ob can be mutated. This means that the ref and
321 proxy pointers we got back earlier may have been collected,
322 so we need to compute these values again before we use
323 them. */
324 self = (PyWeakReference *) (type->tp_alloc(type, 0));
325 if (self != NULL) {
326 init_weakref(self, ob, callback);
327 if (callback == NULL && type == &_PyWeakref_RefType) {
328 insert_head(self, list);
329 }
330 else {
331 PyWeakReference *prev;
332
333 get_basic_refs(*list, &ref, &proxy);
334 prev = (proxy == NULL) ? ref : proxy;
335 if (prev == NULL)
336 insert_head(self, list);
337 else
338 insert_after(self, prev);
339 }
340 }
341 }
342 return (PyObject *)self;
343}
344
345static int
346weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
347{
348 PyObject *tmp;
349
Serhiy Storchaka6cca5c82017-06-08 14:41:19 +0300350 if (!_PyArg_NoKeywords("ref", kwargs))
Serhiy Storchaka21eb4872016-05-07 15:41:09 +0300351 return -1;
352
Fred Drake0a4dd392004-07-02 18:57:45 +0000353 if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
354 return 0;
355 else
Benjamin Peterson9aa42992008-09-10 21:57:34 +0000356 return -1;
Fred Drake0a4dd392004-07-02 18:57:45 +0000357}
358
Fred Drake8844d522001-10-05 21:52:26 +0000359
Mark Dickinson556e94b2013-04-13 15:45:44 +0100360static PyMemberDef weakref_members[] = {
361 {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
362 {NULL} /* Sentinel */
363};
364
Ethan Smith8ef87502020-04-13 21:54:40 -0700365static PyMethodDef weakref_methods[] = {
366 {"__class_getitem__", (PyCFunction)Py_GenericAlias,
367 METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
368 {NULL} /* Sentinel */
369};
370
Fred Drake8844d522001-10-05 21:52:26 +0000371PyTypeObject
372_PyWeakref_RefType = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000373 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000374 "weakref",
375 sizeof(PyWeakReference),
376 0,
Fred Drake0a4dd392004-07-02 18:57:45 +0000377 weakref_dealloc, /*tp_dealloc*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200378 0, /*tp_vectorcall_offset*/
Fred Drake8844d522001-10-05 21:52:26 +0000379 0, /*tp_getattr*/
380 0, /*tp_setattr*/
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200381 0, /*tp_as_async*/
Fred Drake8844d522001-10-05 21:52:26 +0000382 (reprfunc)weakref_repr, /*tp_repr*/
383 0, /*tp_as_number*/
384 0, /*tp_as_sequence*/
385 0, /*tp_as_mapping*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000386 (hashfunc)weakref_hash, /*tp_hash*/
Fred Drake8844d522001-10-05 21:52:26 +0000387 (ternaryfunc)weakref_call, /*tp_call*/
388 0, /*tp_str*/
389 0, /*tp_getattro*/
390 0, /*tp_setattro*/
391 0, /*tp_as_buffer*/
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000392 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
Fred Drake0a4dd392004-07-02 18:57:45 +0000393 | Py_TPFLAGS_BASETYPE, /*tp_flags*/
Fred Drake8844d522001-10-05 21:52:26 +0000394 0, /*tp_doc*/
395 (traverseproc)gc_traverse, /*tp_traverse*/
396 (inquiry)gc_clear, /*tp_clear*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000397 (richcmpfunc)weakref_richcompare, /*tp_richcompare*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000398 0, /*tp_weaklistoffset*/
399 0, /*tp_iter*/
400 0, /*tp_iternext*/
Ethan Smith8ef87502020-04-13 21:54:40 -0700401 weakref_methods, /*tp_methods*/
Mark Dickinson556e94b2013-04-13 15:45:44 +0100402 weakref_members, /*tp_members*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000403 0, /*tp_getset*/
404 0, /*tp_base*/
405 0, /*tp_dict*/
406 0, /*tp_descr_get*/
407 0, /*tp_descr_set*/
408 0, /*tp_dictoffset*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000409 weakref___init__, /*tp_init*/
Fred Drake0a4dd392004-07-02 18:57:45 +0000410 PyType_GenericAlloc, /*tp_alloc*/
411 weakref___new__, /*tp_new*/
412 PyObject_GC_Del, /*tp_free*/
Fred Drake8844d522001-10-05 21:52:26 +0000413};
414
415
416static int
417proxy_checkref(PyWeakReference *proxy)
418{
419 if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
420 PyErr_SetString(PyExc_ReferenceError,
421 "weakly-referenced object no longer exists");
422 return 0;
423 }
424 return 1;
425}
426
427
Fred Drake73006d02001-10-18 18:04:18 +0000428/* If a parameter is a proxy, check that it is still "live" and wrap it,
429 * replacing the original value with the raw object. Raises ReferenceError
430 * if the param is a dead proxy.
431 */
432#define UNWRAP(o) \
433 if (PyWeakref_CheckProxy(o)) { \
434 if (!proxy_checkref((PyWeakReference *)o)) \
435 return NULL; \
436 o = PyWeakref_GET_OBJECT(o); \
437 }
438
Fred Drake8844d522001-10-05 21:52:26 +0000439#define WRAP_UNARY(method, generic) \
440 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000441 method(PyObject *proxy) { \
442 UNWRAP(proxy); \
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100443 Py_INCREF(proxy); \
444 PyObject* res = generic(proxy); \
445 Py_DECREF(proxy); \
446 return res; \
Fred Drake8844d522001-10-05 21:52:26 +0000447 }
448
449#define WRAP_BINARY(method, generic) \
450 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000451 method(PyObject *x, PyObject *y) { \
452 UNWRAP(x); \
453 UNWRAP(y); \
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100454 Py_INCREF(x); \
455 Py_INCREF(y); \
456 PyObject* res = generic(x, y); \
457 Py_DECREF(x); \
458 Py_DECREF(y); \
459 return res; \
Fred Drake8844d522001-10-05 21:52:26 +0000460 }
461
Fred Drake31f4d1f2001-10-18 19:21:46 +0000462/* Note that the third arg needs to be checked for NULL since the tp_call
463 * slot can receive NULL for this arg.
Fred Drake73006d02001-10-18 18:04:18 +0000464 */
Fred Drake8844d522001-10-05 21:52:26 +0000465#define WRAP_TERNARY(method, generic) \
466 static PyObject * \
Fred Drake73006d02001-10-18 18:04:18 +0000467 method(PyObject *proxy, PyObject *v, PyObject *w) { \
468 UNWRAP(proxy); \
Fred Drake31f4d1f2001-10-18 19:21:46 +0000469 UNWRAP(v); \
Fred Drake73006d02001-10-18 18:04:18 +0000470 if (w != NULL) \
471 UNWRAP(w); \
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100472 Py_INCREF(proxy); \
473 Py_INCREF(v); \
474 Py_XINCREF(w); \
475 PyObject* res = generic(proxy, v, w); \
476 Py_DECREF(proxy); \
477 Py_DECREF(v); \
478 Py_XDECREF(w); \
479 return res; \
Fred Drake8844d522001-10-05 21:52:26 +0000480 }
481
Benjamin Peterson32019772009-11-19 03:08:32 +0000482#define WRAP_METHOD(method, special) \
483 static PyObject * \
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530484 method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
Martin v. Löwisbd928fe2011-10-14 10:20:37 +0200485 _Py_IDENTIFIER(special); \
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000486 UNWRAP(proxy); \
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100487 Py_INCREF(proxy); \
488 PyObject* res = _PyObject_CallMethodIdNoArgs(proxy, &PyId_##special); \
489 Py_DECREF(proxy); \
490 return res; \
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000491 }
Benjamin Peterson32019772009-11-19 03:08:32 +0000492
Fred Drake8844d522001-10-05 21:52:26 +0000493
494/* direct slots */
495
496WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
497WRAP_UNARY(proxy_str, PyObject_Str)
INADA Naoki72dccde2017-02-16 09:26:01 +0900498WRAP_TERNARY(proxy_call, PyObject_Call)
Fred Drake8844d522001-10-05 21:52:26 +0000499
Fred Drake8844d522001-10-05 21:52:26 +0000500static PyObject *
501proxy_repr(PyWeakReference *proxy)
502{
Victor Stinner499dfcf2011-03-21 13:26:24 +0100503 return PyUnicode_FromFormat(
504 "<weakproxy at %p to %s at %p>",
505 proxy,
506 Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
507 PyWeakref_GET_OBJECT(proxy));
Fred Drake8844d522001-10-05 21:52:26 +0000508}
509
510
511static int
512proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
513{
514 if (!proxy_checkref(proxy))
515 return -1;
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100516 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
517 Py_INCREF(obj);
518 int res = PyObject_SetAttr(obj, name, value);
519 Py_DECREF(obj);
520 return res;
Fred Drake8844d522001-10-05 21:52:26 +0000521}
522
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000523static PyObject *
524proxy_richcompare(PyObject *proxy, PyObject *v, int op)
Fred Drake8844d522001-10-05 21:52:26 +0000525{
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000526 UNWRAP(proxy);
527 UNWRAP(v);
528 return PyObject_RichCompare(proxy, v, op);
Fred Drake8844d522001-10-05 21:52:26 +0000529}
530
531/* number slots */
532WRAP_BINARY(proxy_add, PyNumber_Add)
533WRAP_BINARY(proxy_sub, PyNumber_Subtract)
534WRAP_BINARY(proxy_mul, PyNumber_Multiply)
Georg Brandlb533e262008-05-25 18:19:30 +0000535WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
536WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
Fred Drake8844d522001-10-05 21:52:26 +0000537WRAP_BINARY(proxy_mod, PyNumber_Remainder)
538WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
539WRAP_TERNARY(proxy_pow, PyNumber_Power)
540WRAP_UNARY(proxy_neg, PyNumber_Negative)
541WRAP_UNARY(proxy_pos, PyNumber_Positive)
542WRAP_UNARY(proxy_abs, PyNumber_Absolute)
543WRAP_UNARY(proxy_invert, PyNumber_Invert)
544WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
545WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
546WRAP_BINARY(proxy_and, PyNumber_And)
547WRAP_BINARY(proxy_xor, PyNumber_Xor)
548WRAP_BINARY(proxy_or, PyNumber_Or)
Mark Dickinson17c7cd82009-01-17 21:57:11 +0000549WRAP_UNARY(proxy_int, PyNumber_Long)
Fred Drake8844d522001-10-05 21:52:26 +0000550WRAP_UNARY(proxy_float, PyNumber_Float)
551WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
552WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
553WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
Georg Brandlb533e262008-05-25 18:19:30 +0000554WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
555WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
Fred Drake8844d522001-10-05 21:52:26 +0000556WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
557WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
558WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
559WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
560WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
561WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
562WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
Georg Brandlb533e262008-05-25 18:19:30 +0000563WRAP_UNARY(proxy_index, PyNumber_Index)
Mark Dickinson7abb6c02019-04-26 15:56:15 +0900564WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply)
565WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
Fred Drake8844d522001-10-05 21:52:26 +0000566
Tim Peters403a2032003-11-20 21:21:46 +0000567static int
Jack Diederich4dafcc42006-11-28 19:15:13 +0000568proxy_bool(PyWeakReference *proxy)
Fred Drake8844d522001-10-05 21:52:26 +0000569{
570 PyObject *o = PyWeakref_GET_OBJECT(proxy);
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100571 if (!proxy_checkref(proxy)) {
Neal Norwitzbdcb9412004-07-08 01:22:31 +0000572 return -1;
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100573 }
574 Py_INCREF(o);
575 int res = PyObject_IsTrue(o);
576 Py_DECREF(o);
577 return res;
Fred Drake8844d522001-10-05 21:52:26 +0000578}
579
Fred Drake0a4dd392004-07-02 18:57:45 +0000580static void
581proxy_dealloc(PyWeakReference *self)
582{
583 if (self->wr_callback != NULL)
584 PyObject_GC_UnTrack((PyObject *)self);
585 clear_weakref(self);
586 PyObject_GC_Del(self);
587}
588
Fred Drake8844d522001-10-05 21:52:26 +0000589/* sequence slots */
590
Fred Drake8844d522001-10-05 21:52:26 +0000591static int
592proxy_contains(PyWeakReference *proxy, PyObject *value)
593{
594 if (!proxy_checkref(proxy))
595 return -1;
Fred Drake8844d522001-10-05 21:52:26 +0000596
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100597 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
598 Py_INCREF(obj);
599 int res = PySequence_Contains(obj, value);
600 Py_DECREF(obj);
601 return res;
602}
Fred Drake8844d522001-10-05 21:52:26 +0000603
604/* mapping slots */
605
Martin v. Löwis18e16552006-02-15 17:27:45 +0000606static Py_ssize_t
Fred Drake8844d522001-10-05 21:52:26 +0000607proxy_length(PyWeakReference *proxy)
608{
609 if (!proxy_checkref(proxy))
610 return -1;
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100611
612 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
613 Py_INCREF(obj);
614 Py_ssize_t res = PyObject_Length(obj);
615 Py_DECREF(obj);
616 return res;
Fred Drake8844d522001-10-05 21:52:26 +0000617}
618
619WRAP_BINARY(proxy_getitem, PyObject_GetItem)
620
621static int
622proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
623{
624 if (!proxy_checkref(proxy))
625 return -1;
Raymond Hettingerd693a812003-06-30 04:18:48 +0000626
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100627 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
628 Py_INCREF(obj);
629 int res;
630 if (value == NULL) {
631 res = PyObject_DelItem(obj, key);
632 } else {
633 res = PyObject_SetItem(obj, key, value);
634 }
635 Py_DECREF(obj);
636 return res;
Fred Drake8844d522001-10-05 21:52:26 +0000637}
638
Fred Drakef16c3dc2002-08-09 18:34:16 +0000639/* iterator slots */
640
641static PyObject *
642proxy_iter(PyWeakReference *proxy)
643{
644 if (!proxy_checkref(proxy))
645 return NULL;
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100646 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
647 Py_INCREF(obj);
648 PyObject* res = PyObject_GetIter(obj);
649 Py_DECREF(obj);
650 return res;
Fred Drakef16c3dc2002-08-09 18:34:16 +0000651}
652
653static PyObject *
654proxy_iternext(PyWeakReference *proxy)
655{
656 if (!proxy_checkref(proxy))
657 return NULL;
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100658
659 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
Miss Islington (bot)659030c2021-07-24 02:45:13 -0700660 if (!PyIter_Check(obj)) {
661 PyErr_Format(PyExc_TypeError,
662 "Weakref proxy referenced a non-iterator '%.200s' object",
663 Py_TYPE(obj)->tp_name);
664 return NULL;
665 }
Pablo Galindo10cd00a2019-10-08 16:30:50 +0100666 Py_INCREF(obj);
667 PyObject* res = PyIter_Next(obj);
668 Py_DECREF(obj);
669 return res;
Fred Drakef16c3dc2002-08-09 18:34:16 +0000670}
671
Fred Drake8844d522001-10-05 21:52:26 +0000672
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200673WRAP_METHOD(proxy_bytes, __bytes__)
Pablo Galindo96074de2020-05-05 22:58:19 +0100674WRAP_METHOD(proxy_reversed, __reversed__)
Benjamin Peterson32019772009-11-19 03:08:32 +0000675
676
677static PyMethodDef proxy_methods[] = {
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530678 {"__bytes__", proxy_bytes, METH_NOARGS},
Pablo Galindo96074de2020-05-05 22:58:19 +0100679 {"__reversed__", proxy_reversed, METH_NOARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000680 {NULL, NULL}
Benjamin Peterson32019772009-11-19 03:08:32 +0000681};
682
683
Fred Drake8844d522001-10-05 21:52:26 +0000684static PyNumberMethods proxy_as_number = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000685 proxy_add, /*nb_add*/
686 proxy_sub, /*nb_subtract*/
687 proxy_mul, /*nb_multiply*/
688 proxy_mod, /*nb_remainder*/
689 proxy_divmod, /*nb_divmod*/
690 proxy_pow, /*nb_power*/
691 proxy_neg, /*nb_negative*/
692 proxy_pos, /*nb_positive*/
693 proxy_abs, /*nb_absolute*/
Jack Diederich4dafcc42006-11-28 19:15:13 +0000694 (inquiry)proxy_bool, /*nb_bool*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000695 proxy_invert, /*nb_invert*/
696 proxy_lshift, /*nb_lshift*/
697 proxy_rshift, /*nb_rshift*/
698 proxy_and, /*nb_and*/
699 proxy_xor, /*nb_xor*/
700 proxy_or, /*nb_or*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000701 proxy_int, /*nb_int*/
Mark Dickinson8055afd2009-01-17 10:04:45 +0000702 0, /*nb_reserved*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000703 proxy_float, /*nb_float*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000704 proxy_iadd, /*nb_inplace_add*/
705 proxy_isub, /*nb_inplace_subtract*/
706 proxy_imul, /*nb_inplace_multiply*/
707 proxy_imod, /*nb_inplace_remainder*/
708 proxy_ipow, /*nb_inplace_power*/
709 proxy_ilshift, /*nb_inplace_lshift*/
710 proxy_irshift, /*nb_inplace_rshift*/
711 proxy_iand, /*nb_inplace_and*/
712 proxy_ixor, /*nb_inplace_xor*/
713 proxy_ior, /*nb_inplace_or*/
Georg Brandlb533e262008-05-25 18:19:30 +0000714 proxy_floor_div, /*nb_floor_divide*/
715 proxy_true_div, /*nb_true_divide*/
716 proxy_ifloor_div, /*nb_inplace_floor_divide*/
717 proxy_itrue_div, /*nb_inplace_true_divide*/
718 proxy_index, /*nb_index*/
Mark Dickinson7abb6c02019-04-26 15:56:15 +0900719 proxy_matmul, /*nb_matrix_multiply*/
720 proxy_imatmul, /*nb_inplace_matrix_multiply*/
Fred Drake8844d522001-10-05 21:52:26 +0000721};
722
723static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000724 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000725 0, /*sq_concat*/
726 0, /*sq_repeat*/
727 0, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000728 0, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000729 0, /*sq_ass_item*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000730 0, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000731 (objobjproc)proxy_contains, /* sq_contains */
732};
733
734static PyMappingMethods proxy_as_mapping = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000735 (lenfunc)proxy_length, /*mp_length*/
736 proxy_getitem, /*mp_subscript*/
Fred Drake8844d522001-10-05 21:52:26 +0000737 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
738};
739
740
741PyTypeObject
742_PyWeakref_ProxyType = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000743 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000744 "weakproxy",
745 sizeof(PyWeakReference),
746 0,
747 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000748 (destructor)proxy_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200749 0, /* tp_vectorcall_offset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000750 0, /* tp_getattr */
751 0, /* tp_setattr */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200752 0, /* tp_as_async */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000753 (reprfunc)proxy_repr, /* tp_repr */
754 &proxy_as_number, /* tp_as_number */
755 &proxy_as_sequence, /* tp_as_sequence */
756 &proxy_as_mapping, /* tp_as_mapping */
Miss Islington (bot)2df13e12021-06-29 16:19:06 -0700757// Notice that tp_hash is intentionally omitted as proxies are "mutable" (when the reference dies).
758 0, /* tp_hash */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000759 0, /* tp_call */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000760 proxy_str, /* tp_str */
761 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000762 (setattrofunc)proxy_setattr, /* tp_setattro */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000763 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000764 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000765 0, /* tp_doc */
766 (traverseproc)gc_traverse, /* tp_traverse */
767 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000768 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000769 0, /* tp_weaklistoffset */
770 (getiterfunc)proxy_iter, /* tp_iter */
771 (iternextfunc)proxy_iternext, /* tp_iternext */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000772 proxy_methods, /* tp_methods */
Fred Drake8844d522001-10-05 21:52:26 +0000773};
774
775
776PyTypeObject
777_PyWeakref_CallableProxyType = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000778 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000779 "weakcallableproxy",
780 sizeof(PyWeakReference),
781 0,
782 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000783 (destructor)proxy_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200784 0, /* tp_vectorcall_offset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000785 0, /* tp_getattr */
786 0, /* tp_setattr */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200787 0, /* tp_as_async */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000788 (unaryfunc)proxy_repr, /* tp_repr */
789 &proxy_as_number, /* tp_as_number */
790 &proxy_as_sequence, /* tp_as_sequence */
791 &proxy_as_mapping, /* tp_as_mapping */
792 0, /* tp_hash */
793 proxy_call, /* tp_call */
794 proxy_str, /* tp_str */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000795 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000796 (setattrofunc)proxy_setattr, /* tp_setattro */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000797 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000798 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000799 0, /* tp_doc */
800 (traverseproc)gc_traverse, /* tp_traverse */
801 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000802 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000803 0, /* tp_weaklistoffset */
804 (getiterfunc)proxy_iter, /* tp_iter */
805 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000806};
807
808
Fred Drake8844d522001-10-05 21:52:26 +0000809
810PyObject *
811PyWeakref_NewRef(PyObject *ob, PyObject *callback)
812{
813 PyWeakReference *result = NULL;
814 PyWeakReference **list;
815 PyWeakReference *ref, *proxy;
816
Christian Heimes90aa7642007-12-19 02:45:37 +0000817 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
Fred Drake8844d522001-10-05 21:52:26 +0000818 PyErr_Format(PyExc_TypeError,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000819 "cannot create weak reference to '%s' object",
Christian Heimes90aa7642007-12-19 02:45:37 +0000820 Py_TYPE(ob)->tp_name);
Fred Drake8844d522001-10-05 21:52:26 +0000821 return NULL;
822 }
823 list = GET_WEAKREFS_LISTPTR(ob);
824 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000825 if (callback == Py_None)
826 callback = NULL;
827 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000828 /* return existing weak reference if it exists */
829 result = ref;
830 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000831 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000832 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000833 /* Note: new_weakref() can trigger cyclic GC, so the weakref
834 list on ob can be mutated. This means that the ref and
835 proxy pointers we got back earlier may have been collected,
836 so we need to compute these values again before we use
837 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000838 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000839 if (result != NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000840 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000841 if (callback == NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000842 if (ref == NULL)
843 insert_head(result, list);
844 else {
845 /* Someone else added a ref without a callback
846 during GC. Return that one instead of this one
847 to avoid violating the invariants of the list
848 of weakrefs for ob. */
849 Py_DECREF(result);
850 Py_INCREF(ref);
851 result = ref;
852 }
Fred Drake8844d522001-10-05 21:52:26 +0000853 }
854 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000855 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000856
Fred Drakebc875f52004-02-04 23:14:14 +0000857 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000858 if (prev == NULL)
859 insert_head(result, list);
860 else
861 insert_after(result, prev);
862 }
Fred Drake8844d522001-10-05 21:52:26 +0000863 }
864 }
865 return (PyObject *) result;
866}
867
868
869PyObject *
870PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
871{
872 PyWeakReference *result = NULL;
873 PyWeakReference **list;
874 PyWeakReference *ref, *proxy;
875
Christian Heimes90aa7642007-12-19 02:45:37 +0000876 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
Fred Drake8844d522001-10-05 21:52:26 +0000877 PyErr_Format(PyExc_TypeError,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000878 "cannot create weak reference to '%s' object",
Christian Heimes90aa7642007-12-19 02:45:37 +0000879 Py_TYPE(ob)->tp_name);
Fred Drake8844d522001-10-05 21:52:26 +0000880 return NULL;
881 }
882 list = GET_WEAKREFS_LISTPTR(ob);
883 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000884 if (callback == Py_None)
885 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000886 if (callback == NULL)
887 /* attempt to return an existing weak reference if it exists */
888 result = proxy;
889 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000890 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000891 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000892 /* Note: new_weakref() can trigger cyclic GC, so the weakref
893 list on ob can be mutated. This means that the ref and
894 proxy pointers we got back earlier may have been collected,
895 so we need to compute these values again before we use
896 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000897 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000898 if (result != NULL) {
899 PyWeakReference *prev;
900
Victor Stinnerd2ec81a2020-02-07 09:17:07 +0100901 if (PyCallable_Check(ob)) {
902 Py_SET_TYPE(result, &_PyWeakref_CallableProxyType);
903 }
904 else {
905 Py_SET_TYPE(result, &_PyWeakref_ProxyType);
906 }
Fred Drakebc875f52004-02-04 23:14:14 +0000907 get_basic_refs(*list, &ref, &proxy);
Fred Drake6d3265d2004-08-03 14:47:25 +0000908 if (callback == NULL) {
909 if (proxy != NULL) {
910 /* Someone else added a proxy without a callback
911 during GC. Return that one instead of this one
912 to avoid violating the invariants of the list
913 of weakrefs for ob. */
914 Py_DECREF(result);
Victor Stinnerb37672d2018-11-22 03:37:50 +0100915 result = proxy;
916 Py_INCREF(result);
Fred Drake6d3265d2004-08-03 14:47:25 +0000917 goto skip_insert;
918 }
Fred Drake8844d522001-10-05 21:52:26 +0000919 prev = ref;
Fred Drake6d3265d2004-08-03 14:47:25 +0000920 }
Fred Drake8844d522001-10-05 21:52:26 +0000921 else
922 prev = (proxy == NULL) ? ref : proxy;
923
924 if (prev == NULL)
925 insert_head(result, list);
926 else
927 insert_after(result, prev);
Fred Drake6d3265d2004-08-03 14:47:25 +0000928 skip_insert:
929 ;
Fred Drake8844d522001-10-05 21:52:26 +0000930 }
931 }
932 return (PyObject *) result;
933}
934
935
936PyObject *
937PyWeakref_GetObject(PyObject *ref)
938{
939 if (ref == NULL || !PyWeakref_Check(ref)) {
940 PyErr_BadInternalCall();
941 return NULL;
942 }
943 return PyWeakref_GET_OBJECT(ref);
944}
945
Tim Petersead8b7a2004-10-30 23:09:22 +0000946/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
947 * handle_weakrefs().
948 */
Fred Drakeef8ebd12001-12-10 23:44:54 +0000949static void
950handle_callback(PyWeakReference *ref, PyObject *callback)
951{
Petr Viktorinffd97532020-02-11 17:46:57 +0100952 PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000953
954 if (cbresult == NULL)
955 PyErr_WriteUnraisable(callback);
956 else
957 Py_DECREF(cbresult);
958}
959
960/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000961 *
962 * This iterates through the weak references for 'object' and calls callbacks
963 * for those references which have one. It returns when all callbacks have
964 * been attempted.
965 */
966void
967PyObject_ClearWeakRefs(PyObject *object)
968{
969 PyWeakReference **list;
970
971 if (object == NULL
Christian Heimes90aa7642007-12-19 02:45:37 +0000972 || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
Victor Stinnera93c51e2020-02-07 00:38:59 +0100973 || Py_REFCNT(object) != 0)
974 {
Fred Drake8844d522001-10-05 21:52:26 +0000975 PyErr_BadInternalCall();
976 return;
977 }
978 list = GET_WEAKREFS_LISTPTR(object);
979 /* Remove the callback-less basic and proxy references */
980 if (*list != NULL && (*list)->wr_callback == NULL) {
981 clear_weakref(*list);
982 if (*list != NULL && (*list)->wr_callback == NULL)
983 clear_weakref(*list);
984 }
985 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000986 PyWeakReference *current = *list;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000987 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000988 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000989
Serhiy Storchaka4aa86792015-03-30 09:52:29 +0300990 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000991 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +0000992 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +0000993
Fred Drakeef8ebd12001-12-10 23:44:54 +0000994 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000995 clear_weakref(current);
Fred Drake0a4dd392004-07-02 18:57:45 +0000996 if (callback != NULL) {
Victor Stinnera93c51e2020-02-07 00:38:59 +0100997 if (Py_REFCNT((PyObject *)current) > 0) {
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +0000998 handle_callback(current, callback);
Victor Stinnera93c51e2020-02-07 00:38:59 +0100999 }
Fred Drake0a4dd392004-07-02 18:57:45 +00001000 Py_DECREF(callback);
1001 }
Fred Drake8844d522001-10-05 21:52:26 +00001002 }
1003 else {
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +00001004 PyObject *tuple;
Martin v. Löwis18e16552006-02-15 17:27:45 +00001005 Py_ssize_t i = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001006
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +00001007 tuple = PyTuple_New(count * 2);
1008 if (tuple == NULL) {
Serhiy Storchaka4aa86792015-03-30 09:52:29 +03001009 _PyErr_ChainExceptions(err_type, err_value, err_tb);
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +00001010 return;
1011 }
Fred Drake8844d522001-10-05 21:52:26 +00001012
1013 for (i = 0; i < count; ++i) {
1014 PyWeakReference *next = current->wr_next;
1015
Victor Stinnera93c51e2020-02-07 00:38:59 +01001016 if (Py_REFCNT((PyObject *)current) > 0) {
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +00001017 Py_INCREF(current);
1018 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
1019 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
1020 }
1021 else {
1022 Py_DECREF(current->wr_callback);
1023 }
Fred Drake8844d522001-10-05 21:52:26 +00001024 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +00001025 clear_weakref(current);
1026 current = next;
1027 }
1028 for (i = 0; i < count; ++i) {
Fred Drake8844d522001-10-05 21:52:26 +00001029 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +00001030
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +00001031 /* The tuple may have slots left to NULL */
Fred Drake0a4dd392004-07-02 18:57:45 +00001032 if (callback != NULL) {
Neal Norwitz0c6e2f12006-01-08 06:13:44 +00001033 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
1034 handle_callback((PyWeakReference *)item, callback);
Fred Drake0a4dd392004-07-02 18:57:45 +00001035 }
Fred Drake8844d522001-10-05 21:52:26 +00001036 }
1037 Py_DECREF(tuple);
1038 }
Serhiy Storchaka4aa86792015-03-30 09:52:29 +03001039 assert(!PyErr_Occurred());
1040 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +00001041 }
1042}