Coverage Report

Created: 2022-07-08 09:39

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