• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "Python.h"
2 #include "pycore_object.h"        // _PyObject_GET_WEAKREFS_LISTPTR()
3 #include "structmember.h"         // PyMemberDef
4 
5 
6 #define GET_WEAKREFS_LISTPTR(o) \
7         ((PyWeakReference **) _PyObject_GET_WEAKREFS_LISTPTR(o))
8 
9 
10 Py_ssize_t
_PyWeakref_GetWeakrefCount(PyWeakReference * head)11 _PyWeakref_GetWeakrefCount(PyWeakReference *head)
12 {
13     Py_ssize_t count = 0;
14 
15     while (head != NULL) {
16         ++count;
17         head = head->wr_next;
18     }
19     return count;
20 }
21 
22 
23 static void
init_weakref(PyWeakReference * self,PyObject * ob,PyObject * callback)24 init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
25 {
26     self->hash = -1;
27     self->wr_object = ob;
28     self->wr_prev = NULL;
29     self->wr_next = NULL;
30     Py_XINCREF(callback);
31     self->wr_callback = callback;
32 }
33 
34 static PyWeakReference *
new_weakref(PyObject * ob,PyObject * callback)35 new_weakref(PyObject *ob, PyObject *callback)
36 {
37     PyWeakReference *result;
38 
39     result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
40     if (result) {
41         init_weakref(result, ob, callback);
42         PyObject_GC_Track(result);
43     }
44     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  */
53 static void
clear_weakref(PyWeakReference * self)54 clear_weakref(PyWeakReference *self)
55 {
56     PyObject *callback = self->wr_callback;
57 
58     if (self->wr_object != Py_None) {
59         PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
60 
61         if (*list == self)
62             /* 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. */
65             *list = self->wr_next;
66         self->wr_object = Py_None;
67         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;
73     }
74     if (callback != NULL) {
75         Py_DECREF(callback);
76         self->wr_callback = NULL;
77     }
78 }
79 
80 /* 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  */
91 void
_PyWeakref_ClearRef(PyWeakReference * self)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 }
104 
105 static void
weakref_dealloc(PyObject * self)106 weakref_dealloc(PyObject *self)
107 {
108     PyObject_GC_UnTrack(self);
109     clear_weakref((PyWeakReference *) self);
110     Py_TYPE(self)->tp_free(self);
111 }
112 
113 
114 static int
gc_traverse(PyWeakReference * self,visitproc visit,void * arg)115 gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
116 {
117     Py_VISIT(self->wr_callback);
118     return 0;
119 }
120 
121 
122 static int
gc_clear(PyWeakReference * self)123 gc_clear(PyWeakReference *self)
124 {
125     clear_weakref(self);
126     return 0;
127 }
128 
129 
130 static PyObject *
weakref_call(PyWeakReference * self,PyObject * args,PyObject * kw)131 weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
132 {
133     static char *kwlist[] = {NULL};
134 
135     if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
136         PyObject *object = PyWeakref_GET_OBJECT(self);
137         Py_INCREF(object);
138         return (object);
139     }
140     return NULL;
141 }
142 
143 
144 static Py_hash_t
weakref_hash(PyWeakReference * self)145 weakref_hash(PyWeakReference *self)
146 {
147     if (self->hash != -1)
148         return self->hash;
149     PyObject* obj = PyWeakref_GET_OBJECT(self);
150     if (obj == Py_None) {
151         PyErr_SetString(PyExc_TypeError, "weak object has gone away");
152         return -1;
153     }
154     Py_INCREF(obj);
155     self->hash = PyObject_Hash(obj);
156     Py_DECREF(obj);
157     return self->hash;
158 }
159 
160 
161 static PyObject *
weakref_repr(PyWeakReference * self)162 weakref_repr(PyWeakReference *self)
163 {
164     PyObject *name, *repr;
165     _Py_IDENTIFIER(__name__);
166     PyObject* obj = PyWeakref_GET_OBJECT(self);
167 
168     if (obj == Py_None) {
169         return PyUnicode_FromFormat("<weakref at %p; dead>", self);
170     }
171 
172     Py_INCREF(obj);
173     if (_PyObject_LookupAttrId(obj, &PyId___name__, &name) < 0) {
174         Py_DECREF(obj);
175         return NULL;
176     }
177     if (name == NULL || !PyUnicode_Check(name)) {
178         repr = PyUnicode_FromFormat(
179             "<weakref at %p; to '%s' at %p>",
180             self,
181             Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
182             obj);
183     }
184     else {
185         repr = PyUnicode_FromFormat(
186             "<weakref at %p; to '%s' at %p (%U)>",
187             self,
188             Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
189             obj,
190             name);
191     }
192     Py_DECREF(obj);
193     Py_XDECREF(name);
194     return repr;
195 }
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 
201 static PyObject *
weakref_richcompare(PyWeakReference * self,PyWeakReference * other,int op)202 weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
203 {
204     if ((op != Py_EQ && op != Py_NE) ||
205         !PyWeakref_Check(self) ||
206         !PyWeakref_Check(other)) {
207         Py_RETURN_NOTIMPLEMENTED;
208     }
209     if (PyWeakref_GET_OBJECT(self) == Py_None
210         || PyWeakref_GET_OBJECT(other) == Py_None) {
211         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;
218     }
219     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;
227 }
228 
229 /* 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  */
234 static void
get_basic_refs(PyWeakReference * head,PyWeakReference ** refp,PyWeakReference ** proxyp)235 get_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. */
259 static void
insert_after(PyWeakReference * newref,PyWeakReference * prev)260 insert_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  */
272 static void
insert_head(PyWeakReference * newref,PyWeakReference ** list)273 insert_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 
284 static int
parse_weakref_init_args(const char * funcname,PyObject * args,PyObject * kwargs,PyObject ** obp,PyObject ** callbackp)285 parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs,
286                         PyObject **obp, PyObject **callbackp)
287 {
288     return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
289 }
290 
291 static PyObject *
weakref___new__(PyTypeObject * type,PyObject * args,PyObject * kwargs)292 weakref___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 
301         if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
302             PyErr_Format(PyExc_TypeError,
303                          "cannot create weak reference to '%s' object",
304                          Py_TYPE(ob)->tp_name);
305             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 
345 static int
weakref___init__(PyObject * self,PyObject * args,PyObject * kwargs)346 weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
347 {
348     PyObject *tmp;
349 
350     if (!_PyArg_NoKeywords("ref", kwargs))
351         return -1;
352 
353     if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
354         return 0;
355     else
356         return -1;
357 }
358 
359 
360 static PyMemberDef weakref_members[] = {
361     {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
362     {NULL} /* Sentinel */
363 };
364 
365 static PyMethodDef weakref_methods[] = {
366     {"__class_getitem__",    (PyCFunction)Py_GenericAlias,
367     METH_O|METH_CLASS,       PyDoc_STR("See PEP 585")},
368     {NULL} /* Sentinel */
369 };
370 
371 PyTypeObject
372 _PyWeakref_RefType = {
373     PyVarObject_HEAD_INIT(&PyType_Type, 0)
374     "weakref",
375     sizeof(PyWeakReference),
376     0,
377     weakref_dealloc,            /*tp_dealloc*/
378     0,                          /*tp_vectorcall_offset*/
379     0,                          /*tp_getattr*/
380     0,                          /*tp_setattr*/
381     0,                          /*tp_as_async*/
382     (reprfunc)weakref_repr,     /*tp_repr*/
383     0,                          /*tp_as_number*/
384     0,                          /*tp_as_sequence*/
385     0,                          /*tp_as_mapping*/
386     (hashfunc)weakref_hash,     /*tp_hash*/
387     (ternaryfunc)weakref_call,  /*tp_call*/
388     0,                          /*tp_str*/
389     0,                          /*tp_getattro*/
390     0,                          /*tp_setattro*/
391     0,                          /*tp_as_buffer*/
392     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
393         | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
394     0,                          /*tp_doc*/
395     (traverseproc)gc_traverse,  /*tp_traverse*/
396     (inquiry)gc_clear,          /*tp_clear*/
397     (richcmpfunc)weakref_richcompare,   /*tp_richcompare*/
398     0,                          /*tp_weaklistoffset*/
399     0,                          /*tp_iter*/
400     0,                          /*tp_iternext*/
401     weakref_methods,            /*tp_methods*/
402     weakref_members,            /*tp_members*/
403     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*/
409     weakref___init__,           /*tp_init*/
410     PyType_GenericAlloc,        /*tp_alloc*/
411     weakref___new__,            /*tp_new*/
412     PyObject_GC_Del,            /*tp_free*/
413 };
414 
415 
416 static int
proxy_checkref(PyWeakReference * proxy)417 proxy_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 
428 /* 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 
439 #define WRAP_UNARY(method, generic) \
440     static PyObject * \
441     method(PyObject *proxy) { \
442         UNWRAP(proxy); \
443         Py_INCREF(proxy); \
444         PyObject* res = generic(proxy); \
445         Py_DECREF(proxy); \
446         return res; \
447     }
448 
449 #define WRAP_BINARY(method, generic) \
450     static PyObject * \
451     method(PyObject *x, PyObject *y) { \
452         UNWRAP(x); \
453         UNWRAP(y); \
454         Py_INCREF(x); \
455         Py_INCREF(y); \
456         PyObject* res = generic(x, y); \
457         Py_DECREF(x); \
458         Py_DECREF(y); \
459         return res; \
460     }
461 
462 /* Note that the third arg needs to be checked for NULL since the tp_call
463  * slot can receive NULL for this arg.
464  */
465 #define WRAP_TERNARY(method, generic) \
466     static PyObject * \
467     method(PyObject *proxy, PyObject *v, PyObject *w) { \
468         UNWRAP(proxy); \
469         UNWRAP(v); \
470         if (w != NULL) \
471             UNWRAP(w); \
472         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; \
480     }
481 
482 #define WRAP_METHOD(method, special) \
483     static PyObject * \
484     method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
485             _Py_IDENTIFIER(special); \
486             UNWRAP(proxy); \
487             Py_INCREF(proxy); \
488             PyObject* res = _PyObject_CallMethodIdNoArgs(proxy, &PyId_##special); \
489             Py_DECREF(proxy); \
490             return res; \
491         }
492 
493 
494 /* direct slots */
495 
WRAP_BINARY(proxy_getattr,PyObject_GetAttr)496 WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
497 WRAP_UNARY(proxy_str, PyObject_Str)
498 WRAP_TERNARY(proxy_call, PyObject_Call)
499 
500 static PyObject *
501 proxy_repr(PyWeakReference *proxy)
502 {
503     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));
508 }
509 
510 
511 static int
proxy_setattr(PyWeakReference * proxy,PyObject * name,PyObject * value)512 proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
513 {
514     if (!proxy_checkref(proxy))
515         return -1;
516     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;
521 }
522 
523 static PyObject *
proxy_richcompare(PyObject * proxy,PyObject * v,int op)524 proxy_richcompare(PyObject *proxy, PyObject *v, int op)
525 {
526     UNWRAP(proxy);
527     UNWRAP(v);
528     return PyObject_RichCompare(proxy, v, op);
529 }
530 
531 /* number slots */
WRAP_BINARY(proxy_add,PyNumber_Add)532 WRAP_BINARY(proxy_add, PyNumber_Add)
533 WRAP_BINARY(proxy_sub, PyNumber_Subtract)
534 WRAP_BINARY(proxy_mul, PyNumber_Multiply)
535 WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
536 WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
537 WRAP_BINARY(proxy_mod, PyNumber_Remainder)
538 WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
539 WRAP_TERNARY(proxy_pow, PyNumber_Power)
540 WRAP_UNARY(proxy_neg, PyNumber_Negative)
541 WRAP_UNARY(proxy_pos, PyNumber_Positive)
542 WRAP_UNARY(proxy_abs, PyNumber_Absolute)
543 WRAP_UNARY(proxy_invert, PyNumber_Invert)
544 WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
545 WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
546 WRAP_BINARY(proxy_and, PyNumber_And)
547 WRAP_BINARY(proxy_xor, PyNumber_Xor)
548 WRAP_BINARY(proxy_or, PyNumber_Or)
549 WRAP_UNARY(proxy_int, PyNumber_Long)
550 WRAP_UNARY(proxy_float, PyNumber_Float)
551 WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
552 WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
553 WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
554 WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
555 WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
556 WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
557 WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
558 WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
559 WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
560 WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
561 WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
562 WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
563 WRAP_UNARY(proxy_index, PyNumber_Index)
564 WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply)
565 WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
566 
567 static int
568 proxy_bool(PyWeakReference *proxy)
569 {
570     PyObject *o = PyWeakref_GET_OBJECT(proxy);
571     if (!proxy_checkref(proxy)) {
572         return -1;
573     }
574     Py_INCREF(o);
575     int res = PyObject_IsTrue(o);
576     Py_DECREF(o);
577     return res;
578 }
579 
580 static void
proxy_dealloc(PyWeakReference * self)581 proxy_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 
589 /* sequence slots */
590 
591 static int
proxy_contains(PyWeakReference * proxy,PyObject * value)592 proxy_contains(PyWeakReference *proxy, PyObject *value)
593 {
594     if (!proxy_checkref(proxy))
595         return -1;
596 
597     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 }
603 
604 /* mapping slots */
605 
606 static Py_ssize_t
proxy_length(PyWeakReference * proxy)607 proxy_length(PyWeakReference *proxy)
608 {
609     if (!proxy_checkref(proxy))
610         return -1;
611 
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;
617 }
618 
WRAP_BINARY(proxy_getitem,PyObject_GetItem)619 WRAP_BINARY(proxy_getitem, PyObject_GetItem)
620 
621 static int
622 proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
623 {
624     if (!proxy_checkref(proxy))
625         return -1;
626 
627     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;
637 }
638 
639 /* iterator slots */
640 
641 static PyObject *
proxy_iter(PyWeakReference * proxy)642 proxy_iter(PyWeakReference *proxy)
643 {
644     if (!proxy_checkref(proxy))
645         return NULL;
646     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
647     Py_INCREF(obj);
648     PyObject* res = PyObject_GetIter(obj);
649     Py_DECREF(obj);
650     return res;
651 }
652 
653 static PyObject *
proxy_iternext(PyWeakReference * proxy)654 proxy_iternext(PyWeakReference *proxy)
655 {
656     if (!proxy_checkref(proxy))
657         return NULL;
658 
659     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
660     Py_INCREF(obj);
661     PyObject* res = PyIter_Next(obj);
662     Py_DECREF(obj);
663     return res;
664 }
665 
666 
667 WRAP_METHOD(proxy_bytes, __bytes__)
668 WRAP_METHOD(proxy_reversed, __reversed__)
669 
670 
671 static PyMethodDef proxy_methods[] = {
672         {"__bytes__", proxy_bytes, METH_NOARGS},
673         {"__reversed__", proxy_reversed, METH_NOARGS},
674         {NULL, NULL}
675 };
676 
677 
678 static PyNumberMethods proxy_as_number = {
679     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*/
688     (inquiry)proxy_bool,    /*nb_bool*/
689     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*/
695     proxy_int,              /*nb_int*/
696     0,                      /*nb_reserved*/
697     proxy_float,            /*nb_float*/
698     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*/
708     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*/
713     proxy_matmul,           /*nb_matrix_multiply*/
714     proxy_imatmul,          /*nb_inplace_matrix_multiply*/
715 };
716 
717 static PySequenceMethods proxy_as_sequence = {
718     (lenfunc)proxy_length,      /*sq_length*/
719     0,                          /*sq_concat*/
720     0,                          /*sq_repeat*/
721     0,                          /*sq_item*/
722     0,                          /*sq_slice*/
723     0,                          /*sq_ass_item*/
724     0,                           /*sq_ass_slice*/
725     (objobjproc)proxy_contains, /* sq_contains */
726 };
727 
728 static PyMappingMethods proxy_as_mapping = {
729     (lenfunc)proxy_length,        /*mp_length*/
730     proxy_getitem,                /*mp_subscript*/
731     (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
732 };
733 
734 
735 static Py_hash_t
proxy_hash(PyObject * self)736 proxy_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 
750 PyTypeObject
751 _PyWeakref_ProxyType = {
752     PyVarObject_HEAD_INIT(&PyType_Type, 0)
753     "weakproxy",
754     sizeof(PyWeakReference),
755     0,
756     /* methods */
757     (destructor)proxy_dealloc,          /* tp_dealloc */
758     0,                                  /* tp_vectorcall_offset */
759     0,                                  /* tp_getattr */
760     0,                                  /* tp_setattr */
761     0,                                  /* tp_as_async */
762     (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 */
766     proxy_hash,                         /* tp_hash */
767     0,                                  /* tp_call */
768     proxy_str,                          /* tp_str */
769     proxy_getattr,                      /* tp_getattro */
770     (setattrofunc)proxy_setattr,        /* tp_setattro */
771     0,                                  /* tp_as_buffer */
772     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
773     0,                                  /* tp_doc */
774     (traverseproc)gc_traverse,          /* tp_traverse */
775     (inquiry)gc_clear,                  /* tp_clear */
776     proxy_richcompare,                  /* tp_richcompare */
777     0,                                  /* tp_weaklistoffset */
778     (getiterfunc)proxy_iter,            /* tp_iter */
779     (iternextfunc)proxy_iternext,       /* tp_iternext */
780         proxy_methods,                      /* tp_methods */
781 };
782 
783 
784 PyTypeObject
785 _PyWeakref_CallableProxyType = {
786     PyVarObject_HEAD_INIT(&PyType_Type, 0)
787     "weakcallableproxy",
788     sizeof(PyWeakReference),
789     0,
790     /* methods */
791     (destructor)proxy_dealloc,          /* tp_dealloc */
792     0,                                  /* tp_vectorcall_offset */
793     0,                                  /* tp_getattr */
794     0,                                  /* tp_setattr */
795     0,                                  /* tp_as_async */
796     (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 */
803     proxy_getattr,                      /* tp_getattro */
804     (setattrofunc)proxy_setattr,        /* tp_setattro */
805     0,                                  /* tp_as_buffer */
806     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
807     0,                                  /* tp_doc */
808     (traverseproc)gc_traverse,          /* tp_traverse */
809     (inquiry)gc_clear,                  /* tp_clear */
810     proxy_richcompare,                  /* tp_richcompare */
811     0,                                  /* tp_weaklistoffset */
812     (getiterfunc)proxy_iter,            /* tp_iter */
813     (iternextfunc)proxy_iternext,       /* tp_iternext */
814 };
815 
816 
817 
818 PyObject *
PyWeakref_NewRef(PyObject * ob,PyObject * callback)819 PyWeakref_NewRef(PyObject *ob, PyObject *callback)
820 {
821     PyWeakReference *result = NULL;
822     PyWeakReference **list;
823     PyWeakReference *ref, *proxy;
824 
825     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
826         PyErr_Format(PyExc_TypeError,
827                      "cannot create weak reference to '%s' object",
828                      Py_TYPE(ob)->tp_name);
829         return NULL;
830     }
831     list = GET_WEAKREFS_LISTPTR(ob);
832     get_basic_refs(*list, &ref, &proxy);
833     if (callback == Py_None)
834         callback = NULL;
835     if (callback == NULL)
836         /* return existing weak reference if it exists */
837         result = ref;
838     if (result != NULL)
839         Py_INCREF(result);
840     else {
841         /* 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. */
846         result = new_weakref(ob, callback);
847         if (result != NULL) {
848             get_basic_refs(*list, &ref, &proxy);
849             if (callback == NULL) {
850                 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                 }
861             }
862             else {
863                 PyWeakReference *prev;
864 
865                 prev = (proxy == NULL) ? ref : proxy;
866                 if (prev == NULL)
867                     insert_head(result, list);
868                 else
869                     insert_after(result, prev);
870             }
871         }
872     }
873     return (PyObject *) result;
874 }
875 
876 
877 PyObject *
PyWeakref_NewProxy(PyObject * ob,PyObject * callback)878 PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
879 {
880     PyWeakReference *result = NULL;
881     PyWeakReference **list;
882     PyWeakReference *ref, *proxy;
883 
884     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
885         PyErr_Format(PyExc_TypeError,
886                      "cannot create weak reference to '%s' object",
887                      Py_TYPE(ob)->tp_name);
888         return NULL;
889     }
890     list = GET_WEAKREFS_LISTPTR(ob);
891     get_basic_refs(*list, &ref, &proxy);
892     if (callback == Py_None)
893         callback = NULL;
894     if (callback == NULL)
895         /* attempt to return an existing weak reference if it exists */
896         result = proxy;
897     if (result != NULL)
898         Py_INCREF(result);
899     else {
900         /* 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. */
905         result = new_weakref(ob, callback);
906         if (result != NULL) {
907             PyWeakReference *prev;
908 
909             if (PyCallable_Check(ob)) {
910                 Py_SET_TYPE(result, &_PyWeakref_CallableProxyType);
911             }
912             else {
913                 Py_SET_TYPE(result, &_PyWeakref_ProxyType);
914             }
915             get_basic_refs(*list, &ref, &proxy);
916             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);
923                     result = proxy;
924                     Py_INCREF(result);
925                     goto skip_insert;
926                 }
927                 prev = ref;
928             }
929             else
930                 prev = (proxy == NULL) ? ref : proxy;
931 
932             if (prev == NULL)
933                 insert_head(result, list);
934             else
935                 insert_after(result, prev);
936         skip_insert:
937             ;
938         }
939     }
940     return (PyObject *) result;
941 }
942 
943 
944 PyObject *
PyWeakref_GetObject(PyObject * ref)945 PyWeakref_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 
954 /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
955  * handle_weakrefs().
956  */
957 static void
handle_callback(PyWeakReference * ref,PyObject * callback)958 handle_callback(PyWeakReference *ref, PyObject *callback)
959 {
960     PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref);
961 
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.
969  *
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  */
974 void
PyObject_ClearWeakRefs(PyObject * object)975 PyObject_ClearWeakRefs(PyObject *object)
976 {
977     PyWeakReference **list;
978 
979     if (object == NULL
980         || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
981         || Py_REFCNT(object) != 0)
982     {
983         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) {
994         PyWeakReference *current = *list;
995         Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
996         PyObject *err_type, *err_value, *err_tb;
997 
998         PyErr_Fetch(&err_type, &err_value, &err_tb);
999         if (count == 1) {
1000             PyObject *callback = current->wr_callback;
1001 
1002             current->wr_callback = NULL;
1003             clear_weakref(current);
1004             if (callback != NULL) {
1005                 if (Py_REFCNT((PyObject *)current) > 0) {
1006                     handle_callback(current, callback);
1007                 }
1008                 Py_DECREF(callback);
1009             }
1010         }
1011         else {
1012             PyObject *tuple;
1013             Py_ssize_t i = 0;
1014 
1015             tuple = PyTuple_New(count * 2);
1016             if (tuple == NULL) {
1017                 _PyErr_ChainExceptions(err_type, err_value, err_tb);
1018                 return;
1019             }
1020 
1021             for (i = 0; i < count; ++i) {
1022                 PyWeakReference *next = current->wr_next;
1023 
1024                 if (Py_REFCNT((PyObject *)current) > 0) {
1025                     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                 }
1032                 current->wr_callback = NULL;
1033                 clear_weakref(current);
1034                 current = next;
1035             }
1036             for (i = 0; i < count; ++i) {
1037                 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
1038 
1039                 /* The tuple may have slots left to NULL */
1040                 if (callback != NULL) {
1041                     PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
1042                     handle_callback((PyWeakReference *)item, callback);
1043                 }
1044             }
1045             Py_DECREF(tuple);
1046         }
1047         assert(!PyErr_Occurred());
1048         PyErr_Restore(err_type, err_value, err_tb);
1049     }
1050 }
1051