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