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 Py_INCREF(obj);
661 PyObject* res = PyIter_Next(obj);
662 Py_DECREF(obj);
663 return res;
664 }
665
666
667 WRAP_METHOD(proxy_bytes, __bytes__)
668 WRAP_METHOD(proxy_reversed, __reversed__)
669
670
671 static PyMethodDef proxy_methods[] = {
672 {"__bytes__", proxy_bytes, METH_NOARGS},
673 {"__reversed__", proxy_reversed, METH_NOARGS},
674 {NULL, NULL}
675 };
676
677
678 static PyNumberMethods proxy_as_number = {
679 proxy_add, /*nb_add*/
680 proxy_sub, /*nb_subtract*/
681 proxy_mul, /*nb_multiply*/
682 proxy_mod, /*nb_remainder*/
683 proxy_divmod, /*nb_divmod*/
684 proxy_pow, /*nb_power*/
685 proxy_neg, /*nb_negative*/
686 proxy_pos, /*nb_positive*/
687 proxy_abs, /*nb_absolute*/
688 (inquiry)proxy_bool, /*nb_bool*/
689 proxy_invert, /*nb_invert*/
690 proxy_lshift, /*nb_lshift*/
691 proxy_rshift, /*nb_rshift*/
692 proxy_and, /*nb_and*/
693 proxy_xor, /*nb_xor*/
694 proxy_or, /*nb_or*/
695 proxy_int, /*nb_int*/
696 0, /*nb_reserved*/
697 proxy_float, /*nb_float*/
698 proxy_iadd, /*nb_inplace_add*/
699 proxy_isub, /*nb_inplace_subtract*/
700 proxy_imul, /*nb_inplace_multiply*/
701 proxy_imod, /*nb_inplace_remainder*/
702 proxy_ipow, /*nb_inplace_power*/
703 proxy_ilshift, /*nb_inplace_lshift*/
704 proxy_irshift, /*nb_inplace_rshift*/
705 proxy_iand, /*nb_inplace_and*/
706 proxy_ixor, /*nb_inplace_xor*/
707 proxy_ior, /*nb_inplace_or*/
708 proxy_floor_div, /*nb_floor_divide*/
709 proxy_true_div, /*nb_true_divide*/
710 proxy_ifloor_div, /*nb_inplace_floor_divide*/
711 proxy_itrue_div, /*nb_inplace_true_divide*/
712 proxy_index, /*nb_index*/
713 proxy_matmul, /*nb_matrix_multiply*/
714 proxy_imatmul, /*nb_inplace_matrix_multiply*/
715 };
716
717 static PySequenceMethods proxy_as_sequence = {
718 (lenfunc)proxy_length, /*sq_length*/
719 0, /*sq_concat*/
720 0, /*sq_repeat*/
721 0, /*sq_item*/
722 0, /*sq_slice*/
723 0, /*sq_ass_item*/
724 0, /*sq_ass_slice*/
725 (objobjproc)proxy_contains, /* sq_contains */
726 };
727
728 static PyMappingMethods proxy_as_mapping = {
729 (lenfunc)proxy_length, /*mp_length*/
730 proxy_getitem, /*mp_subscript*/
731 (objobjargproc)proxy_setitem, /*mp_ass_subscript*/
732 };
733
734
735 static Py_hash_t
proxy_hash(PyObject * self)736 proxy_hash(PyObject *self)
737 {
738 PyWeakReference *proxy = (PyWeakReference *)self;
739 if (!proxy_checkref(proxy)) {
740 return -1;
741 }
742 PyObject *obj = PyWeakref_GET_OBJECT(proxy);
743 Py_INCREF(obj);
744 Py_hash_t res = PyObject_Hash(obj);
745 Py_DECREF(obj);
746 return res;
747 }
748
749
750 PyTypeObject
751 _PyWeakref_ProxyType = {
752 PyVarObject_HEAD_INIT(&PyType_Type, 0)
753 "weakproxy",
754 sizeof(PyWeakReference),
755 0,
756 /* methods */
757 (destructor)proxy_dealloc, /* tp_dealloc */
758 0, /* tp_vectorcall_offset */
759 0, /* tp_getattr */
760 0, /* tp_setattr */
761 0, /* tp_as_async */
762 (reprfunc)proxy_repr, /* tp_repr */
763 &proxy_as_number, /* tp_as_number */
764 &proxy_as_sequence, /* tp_as_sequence */
765 &proxy_as_mapping, /* tp_as_mapping */
766 proxy_hash, /* tp_hash */
767 0, /* tp_call */
768 proxy_str, /* tp_str */
769 proxy_getattr, /* tp_getattro */
770 (setattrofunc)proxy_setattr, /* tp_setattro */
771 0, /* tp_as_buffer */
772 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
773 0, /* tp_doc */
774 (traverseproc)gc_traverse, /* tp_traverse */
775 (inquiry)gc_clear, /* tp_clear */
776 proxy_richcompare, /* tp_richcompare */
777 0, /* tp_weaklistoffset */
778 (getiterfunc)proxy_iter, /* tp_iter */
779 (iternextfunc)proxy_iternext, /* tp_iternext */
780 proxy_methods, /* tp_methods */
781 };
782
783
784 PyTypeObject
785 _PyWeakref_CallableProxyType = {
786 PyVarObject_HEAD_INIT(&PyType_Type, 0)
787 "weakcallableproxy",
788 sizeof(PyWeakReference),
789 0,
790 /* methods */
791 (destructor)proxy_dealloc, /* tp_dealloc */
792 0, /* tp_vectorcall_offset */
793 0, /* tp_getattr */
794 0, /* tp_setattr */
795 0, /* tp_as_async */
796 (unaryfunc)proxy_repr, /* tp_repr */
797 &proxy_as_number, /* tp_as_number */
798 &proxy_as_sequence, /* tp_as_sequence */
799 &proxy_as_mapping, /* tp_as_mapping */
800 0, /* tp_hash */
801 proxy_call, /* tp_call */
802 proxy_str, /* tp_str */
803 proxy_getattr, /* tp_getattro */
804 (setattrofunc)proxy_setattr, /* tp_setattro */
805 0, /* tp_as_buffer */
806 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
807 0, /* tp_doc */
808 (traverseproc)gc_traverse, /* tp_traverse */
809 (inquiry)gc_clear, /* tp_clear */
810 proxy_richcompare, /* tp_richcompare */
811 0, /* tp_weaklistoffset */
812 (getiterfunc)proxy_iter, /* tp_iter */
813 (iternextfunc)proxy_iternext, /* tp_iternext */
814 };
815
816
817
818 PyObject *
PyWeakref_NewRef(PyObject * ob,PyObject * callback)819 PyWeakref_NewRef(PyObject *ob, PyObject *callback)
820 {
821 PyWeakReference *result = NULL;
822 PyWeakReference **list;
823 PyWeakReference *ref, *proxy;
824
825 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
826 PyErr_Format(PyExc_TypeError,
827 "cannot create weak reference to '%s' object",
828 Py_TYPE(ob)->tp_name);
829 return NULL;
830 }
831 list = GET_WEAKREFS_LISTPTR(ob);
832 get_basic_refs(*list, &ref, &proxy);
833 if (callback == Py_None)
834 callback = NULL;
835 if (callback == NULL)
836 /* return existing weak reference if it exists */
837 result = ref;
838 if (result != NULL)
839 Py_INCREF(result);
840 else {
841 /* Note: new_weakref() can trigger cyclic GC, so the weakref
842 list on ob can be mutated. This means that the ref and
843 proxy pointers we got back earlier may have been collected,
844 so we need to compute these values again before we use
845 them. */
846 result = new_weakref(ob, callback);
847 if (result != NULL) {
848 get_basic_refs(*list, &ref, &proxy);
849 if (callback == NULL) {
850 if (ref == NULL)
851 insert_head(result, list);
852 else {
853 /* Someone else added a ref 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(ref);
859 result = ref;
860 }
861 }
862 else {
863 PyWeakReference *prev;
864
865 prev = (proxy == NULL) ? ref : proxy;
866 if (prev == NULL)
867 insert_head(result, list);
868 else
869 insert_after(result, prev);
870 }
871 }
872 }
873 return (PyObject *) result;
874 }
875
876
877 PyObject *
PyWeakref_NewProxy(PyObject * ob,PyObject * callback)878 PyWeakref_NewProxy(PyObject *ob, PyObject *callback)
879 {
880 PyWeakReference *result = NULL;
881 PyWeakReference **list;
882 PyWeakReference *ref, *proxy;
883
884 if (!PyType_SUPPORTS_WEAKREFS(Py_TYPE(ob))) {
885 PyErr_Format(PyExc_TypeError,
886 "cannot create weak reference to '%s' object",
887 Py_TYPE(ob)->tp_name);
888 return NULL;
889 }
890 list = GET_WEAKREFS_LISTPTR(ob);
891 get_basic_refs(*list, &ref, &proxy);
892 if (callback == Py_None)
893 callback = NULL;
894 if (callback == NULL)
895 /* attempt to return an existing weak reference if it exists */
896 result = proxy;
897 if (result != NULL)
898 Py_INCREF(result);
899 else {
900 /* Note: new_weakref() can trigger cyclic GC, so the weakref
901 list on ob can be mutated. This means that the ref and
902 proxy pointers we got back earlier may have been collected,
903 so we need to compute these values again before we use
904 them. */
905 result = new_weakref(ob, callback);
906 if (result != NULL) {
907 PyWeakReference *prev;
908
909 if (PyCallable_Check(ob)) {
910 Py_SET_TYPE(result, &_PyWeakref_CallableProxyType);
911 }
912 else {
913 Py_SET_TYPE(result, &_PyWeakref_ProxyType);
914 }
915 get_basic_refs(*list, &ref, &proxy);
916 if (callback == NULL) {
917 if (proxy != NULL) {
918 /* Someone else added a proxy without a callback
919 during GC. Return that one instead of this one
920 to avoid violating the invariants of the list
921 of weakrefs for ob. */
922 Py_DECREF(result);
923 result = proxy;
924 Py_INCREF(result);
925 goto skip_insert;
926 }
927 prev = ref;
928 }
929 else
930 prev = (proxy == NULL) ? ref : proxy;
931
932 if (prev == NULL)
933 insert_head(result, list);
934 else
935 insert_after(result, prev);
936 skip_insert:
937 ;
938 }
939 }
940 return (PyObject *) result;
941 }
942
943
944 PyObject *
PyWeakref_GetObject(PyObject * ref)945 PyWeakref_GetObject(PyObject *ref)
946 {
947 if (ref == NULL || !PyWeakref_Check(ref)) {
948 PyErr_BadInternalCall();
949 return NULL;
950 }
951 return PyWeakref_GET_OBJECT(ref);
952 }
953
954 /* Note that there's an inlined copy-paste of handle_callback() in gcmodule.c's
955 * handle_weakrefs().
956 */
957 static void
handle_callback(PyWeakReference * ref,PyObject * callback)958 handle_callback(PyWeakReference *ref, PyObject *callback)
959 {
960 PyObject *cbresult = PyObject_CallOneArg(callback, (PyObject *)ref);
961
962 if (cbresult == NULL)
963 PyErr_WriteUnraisable(callback);
964 else
965 Py_DECREF(cbresult);
966 }
967
968 /* This function is called by the tp_dealloc handler to clear weak references.
969 *
970 * This iterates through the weak references for 'object' and calls callbacks
971 * for those references which have one. It returns when all callbacks have
972 * been attempted.
973 */
974 void
PyObject_ClearWeakRefs(PyObject * object)975 PyObject_ClearWeakRefs(PyObject *object)
976 {
977 PyWeakReference **list;
978
979 if (object == NULL
980 || !PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))
981 || Py_REFCNT(object) != 0)
982 {
983 PyErr_BadInternalCall();
984 return;
985 }
986 list = GET_WEAKREFS_LISTPTR(object);
987 /* Remove the callback-less basic and proxy references */
988 if (*list != NULL && (*list)->wr_callback == NULL) {
989 clear_weakref(*list);
990 if (*list != NULL && (*list)->wr_callback == NULL)
991 clear_weakref(*list);
992 }
993 if (*list != NULL) {
994 PyWeakReference *current = *list;
995 Py_ssize_t count = _PyWeakref_GetWeakrefCount(current);
996 PyObject *err_type, *err_value, *err_tb;
997
998 PyErr_Fetch(&err_type, &err_value, &err_tb);
999 if (count == 1) {
1000 PyObject *callback = current->wr_callback;
1001
1002 current->wr_callback = NULL;
1003 clear_weakref(current);
1004 if (callback != NULL) {
1005 if (Py_REFCNT((PyObject *)current) > 0) {
1006 handle_callback(current, callback);
1007 }
1008 Py_DECREF(callback);
1009 }
1010 }
1011 else {
1012 PyObject *tuple;
1013 Py_ssize_t i = 0;
1014
1015 tuple = PyTuple_New(count * 2);
1016 if (tuple == NULL) {
1017 _PyErr_ChainExceptions(err_type, err_value, err_tb);
1018 return;
1019 }
1020
1021 for (i = 0; i < count; ++i) {
1022 PyWeakReference *next = current->wr_next;
1023
1024 if (Py_REFCNT((PyObject *)current) > 0) {
1025 Py_INCREF(current);
1026 PyTuple_SET_ITEM(tuple, i * 2, (PyObject *) current);
1027 PyTuple_SET_ITEM(tuple, i * 2 + 1, current->wr_callback);
1028 }
1029 else {
1030 Py_DECREF(current->wr_callback);
1031 }
1032 current->wr_callback = NULL;
1033 clear_weakref(current);
1034 current = next;
1035 }
1036 for (i = 0; i < count; ++i) {
1037 PyObject *callback = PyTuple_GET_ITEM(tuple, i * 2 + 1);
1038
1039 /* The tuple may have slots left to NULL */
1040 if (callback != NULL) {
1041 PyObject *item = PyTuple_GET_ITEM(tuple, i * 2);
1042 handle_callback((PyWeakReference *)item, callback);
1043 }
1044 }
1045 Py_DECREF(tuple);
1046 }
1047 assert(!PyErr_Occurred());
1048 PyErr_Restore(err_type, err_value, err_tb);
1049 }
1050 }
1051