• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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