Coverage Report

Created: 2025-07-11 06:53

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