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