/* ffi.dlopen() interface with dlopen()/dlsym()/dlclose() */ static void *cdlopen_fetch(PyObject *libname, void *libhandle, const char *symbol) { void *address; if (libhandle == NULL) { PyErr_Format(FFIError, "library '%s' has been closed", PyText_AS_UTF8(libname)); return NULL; } dlerror(); /* clear error condition */ address = dlsym(libhandle, symbol); if (address == NULL) { const char *error = dlerror(); PyErr_Format(FFIError, "symbol '%s' not found in library '%s': %s", symbol, PyText_AS_UTF8(libname), error); } return address; } static void cdlopen_close_ignore_errors(void *libhandle) { if (libhandle != NULL) dlclose(libhandle); } static int cdlopen_close(PyObject *libname, void *libhandle) { if (libhandle != NULL && dlclose(libhandle) != 0) { const char *error = dlerror(); PyErr_Format(FFIError, "closing library '%s': %s", PyText_AS_UTF8(libname), error); return -1; } return 0; } static PyObject *ffi_dlopen(PyObject *self, PyObject *args) { const char *modname; PyObject *temp, *result = NULL; void *handle; int auto_close; handle = b_do_dlopen(args, &modname, &temp, &auto_close); if (handle != NULL) { result = (PyObject *)lib_internal_new((FFIObject *)self, modname, handle, auto_close); } Py_XDECREF(temp); return result; } static PyObject *ffi_dlclose(PyObject *self, PyObject *args) { LibObject *lib; void *libhandle; if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib)) return NULL; libhandle = lib->l_libhandle; if (libhandle != NULL) { lib->l_libhandle = NULL; /* Clear the dict to force further accesses to do cdlopen_fetch() again, and fail because the library was closed. */ PyDict_Clear(lib->l_dict); if (cdlopen_close(lib->l_libname, libhandle) < 0) return NULL; } Py_INCREF(Py_None); return Py_None; } static Py_ssize_t cdl_4bytes(char *src) { /* read 4 bytes in little-endian order; return it as a signed integer */ signed char *ssrc = (signed char *)src; unsigned char *usrc = (unsigned char *)src; return (ssrc[0] << 24) | (usrc[1] << 16) | (usrc[2] << 8) | usrc[3]; } static _cffi_opcode_t cdl_opcode(char *src) { return (_cffi_opcode_t)cdl_4bytes(src); } typedef struct { unsigned long long value; int neg; } cdl_intconst_t; static int _cdl_realize_global_int(struct _cffi_getconst_s *gc) { /* The 'address' field of 'struct _cffi_global_s' is set to point to this function in case ffiobj_init() sees constant integers. This fishes around after the 'ctx->globals' array, which is initialized to contain another array, this time of 'cdl_intconst_t' structures. We get the nth one and it tells us what to return. */ cdl_intconst_t *ic; ic = (cdl_intconst_t *)(gc->ctx->globals + gc->ctx->num_globals); ic += gc->gindex; gc->value = ic->value; return ic->neg; } static int ffiobj_init(PyObject *self, PyObject *args, PyObject *kwds) { FFIObject *ffi; static char *keywords[] = {"module_name", "_version", "_types", "_globals", "_struct_unions", "_enums", "_typenames", "_includes", NULL}; char *ffiname = "?", *types = NULL, *building = NULL; Py_ssize_t version = -1; Py_ssize_t types_len = 0; PyObject *globals = NULL, *struct_unions = NULL, *enums = NULL; PyObject *typenames = NULL, *includes = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sns#O!O!O!O!O!:FFI", keywords, &ffiname, &version, &types, &types_len, &PyTuple_Type, &globals, &PyTuple_Type, &struct_unions, &PyTuple_Type, &enums, &PyTuple_Type, &typenames, &PyTuple_Type, &includes)) return -1; ffi = (FFIObject *)self; if (ffi->ctx_is_nonempty) { PyErr_SetString(PyExc_ValueError, "cannot call FFI.__init__() more than once"); return -1; } ffi->ctx_is_nonempty = 1; if (version == -1 && types_len == 0) return 0; if (version < CFFI_VERSION_MIN || version > CFFI_VERSION_MAX) { PyErr_Format(PyExc_ImportError, "cffi out-of-line Python module '%s' has unknown " "version %p", ffiname, (void *)version); return -1; } if (types_len > 0) { /* unpack a string of 4-byte entries into an array of _cffi_opcode_t */ _cffi_opcode_t *ntypes; Py_ssize_t i, n = types_len / 4; building = PyMem_Malloc(n * sizeof(_cffi_opcode_t)); if (building == NULL) goto error; ntypes = (_cffi_opcode_t *)building; for (i = 0; i < n; i++) { ntypes[i] = cdl_opcode(types); types += 4; } ffi->types_builder.ctx.types = ntypes; ffi->types_builder.ctx.num_types = n; building = NULL; } if (globals != NULL) { /* unpack a tuple alternating strings and ints, each two together describing one global_s entry with no specified address or size. The int is only used with integer constants. */ struct _cffi_global_s *nglobs; cdl_intconst_t *nintconsts; Py_ssize_t i, n = PyTuple_GET_SIZE(globals) / 2; i = n * (sizeof(struct _cffi_global_s) + sizeof(cdl_intconst_t)); building = PyMem_Malloc(i); if (building == NULL) goto error; memset(building, 0, i); nglobs = (struct _cffi_global_s *)building; nintconsts = (cdl_intconst_t *)(nglobs + n); for (i = 0; i < n; i++) { char *g = PyBytes_AS_STRING(PyTuple_GET_ITEM(globals, i * 2)); nglobs[i].type_op = cdl_opcode(g); g += 4; nglobs[i].name = g; if (_CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_CONSTANT_INT || _CFFI_GETOP(nglobs[i].type_op) == _CFFI_OP_ENUM) { PyObject *o = PyTuple_GET_ITEM(globals, i * 2 + 1); nglobs[i].address = &_cdl_realize_global_int; #if PY_MAJOR_VERSION < 3 if (PyInt_Check(o)) { nintconsts[i].neg = PyInt_AS_LONG(o) <= 0; nintconsts[i].value = (long long)PyInt_AS_LONG(o); } else #endif { nintconsts[i].neg = PyObject_RichCompareBool(o, Py_False, Py_LE); nintconsts[i].value = PyLong_AsUnsignedLongLongMask(o); if (PyErr_Occurred()) goto error; } } } ffi->types_builder.ctx.globals = nglobs; ffi->types_builder.ctx.num_globals = n; building = NULL; } if (struct_unions != NULL) { /* unpack a tuple of struct/unions, each described as a sub-tuple; the item 0 of each sub-tuple describes the struct/union, and the items 1..N-1 describe the fields, if any */ struct _cffi_struct_union_s *nstructs; struct _cffi_field_s *nfields; Py_ssize_t i, n = PyTuple_GET_SIZE(struct_unions); Py_ssize_t nf = 0; /* total number of fields */ for (i = 0; i < n; i++) { nf += PyTuple_GET_SIZE(PyTuple_GET_ITEM(struct_unions, i)) - 1; } i = (n * sizeof(struct _cffi_struct_union_s) + nf * sizeof(struct _cffi_field_s)); building = PyMem_Malloc(i); if (building == NULL) goto error; memset(building, 0, i); nstructs = (struct _cffi_struct_union_s *)building; nfields = (struct _cffi_field_s *)(nstructs + n); nf = 0; for (i = 0; i < n; i++) { /* 'desc' is the tuple of strings (desc_struct, desc_field_1, ..) */ PyObject *desc = PyTuple_GET_ITEM(struct_unions, i); Py_ssize_t j, nf1 = PyTuple_GET_SIZE(desc) - 1; char *s = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, 0)); /* 's' is the first string, describing the struct/union */ nstructs[i].type_index = cdl_4bytes(s); s += 4; nstructs[i].flags = cdl_4bytes(s); s += 4; nstructs[i].name = s; if (nstructs[i].flags & (_CFFI_F_OPAQUE | _CFFI_F_EXTERNAL)) { nstructs[i].size = (size_t)-1; nstructs[i].alignment = -1; nstructs[i].first_field_index = -1; nstructs[i].num_fields = 0; assert(nf1 == 0); } else { nstructs[i].size = (size_t)-2; nstructs[i].alignment = -2; nstructs[i].first_field_index = nf; nstructs[i].num_fields = nf1; } for (j = 0; j < nf1; j++) { char *f = PyBytes_AS_STRING(PyTuple_GET_ITEM(desc, j + 1)); /* 'f' is one of the other strings beyond the first one, describing one field each */ nfields[nf].field_type_op = cdl_opcode(f); f += 4; nfields[nf].field_offset = (size_t)-1; if (_CFFI_GETOP(nfields[nf].field_type_op) != _CFFI_OP_NOOP) { nfields[nf].field_size = cdl_4bytes(f); f += 4; } else { nfields[nf].field_size = (size_t)-1; } nfields[nf].name = f; nf++; } } ffi->types_builder.ctx.struct_unions = nstructs; ffi->types_builder.ctx.fields = nfields; ffi->types_builder.ctx.num_struct_unions = n; building = NULL; } if (enums != NULL) { /* unpack a tuple of strings, each of which describes one enum_s entry */ struct _cffi_enum_s *nenums; Py_ssize_t i, n = PyTuple_GET_SIZE(enums); i = n * sizeof(struct _cffi_enum_s); building = PyMem_Malloc(i); if (building == NULL) goto error; memset(building, 0, i); nenums = (struct _cffi_enum_s *)building; for (i = 0; i < n; i++) { char *e = PyBytes_AS_STRING(PyTuple_GET_ITEM(enums, i)); /* 'e' is a string describing the enum */ nenums[i].type_index = cdl_4bytes(e); e += 4; nenums[i].type_prim = cdl_4bytes(e); e += 4; nenums[i].name = e; e += strlen(e) + 1; nenums[i].enumerators = e; } ffi->types_builder.ctx.enums = nenums; ffi->types_builder.ctx.num_enums = n; building = NULL; } if (typenames != NULL) { /* unpack a tuple of strings, each of which describes one typename_s entry */ struct _cffi_typename_s *ntypenames; Py_ssize_t i, n = PyTuple_GET_SIZE(typenames); i = n * sizeof(struct _cffi_typename_s); building = PyMem_Malloc(i); if (building == NULL) goto error; memset(building, 0, i); ntypenames = (struct _cffi_typename_s *)building; for (i = 0; i < n; i++) { char *t = PyBytes_AS_STRING(PyTuple_GET_ITEM(typenames, i)); /* 't' is a string describing the typename */ ntypenames[i].type_index = cdl_4bytes(t); t += 4; ntypenames[i].name = t; } ffi->types_builder.ctx.typenames = ntypenames; ffi->types_builder.ctx.num_typenames = n; building = NULL; } if (includes != NULL) { PyObject *included_libs; included_libs = PyTuple_New(PyTuple_GET_SIZE(includes)); if (included_libs == NULL) return -1; Py_INCREF(includes); ffi->types_builder.included_ffis = includes; ffi->types_builder.included_libs = included_libs; } /* Above, we took directly some "char *" strings out of the strings, typically from somewhere inside tuples. Keep them alive by incref'ing the whole input arguments. */ Py_INCREF(args); Py_XINCREF(kwds); ffi->types_builder._keepalive1 = args; ffi->types_builder._keepalive2 = kwds; return 0; error: if (building != NULL) PyMem_Free(building); if (!PyErr_Occurred()) PyErr_NoMemory(); return -1; }