Coverage Report

Created: 2025-07-11 06:59

/src/Python-3.8.3/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
5
/* Internal structure of PyCapsule */
6
typedef struct {
7
    PyObject_HEAD
8
    void *pointer;
9
    const char *name;
10
    void *context;
11
    PyCapsule_Destructor destructor;
12
} PyCapsule;
13
14
15
16
static int
17
_is_legal_capsule(PyCapsule *capsule, const char *invalid_capsule)
18
6
{
19
6
    if (!capsule || !PyCapsule_CheckExact(capsule) || capsule->pointer == NULL) {
20
0
        PyErr_SetString(PyExc_ValueError, invalid_capsule);
21
0
        return 0;
22
0
    }
23
6
    return 1;
24
6
}
25
26
#define is_legal_capsule(capsule, name) \
27
6
    (_is_legal_capsule(capsule, \
28
6
     name " called with invalid PyCapsule object"))
29
30
31
static int
32
6
name_matches(const char *name1, const char *name2) {
33
    /* if either is NULL, */
34
6
    if (!name1 || !name2) {
35
        /* they're only the same if they're both NULL. */
36
0
        return name1 == name2;
37
0
    }
38
6
    return !strcmp(name1, name2);
39
6
}
40
41
42
43
PyObject *
44
PyCapsule_New(void *pointer, const char *name, PyCapsule_Destructor destructor)
45
20
{
46
20
    PyCapsule *capsule;
47
48
20
    if (!pointer) {
49
0
        PyErr_SetString(PyExc_ValueError, "PyCapsule_New called with null pointer");
50
0
        return NULL;
51
0
    }
52
53
20
    capsule = PyObject_NEW(PyCapsule, &PyCapsule_Type);
54
20
    if (capsule == NULL) {
55
0
        return NULL;
56
0
    }
57
58
20
    capsule->pointer = pointer;
59
20
    capsule->name = name;
60
20
    capsule->context = NULL;
61
20
    capsule->destructor = destructor;
62
63
20
    return (PyObject *)capsule;
64
20
}
65
66
67
int
68
PyCapsule_IsValid(PyObject *o, const char *name)
69
0
{
70
0
    PyCapsule *capsule = (PyCapsule *)o;
71
72
0
    return (capsule != NULL &&
73
0
            PyCapsule_CheckExact(capsule) &&
74
0
            capsule->pointer != NULL &&
75
0
            name_matches(capsule->name, name));
76
0
}
77
78
79
void *
80
PyCapsule_GetPointer(PyObject *o, const char *name)
81
6
{
82
6
    PyCapsule *capsule = (PyCapsule *)o;
83
84
6
    if (!is_legal_capsule(capsule, "PyCapsule_GetPointer")) {
85
0
        return NULL;
86
0
    }
87
88
6
    if (!name_matches(name, capsule->name)) {
89
0
        PyErr_SetString(PyExc_ValueError, "PyCapsule_GetPointer called with incorrect name");
90
0
        return NULL;
91
0
    }
92
93
6
    return capsule->pointer;
94
6
}
95
96
97
const char *
98
PyCapsule_GetName(PyObject *o)
99
0
{
100
0
    PyCapsule *capsule = (PyCapsule *)o;
101
102
0
    if (!is_legal_capsule(capsule, "PyCapsule_GetName")) {
103
0
        return NULL;
104
0
    }
105
0
    return capsule->name;
106
0
}
107
108
109
PyCapsule_Destructor
110
PyCapsule_GetDestructor(PyObject *o)
111
0
{
112
0
    PyCapsule *capsule = (PyCapsule *)o;
113
114
0
    if (!is_legal_capsule(capsule, "PyCapsule_GetDestructor")) {
115
0
        return NULL;
116
0
    }
117
0
    return capsule->destructor;
118
0
}
119
120
121
void *
122
PyCapsule_GetContext(PyObject *o)
123
0
{
124
0
    PyCapsule *capsule = (PyCapsule *)o;
125
126
0
    if (!is_legal_capsule(capsule, "PyCapsule_GetContext")) {
127
0
        return NULL;
128
0
    }
129
0
    return capsule->context;
130
0
}
131
132
133
int
134
PyCapsule_SetPointer(PyObject *o, void *pointer)
135
0
{
136
0
    PyCapsule *capsule = (PyCapsule *)o;
137
138
0
    if (!pointer) {
139
0
        PyErr_SetString(PyExc_ValueError, "PyCapsule_SetPointer called with null pointer");
140
0
        return -1;
141
0
    }
142
143
0
    if (!is_legal_capsule(capsule, "PyCapsule_SetPointer")) {
144
0
        return -1;
145
0
    }
146
147
0
    capsule->pointer = pointer;
148
0
    return 0;
149
0
}
150
151
152
int
153
PyCapsule_SetName(PyObject *o, const char *name)
154
0
{
155
0
    PyCapsule *capsule = (PyCapsule *)o;
156
157
0
    if (!is_legal_capsule(capsule, "PyCapsule_SetName")) {
158
0
        return -1;
159
0
    }
160
161
0
    capsule->name = name;
162
0
    return 0;
163
0
}
164
165
166
int
167
PyCapsule_SetDestructor(PyObject *o, PyCapsule_Destructor destructor)
168
0
{
169
0
    PyCapsule *capsule = (PyCapsule *)o;
170
171
0
    if (!is_legal_capsule(capsule, "PyCapsule_SetDestructor")) {
172
0
        return -1;
173
0
    }
174
175
0
    capsule->destructor = destructor;
176
0
    return 0;
177
0
}
178
179
180
int
181
PyCapsule_SetContext(PyObject *o, void *context)
182
0
{
183
0
    PyCapsule *capsule = (PyCapsule *)o;
184
185
0
    if (!is_legal_capsule(capsule, "PyCapsule_SetContext")) {
186
0
        return -1;
187
0
    }
188
189
0
    capsule->context = context;
190
0
    return 0;
191
0
}
192
193
194
void *
195
PyCapsule_Import(const char *name, int no_block)
196
0
{
197
0
    PyObject *object = NULL;
198
0
    void *return_value = NULL;
199
0
    char *trace;
200
0
    size_t name_length = (strlen(name) + 1) * sizeof(char);
201
0
    char *name_dup = (char *)PyMem_MALLOC(name_length);
202
203
0
    if (!name_dup) {
204
0
        return PyErr_NoMemory();
205
0
    }
206
207
0
    memcpy(name_dup, name, name_length);
208
209
0
    trace = name_dup;
210
0
    while (trace) {
211
0
        char *dot = strchr(trace, '.');
212
0
        if (dot) {
213
0
            *dot++ = '\0';
214
0
        }
215
216
0
        if (object == NULL) {
217
0
            if (no_block) {
218
0
                object = PyImport_ImportModuleNoBlock(trace);
219
0
            } else {
220
0
                object = PyImport_ImportModule(trace);
221
0
                if (!object) {
222
0
                    PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
223
0
                }
224
0
            }
225
0
        } else {
226
0
            PyObject *object2 = PyObject_GetAttrString(object, trace);
227
0
            Py_DECREF(object);
228
0
            object = object2;
229
0
        }
230
0
        if (!object) {
231
0
            goto EXIT;
232
0
        }
233
234
0
        trace = dot;
235
0
    }
236
237
    /* compare attribute name to module.name by hand */
238
0
    if (PyCapsule_IsValid(object, name)) {
239
0
        PyCapsule *capsule = (PyCapsule *)object;
240
0
        return_value = capsule->pointer;
241
0
    } else {
242
0
        PyErr_Format(PyExc_AttributeError,
243
0
            "PyCapsule_Import \"%s\" is not valid",
244
0
            name);
245
0
    }
246
247
0
EXIT:
248
0
    Py_XDECREF(object);
249
0
    if (name_dup) {
250
0
        PyMem_FREE(name_dup);
251
0
    }
252
0
    return return_value;
253
0
}
254
255
256
static void
257
capsule_dealloc(PyObject *o)
258
6
{
259
6
    PyCapsule *capsule = (PyCapsule *)o;
260
6
    if (capsule->destructor) {
261
0
        capsule->destructor(o);
262
0
    }
263
6
    PyObject_DEL(o);
264
6
}
265
266
267
static PyObject *
268
capsule_repr(PyObject *o)
269
0
{
270
0
    PyCapsule *capsule = (PyCapsule *)o;
271
0
    const char *name;
272
0
    const char *quote;
273
274
0
    if (capsule->name) {
275
0
        quote = "\"";
276
0
        name = capsule->name;
277
0
    } else {
278
0
        quote = "";
279
0
        name = "NULL";
280
0
    }
281
282
0
    return PyUnicode_FromFormat("<capsule object %s%s%s at %p>",
283
0
        quote, name, quote, capsule);
284
0
}
285
286
287
288
PyDoc_STRVAR(PyCapsule_Type__doc__,
289
"Capsule objects let you wrap a C \"void *\" pointer in a Python\n\
290
object.  They're a way of passing data through the Python interpreter\n\
291
without creating your own custom type.\n\
292
\n\
293
Capsules are used for communication between extension modules.\n\
294
They provide a way for an extension module to export a C interface\n\
295
to other extension modules, so that extension modules can use the\n\
296
Python import mechanism to link to one another.\n\
297
");
298
299
PyTypeObject PyCapsule_Type = {
300
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
301
    "PyCapsule",                /*tp_name*/
302
    sizeof(PyCapsule),          /*tp_basicsize*/
303
    0,                          /*tp_itemsize*/
304
    /* methods */
305
    capsule_dealloc, /*tp_dealloc*/
306
    0,                          /*tp_vectorcall_offset*/
307
    0,                          /*tp_getattr*/
308
    0,                          /*tp_setattr*/
309
    0,                          /*tp_as_async*/
310
    capsule_repr, /*tp_repr*/
311
    0,                          /*tp_as_number*/
312
    0,                          /*tp_as_sequence*/
313
    0,                          /*tp_as_mapping*/
314
    0,                          /*tp_hash*/
315
    0,                          /*tp_call*/
316
    0,                          /*tp_str*/
317
    0,                          /*tp_getattro*/
318
    0,                          /*tp_setattro*/
319
    0,                          /*tp_as_buffer*/
320
    0,                          /*tp_flags*/
321
    PyCapsule_Type__doc__       /*tp_doc*/
322
};
323
324