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