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