• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */
2 
cdlopen_fetch(PyObject * libname,void * libhandle,const char * symbol)3 static void *cdlopen_fetch(PyObject *libname, void *libhandle,
4                            const char *symbol)
5 {
6     void *address;
7 
8     if (libhandle == NULL) {
9         PyErr_Format(FFIError, "library '%s' has been closed",
10                      PyText_AS_UTF8(libname));
11         return NULL;
12     }
13 
14     dlerror();   /* clear error condition */
15     address = dlsym(libhandle, symbol);
16     if (address == NULL) {
17         const char *error = dlerror();
18         PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s",
19                      symbol, PyText_AS_UTF8(libname), error);
20     }
21     return address;
22 }
23 
cdlopen_close_ignore_errors(void * libhandle)24 static void cdlopen_close_ignore_errors(void *libhandle)
25 {
26     if (libhandle != NULL)
27         dlclose(libhandle);
28 }
29 
cdlopen_close(PyObject * libname,void * libhandle)30 static int cdlopen_close(PyObject *libname, void *libhandle)
31 {
32     if (libhandle != NULL && dlclose(libhandle) != 0) {
33         const char *error = dlerror();
34         PyErr_Format(FFIError, "closing library '%s': %s",
35                      PyText_AS_UTF8(libname), error);
36         return -1;
37     }
38     return 0;
39 }
40 
ffi_dlopen(PyObject * self,PyObject * args)41 static PyObject *ffi_dlopen(PyObject *self, PyObject *args)
42 {
43     const char *modname;
44     PyObject *temp, *result = NULL;
45     void *handle;
46 
47     handle = b_do_dlopen(args, &modname, &temp);
48     if (handle != NULL)
49     {
50         result = (PyObject *)lib_internal_new((FFIObject *)self,
51                                               modname, handle);
52     }
53     Py_XDECREF(temp);
54     return result;
55 }
56 
ffi_dlclose(PyObject * self,PyObject * args)57 static PyObject *ffi_dlclose(PyObject *self, PyObject *args)
58 {
59     LibObject *lib;
60     void *libhandle;
61     if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib))
62         return NULL;
63 
64     libhandle = lib->l_libhandle;
65     if (libhandle != NULL)
66     {
67         lib->l_libhandle = NULL;
68 
69         /* Clear the dict to force further accesses to do cdlopen_fetch()
70            again, and fail because the library was closed. */
71         PyDict_Clear(lib->l_dict);
72 
73         if (cdlopen_close(lib->l_libname, libhandle) < 0)
74             return NULL;
75     }
76     Py_INCREF(Py_None);
77     return Py_None;
78 }
79 
80 
cdl_4bytes(char * src)81 static Py_ssize_t cdl_4bytes(char *src)
82 {
83     /* read 4 bytes in little-endian order; return it as a signed integer */
84     signed char *ssrc = (signed char *)src;
85     unsigned char *usrc = (unsigned char *)src;
86     return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3];
87 }
88 
cdl_opcode(char * src)89 static _cffi_opcode_t cdl_opcode(char *src)
90 {
91     return (_cffi_opcode_t)cdl_4bytes(src);
92 }
93 
94 typedef struct {
95     unsigned long long value;
96     int neg;
97 } cdl_intconst_t;
98 
_cdl_realize_global_int(struct _cffi_getconst_s * gc)99 static int _cdl_realize_global_int(struct _cffi_getconst_s *gc)
100 {
101     /* The 'address' field of 'struct _cffi_global_s' is set to point
102        to this function in case ffiobj_init() sees constant integers.
103        This fishes around after the 'ctx->globals' array, which is
104        initialized to contain another array, this time of
105        'cdl_intconst_t' structures.  We get the nth one and it tells
106        us what to return.
107     */
108     cdl_intconst_t *ic;
109     ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals);
110     ic += gc->gindex;
111     gc->value = ic->value;
112     return ic->neg;
113 }
114 
ffiobj_init(PyObject * self,PyObject * args,PyObject * kwds)115 static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds)
116 {
117     FFIObject *ffi;
118     static char *keywords[] = {"module_name", "_version", "_types",
119                                "_globals", "_struct_unions", "_enums",
120                                "_typenames", "_includes", NULL};
121     char *ffiname = "?", *types = NULL, *building = NULL;
122     Py_ssize_t version = -1;
123     Py_ssize_t types_len = 0;
124     PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL;
125     PyObject *typenames = NULL, *includes = NULL;
126 
127     if (!PyArg_ParseTupleAndKeywords(args, kwds,
128                                      "|sns#O!O!O!O!O!:FFI", keywords,
129                                      &ffiname, &version, &types, &types_len,
130                                      &PyTuple_Type, &globals,
131                                      &PyTuple_Type, &struct_unions,
132                                      &PyTuple_Type, &enums,
133                                      &PyTuple_Type, &typenames,
134                                      &PyTuple_Type, &includes))
135         return -1;
136 
137     ffi = (FFIObject *)self;
138     if (ffi->ctx_is_nonempty) {
139         PyErr_SetString(PyExc_ValueError,
140                         "cannot call FFI.__init__() more than once");
141         return -1;
142     }
143     ffi->ctx_is_nonempty = 1;
144 
145     if (version == -1 && types_len == 0)
146         return 0;
147     if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) {
148         PyErr_Format(PyExc_ImportError,
149                      "cffi out-of-line Python module '%s' has unknown "
150                      "version %p", ffiname, (void *)version);
151         return -1;
152     }
153 
154     if (types_len > 0) {
155         /* unpack a string of 4-byte entries into an array of _cffi_opcode_t */
156         _cffi_opcode_t *ntypes;
157         Py_ssize_t i, n = types_len / 4;
158 
159         building = PyMem_Malloc(n * sizeof(_cffi_opcode_t));
160         if (building == NULL)
161             goto error;
162         ntypes = (_cffi_opcode_t *)building;
163 
164         for (i = 0; i < n; i++) {
165             ntypes[i] = cdl_opcode(types);
166             types += 4;
167         }
168         ffi->types_builder.ctx.types = ntypes;
169         ffi->types_builder.ctx.num_types = n;
170         building = NULL;
171     }
172 
173     if (globals != NULL) {
174         /* unpack a tuple alternating strings and ints, each two together
175            describing one global_s entry with no specified address or size.
176            The int is only used with integer constants. */
177         struct _cffi_global_s *nglobs;
178         cdl_intconst_t *nintconsts;
179         Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2;
180 
181         i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t));
182         building = PyMem_Malloc(i);
183         if (building == NULL)
184             goto error;
185         memset(building, 0, i);
186         nglobs = (struct _cffi_global_s *)building;
187         nintconsts = (cdl_intconst_t *)(nglobs + n);
188 
189         for (i = 0; i < n; i++) {
190             char *g = PyBytes_AS_STRING(PyTuple_GET_ITEM(globals, i * 2));
191             nglobs[i].type_op = cdl_opcode(g); g += 4;
192             nglobs[i].name = g;
193             if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT ||
194                 _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) {
195                 PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1);
196                 nglobs[i].address = &_cdl_realize_global_int;
197 #if PY_MAJOR_VERSION < 3
198                 if (PyInt_Check(o)) {
199                     nintconsts[i].neg = PyInt_AS_LONG(o) <= 0;
200                     nintconsts[i].value = (long long)PyInt_AS_LONG(o);
201                 }
202                 else
203 #endif
204                 {
205                     nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False,
206                                                                  Py_LE);
207                     nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o);
208                     if (PyErr_Occurred())
209                         goto error;
210                 }
211             }
212         }
213         ffi->types_builder.ctx.globals = nglobs;
214         ffi->types_builder.ctx.num_globals = n;
215         building = NULL;
216     }
217 
218     if (struct_unions != NULL) {
219         /* unpack a tuple of struct/unions, each described as a sub-tuple;
220            the item 0 of each sub-tuple describes the struct/union, and
221            the items 1..N-1 describe the fields, if any */
222         struct _cffi_struct_union_s *nstructs;
223         struct _cffi_field_s *nfields;
224         Py_ssize_t i, n = PyTuple_GET_SIZE(struct_unions);
225         Py_ssize_t nf = 0;   /* total number of fields */
226 
227         for (i = 0; i < n; i++) {
228             nf += PyTuple_GET_SIZE(PyTuple_GET_ITEM(struct_unions, i)) - 1;
229         }
230         i = (n * sizeof(struct _cffi_struct_union_s) +
231              nf * sizeof(struct _cffi_field_s));
232         building = PyMem_Malloc(i);
233         if (building == NULL)
234             goto error;
235         memset(building, 0, i);
236         nstructs = (struct _cffi_struct_union_s *)building;
237         nfields = (struct _cffi_field_s *)(nstructs + n);
238         nf = 0;
239 
240         for (i = 0; i < n; i++) {
241             /* 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) */
242             PyObject *desc = PyTuple_GET_ITEM(struct_unions, i);
243             Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1;
244             char *s = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, 0));
245             /* 's' is the first string, describing the struct/union */
246             nstructs[i].type_index = cdl_4bytes(s); s += 4;
247             nstructs[i].flags = cdl_4bytes(s); s += 4;
248             nstructs[i].name = s;
249             if (nstructs[i].flags & (_CFFI_F_OPAQUE | _CFFI_F_EXTERNAL)) {
250                 nstructs[i].size = (size_t)-1;
251                 nstructs[i].alignment = -1;
252                 nstructs[i].first_field_index = -1;
253                 nstructs[i].num_fields = 0;
254                 assert(nf1 == 0);
255             }
256             else {
257                 nstructs[i].size = (size_t)-2;
258                 nstructs[i].alignment = -2;
259                 nstructs[i].first_field_index = nf;
260                 nstructs[i].num_fields = nf1;
261             }
262             for (j = 0; j < nf1; j++) {
263                 char *f = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, j + 1));
264                 /* 'f' is one of the other strings beyond the first one,
265                    describing one field each */
266                 nfields[nf].field_type_op = cdl_opcode(f); f += 4;
267                 nfields[nf].field_offset = (size_t)-1;
268                 if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) {
269                     nfields[nf].field_size = cdl_4bytes(f); f += 4;
270                 }
271                 else {
272                     nfields[nf].field_size = (size_t)-1;
273                 }
274                 nfields[nf].name = f;
275                 nf++;
276             }
277         }
278         ffi->types_builder.ctx.struct_unions = nstructs;
279         ffi->types_builder.ctx.fields = nfields;
280         ffi->types_builder.ctx.num_struct_unions = n;
281         building = NULL;
282     }
283 
284     if (enums != NULL) {
285         /* unpack a tuple of strings, each of which describes one enum_s
286            entry */
287         struct _cffi_enum_s *nenums;
288         Py_ssize_t i, n = PyTuple_GET_SIZE(enums);
289 
290         i = n * sizeof(struct _cffi_enum_s);
291         building = PyMem_Malloc(i);
292         if (building == NULL)
293             goto error;
294         memset(building, 0, i);
295         nenums = (struct _cffi_enum_s *)building;
296 
297         for (i = 0; i < n; i++) {
298             char *e = PyBytes_AS_STRING(PyTuple_GET_ITEM(enums, i));
299             /* 'e' is a string describing the enum */
300             nenums[i].type_index = cdl_4bytes(e); e += 4;
301             nenums[i].type_prim = cdl_4bytes(e); e += 4;
302             nenums[i].name = e; e += strlen(e) + 1;
303             nenums[i].enumerators = e;
304         }
305         ffi->types_builder.ctx.enums = nenums;
306         ffi->types_builder.ctx.num_enums = n;
307         building = NULL;
308     }
309 
310     if (typenames != NULL) {
311         /* unpack a tuple of strings, each of which describes one typename_s
312            entry */
313         struct _cffi_typename_s *ntypenames;
314         Py_ssize_t i, n = PyTuple_GET_SIZE(typenames);
315 
316         i = n * sizeof(struct _cffi_typename_s);
317         building = PyMem_Malloc(i);
318         if (building == NULL)
319             goto error;
320         memset(building, 0, i);
321         ntypenames = (struct _cffi_typename_s *)building;
322 
323         for (i = 0; i < n; i++) {
324             char *t = PyBytes_AS_STRING(PyTuple_GET_ITEM(typenames, i));
325             /* 't' is a string describing the typename */
326             ntypenames[i].type_index = cdl_4bytes(t); t += 4;
327             ntypenames[i].name = t;
328         }
329         ffi->types_builder.ctx.typenames = ntypenames;
330         ffi->types_builder.ctx.num_typenames = n;
331         building = NULL;
332     }
333 
334     if (includes != NULL) {
335         PyObject *included_libs;
336 
337         included_libs = PyTuple_New(PyTuple_GET_SIZE(includes));
338         if (included_libs == NULL)
339             return -1;
340 
341         Py_INCREF(includes);
342         ffi->types_builder.included_ffis = includes;
343         ffi->types_builder.included_libs = included_libs;
344     }
345 
346     /* Above, we took directly some "char *" strings out of the strings,
347        typically from somewhere inside tuples.  Keep them alive by
348        incref'ing the whole input arguments. */
349     Py_INCREF(args);
350     Py_XINCREF(kwds);
351     ffi->types_builder._keepalive1 = args;
352     ffi->types_builder._keepalive2 = kwds;
353     return 0;
354 
355  error:
356     if (building != NULL)
357         PyMem_Free(building);
358     if (!PyErr_Occurred())
359         PyErr_NoMemory();
360     return -1;
361 }
362