Coverage Report

Created: 2026-10-31 06:21

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