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