Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Modules/_weakref.c
Line
Count
Source (jump to first uncovered line)
1
#include "Python.h"
2
#include "pycore_dict.h"              // _PyDict_DelItemIf()
3
#include "pycore_object.h"            // _PyObject_GET_WEAKREFS_LISTPTR()
4
#include "pycore_weakref.h"           // _PyWeakref_IS_DEAD()
5
6
#define GET_WEAKREFS_LISTPTR(o) \
7
0
        ((PyWeakReference **) _PyObject_GET_WEAKREFS_LISTPTR(o))
8
9
/*[clinic input]
10
module _weakref
11
[clinic start generated code]*/
12
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ffec73b85846596d]*/
13
14
#include "clinic/_weakref.c.h"
15
16
/*[clinic input]
17
_weakref.getweakrefcount -> Py_ssize_t
18
19
  object: object
20
  /
21
22
Return the number of weak references to 'object'.
23
[clinic start generated code]*/
24
25
static Py_ssize_t
26
_weakref_getweakrefcount_impl(PyObject *module, PyObject *object)
27
/*[clinic end generated code: output=301806d59558ff3e input=7d4d04fcaccf64d5]*/
28
0
{
29
0
    return _PyWeakref_GetWeakrefCount(object);
30
0
}
31
32
33
static int
34
is_dead_weakref(PyObject *value, void *unused)
35
2.91k
{
36
2.91k
    if (!PyWeakref_Check(value)) {
37
0
        PyErr_SetString(PyExc_TypeError, "not a weakref");
38
0
        return -1;
39
0
    }
40
2.91k
    return _PyWeakref_IS_DEAD(value);
41
2.91k
}
42
43
/*[clinic input]
44
45
_weakref._remove_dead_weakref -> object
46
47
  dct: object(subclass_of='&PyDict_Type')
48
  key: object
49
  /
50
51
Atomically remove key from dict if it points to a dead weakref.
52
[clinic start generated code]*/
53
54
static PyObject *
55
_weakref__remove_dead_weakref_impl(PyObject *module, PyObject *dct,
56
                                   PyObject *key)
57
/*[clinic end generated code: output=d9ff53061fcb875c input=19fc91f257f96a1d]*/
58
2.91k
{
59
2.91k
    if (_PyDict_DelItemIf(dct, key, is_dead_weakref, NULL) < 0) {
60
0
        return NULL;
61
0
    }
62
2.91k
    Py_RETURN_NONE;
63
2.91k
}
64
65
66
/*[clinic input]
67
_weakref.getweakrefs
68
    object: object
69
    /
70
71
Return a list of all weak reference objects pointing to 'object'.
72
[clinic start generated code]*/
73
74
static PyObject *
75
_weakref_getweakrefs(PyObject *module, PyObject *object)
76
/*[clinic end generated code: output=25c7731d8e011824 input=00c6d0e5d3206693]*/
77
0
{
78
0
    if (!_PyType_SUPPORTS_WEAKREFS(Py_TYPE(object))) {
79
0
        return PyList_New(0);
80
0
    }
81
82
0
    PyObject *result = PyList_New(0);
83
0
    if (result == NULL) {
84
0
        return NULL;
85
0
    }
86
87
0
    LOCK_WEAKREFS(object);
88
0
    PyWeakReference *current = *GET_WEAKREFS_LISTPTR(object);
89
0
    while (current != NULL) {
90
0
        PyObject *curobj = (PyObject *) current;
91
0
        if (_Py_TryIncref(curobj)) {
92
0
            if (PyList_Append(result, curobj)) {
93
0
                UNLOCK_WEAKREFS(object);
94
0
                Py_DECREF(curobj);
95
0
                Py_DECREF(result);
96
0
                return NULL;
97
0
            }
98
0
            else {
99
                // Undo our _Py_TryIncref. This is safe to do with the lock
100
                // held in free-threaded builds; the list holds a reference to
101
                // curobj so we're guaranteed not to invoke the destructor.
102
0
                Py_DECREF(curobj);
103
0
            }
104
0
        }
105
0
        current = current->wr_next;
106
0
    }
107
0
    UNLOCK_WEAKREFS(object);
108
0
    return result;
109
0
}
110
111
112
/*[clinic input]
113
114
_weakref.proxy
115
    object: object
116
    callback: object(c_default="NULL") = None
117
    /
118
119
Create a proxy object that weakly references 'object'.
120
121
'callback', if given, is called with a reference to the
122
proxy when 'object' is about to be finalized.
123
[clinic start generated code]*/
124
125
static PyObject *
126
_weakref_proxy_impl(PyObject *module, PyObject *object, PyObject *callback)
127
/*[clinic end generated code: output=d68fa4ad9ea40519 input=4808adf22fd137e7]*/
128
0
{
129
0
    return PyWeakref_NewProxy(object, callback);
130
0
}
131
132
133
static PyMethodDef
134
weakref_functions[] =  {
135
    _WEAKREF_GETWEAKREFCOUNT_METHODDEF
136
    _WEAKREF__REMOVE_DEAD_WEAKREF_METHODDEF
137
    _WEAKREF_GETWEAKREFS_METHODDEF
138
    _WEAKREF_PROXY_METHODDEF
139
    {NULL, NULL, 0, NULL}
140
};
141
142
static int
143
weakref_exec(PyObject *module)
144
16
{
145
16
    if (PyModule_AddObjectRef(module, "ref", (PyObject *) &_PyWeakref_RefType) < 0) {
146
0
        return -1;
147
0
    }
148
16
    if (PyModule_AddObjectRef(module, "ReferenceType",
149
16
                           (PyObject *) &_PyWeakref_RefType) < 0) {
150
0
        return -1;
151
0
    }
152
16
    if (PyModule_AddObjectRef(module, "ProxyType",
153
16
                           (PyObject *) &_PyWeakref_ProxyType) < 0) {
154
0
        return -1;
155
0
    }
156
16
    if (PyModule_AddObjectRef(module, "CallableProxyType",
157
16
                           (PyObject *) &_PyWeakref_CallableProxyType) < 0) {
158
0
        return -1;
159
0
    }
160
161
16
    return 0;
162
16
}
163
164
static struct PyModuleDef_Slot weakref_slots[] = {
165
    {Py_mod_exec, weakref_exec},
166
    {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
167
    {Py_mod_gil, Py_MOD_GIL_NOT_USED},
168
    {0, NULL}
169
};
170
171
static struct PyModuleDef weakrefmodule = {
172
    PyModuleDef_HEAD_INIT,
173
    "_weakref",
174
    "Weak-reference support module.",
175
    0,
176
    weakref_functions,
177
    weakref_slots,
178
    NULL,
179
    NULL,
180
    NULL
181
};
182
183
PyMODINIT_FUNC
184
PyInit__weakref(void)
185
16
{
186
16
    return PyModuleDef_Init(&weakrefmodule);
187
16
}