Coverage Report

Created: 2025-07-11 06:59

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