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