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