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