blob: 313e8abab5a25fe47d06670caa9eee1bc936ab6e [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);
660 Py_INCREF(obj);
661 PyObject* res = PyIter_Next(obj);
662 Py_DECREF(obj);
663 return res;
Fred Drakef16c3dc2002-08-09 18:34:16 +0000664}
665
Fred Drake8844d522001-10-05 21:52:26 +0000666
Martin v. Löwisafe55bb2011-10-09 10:38:36 +0200667WRAP_METHOD(proxy_bytes, __bytes__)
Pablo Galindo96074de2020-05-05 22:58:19 +0100668WRAP_METHOD(proxy_reversed, __reversed__)
Benjamin Peterson32019772009-11-19 03:08:32 +0000669
670
671static PyMethodDef proxy_methods[] = {
Siddhesh Poyarekar55edd0c2018-04-30 00:29:33 +0530672 {"__bytes__", proxy_bytes, METH_NOARGS},
Pablo Galindo96074de2020-05-05 22:58:19 +0100673 {"__reversed__", proxy_reversed, METH_NOARGS},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000674 {NULL, NULL}
Benjamin Peterson32019772009-11-19 03:08:32 +0000675};
676
677
Fred Drake8844d522001-10-05 21:52:26 +0000678static PyNumberMethods proxy_as_number = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000679 proxy_add, /*nb_add*/
680 proxy_sub, /*nb_subtract*/
681 proxy_mul, /*nb_multiply*/
682 proxy_mod, /*nb_remainder*/
683 proxy_divmod, /*nb_divmod*/
684 proxy_pow, /*nb_power*/
685 proxy_neg, /*nb_negative*/
686 proxy_pos, /*nb_positive*/
687 proxy_abs, /*nb_absolute*/
Jack Diederich4dafcc42006-11-28 19:15:13 +0000688 (inquiry)proxy_bool, /*nb_bool*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000689 proxy_invert, /*nb_invert*/
690 proxy_lshift, /*nb_lshift*/
691 proxy_rshift, /*nb_rshift*/
692 proxy_and, /*nb_and*/
693 proxy_xor, /*nb_xor*/
694 proxy_or, /*nb_or*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000695 proxy_int, /*nb_int*/
Mark Dickinson8055afd2009-01-17 10:04:45 +0000696 0, /*nb_reserved*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000697 proxy_float, /*nb_float*/
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000698 proxy_iadd, /*nb_inplace_add*/
699 proxy_isub, /*nb_inplace_subtract*/
700 proxy_imul, /*nb_inplace_multiply*/
701 proxy_imod, /*nb_inplace_remainder*/
702 proxy_ipow, /*nb_inplace_power*/
703 proxy_ilshift, /*nb_inplace_lshift*/
704 proxy_irshift, /*nb_inplace_rshift*/
705 proxy_iand, /*nb_inplace_and*/
706 proxy_ixor, /*nb_inplace_xor*/
707 proxy_ior, /*nb_inplace_or*/
Georg Brandlb533e262008-05-25 18:19:30 +0000708 proxy_floor_div, /*nb_floor_divide*/
709 proxy_true_div, /*nb_true_divide*/
710 proxy_ifloor_div, /*nb_inplace_floor_divide*/
711 proxy_itrue_div, /*nb_inplace_true_divide*/
712 proxy_index, /*nb_index*/
Mark Dickinson7abb6c02019-04-26 15:56:15 +0900713 proxy_matmul, /*nb_matrix_multiply*/
714 proxy_imatmul, /*nb_inplace_matrix_multiply*/
Fred Drake8844d522001-10-05 21:52:26 +0000715};
716
717static PySequenceMethods proxy_as_sequence = {
Martin v. Löwis18e16552006-02-15 17:27:45 +0000718 (lenfunc)proxy_length, /*sq_length*/
Fred Drake8844d522001-10-05 21:52:26 +0000719 0, /*sq_concat*/
720 0, /*sq_repeat*/
721 0, /*sq_item*/
Thomas Woutersd2cf20e2007-08-30 22:57:53 +0000722 0, /*sq_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000723 0, /*sq_ass_item*/
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000724 0, /*sq_ass_slice*/
Fred Drake8844d522001-10-05 21:52:26 +0000725 (objobjproc)proxy_contains, /* sq_contains */
726};
727
728static PyMappingMethods proxy_as_mapping = {
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000729 (lenfunc)proxy_length, /*mp_length*/
730 proxy_getitem, /*mp_subscript*/
Fred Drake8844d522001-10-05 21:52:26 +0000731 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
732};
733
734
Pablo Galindo96074de2020-05-05 22:58:19 +0100735static Py_hash_t
736proxy_hash(PyObject *self)
737{
738 PyWeakReference *proxy = (PyWeakReference *)self;
739 if (!proxy_checkref(proxy)) {
740 return -1;
741 }
742 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
743 Py_INCREF(obj);
744 Py_hash_t res = PyObject_Hash(obj);
745 Py_DECREF(obj);
746 return res;
747}
748
749
Fred Drake8844d522001-10-05 21:52:26 +0000750PyTypeObject
751_PyWeakref_ProxyType = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000752 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000753 "weakproxy",
754 sizeof(PyWeakReference),
755 0,
756 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000757 (destructor)proxy_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200758 0, /* tp_vectorcall_offset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000759 0, /* tp_getattr */
760 0, /* tp_setattr */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200761 0, /* tp_as_async */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000762 (reprfunc)proxy_repr, /* tp_repr */
763 &proxy_as_number, /* tp_as_number */
764 &proxy_as_sequence, /* tp_as_sequence */
765 &proxy_as_mapping, /* tp_as_mapping */
Pablo Galindo96074de2020-05-05 22:58:19 +0100766 proxy_hash, /* tp_hash */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000767 0, /* tp_call */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000768 proxy_str, /* tp_str */
769 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000770 (setattrofunc)proxy_setattr, /* tp_setattro */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000771 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000772 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000773 0, /* tp_doc */
774 (traverseproc)gc_traverse, /* tp_traverse */
775 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000776 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000777 0, /* tp_weaklistoffset */
778 (getiterfunc)proxy_iter, /* tp_iter */
779 (iternextfunc)proxy_iternext, /* tp_iternext */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000780 proxy_methods, /* tp_methods */
Fred Drake8844d522001-10-05 21:52:26 +0000781};
782
783
784PyTypeObject
785_PyWeakref_CallableProxyType = {
Martin v. Löwis9f2e3462007-07-21 17:22:18 +0000786 PyVarObject_HEAD_INIT(&PyType_Type, 0)
Fred Drake8844d522001-10-05 21:52:26 +0000787 "weakcallableproxy",
788 sizeof(PyWeakReference),
789 0,
790 /* methods */
Fred Drake0a4dd392004-07-02 18:57:45 +0000791 (destructor)proxy_dealloc, /* tp_dealloc */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200792 0, /* tp_vectorcall_offset */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000793 0, /* tp_getattr */
794 0, /* tp_setattr */
Jeroen Demeyer530f5062019-05-31 04:13:39 +0200795 0, /* tp_as_async */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000796 (unaryfunc)proxy_repr, /* tp_repr */
797 &proxy_as_number, /* tp_as_number */
798 &proxy_as_sequence, /* tp_as_sequence */
799 &proxy_as_mapping, /* tp_as_mapping */
800 0, /* tp_hash */
801 proxy_call, /* tp_call */
802 proxy_str, /* tp_str */
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000803 proxy_getattr, /* tp_getattro */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000804 (setattrofunc)proxy_setattr, /* tp_setattro */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000805 0, /* tp_as_buffer */
Guido van Rossum3cf5b1e2006-07-27 21:53:35 +0000806 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000807 0, /* tp_doc */
808 (traverseproc)gc_traverse, /* tp_traverse */
809 (inquiry)gc_clear, /* tp_clear */
Guido van Rossum47b9ff62006-08-24 00:41:19 +0000810 proxy_richcompare, /* tp_richcompare */
Fred Drakef16c3dc2002-08-09 18:34:16 +0000811 0, /* tp_weaklistoffset */
812 (getiterfunc)proxy_iter, /* tp_iter */
813 (iternextfunc)proxy_iternext, /* tp_iternext */
Fred Drake8844d522001-10-05 21:52:26 +0000814};
815
816
Fred Drake8844d522001-10-05 21:52:26 +0000817
818PyObject *
819PyWeakref_NewRef(PyObject *ob, PyObject *callback)
820{
821 PyWeakReference *result = NULL;
822 PyWeakReference **list;
823 PyWeakReference *ref, *proxy;
824
Christian Heimes90aa7642007-12-19 02:45:37 +0000825 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
Fred Drake8844d522001-10-05 21:52:26 +0000826 PyErr_Format(PyExc_TypeError,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000827 "cannot create weak reference to '%s' object",
Christian Heimes90aa7642007-12-19 02:45:37 +0000828 Py_TYPE(ob)->tp_name);
Fred Drake8844d522001-10-05 21:52:26 +0000829 return NULL;
830 }
831 list = GET_WEAKREFS_LISTPTR(ob);
832 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000833 if (callback == Py_None)
834 callback = NULL;
835 if (callback == NULL)
Fred Drake8844d522001-10-05 21:52:26 +0000836 /* return existing weak reference if it exists */
837 result = ref;
838 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000839 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000840 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000841 /* Note: new_weakref() can trigger cyclic GC, so the weakref
842 list on ob can be mutated. This means that the ref and
843 proxy pointers we got back earlier may have been collected,
844 so we need to compute these values again before we use
845 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000846 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000847 if (result != NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000848 get_basic_refs(*list, &ref, &proxy);
Fred Drake8844d522001-10-05 21:52:26 +0000849 if (callback == NULL) {
Fred Drake6d3265d2004-08-03 14:47:25 +0000850 if (ref == NULL)
851 insert_head(result, list);
852 else {
853 /* Someone else added a ref without a callback
854 during GC. Return that one instead of this one
855 to avoid violating the invariants of the list
856 of weakrefs for ob. */
857 Py_DECREF(result);
858 Py_INCREF(ref);
859 result = ref;
860 }
Fred Drake8844d522001-10-05 21:52:26 +0000861 }
862 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000863 PyWeakReference *prev;
Fred Drake8844d522001-10-05 21:52:26 +0000864
Fred Drakebc875f52004-02-04 23:14:14 +0000865 prev = (proxy == NULL) ? ref : proxy;
Fred Drake8844d522001-10-05 21:52:26 +0000866 if (prev == NULL)
867 insert_head(result, list);
868 else
869 insert_after(result, prev);
870 }
Fred Drake8844d522001-10-05 21:52:26 +0000871 }
872 }
873 return (PyObject *) result;
874}
875
876
877PyObject *
878PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
879{
880 PyWeakReference *result = NULL;
881 PyWeakReference **list;
882 PyWeakReference *ref, *proxy;
883
Christian Heimes90aa7642007-12-19 02:45:37 +0000884 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
Fred Drake8844d522001-10-05 21:52:26 +0000885 PyErr_Format(PyExc_TypeError,
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000886 "cannot create weak reference to '%s' object",
Christian Heimes90aa7642007-12-19 02:45:37 +0000887 Py_TYPE(ob)->tp_name);
Fred Drake8844d522001-10-05 21:52:26 +0000888 return NULL;
889 }
890 list = GET_WEAKREFS_LISTPTR(ob);
891 get_basic_refs(*list, &ref, &proxy);
Fred Drake6a2852c2004-02-03 19:52:56 +0000892 if (callback == Py_None)
893 callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +0000894 if (callback == NULL)
895 /* attempt to return an existing weak reference if it exists */
896 result = proxy;
897 if (result != NULL)
Fred Drakebc875f52004-02-04 23:14:14 +0000898 Py_INCREF(result);
Fred Drake8844d522001-10-05 21:52:26 +0000899 else {
Fred Drakebc875f52004-02-04 23:14:14 +0000900 /* Note: new_weakref() can trigger cyclic GC, so the weakref
901 list on ob can be mutated. This means that the ref and
902 proxy pointers we got back earlier may have been collected,
903 so we need to compute these values again before we use
904 them. */
Neil Schemenauer38a89162002-03-27 15:18:21 +0000905 result = new_weakref(ob, callback);
Fred Drake8844d522001-10-05 21:52:26 +0000906 if (result != NULL) {
907 PyWeakReference *prev;
908
Victor Stinnerd2ec81a2020-02-07 09:17:07 +0100909 if (PyCallable_Check(ob)) {
910 Py_SET_TYPE(result, &_PyWeakref_CallableProxyType);
911 }
912 else {
913 Py_SET_TYPE(result, &_PyWeakref_ProxyType);
914 }
Fred Drakebc875f52004-02-04 23:14:14 +0000915 get_basic_refs(*list, &ref, &proxy);
Fred Drake6d3265d2004-08-03 14:47:25 +0000916 if (callback == NULL) {
917 if (proxy != NULL) {
918 /* Someone else added a proxy without a callback
919 during GC. Return that one instead of this one
920 to avoid violating the invariants of the list
921 of weakrefs for ob. */
922 Py_DECREF(result);
Victor Stinnerb37672d2018-11-22 03:37:50 +0100923 result = proxy;
924 Py_INCREF(result);
Fred Drake6d3265d2004-08-03 14:47:25 +0000925 goto skip_insert;
926 }
Fred Drake8844d522001-10-05 21:52:26 +0000927 prev = ref;
Fred Drake6d3265d2004-08-03 14:47:25 +0000928 }
Fred Drake8844d522001-10-05 21:52:26 +0000929 else
930 prev = (proxy == NULL) ? ref : proxy;
931
932 if (prev == NULL)
933 insert_head(result, list);
934 else
935 insert_after(result, prev);
Fred Drake6d3265d2004-08-03 14:47:25 +0000936 skip_insert:
937 ;
Fred Drake8844d522001-10-05 21:52:26 +0000938 }
939 }
940 return (PyObject *) result;
941}
942
943
944PyObject *
945PyWeakref_GetObject(PyObject *ref)
946{
947 if (ref == NULL || !PyWeakref_Check(ref)) {
948 PyErr_BadInternalCall();
949 return NULL;
950 }
951 return PyWeakref_GET_OBJECT(ref);
952}
953
Tim Petersead8b7a2004-10-30 23:09:22 +0000954/* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
955 * handle_weakrefs().
956 */
Fred Drakeef8ebd12001-12-10 23:44:54 +0000957static void
958handle_callback(PyWeakReference *ref, PyObject *callback)
959{
Petr Viktorinffd97532020-02-11 17:46:57 +0100960 PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000961
962 if (cbresult == NULL)
963 PyErr_WriteUnraisable(callback);
964 else
965 Py_DECREF(cbresult);
966}
967
968/* This function is called by the tp_dealloc handler to clear weak references.
Fred Drake8844d522001-10-05 21:52:26 +0000969 *
970 * This iterates through the weak references for 'object' and calls callbacks
971 * for those references which have one. It returns when all callbacks have
972 * been attempted.
973 */
974void
975PyObject_ClearWeakRefs(PyObject *object)
976{
977 PyWeakReference **list;
978
979 if (object == NULL
Christian Heimes90aa7642007-12-19 02:45:37 +0000980 || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
Victor Stinnera93c51e2020-02-07 00:38:59 +0100981 || Py_REFCNT(object) != 0)
982 {
Fred Drake8844d522001-10-05 21:52:26 +0000983 PyErr_BadInternalCall();
984 return;
985 }
986 list = GET_WEAKREFS_LISTPTR(object);
987 /* Remove the callback-less basic and proxy references */
988 if (*list != NULL && (*list)->wr_callback == NULL) {
989 clear_weakref(*list);
990 if (*list != NULL && (*list)->wr_callback == NULL)
991 clear_weakref(*list);
992 }
993 if (*list != NULL) {
Fred Drakeef8ebd12001-12-10 23:44:54 +0000994 PyWeakReference *current = *list;
Martin v. Löwis18e16552006-02-15 17:27:45 +0000995 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
Fred Drakeef8ebd12001-12-10 23:44:54 +0000996 PyObject *err_type, *err_value, *err_tb;
Fred Drake8844d522001-10-05 21:52:26 +0000997
Serhiy Storchaka4aa86792015-03-30 09:52:29 +0300998 PyErr_Fetch(&err_type, &err_value, &err_tb);
Fred Drake8844d522001-10-05 21:52:26 +0000999 if (count == 1) {
Fred Drake8844d522001-10-05 21:52:26 +00001000 PyObject *callback = current->wr_callback;
Fred Drake8844d522001-10-05 21:52:26 +00001001
Fred Drakeef8ebd12001-12-10 23:44:54 +00001002 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +00001003 clear_weakref(current);
Fred Drake0a4dd392004-07-02 18:57:45 +00001004 if (callback != NULL) {
Victor Stinnera93c51e2020-02-07 00:38:59 +01001005 if (Py_REFCNT((PyObject *)current) > 0) {
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +00001006 handle_callback(current, callback);
Victor Stinnera93c51e2020-02-07 00:38:59 +01001007 }
Fred Drake0a4dd392004-07-02 18:57:45 +00001008 Py_DECREF(callback);
1009 }
Fred Drake8844d522001-10-05 21:52:26 +00001010 }
1011 else {
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +00001012 PyObject *tuple;
Martin v. Löwis18e16552006-02-15 17:27:45 +00001013 Py_ssize_t i = 0;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +00001014
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +00001015 tuple = PyTuple_New(count * 2);
1016 if (tuple == NULL) {
Serhiy Storchaka4aa86792015-03-30 09:52:29 +03001017 _PyErr_ChainExceptions(err_type, err_value, err_tb);
Hye-Shik Chang4af5c8c2006-03-07 15:39:21 +00001018 return;
1019 }
Fred Drake8844d522001-10-05 21:52:26 +00001020
1021 for (i = 0; i < count; ++i) {
1022 PyWeakReference *next = current->wr_next;
1023
Victor Stinnera93c51e2020-02-07 00:38:59 +01001024 if (Py_REFCNT((PyObject *)current) > 0) {
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +00001025 Py_INCREF(current);
1026 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
1027 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
1028 }
1029 else {
1030 Py_DECREF(current->wr_callback);
1031 }
Fred Drake8844d522001-10-05 21:52:26 +00001032 current->wr_callback = NULL;
Fred Drake8844d522001-10-05 21:52:26 +00001033 clear_weakref(current);
1034 current = next;
1035 }
1036 for (i = 0; i < count; ++i) {
Fred Drake8844d522001-10-05 21:52:26 +00001037 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
Fred Drakeef8ebd12001-12-10 23:44:54 +00001038
Amaury Forgeot d'Arcc856c7a2008-06-16 19:50:09 +00001039 /* The tuple may have slots left to NULL */
Fred Drake0a4dd392004-07-02 18:57:45 +00001040 if (callback != NULL) {
Neal Norwitz0c6e2f12006-01-08 06:13:44 +00001041 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
1042 handle_callback((PyWeakReference *)item, callback);
Fred Drake0a4dd392004-07-02 18:57:45 +00001043 }
Fred Drake8844d522001-10-05 21:52:26 +00001044 }
1045 Py_DECREF(tuple);
1046 }
Serhiy Storchaka4aa86792015-03-30 09:52:29 +03001047 assert(!PyErr_Occurred());
1048 PyErr_Restore(err_type, err_value, err_tb);
Fred Drake8844d522001-10-05 21:52:26 +00001049 }
1050}