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