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