Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Objects/capsule.c
Line
Count
Source (jump to first uncovered line)
1
/* Wrap void * pointers to be passed between C modules */
2
3
#include "Python.h"
4
#include "pycore_capsule.h"       // export _PyCapsule_SetTraverse()
5
#include "pycore_gc.h"            // _PyObject_GC_IS_TRACKED()
6
#include "pycore_object.h"        // _PyObject_GC_TRACK()
7
8
9
/* Internal structure of PyCapsule */
10
typedef struct {
11
    PyObject_HEAD
12
    void *pointer;
13
    const char *name;
14
    void *context;
15
    PyCapsule_Destructor destructor;
16
    traverseproc traverse_func;
17
    inquiry clear_func;
18
} PyCapsule;
19
20
21
10.1k
#define _PyCapsule_CAST(op)     ((PyCapsule *)(op))
22
23
24
static int
25
_is_legal_capsule(PyObject *op, const char *invalid_capsule)
26
14.5k
{
27
14.5k
    if (!op || !PyCapsule_CheckExact(op)) {
28
0
        goto error;
29
0
    }
30
14.5k
    PyCapsule *capsule = (PyCapsule *)op;
31
32
14.5k
    if (capsule->pointer == NULL) {
33
0
        goto error;
34
0
    }
35
14.5k
    return 1;
36
37
0
error:
38
0
    PyErr_SetString(PyExc_ValueError, invalid_capsule);
39
0
    return 0;
40
14.5k
}
41
42
#define is_legal_capsule(capsule, name) \
43
14.5k
    (_is_legal_capsule(capsule, \
44
14.5k
     name " called with invalid PyCapsule object"))
