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