1 #include "Python.h"
2 #include "structmember.h"
3 
4 
5 #define GET_WEAKREFS_LISTPTR(o) \
6         ((PyWeakReference **) PyObject_GET_WEAKREFS_LISTPTR(o))
7 
8 
9 Py_ssize_t
_PyWeakref_GetWeakrefCount(PyWeakReference * head)10 _PyWeakref_GetWeakrefCount(PyWeakReference *head)
11 {
12     Py_ssize_t count = 0;
13 
14     while (head != NULL) {
15         ++count;
16         head = head->wr_next;
17     }
18     return count;
19 }
20 
21 
22 static void
init_weakref(PyWeakReference * self,PyObject * ob,PyObject * callback)23 init_weakref(PyWeakReference *self, PyObject *ob, PyObject *callback)
24 {
25     self->hash = -1;
26     self->wr_object = ob;
27     self->wr_prev = NULL;
28     self->wr_next = NULL;
29     Py_XINCREF(callback);
30     self->wr_callback = callback;
31 }
32 
33 static PyWeakReference *
new_weakref(PyObject * ob,PyObject * callback)34 new_weakref(PyObject *ob, PyObject *callback)
35 {
36     PyWeakReference *result;
37 
38     result = PyObject_GC_New(PyWeakReference, &_PyWeakref_RefType);
39     if (result) {
40         init_weakref(result, ob, callback);
41         PyObject_GC_Track(result);
42     }
43     return result;
44 }
45 
46 
47 /* This function clears the passed-in reference and removes it from the
48  * list of weak references for the referent.  This is the only code that
49  * removes an item from the doubly-linked list of weak references for an
50  * object; it is also responsible for clearing the callback slot.
51  */
52 static void
clear_weakref(PyWeakReference * self)53 clear_weakref(PyWeakReference *self)
54 {
55     PyObject *callback = self->wr_callback;
56 
57     if (self->wr_object != Py_None) {
58         PyWeakReference **list = GET_WEAKREFS_LISTPTR(self->wr_object);
59 
60         if (*list == self)
61             /* If 'self' is the end of the list (and thus self->wr_next == NULL)
62                then the weakref list itself (and thus the value of *list) will
63                end up being set to NULL. */
64             *list = self->wr_next;
65         self->wr_object = Py_None;
66         if (self->wr_prev != NULL)
67             self->wr_prev->wr_next = self->wr_next;
68         if (self->wr_next != NULL)
69             self->wr_next->wr_prev = self->wr_prev;
70         self->wr_prev = NULL;
71         self->wr_next = NULL;
72     }
73     if (callback != NULL) {
74         Py_DECREF(callback);
75         self->wr_callback = NULL;
76     }
77 }
78 
79 /* Cyclic gc uses this to *just* clear the passed-in reference, leaving
80  * the callback intact and uncalled.  It must be possible to call self's
81  * tp_dealloc() after calling this, so self has to be left in a sane enough
82  * state for that to work.  We expect tp_dealloc to decref the callback
83  * then.  The reason for not letting clear_weakref() decref the callback
84  * right now is that if the callback goes away, that may in turn trigger
85  * another callback (if a weak reference to the callback exists) -- running
86  * arbitrary Python code in the middle of gc is a disaster.  The convolution
87  * here allows gc to delay triggering such callbacks until the world is in
88  * a sane state again.
89  */
90 void
_PyWeakref_ClearRef(PyWeakReference * self)91 _PyWeakref_ClearRef(PyWeakReference *self)
92 {
93     PyObject *callback;
94 
95     assert(self != NULL);
96     assert(PyWeakref_Check(self));
97     /* Preserve and restore the callback around clear_weakref. */
98     callback = self->wr_callback;
99     self->wr_callback = NULL;
100     clear_weakref(self);
101     self->wr_callback = callback;
102 }
103 
104 static void
weakref_dealloc(PyObject * self)105 weakref_dealloc(PyObject *self)
106 {
107     PyObject_GC_UnTrack(self);
108     clear_weakref((PyWeakReference *) self);
109     Py_TYPE(self)->tp_free(self);
110 }
111 
112 
113 static int
gc_traverse(PyWeakReference * self,visitproc visit,void * arg)114 gc_traverse(PyWeakReference *self, visitproc visit, void *arg)
115 {
116     Py_VISIT(self->wr_callback);
117     return 0;
118 }
119 
120 
121 static int
gc_clear(PyWeakReference * self)122 gc_clear(PyWeakReference *self)
123 {
124     clear_weakref(self);
125     return 0;
126 }
127 
128 
129 static PyObject *
weakref_call(PyWeakReference * self,PyObject * args,PyObject * kw)130 weakref_call(PyWeakReference *self, PyObject *args, PyObject *kw)
131 {
132     static char *kwlist[] = {NULL};
133 
134     if (PyArg_ParseTupleAndKeywords(args, kw, ":__call__", kwlist)) {
135         PyObject *object = PyWeakref_GET_OBJECT(self);
136         Py_INCREF(object);
137         return (object);
138     }
139     return NULL;
140 }
141 
142 
143 static Py_hash_t
weakref_hash(PyWeakReference * self)144 weakref_hash(PyWeakReference *self)
145 {
146     if (self->hash != -1)
147         return self->hash;
148     PyObject* obj = PyWeakref_GET_OBJECT(self);
149     if (obj == Py_None) {
150         PyErr_SetString(PyExc_TypeError, "weak object has gone away");
151         return -1;
152     }
153     Py_INCREF(obj);
154     self->hash = PyObject_Hash(obj);
155     Py_DECREF(obj);
156     return self->hash;
157 }
158 
159 
160 static PyObject *
weakref_repr(PyWeakReference * self)161 weakref_repr(PyWeakReference *self)
162 {
163     PyObject *name, *repr;
164     _Py_IDENTIFIER(__name__);
165     PyObject* obj = PyWeakref_GET_OBJECT(self);
166 
167     if (obj == Py_None) {
168         return PyUnicode_FromFormat("<weakref at %p; dead>", self);
169     }
170 
171     Py_INCREF(obj);
172     if (_PyObject_LookupAttrId(obj, &PyId___name__, &name) < 0) {
173         Py_DECREF(obj);
174         return NULL;
175     }
176     if (name == NULL || !PyUnicode_Check(name)) {
177         repr = PyUnicode_FromFormat(
178             "<weakref at %p; to '%s' at %p>",
179             self,
180             Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
181             obj);
182     }
183     else {
184         repr = PyUnicode_FromFormat(
185             "<weakref at %p; to '%s' at %p (%U)>",
186             self,
187             Py_TYPE(PyWeakref_GET_OBJECT(self))->tp_name,
188             obj,
189             name);
190     }
191     Py_DECREF(obj);
192     Py_XDECREF(name);
193     return repr;
194 }
195 
196 /* Weak references only support equality, not ordering. Two weak references
197    are equal if the underlying objects are equal. If the underlying object has
198    gone away, they are equal if they are identical. */
199 
200 static PyObject *
weakref_richcompare(PyWeakReference * self,PyWeakReference * other,int op)201 weakref_richcompare(PyWeakReference* self, PyWeakReference* other, int op)
202 {
203     if ((op != Py_EQ && op != Py_NE) ||
204         !PyWeakref_Check(self) ||
205         !PyWeakref_Check(other)) {
206         Py_RETURN_NOTIMPLEMENTED;
207     }
208     if (PyWeakref_GET_OBJECT(self) == Py_None
209         || PyWeakref_GET_OBJECT(other) == Py_None) {
210         int res = (self == other);
211         if (op == Py_NE)
212             res = !res;
213         if (res)
214             Py_RETURN_TRUE;
215         else
216             Py_RETURN_FALSE;
217     }
218     PyObject* obj = PyWeakref_GET_OBJECT(self);
219     PyObject* other_obj = PyWeakref_GET_OBJECT(other);
220     Py_INCREF(obj);
221     Py_INCREF(other_obj);
222     PyObject* res = PyObject_RichCompare(obj, other_obj, op);
223     Py_DECREF(obj);
224     Py_DECREF(other_obj);
225     return res;
226 }
227 
228 /* Given the head of an object's list of weak references, extract the
229  * two callback-less refs (ref and proxy).  Used to determine if the
230  * shared references exist and to determine the back link for newly
231  * inserted references.
232  */
233 static void
get_basic_refs(PyWeakReference * head,PyWeakReference ** refp,PyWeakReference ** proxyp)234 get_basic_refs(PyWeakReference *head,
235                PyWeakReference **refp, PyWeakReference **proxyp)
236 {
237     *refp = NULL;
238     *proxyp = NULL;
239 
240     if (head != NULL && head->wr_callback == NULL) {
241         /* We need to be careful that the "basic refs" aren't
242            subclasses of the main types.  That complicates this a
243            little. */
244         if (PyWeakref_CheckRefExact(head)) {
245             *refp = head;
246             head = head->wr_next;
247         }
248         if (head != NULL
249             && head->wr_callback == NULL
250             && PyWeakref_CheckProxy(head)) {
251             *proxyp = head;
252             /* head = head->wr_next; */
253         }
254     }
255 }
256 
257 /* Insert 'newref' in the list after 'prev'.  Both must be non-NULL. */
258 static void
insert_after(PyWeakReference * newref,PyWeakReference * prev)259 insert_after(PyWeakReference *newref, PyWeakReference *prev)
260 {
261     newref->wr_prev = prev;
262     newref->wr_next = prev->wr_next;
263     if (prev->wr_next != NULL)
264         prev->wr_next->wr_prev = newref;
265     prev->wr_next = newref;
266 }
267 
268 /* Insert 'newref' at the head of the list; 'list' points to the variable
269  * that stores the head.
270  */
271 static void
insert_head(PyWeakReference * newref,PyWeakReference ** list)272 insert_head(PyWeakReference *newref, PyWeakReference **list)
273 {
274     PyWeakReference *next = *list;
275 
276     newref->wr_prev = NULL;
277     newref->wr_next = next;
278     if (next != NULL)
279         next->wr_prev = newref;
280     *list = newref;
281 }
282 
283 static int
parse_weakref_init_args(const char * funcname,PyObject * args,PyObject * kwargs,PyObject ** obp,PyObject ** callbackp)284 parse_weakref_init_args(const char *funcname, PyObject *args, PyObject *kwargs,
285                         PyObject **obp, PyObject **callbackp)
286 {
287     return PyArg_UnpackTuple(args, funcname, 1, 2, obp, callbackp);
288 }
289 
290 static PyObject *
weakref___new__(PyTypeObject * type,PyObject * args,PyObject * kwargs)291 weakref___new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
292 {
293     PyWeakReference *self = NULL;
294     PyObject *ob, *callback = NULL;
295 
296     if (parse_weakref_init_args("__new__", args, kwargs, &ob, &callback)) {
297         PyWeakReference *ref, *proxy;
298         PyWeakReference **list;
299 
300         if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
301             PyErr_Format(PyExc_TypeError,
302                          "cannot create weak reference to '%s' object",
303                          Py_TYPE(ob)->tp_name);
304             return NULL;
305         }
306         if (callback == Py_None)
307             callback = NULL;
308         list = GET_WEAKREFS_LISTPTR(ob);
309         get_basic_refs(*list, &ref, &proxy);
310         if (callback == NULL && type == &_PyWeakref_RefType) {
311             if (ref != NULL) {
312                 /* We can re-use an existing reference. */
313                 Py_INCREF(ref);
314                 return (PyObject *)ref;
315             }
316         }
317         /* We have to create a new reference. */
318         /* Note: the tp_alloc() can trigger cyclic GC, so the weakref
319            list on ob can be mutated.  This means that the ref and
320            proxy pointers we got back earlier may have been collected,
321            so we need to compute these values again before we use
322            them. */
323         self = (PyWeakReference *) (type->tp_alloc(type, 0));
324         if (self != NULL) {
325             init_weakref(self, ob, callback);
326             if (callback == NULL && type == &_PyWeakref_RefType) {
327                 insert_head(self, list);
328             }
329             else {
330                 PyWeakReference *prev;
331 
332                 get_basic_refs(*list, &ref, &proxy);
333                 prev = (proxy == NULL) ? ref : proxy;
334                 if (prev == NULL)
335                     insert_head(self, list);
336                 else
337                     insert_after(self, prev);
338             }
339         }
340     }
341     return (PyObject *)self;
342 }
343 
344 static int
weakref___init__(PyObject * self,PyObject * args,PyObject * kwargs)345 weakref___init__(PyObject *self, PyObject *args, PyObject *kwargs)
346 {
347     PyObject *tmp;
348 
349     if (!_PyArg_NoKeywords("ref", kwargs))
350         return -1;
351 
352     if (parse_weakref_init_args("__init__", args, kwargs, &tmp, &tmp))
353         return 0;
354     else
355         return -1;
356 }
357 
358 
359 static PyMemberDef weakref_members[] = {
360     {"__callback__", T_OBJECT, offsetof(PyWeakReference, wr_callback), READONLY},
361     {NULL} /* Sentinel */
362 };
363 
364 PyTypeObject
365 _PyWeakref_RefType = {
366     PyVarObject_HEAD_INIT(&PyType_Type, 0)
367     "weakref",
368     sizeof(PyWeakReference),
369     0,
370     weakref_dealloc,            /*tp_dealloc*/
371     0,                          /*tp_vectorcall_offset*/
372     0,                          /*tp_getattr*/
373     0,                          /*tp_setattr*/
374     0,                          /*tp_as_async*/
375     (reprfunc)weakref_repr,     /*tp_repr*/
376     0,                          /*tp_as_number*/
377     0,                          /*tp_as_sequence*/
378     0,                          /*tp_as_mapping*/
379     (hashfunc)weakref_hash,     /*tp_hash*/
380     (ternaryfunc)weakref_call,  /*tp_call*/
381     0,                          /*tp_str*/
382     0,                          /*tp_getattro*/
383     0,                          /*tp_setattro*/
384     0,                          /*tp_as_buffer*/
385     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
386         | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
387     0,                          /*tp_doc*/
388     (traverseproc)gc_traverse,  /*tp_traverse*/
389     (inquiry)gc_clear,          /*tp_clear*/
390     (richcmpfunc)weakref_richcompare,   /*tp_richcompare*/
391     0,                          /*tp_weaklistoffset*/
392     0,                          /*tp_iter*/
393     0,                          /*tp_iternext*/
394     0,                          /*tp_methods*/
395     weakref_members,            /*tp_members*/
396     0,                          /*tp_getset*/
397     0,                          /*tp_base*/
398     0,                          /*tp_dict*/
399     0,                          /*tp_descr_get*/
400     0,                          /*tp_descr_set*/
401     0,                          /*tp_dictoffset*/
402     weakref___init__,           /*tp_init*/
403     PyType_GenericAlloc,        /*tp_alloc*/
404     weakref___new__,            /*tp_new*/
405     PyObject_GC_Del,            /*tp_free*/
406 };
407 
408 
409 static int
proxy_checkref(PyWeakReference * proxy)410 proxy_checkref(PyWeakReference *proxy)
411 {
412     if (PyWeakref_GET_OBJECT(proxy) == Py_None) {
413         PyErr_SetString(PyExc_ReferenceError,
414                         "weakly-referenced object no longer exists");
415         return 0;
416     }
417     return 1;
418 }
419 
420 
421 /* If a parameter is a proxy, check that it is still "live" and wrap it,
422  * replacing the original value with the raw object.  Raises ReferenceError
423  * if the param is a dead proxy.
424  */
425 #define UNWRAP(o) \
426         if (PyWeakref_CheckProxy(o)) { \
427             if (!proxy_checkref((PyWeakReference *)o)) \
428                 return NULL; \
429             o = PyWeakref_GET_OBJECT(o); \
430         }
431 
432 #define WRAP_UNARY(method, generic) \
433     static PyObject * \
434     method(PyObject *proxy) { \
435         UNWRAP(proxy); \
436         Py_INCREF(proxy); \
437         PyObject* res = generic(proxy); \
438         Py_DECREF(proxy); \
439         return res; \
440     }
441 
442 #define WRAP_BINARY(method, generic) \
443     static PyObject * \
444     method(PyObject *x, PyObject *y) { \
445         UNWRAP(x); \
446         UNWRAP(y); \
447         Py_INCREF(x); \
448         Py_INCREF(y); \
449         PyObject* res = generic(x, y); \
450         Py_DECREF(x); \
451         Py_DECREF(y); \
452         return res; \
453     }
454 
455 /* Note that the third arg needs to be checked for NULL since the tp_call
456  * slot can receive NULL for this arg.
457  */
458 #define WRAP_TERNARY(method, generic) \
459     static PyObject * \
460     method(PyObject *proxy, PyObject *v, PyObject *w) { \
461         UNWRAP(proxy); \
462         UNWRAP(v); \
463         if (w != NULL) \
464             UNWRAP(w); \
465         Py_INCREF(proxy); \
466         Py_INCREF(v); \
467         Py_XINCREF(w); \
468         PyObject* res = generic(proxy, v, w); \
469         Py_DECREF(proxy); \
470         Py_DECREF(v); \
471         Py_XDECREF(w); \
472         return res; \
473     }
474 
475 #define WRAP_METHOD(method, special) \
476     static PyObject * \
477     method(PyObject *proxy, PyObject *Py_UNUSED(ignored)) { \
478             _Py_IDENTIFIER(special); \
479             UNWRAP(proxy); \
480             Py_INCREF(proxy); \
481             PyObject* res = _PyObject_CallMethodId(proxy, &PyId_##special, NULL); \
482             Py_DECREF(proxy); \
483             return res; \
484         }
485 
486 
487 /* direct slots */
488 
WRAP_BINARY(proxy_getattr,PyObject_GetAttr)489 WRAP_BINARY(proxy_getattr, PyObject_GetAttr)
490 WRAP_UNARY(proxy_str, PyObject_Str)
491 WRAP_TERNARY(proxy_call, PyObject_Call)
492 
493 static PyObject *
494 proxy_repr(PyWeakReference *proxy)
495 {
496     return PyUnicode_FromFormat(
497         "<weakproxy at %p to %s at %p>",
498         proxy,
499         Py_TYPE(PyWeakref_GET_OBJECT(proxy))->tp_name,
500         PyWeakref_GET_OBJECT(proxy));
501 }
502 
503 
504 static int
proxy_setattr(PyWeakReference * proxy,PyObject * name,PyObject * value)505 proxy_setattr(PyWeakReference *proxy, PyObject *name, PyObject *value)
506 {
507     if (!proxy_checkref(proxy))
508         return -1;
509     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
510     Py_INCREF(obj);
511     int res = PyObject_SetAttr(obj, name, value);
512     Py_DECREF(obj);
513     return res;
514 }
515 
516 static PyObject *
proxy_richcompare(PyObject * proxy,PyObject * v,int op)517 proxy_richcompare(PyObject *proxy, PyObject *v, int op)
518 {
519     UNWRAP(proxy);
520     UNWRAP(v);
521     return PyObject_RichCompare(proxy, v, op);
522 }
523 
524 /* number slots */
WRAP_BINARY(proxy_add,PyNumber_Add)525 WRAP_BINARY(proxy_add, PyNumber_Add)
526 WRAP_BINARY(proxy_sub, PyNumber_Subtract)
527 WRAP_BINARY(proxy_mul, PyNumber_Multiply)
528 WRAP_BINARY(proxy_floor_div, PyNumber_FloorDivide)
529 WRAP_BINARY(proxy_true_div, PyNumber_TrueDivide)
530 WRAP_BINARY(proxy_mod, PyNumber_Remainder)
531 WRAP_BINARY(proxy_divmod, PyNumber_Divmod)
532 WRAP_TERNARY(proxy_pow, PyNumber_Power)
533 WRAP_UNARY(proxy_neg, PyNumber_Negative)
534 WRAP_UNARY(proxy_pos, PyNumber_Positive)
535 WRAP_UNARY(proxy_abs, PyNumber_Absolute)
536 WRAP_UNARY(proxy_invert, PyNumber_Invert)
537 WRAP_BINARY(proxy_lshift, PyNumber_Lshift)
538 WRAP_BINARY(proxy_rshift, PyNumber_Rshift)
539 WRAP_BINARY(proxy_and, PyNumber_And)
540 WRAP_BINARY(proxy_xor, PyNumber_Xor)
541 WRAP_BINARY(proxy_or, PyNumber_Or)
542 WRAP_UNARY(proxy_int, PyNumber_Long)
543 WRAP_UNARY(proxy_float, PyNumber_Float)
544 WRAP_BINARY(proxy_iadd, PyNumber_InPlaceAdd)
545 WRAP_BINARY(proxy_isub, PyNumber_InPlaceSubtract)
546 WRAP_BINARY(proxy_imul, PyNumber_InPlaceMultiply)
547 WRAP_BINARY(proxy_ifloor_div, PyNumber_InPlaceFloorDivide)
548 WRAP_BINARY(proxy_itrue_div, PyNumber_InPlaceTrueDivide)
549 WRAP_BINARY(proxy_imod, PyNumber_InPlaceRemainder)
550 WRAP_TERNARY(proxy_ipow, PyNumber_InPlacePower)
551 WRAP_BINARY(proxy_ilshift, PyNumber_InPlaceLshift)
552 WRAP_BINARY(proxy_irshift, PyNumber_InPlaceRshift)
553 WRAP_BINARY(proxy_iand, PyNumber_InPlaceAnd)
554 WRAP_BINARY(proxy_ixor, PyNumber_InPlaceXor)
555 WRAP_BINARY(proxy_ior, PyNumber_InPlaceOr)
556 WRAP_UNARY(proxy_index, PyNumber_Index)
557 WRAP_BINARY(proxy_matmul, PyNumber_MatrixMultiply)
558 WRAP_BINARY(proxy_imatmul, PyNumber_InPlaceMatrixMultiply)
559 
560 static int
561 proxy_bool(PyWeakReference *proxy)
562 {
563     PyObject *o = PyWeakref_GET_OBJECT(proxy);
564     if (!proxy_checkref(proxy)) {
565         return -1;
566     }
567     Py_INCREF(o);
568     int res = PyObject_IsTrue(o);
569     Py_DECREF(o);
570     return res;
571 }
572 
573 static void
proxy_dealloc(PyWeakReference * self)574 proxy_dealloc(PyWeakReference *self)
575 {
576     if (self->wr_callback != NULL)
577         PyObject_GC_UnTrack((PyObject *)self);
578     clear_weakref(self);
579     PyObject_GC_Del(self);
580 }
581 
582 /* sequence slots */
583 
584 static int
proxy_contains(PyWeakReference * proxy,PyObject * value)585 proxy_contains(PyWeakReference *proxy, PyObject *value)
586 {
587     if (!proxy_checkref(proxy))
588         return -1;
589 
590     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
591     Py_INCREF(obj);
592     int res = PySequence_Contains(obj, value);
593     Py_DECREF(obj);
594     return res;
595 }
596 
597 /* mapping slots */
598 
599 static Py_ssize_t
proxy_length(PyWeakReference * proxy)600 proxy_length(PyWeakReference *proxy)
601 {
602     if (!proxy_checkref(proxy))
603         return -1;
604 
605     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
606     Py_INCREF(obj);
607     Py_ssize_t res = PyObject_Length(obj);
608     Py_DECREF(obj);
609     return res;
610 }
611 
WRAP_BINARY(proxy_getitem,PyObject_GetItem)612 WRAP_BINARY(proxy_getitem, PyObject_GetItem)
613 
614 static int
615 proxy_setitem(PyWeakReference *proxy, PyObject *key, PyObject *value)
616 {
617     if (!proxy_checkref(proxy))
618         return -1;
619 
620     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
621     Py_INCREF(obj);
622     int res;
623     if (value == NULL) {
624         res = PyObject_DelItem(obj, key);
625     } else {
626         res = PyObject_SetItem(obj, key, value);
627     }
628     Py_DECREF(obj);
629     return res;
630 }
631 
632 /* iterator slots */
633 
634 static PyObject *
proxy_iter(PyWeakReference * proxy)635 proxy_iter(PyWeakReference *proxy)
636 {
637     if (!proxy_checkref(proxy))
638         return NULL;
639     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
640     Py_INCREF(obj);
641     PyObject* res = PyObject_GetIter(obj);
642     Py_DECREF(obj);
643     return res;
644 }
645 
646 static PyObject *
proxy_iternext(PyWeakReference * proxy)647 proxy_iternext(PyWeakReference *proxy)
648 {
649     if (!proxy_checkref(proxy))
650         return NULL;
651 
652     PyObject *obj = PyWeakref_GET_OBJECT(proxy);
653     Py_INCREF(obj);
654     PyObject* res = PyIter_Next(obj);
655     Py_DECREF(obj);
656     return res;
657 }
658 
659 
660 WRAP_METHOD(proxy_bytes, __bytes__)
661 
662 
663 static PyMethodDef proxy_methods[] = {
664         {"__bytes__", proxy_bytes, METH_NOARGS},
665         {NULL, NULL}
666 };
667 
668 
669 static PyNumberMethods proxy_as_number = {
670     proxy_add,              /*nb_add*/
671     proxy_sub,              /*nb_subtract*/
672     proxy_mul,              /*nb_multiply*/
673     proxy_mod,              /*nb_remainder*/
674     proxy_divmod,           /*nb_divmod*/
675     proxy_pow,              /*nb_power*/
676     proxy_neg,              /*nb_negative*/
677     proxy_pos,              /*nb_positive*/
678     proxy_abs,              /*nb_absolute*/
679     (inquiry)proxy_bool,    /*nb_bool*/
680     proxy_invert,           /*nb_invert*/
681     proxy_lshift,           /*nb_lshift*/
682     proxy_rshift,           /*nb_rshift*/
683     proxy_and,              /*nb_and*/
684     proxy_xor,              /*nb_xor*/
685     proxy_or,               /*nb_or*/
686     proxy_int,              /*nb_int*/
687     0,                      /*nb_reserved*/
688     proxy_float,            /*nb_float*/
689     proxy_iadd,             /*nb_inplace_add*/
690     proxy_isub,             /*nb_inplace_subtract*/
691     proxy_imul,             /*nb_inplace_multiply*/
692     proxy_imod,             /*nb_inplace_remainder*/
693     proxy_ipow,             /*nb_inplace_power*/
694     proxy_ilshift,          /*nb_inplace_lshift*/
695     proxy_irshift,          /*nb_inplace_rshift*/
696     proxy_iand,             /*nb_inplace_and*/
697     proxy_ixor,             /*nb_inplace_xor*/
698     proxy_ior,              /*nb_inplace_or*/
699     proxy_floor_div,        /*nb_floor_divide*/
700     proxy_true_div,         /*nb_true_divide*/
701     proxy_ifloor_div,       /*nb_inplace_floor_divide*/
702     proxy_itrue_div,        /*nb_inplace_true_divide*/
703     proxy_index,            /*nb_index*/
704     proxy_matmul,           /*nb_matrix_multiply*/
705     proxy_imatmul,          /*nb_inplace_matrix_multiply*/
706 };
707 
708 static PySequenceMethods proxy_as_sequence = {
709     (lenfunc)proxy_length,      /*sq_length*/
710     0,                          /*sq_concat*/
711     0,                          /*sq_repeat*/
712     0,                          /*sq_item*/
713     0,                          /*sq_slice*/
714     0,                          /*sq_ass_item*/
715     0,                           /*sq_ass_slice*/
716     (objobjproc)proxy_contains, /* sq_contains */
717 };
718 
719 static PyMappingMethods proxy_as_mapping = {
720     (lenfunc)proxy_length,        /*mp_length*/
721     proxy_getitem,                /*mp_subscript*/
722     (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
723 };
724 
725 
726 PyTypeObject
727 _PyWeakref_ProxyType = {
728     PyVarObject_HEAD_INIT(&PyType_Type, 0)
729     "weakproxy",
730     sizeof(PyWeakReference),
731     0,
732     /* methods */
733     (destructor)proxy_dealloc,          /* tp_dealloc */
734     0,                                  /* tp_vectorcall_offset */
735     0,                                  /* tp_getattr */
736     0,                                  /* tp_setattr */
737     0,                                  /* tp_as_async */
738     (reprfunc)proxy_repr,               /* tp_repr */
739     &proxy_as_number,                   /* tp_as_number */
740     &proxy_as_sequence,                 /* tp_as_sequence */
741     &proxy_as_mapping,                  /* tp_as_mapping */
742     0,                                  /* tp_hash */
743     0,                                  /* tp_call */
744     proxy_str,                          /* tp_str */
745     proxy_getattr,                      /* tp_getattro */
746     (setattrofunc)proxy_setattr,        /* tp_setattro */
747     0,                                  /* tp_as_buffer */
748     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
749     0,                                  /* tp_doc */
750     (traverseproc)gc_traverse,          /* tp_traverse */
751     (inquiry)gc_clear,                  /* tp_clear */
752     proxy_richcompare,                  /* tp_richcompare */
753     0,                                  /* tp_weaklistoffset */
754     (getiterfunc)proxy_iter,            /* tp_iter */
755     (iternextfunc)proxy_iternext,       /* tp_iternext */
756         proxy_methods,                      /* tp_methods */
757 };
758 
759 
760 PyTypeObject
761 _PyWeakref_CallableProxyType = {
762     PyVarObject_HEAD_INIT(&PyType_Type, 0)
763     "weakcallableproxy",
764     sizeof(PyWeakReference),
765     0,
766     /* methods */
767     (destructor)proxy_dealloc,          /* tp_dealloc */
768     0,                                  /* tp_vectorcall_offset */
769     0,                                  /* tp_getattr */
770     0,                                  /* tp_setattr */
771     0,                                  /* tp_as_async */
772     (unaryfunc)proxy_repr,              /* tp_repr */
773     &proxy_as_number,                   /* tp_as_number */
774     &proxy_as_sequence,                 /* tp_as_sequence */
775     &proxy_as_mapping,                  /* tp_as_mapping */
776     0,                                  /* tp_hash */
777     proxy_call,                         /* tp_call */
778     proxy_str,                          /* tp_str */
779     proxy_getattr,                      /* tp_getattro */
780     (setattrofunc)proxy_setattr,        /* tp_setattro */
781     0,                                  /* tp_as_buffer */
782     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
783     0,                                  /* tp_doc */
784     (traverseproc)gc_traverse,          /* tp_traverse */
785     (inquiry)gc_clear,                  /* tp_clear */
786     proxy_richcompare,                  /* tp_richcompare */
787     0,                                  /* tp_weaklistoffset */
788     (getiterfunc)proxy_iter,            /* tp_iter */
789     (iternextfunc)proxy_iternext,       /* tp_iternext */
790 };
791 
792 
793 
794 PyObject *
PyWeakref_NewRef(PyObject * ob,PyObject * callback)795 PyWeakref_NewRef(PyObject *ob, PyObject *callback)
796 {
797     PyWeakReference *result = NULL;
798     PyWeakReference **list;
799     PyWeakReference *ref, *proxy;
800 
801     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
802         PyErr_Format(PyExc_TypeError,
803                      "cannot create weak reference to '%s' object",
804                      Py_TYPE(ob)->tp_name);
805         return NULL;
806     }
807     list = GET_WEAKREFS_LISTPTR(ob);
808     get_basic_refs(*list, &ref, &proxy);
809     if (callback == Py_None)
810         callback = NULL;
811     if (callback == NULL)
812         /* return existing weak reference if it exists */
813         result = ref;
814     if (result != NULL)
815         Py_INCREF(result);
816     else {
817         /* Note: new_weakref() can trigger cyclic GC, so the weakref
818            list on ob can be mutated.  This means that the ref and
819            proxy pointers we got back earlier may have been collected,
820            so we need to compute these values again before we use
821            them. */
822         result = new_weakref(ob, callback);
823         if (result != NULL) {
824             get_basic_refs(*list, &ref, &proxy);
825             if (callback == NULL) {
826                 if (ref == NULL)
827                     insert_head(result, list);
828                 else {
829                     /* Someone else added a ref without a callback
830                        during GC.  Return that one instead of this one
831                        to avoid violating the invariants of the list
832                        of weakrefs for ob. */
833                     Py_DECREF(result);
834                     Py_INCREF(ref);
835                     result = ref;
836                 }
837             }
838             else {
839                 PyWeakReference *prev;
840 
841                 prev = (proxy == NULL) ? ref : proxy;
842                 if (prev == NULL)
843                     insert_head(result, list);
844                 else
845                     insert_after(result, prev);
846             }
847         }
848     }
849     return (PyObject *) result;
850 }
851 
852 
853 PyObject *
PyWeakref_NewProxy(PyObject * ob,PyObject * callback)854 PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
855 {
856     PyWeakReference *result = NULL;
857     PyWeakReference **list;
858     PyWeakReference *ref, *proxy;
859 
860     if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
861         PyErr_Format(PyExc_TypeError,
862                      "cannot create weak reference to '%s' object",
863                      Py_TYPE(ob)->tp_name);
864         return NULL;
865     }
866     list = GET_WEAKREFS_LISTPTR(ob);
867     get_basic_refs(*list, &ref, &proxy);
868     if (callback == Py_None)
869         callback = NULL;
870     if (callback == NULL)
871         /* attempt to return an existing weak reference if it exists */
872         result = proxy;
873     if (result != NULL)
874         Py_INCREF(result);
875     else {
876         /* Note: new_weakref() can trigger cyclic GC, so the weakref
877            list on ob can be mutated.  This means that the ref and
878            proxy pointers we got back earlier may have been collected,
879            so we need to compute these values again before we use
880            them. */
881         result = new_weakref(ob, callback);
882         if (result != NULL) {
883             PyWeakReference *prev;
884 
885             if (PyCallable_Check(ob))
886                 Py_TYPE(result) = &_PyWeakref_CallableProxyType;
887             else
888                 Py_TYPE(result) = &_PyWeakref_ProxyType;
889             get_basic_refs(*list, &ref, &proxy);
890             if (callback == NULL) {
891                 if (proxy != NULL) {
892                     /* Someone else added a proxy without a callback
893                        during GC.  Return that one instead of this one
894                        to avoid violating the invariants of the list
895                        of weakrefs for ob. */
896                     Py_DECREF(result);
897                     result = proxy;
898                     Py_INCREF(result);
899                     goto skip_insert;
900                 }
901                 prev = ref;
902             }
903             else
904                 prev = (proxy == NULL) ? ref : proxy;
905 
906             if (prev == NULL)
907                 insert_head(result, list);
908             else
909                 insert_after(result, prev);
910         skip_insert:
911             ;
912         }
913     }
914     return (PyObject *) result;
915 }
916 
917 
918 PyObject *
PyWeakref_GetObject(PyObject * ref)919 PyWeakref_GetObject(PyObject *ref)
920 {
921     if (ref == NULL || !PyWeakref_Check(ref)) {
922         PyErr_BadInternalCall();
923         return NULL;
924     }
925     return PyWeakref_GET_OBJECT(ref);
926 }
927 
928 /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
929  * handle_weakrefs().
930  */
931 static void
handle_callback(PyWeakReference * ref,PyObject * callback)932 handle_callback(PyWeakReference *ref, PyObject *callback)
933 {
934     PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL);
935 
936     if (cbresult == NULL)
937         PyErr_WriteUnraisable(callback);
938     else
939         Py_DECREF(cbresult);
940 }
941 
942 /* This function is called by the tp_dealloc handler to clear weak references.
943  *
944  * This iterates through the weak references for 'object' and calls callbacks
945  * for those references which have one.  It returns when all callbacks have
946  * been attempted.
947  */
948 void
PyObject_ClearWeakRefs(PyObject * object)949 PyObject_ClearWeakRefs(PyObject *object)
950 {
951     PyWeakReference **list;
952 
953     if (object == NULL
954         || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
955         || object->ob_refcnt != 0) {
956         PyErr_BadInternalCall();
957         return;
958     }
959     list = GET_WEAKREFS_LISTPTR(object);
960     /* Remove the callback-less basic and proxy references */
961     if (*list != NULL && (*list)->wr_callback == NULL) {
962         clear_weakref(*list);
963         if (*list != NULL && (*list)->wr_callback == NULL)
964             clear_weakref(*list);
965     }
966     if (*list != NULL) {
967         PyWeakReference *current = *list;
968         Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
969         PyObject *err_type, *err_value, *err_tb;
970 
971         PyErr_Fetch(&err_type, &err_value, &err_tb);
972         if (count == 1) {
973             PyObject *callback = current->wr_callback;
974 
975             current->wr_callback = NULL;
976             clear_weakref(current);
977             if (callback != NULL) {
978                 if (((PyObject *)current)->ob_refcnt > 0)
979                     handle_callback(current, callback);
980                 Py_DECREF(callback);
981             }
982         }
983         else {
984             PyObject *tuple;
985             Py_ssize_t i = 0;
986 
987             tuple = PyTuple_New(count * 2);
988             if (tuple == NULL) {
989                 _PyErr_ChainExceptions(err_type, err_value, err_tb);
990                 return;
991             }
992 
993             for (i = 0; i < count; ++i) {
994                 PyWeakReference *next = current->wr_next;
995 
996                 if (((PyObject *)current)->ob_refcnt > 0)
997                 {
998                     Py_INCREF(current);
999                     PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
1000                     PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
1001                 }
1002                 else {
1003                     Py_DECREF(current->wr_callback);
1004                 }
1005                 current->wr_callback = NULL;
1006                 clear_weakref(current);
1007                 current = next;
1008             }
1009             for (i = 0; i < count; ++i) {
1010                 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
1011 
1012                 /* The tuple may have slots left to NULL */
1013                 if (callback != NULL) {
1014                     PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
1015                     handle_callback((PyWeakReference *)item, callback);
1016                 }
1017             }
1018             Py_DECREF(tuple);
1019         }
1020         assert(!PyErr_Occurred());
1021         PyErr_Restore(err_type, err_value, err_tb);
1022     }
1023 }
1024