45
46
47
static int
48
14.8k
name_matches(const char *name1, const char *name2) {
49
    /* if either is NULL, */
50
14.8k
    if (!name1 || !name2) {
51
        /* they're only the same if they're both NULL. */
52
0
        return name1 == name2;
53
0
    }
54
14.8k
    return !strcmp(name1, name2);
55
14.8k
}
56
57
58
59
PyObject *
60
PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
61
5.60k
{
62
5.60k
    PyCapsule *capsule;
63
64
5.60k
    if (!pointer) {
65
0
        PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer");
66
0
        return NULL;
67
0
    }
68
69
5.60k
    capsule = PyObject_GC_New(PyCapsule, &PyCapsule_Type);
70
5.60k
    if (capsule == NULL) {
71
0
        return NULL;
72
0
    }
73
74
5.60k
    capsule->pointer = pointer;
75
5.60k
    capsule->name = name;
76
5.60k
    capsule->context = NULL;
77
5.60k
    capsule->destructor = destructor;
78
5.60k
    capsule->traverse_func = NULL;
79
5.60k
    capsule->clear_func = NULL;
80
    // Only track the object by the GC when _PyCapsule_SetTraverse() is called
81
82
5.60k
    return (PyObject *)capsule;
83
5.60k
}
84
85
86
int
87
PyCapsule_IsValid(PyObject *op, const char *name)
88
225
{
89
225
    PyCapsule *capsule = (PyCapsule *)op;
90
91
225
    return (capsule != NULL &&
92
225
            PyCapsule_CheckExact(capsule) &&
93
225
            capsule->pointer != NULL &&
94
225
            name_matches(capsule->name, name));
95
225
}
96
97
98
void *
99
PyCapsule_GetPointer(PyObject *op, const char *name)
100
14.5k
{
101
14.5k
    if (!is_legal_capsule(op, "PyCapsule_GetPointer")) {
102
0
        return NULL;
103
0
    }
104
14.5k
    PyCapsule *capsule = (PyCapsule *)op;
105
106
14.5k
    if (!name_matches(name, capsule->name)) {
107
0
        PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name");
108
0
        return NULL;
109
0
    }
110
111
14.5k
    return capsule->pointer;
112
14.5k
}
113
114
115
const char *
116
PyCapsule_GetName(PyObject *op)
117
0
{
118
0
    if (!is_legal_capsule(op, "PyCapsule_GetName")) {
119
0
        return NULL;
120
0
    }
121
0
    PyCapsule *capsule = (PyCapsule *)op;
122
0
    return capsule->name;
123
0
}
124
125
126
PyCapsule_Destructor
127
PyCapsule_GetDestructor(PyObject *op)
128
0
{
129
0
    if (!is_legal_capsule(op, "PyCapsule_GetDestructor")) {
130
0
        return NULL;
131
0
    }
132
0
    PyCapsule *capsule = (PyCapsule *)op;
133
0
    return capsule->destructor;
134
0
}
135
136
137
void *
138
PyCapsule_GetContext(PyObject *op)
139
0
{
140
0
    if (!is_legal_capsule(op, "PyCapsule_GetContext")) {
141
0
        return NULL;
142
0
    }
143
0
    PyCapsule *capsule = (PyCapsule *)op;
144
0
    return capsule->context;
145
0
}
146
147
148
int
149
PyCapsule_SetPointer(PyObject *op, void *pointer)
150
0
{
151
0
    if (!is_legal_capsule(op, "PyCapsule_SetPointer")) {
152
0
        return -1;
153
0
    }
154
0
    PyCapsule *capsule = (PyCapsule *)op;
155
156
0
    if (!pointer) {
157
0
        PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer");
158
0
        return -1;
159
0
    }
160
161
0
    capsule->pointer = pointer;
162
0
    return 0;
163
0
}
164
165
166
int
167
PyCapsule_SetName(PyObject *op, const char *name)
168
0
{
169
0
    if (!is_legal_capsule(op, "PyCapsule_SetName")) {
170
0
        return -1;
171
0
    }
172
0
    PyCapsule *capsule = (PyCapsule *)op;
173
174
0
    capsule->name = name;
175
0
    return 0;
176
0
}
177
178
179
int
180
PyCapsule_SetDestructor(PyObject *op, PyCapsule_Destructor destructor)
181
0
{
182
0
    if (!is_legal_capsule(op, "PyCapsule_SetDestructor")) {
183
0
        return -1;
184
0
    }
185
0
    PyCapsule *capsule = (PyCapsule *)op;
186
187
0
    capsule->destructor = destructor;
188
0
    return 0;
189
0
}
190
191
192
int
193
PyCapsule_SetContext(PyObject *op, void *context)
194
0
{
195
0
    if (!is_legal_capsule(op, "PyCapsule_SetContext")) {
196
0
        return -1;
197
0
    }
198
0
    PyCapsule *capsule = (PyCapsule *)op;
199
200
0
    capsule->context = context;
201
0
    return 0;
202
0
}
203
204
205
int
206
_PyCapsule_SetTraverse(PyObject *op, traverseproc traverse_func, inquiry clear_func)
207
4
{
208
4
    if (!is_legal_capsule(op, "_PyCapsule_SetTraverse")) {
209
0
        return -1;
210
0
    }
211
4
    PyCapsule *capsule = (PyCapsule *)op;
212
213
4
    if (traverse_func == NULL || clear_func == NULL) {
214
0
        PyErr_SetString(PyExc_ValueError,
215
0
                        "_PyCapsule_SetTraverse() called with NULL callback");
216
0
        return -1;
217
0
    }
218
219
4
    if (!_PyObject_GC_IS_TRACKED(op)) {
220
4
        _PyObject_GC_TRACK(op);
221
4
    }
222
223
4
    capsule->traverse_func = traverse_func;
224
4
    capsule->clear_func = clear_func;
225
4
    return 0;
226
4
}
227
228
229
void *
230
PyCapsule_Import(const char *name, int no_block)
231
5
{
232
5
    PyObject *object = NULL;
233
5
    void *return_value = NULL;
234
5
    char *trace;
235
5
    size_t name_length = (strlen(name) + 1) * sizeof(char);
236
5
    char *name_dup = (char *)PyMem_Malloc(name_length);
237
238
5
    if (!name_dup) {
239
0
        return PyErr_NoMemory();
240
0
    }
241
242
5
    memcpy(name_dup, name, name_length);
243
244
5
    trace = name_dup;
245
15
    while (trace) {
246
10
        char *dot = strchr(trace, '.');
247
10
        if (dot) {
248
5
            *dot++ = '\0';
249
5
        }
250
251
10
        if (object == NULL) {
252
5
            object = PyImport_ImportModule(trace);
253
5
            if (!object) {
254
0
                PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
255
0
            }
256
5
        } else {
257
5
            PyObject *object2 = PyObject_GetAttrString(object, trace);
258
5
            Py_SETREF(object, object2);
259
5
        }
260
10
        if (!object) {
261
0
            goto EXIT;
262
0
        }
263
264
10
        trace = dot;
265
10
    }
266
267
    /* compare attribute name to module.name by hand */
268
5
    if (PyCapsule_IsValid(object, name)) {
269
5
        PyCapsule *capsule = (PyCapsule *)object;
270
5
        return_value = capsule->pointer;
271
5
    } else {
272
0
        PyErr_Format(PyExc_AttributeError,
273
0
            "PyCapsule_Import \"%s\" is not valid",
274
0
            name);
275
0
    }
276
277
5
EXIT:
278
5
    Py_XDECREF(object);
279
5
    if (name_dup) {
280
5
        PyMem_Free(name_dup);
281
5
    }
282
5
    return return_value;
283
5
}
284
285
286
static void
287
capsule_dealloc(PyObject *op)
288
5.53k
{
289
5.53k
    PyCapsule *capsule = _PyCapsule_CAST(op);
290
5.53k
    PyObject_GC_UnTrack(op);
291
5.53k
    if (capsule->destructor) {
292
53
        capsule->destructor(op);
293
53
    }
294
5.53k
    PyObject_GC_Del(op);
295
5.53k
}
296
297
298
static PyObject *
299
capsule_repr(PyObject *o)
300
0
{
301
0
    PyCapsule *capsule = _PyCapsule_CAST(o);
302
0
    const char *name;
303
0
    const char *quote;
304
305
0
    if (capsule->name) {
306
0
        quote = "\"";
307
0
        name = capsule->name;
308
0
    } else {
309
0
        quote = "";
310
0
        name = "NULL";
311
0
    }
312
313
0
    return PyUnicode_FromFormat("<capsule object %s%s%s at %p>",
314
0
        quote, name, quote, capsule);
315
0
}
316
317
318
static int
319
capsule_traverse(PyObject *self, visitproc visit, void *arg)
320
4.65k
{
321
    // Capsule object is only tracked by the GC
322
    // if _PyCapsule_SetTraverse() is called, but
323
    // this can still be manually triggered by gc.get_referents()
324
4.65k
    PyCapsule *capsule = _PyCapsule_CAST(self);
325
4.65k
    if (capsule->traverse_func != NULL) {
326
4.65k
        return capsule->traverse_func(self, visit, arg);
327
4.65k
    }
328
0
    return 0;
329
4.65k
}
330
331
332
static int
333
capsule_clear(PyObject *self)
334
0
{
335
    // Capsule object is only tracked by the GC
336
    // if _PyCapsule_SetTraverse() is called
337
0
    PyCapsule *capsule = _PyCapsule_CAST(self);
338
0
    assert(capsule->clear_func != NULL);
339
0
    return capsule->clear_func(self);
340
0
}
341
342
343
PyDoc_STRVAR(PyCapsule_Type__doc__,
344
"Capsule objects let you wrap a C \"void *\" pointer in a Python\n\
345
object.  They're a way of passing data through the Python interpreter\n\
346
without creating your own custom type.\n\
347
\n\
348
Capsules are used for communication between extension modules.\n\
349
They provide a way for an extension module to export a C interface\n\
350
to other extension modules, so that extension modules can use the\n\
351
Python import mechanism to link to one another.\n\
352
");
353
354
PyTypeObject PyCapsule_Type = {
355
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
356
    .tp_name = "PyCapsule",
357
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
358
    .tp_basicsize = sizeof(PyCapsule),
359
    .tp_dealloc = capsule_dealloc,
360
    .tp_repr = capsule_repr,
361
    .tp_doc = PyCapsule_Type__doc__,
362
    .tp_traverse = capsule_traverse,
363
    .tp_clear = capsule_clear,
364
};
365
366