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