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