typedef struct { struct _cffi_type_context_s ctx; /* inlined substructure */ PyObject *types_dict; PyObject *included_ffis; PyObject *included_libs; PyObject *_keepalive1; PyObject *_keepalive2; } builder_c_t; static PyObject *all_primitives[_CFFI__NUM_PRIM]; static CTypeDescrObject *g_ct_voidp, *g_ct_chararray; static PyObject *build_primitive_type(int num); /* forward */ #define primitive_in_range(num) ((num) >= 0 && (num) < _CFFI__NUM_PRIM) #define get_primitive_type(num) \ ((primitive_in_range(num) && all_primitives[num] != NULL) ? \ all_primitives[num] : build_primitive_type(num)) static int init_global_types_dict(PyObject *ffi_type_dict) { int err; PyObject *ct_void, *ct_char, *ct2, *pnull; /* XXX some leaks in case these functions fail, but well, MemoryErrors during importing an extension module are kind of bad anyway */ ct_void = get_primitive_type(_CFFI_PRIM_VOID); // 'void' if (ct_void == NULL) return -1; ct2 = new_pointer_type((CTypeDescrObject *)ct_void); // 'void *' if (ct2 == NULL) return -1; g_ct_voidp = (CTypeDescrObject *)ct2; ct_char = get_primitive_type(_CFFI_PRIM_CHAR); // 'char' if (ct_char == NULL) return -1; ct2 = new_pointer_type((CTypeDescrObject *)ct_char); // 'char *' if (ct2 == NULL) return -1; ct2 = new_array_type((CTypeDescrObject *)ct2, -1); // 'char[]' if (ct2 == NULL) return -1; g_ct_chararray = (CTypeDescrObject *)ct2; pnull = new_simple_cdata(NULL, g_ct_voidp); if (pnull == NULL) return -1; err = PyDict_SetItemString(ffi_type_dict, "NULL", pnull); Py_DECREF(pnull); return err; } static void free_builder_c(builder_c_t *builder, int ctx_is_static) { if (!ctx_is_static) { size_t i; const void *mem[] = {builder->ctx.types, builder->ctx.globals, builder->ctx.struct_unions, //builder->ctx.fields: allocated with struct_unions builder->ctx.enums, builder->ctx.typenames}; for (i = 0; i < sizeof(mem) / sizeof(*mem); i++) { if (mem[i] != NULL) PyMem_Free((void *)mem[i]); } } Py_XDECREF(builder->included_ffis); Py_XDECREF(builder->included_libs); Py_XDECREF(builder->types_dict); Py_XDECREF(builder->_keepalive1); Py_XDECREF(builder->_keepalive2); } static int init_builder_c(builder_c_t *builder, const struct _cffi_type_context_s *ctx) { PyObject *ldict = PyDict_New(); if (ldict == NULL) return -1; if (ctx) builder->ctx = *ctx; else memset(&builder->ctx, 0, sizeof(builder->ctx)); builder->types_dict = ldict; builder->included_ffis = NULL; builder->included_libs = NULL; builder->_keepalive1 = NULL; builder->_keepalive2 = NULL; return 0; } static PyObject *build_primitive_type(int num) { /* XXX too many translations between here and new_primitive_type() */ static const char *primitive_name[] = { NULL, "_Bool", "char", "signed char", "unsigned char", "short", "unsigned short", "int", "unsigned int", "long", "unsigned long", "long long", "unsigned long long", "float", "double", "long double", "wchar_t", "int8_t", "uint8_t", "int16_t", "uint16_t", "int32_t", "uint32_t", "int64_t", "uint64_t", "intptr_t", "uintptr_t", "ptrdiff_t", "size_t", "ssize_t", "int_least8_t", "uint_least8_t", "int_least16_t", "uint_least16_t", "int_least32_t", "uint_least32_t", "int_least64_t", "uint_least64_t", "int_fast8_t", "uint_fast8_t", "int_fast16_t", "uint_fast16_t", "int_fast32_t", "uint_fast32_t", "int_fast64_t", "uint_fast64_t", "intmax_t", "uintmax_t", "float _Complex", "double _Complex", "char16_t", "char32_t", }; PyObject *x; assert(sizeof(primitive_name) == sizeof(*primitive_name) * _CFFI__NUM_PRIM); if (num == _CFFI_PRIM_VOID) { x = new_void_type(); } else if (primitive_in_range(num) && primitive_name[num] != NULL) { x = new_primitive_type(primitive_name[num]); } else if (num == _CFFI__UNKNOWN_PRIM) { PyErr_SetString(FFIError, "primitive integer type with an unexpected " "size (or not an integer type at all)"); return NULL; } else if (num == _CFFI__UNKNOWN_FLOAT_PRIM) { PyErr_SetString(FFIError, "primitive floating-point type with an " "unexpected size (or not a float type at all)"); return NULL; } else if (num == _CFFI__UNKNOWN_LONG_DOUBLE) { PyErr_SetString(FFIError, "primitive floating-point type is " "'long double', not supported for now with " "the syntax 'typedef double... xxx;'"); return NULL; } else { PyErr_Format(PyExc_NotImplementedError, "prim=%d", num); return NULL; } all_primitives[num] = x; return x; } static PyObject *realize_global_int(builder_c_t *builder, int gindex) { int neg; char got[64]; unsigned long long value; struct _cffi_getconst_s gc; const struct _cffi_global_s *g = &builder->ctx.globals[gindex]; gc.ctx = &builder->ctx; gc.gindex = gindex; /* note: we cast g->address to this function type; we do the same in parse_c_type:parse_sequel() too. Note that the called function may be declared simply with "unsigned long long *" as argument, which is fine as it is the first field in _cffi_getconst_s. */ assert(&gc.value == (unsigned long long *)&gc); neg = ((int(*)(struct _cffi_getconst_s *))g->address)(&gc); value = gc.value; switch (neg) { case 0: if (value <= (unsigned long long)LONG_MAX) return PyInt_FromLong((long)value); else return PyLong_FromUnsignedLongLong(value); case 1: if ((long long)value >= (long long)LONG_MIN) return PyInt_FromLong((long)value); else return PyLong_FromLongLong((long long)value); default: break; } if (neg == 2) sprintf(got, "%llu (0x%llx)", value, value); else sprintf(got, "%lld", (long long)value); PyErr_Format(FFIError, "the C compiler says '%.200s' is equal to %s, " "but the cdef disagrees", g->name, got); return NULL; } static CTypeDescrObject * unwrap_fn_as_fnptr(PyObject *x) { assert(PyTuple_Check(x)); return (CTypeDescrObject *)PyTuple_GET_ITEM(x, 0); } static CTypeDescrObject * unexpected_fn_type(PyObject *x) { CTypeDescrObject *ct = unwrap_fn_as_fnptr(x); char *text1 = ct->ct_name; char *text2 = text1 + ct->ct_name_position + 1; assert(text2[-3] == '('); text2[-3] = '\0'; PyErr_Format(FFIError, "the type '%s%s' is a function type, not a " "pointer-to-function type", text1, text2); text2[-3] = '('; return NULL; } static PyObject * realize_c_type_or_func(builder_c_t *builder, _cffi_opcode_t opcodes[], int index); /* forward */ /* Interpret an opcodes[] array. If opcodes == ctx->types, store all the intermediate types back in the opcodes[]. Returns a new reference. */ static CTypeDescrObject * realize_c_type(builder_c_t *builder, _cffi_opcode_t opcodes[], int index) { PyObject *x = realize_c_type_or_func(builder, opcodes, index); if (x == NULL || CTypeDescr_Check(x)) return (CTypeDescrObject *)x; else { unexpected_fn_type(x); Py_DECREF(x); return NULL; } } static void _realize_name(char *target, const char *prefix, const char *srcname) { /* "xyz" => "struct xyz" "$xyz" => "xyz" "$1" => "struct $1" */ if (srcname[0] == '$' && srcname[1] != '$' && !('0' <= srcname[1] && srcname[1] <= '9')) { strcpy(target, &srcname[1]); } else { strcpy(target, prefix); strcat(target, srcname); } } static void _unrealize_name(char *target, const char *srcname) { /* reverse of _realize_name() */ if (strncmp(srcname, "struct ", 7) == 0) { strcpy(target, &srcname[7]); } else if (strncmp(srcname, "union ", 6) == 0) { strcpy(target, &srcname[6]); } else if (strncmp(srcname, "enum ", 5) == 0) { strcpy(target, &srcname[5]); } else { strcpy(target, "$"); strcat(target, srcname); } } static PyObject * /* forward */ _fetch_external_struct_or_union(const struct _cffi_struct_union_s *s, PyObject *included_ffis, int recursion); static PyObject * _realize_c_struct_or_union(builder_c_t *builder, int sindex) { PyObject *x; _cffi_opcode_t op2; const struct _cffi_struct_union_s *s; if (sindex == _CFFI__IO_FILE_STRUCT) { /* returns a single global cached opaque type */ static PyObject *file_struct = NULL; if (file_struct == NULL) file_struct = new_struct_or_union_type("FILE", CT_STRUCT | CT_IS_FILE); Py_XINCREF(file_struct); return file_struct; } s = &builder->ctx.struct_unions[sindex]; op2 = builder->ctx.types[s->type_index]; if ((((uintptr_t)op2) & 1) == 0) { x = (PyObject *)op2; /* found already in the "primary" slot */ Py_INCREF(x); } else { CTypeDescrObject *ct = NULL; if (!(s->flags & _CFFI_F_EXTERNAL)) { int flags = (s->flags & _CFFI_F_UNION) ? CT_UNION : CT_STRUCT; char *name = alloca(8 + strlen(s->name)); _realize_name(name, (s->flags & _CFFI_F_UNION) ? "union " : "struct ", s->name); if (strcmp(name, "struct _IO_FILE") == 0) x = _realize_c_struct_or_union(builder, _CFFI__IO_FILE_STRUCT); else x = new_struct_or_union_type(name, flags); if (x == NULL) return NULL; if (!(s->flags & _CFFI_F_OPAQUE)) { assert(s->first_field_index >= 0); ct = (CTypeDescrObject *)x; ct->ct_size = (Py_ssize_t)s->size; ct->ct_length = s->alignment; /* may be -1 */ ct->ct_flags &= ~CT_IS_OPAQUE; ct->ct_flags |= CT_LAZY_FIELD_LIST; ct->ct_extra = builder; } else assert(s->first_field_index < 0); } else { assert(s->first_field_index < 0); x = _fetch_external_struct_or_union(s, builder->included_ffis, 0); if (x == NULL) { if (!PyErr_Occurred()) PyErr_Format(FFIError, "'%s %.200s' should come from " "ffi.include() but was not found", (s->flags & _CFFI_F_UNION) ? "union" : "struct", s->name); return NULL; } if (!(s->flags & _CFFI_F_OPAQUE)) { if (((CTypeDescrObject *)x)->ct_flags & CT_IS_OPAQUE) { const char *prefix = (s->flags & _CFFI_F_UNION) ? "union" : "struct"; PyErr_Format(PyExc_NotImplementedError, "'%s %.200s' is opaque in the ffi.include(), " "but no longer in the ffi doing the include " "(workaround: don't use ffi.include() but " "duplicate the declarations of everything " "using %s %.200s)", prefix, s->name, prefix, s->name); Py_DECREF(x); return NULL; } } } /* Update the "primary" OP_STRUCT_UNION slot */ assert((((uintptr_t)x) & 1) == 0); assert(builder->ctx.types[s->type_index] == op2); Py_INCREF(x); builder->ctx.types[s->type_index] = x; if (ct != NULL && s->size == (size_t)-2) { /* oops, this struct is unnamed and we couldn't generate a C expression to get its size. We have to rely on complete_struct_or_union() to compute it now. */ if (do_realize_lazy_struct(ct) < 0) { builder->ctx.types[s->type_index] = op2; return NULL; } } } return x; } static PyObject * realize_c_type_or_func_now(builder_c_t *builder, _cffi_opcode_t op, _cffi_opcode_t opcodes[], int index) { PyObject *x, *y, *z; Py_ssize_t length = -1; switch (_CFFI_GETOP(op)) { case _CFFI_OP_PRIMITIVE: x = get_primitive_type(_CFFI_GETARG(op)); Py_XINCREF(x); break; case _CFFI_OP_POINTER: y = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op)); if (y == NULL) return NULL; if (CTypeDescr_Check(y)) { x = new_pointer_type((CTypeDescrObject *)y); } else { assert(PyTuple_Check(y)); /* from _CFFI_OP_FUNCTION */ x = PyTuple_GET_ITEM(y, 0); Py_INCREF(x); } Py_DECREF(y); break; case _CFFI_OP_ARRAY: length = (Py_ssize_t)opcodes[index + 1]; /* fall-through */ case _CFFI_OP_OPEN_ARRAY: y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op)); if (y == NULL) return NULL; z = new_pointer_type((CTypeDescrObject *)y); Py_DECREF(y); if (z == NULL) return NULL; x = new_array_type((CTypeDescrObject *)z, length); Py_DECREF(z); break; case _CFFI_OP_STRUCT_UNION: x = _realize_c_struct_or_union(builder, _CFFI_GETARG(op)); break; case _CFFI_OP_ENUM: { const struct _cffi_enum_s *e; _cffi_opcode_t op2; e = &builder->ctx.enums[_CFFI_GETARG(op)]; op2 = builder->ctx.types[e->type_index]; if ((((uintptr_t)op2) & 1) == 0) { x = (PyObject *)op2; Py_INCREF(x); } else { PyObject *enumerators = NULL, *enumvalues = NULL, *tmp; Py_ssize_t i, j, n = 0; const char *p; int gindex; PyObject *args; PyObject *basetd = get_primitive_type(e->type_prim); if (basetd == NULL) return NULL; if (*e->enumerators != '\0') { n++; for (p = e->enumerators; *p != '\0'; p++) n += (*p == ','); } enumerators = PyTuple_New(n); if (enumerators == NULL) return NULL; enumvalues = PyTuple_New(n); if (enumvalues == NULL) { Py_DECREF(enumerators); return NULL; } p = e->enumerators; for (i = 0; i < n; i++) { j = 0; while (p[j] != ',' && p[j] != '\0') j++; tmp = PyText_FromStringAndSize(p, j); if (tmp == NULL) break; PyTuple_SET_ITEM(enumerators, i, tmp); gindex = search_in_globals(&builder->ctx, p, j); assert(gindex >= 0); assert(builder->ctx.globals[gindex].type_op == _CFFI_OP(_CFFI_OP_ENUM, -1)); tmp = realize_global_int(builder, gindex); if (tmp == NULL) break; PyTuple_SET_ITEM(enumvalues, i, tmp); p += j + 1; } args = NULL; if (!PyErr_Occurred()) { char *name = alloca(6 + strlen(e->name)); _realize_name(name, "enum ", e->name); args = Py_BuildValue("(sOOO)", name, enumerators, enumvalues, basetd); } Py_DECREF(enumerators); Py_DECREF(enumvalues); if (args == NULL) return NULL; x = b_new_enum_type(NULL, args); Py_DECREF(args); if (x == NULL) return NULL; /* Update the "primary" _CFFI_OP_ENUM slot, which may be the same or a different slot than the "current" one */ assert((((uintptr_t)x) & 1) == 0); assert(builder->ctx.types[e->type_index] == op2); Py_INCREF(x); builder->ctx.types[e->type_index] = x; /* Done, leave without updating the "current" slot because it may be done already above. If not, never mind, the next call to realize_c_type() will do it. */ return x; } break; } case _CFFI_OP_FUNCTION: { PyObject *fargs; int i, base_index, num_args, ellipsis, abi; y = (PyObject *)realize_c_type(builder, opcodes, _CFFI_GETARG(op)); if (y == NULL) return NULL; base_index = index + 1; num_args = 0; /* note that if the arguments are already built, they have a pointer in the 'opcodes' array, and GETOP() returns a random even value. But OP_FUNCTION_END is odd, so the condition below still works correctly. */ while (_CFFI_GETOP(opcodes[base_index + num_args]) != _CFFI_OP_FUNCTION_END) num_args++; ellipsis = _CFFI_GETARG(opcodes[base_index + num_args]) & 0x01; abi = _CFFI_GETARG(opcodes[base_index + num_args]) & 0xFE; switch (abi) { case 0: abi = FFI_DEFAULT_ABI; break; case 2: #if defined(MS_WIN32) && !defined(_WIN64) abi = FFI_STDCALL; #else abi = FFI_DEFAULT_ABI; #endif break; default: PyErr_Format(FFIError, "abi number %d not supported", abi); Py_DECREF(y); return NULL; } fargs = PyTuple_New(num_args); if (fargs == NULL) { Py_DECREF(y); return NULL; } for (i = 0; i < num_args; i++) { z = (PyObject *)realize_c_type(builder, opcodes, base_index + i); if (z == NULL) { Py_DECREF(fargs); Py_DECREF(y); return NULL; } PyTuple_SET_ITEM(fargs, i, z); } z = new_function_type(fargs, (CTypeDescrObject *)y, ellipsis, abi); Py_DECREF(fargs); Py_DECREF(y); if (z == NULL) return NULL; x = PyTuple_Pack(1, z); /* hack: hide the CT_FUNCTIONPTR. it will be revealed again by the OP_POINTER */ Py_DECREF(z); break; } case _CFFI_OP_NOOP: x = realize_c_type_or_func(builder, opcodes, _CFFI_GETARG(op)); break; case _CFFI_OP_TYPENAME: { /* essential: the TYPENAME opcode resolves the type index looked up in the 'ctx->typenames' array, but it does so in 'ctx->types' instead of in 'opcodes'! */ int type_index = builder->ctx.typenames[_CFFI_GETARG(op)].type_index; x = realize_c_type_or_func(builder, builder->ctx.types, type_index); break; } default: PyErr_Format(PyExc_NotImplementedError, "op=%d", (int)_CFFI_GETOP(op)); return NULL; } return x; } static int _realize_recursion_level; static PyObject * realize_c_type_or_func(builder_c_t *builder, _cffi_opcode_t opcodes[], int index) { PyObject *x; _cffi_opcode_t op = opcodes[index]; if ((((uintptr_t)op) & 1) == 0) { x = (PyObject *)op; Py_INCREF(x); return x; } if (_realize_recursion_level >= 1000) { PyErr_Format(PyExc_RuntimeError, "type-building recursion too deep or infinite. " "This is known to occur e.g. in ``struct s { void(*callable)" "(struct s); }''. Please report if you get this error and " "really need support for your case."); return NULL; } _realize_recursion_level++; x = realize_c_type_or_func_now(builder, op, opcodes, index); _realize_recursion_level--; if (x != NULL && opcodes == builder->ctx.types && opcodes[index] != x) { assert((((uintptr_t)x) & 1) == 0); assert((((uintptr_t)opcodes[index]) & 1) == 1); Py_INCREF(x); opcodes[index] = x; } return x; } static CTypeDescrObject * realize_c_func_return_type(builder_c_t *builder, _cffi_opcode_t opcodes[], int index) { PyObject *x; _cffi_opcode_t op = opcodes[index]; if ((((uintptr_t)op) & 1) == 0) { /* already built: assert that it is a function and fish for the return type */ x = (PyObject *)op; assert(PyTuple_Check(x)); /* from _CFFI_OP_FUNCTION */ x = PyTuple_GET_ITEM(x, 0); assert(CTypeDescr_Check(x)); assert(((CTypeDescrObject *)x)->ct_flags & CT_FUNCTIONPTR); x = PyTuple_GET_ITEM(((CTypeDescrObject *)x)->ct_stuff, 1); assert(CTypeDescr_Check(x)); Py_INCREF(x); return (CTypeDescrObject *)x; } else { assert(_CFFI_GETOP(op) == _CFFI_OP_FUNCTION); return realize_c_type(builder, opcodes, _CFFI_GETARG(opcodes[index])); } } static int do_realize_lazy_struct(CTypeDescrObject *ct) { /* This is called by force_lazy_struct() in _cffi_backend.c */ assert(ct->ct_flags & (CT_STRUCT | CT_UNION)); if (ct->ct_flags & CT_LAZY_FIELD_LIST) { builder_c_t *builder; char *p; int n, i, sflags; const struct _cffi_struct_union_s *s; const struct _cffi_field_s *fld; PyObject *fields, *args, *res; assert(!(ct->ct_flags & CT_IS_OPAQUE)); builder = ct->ct_extra; assert(builder != NULL); p = alloca(2 + strlen(ct->ct_name)); _unrealize_name(p, ct->ct_name); n = search_in_struct_unions(&builder->ctx, p, strlen(p)); if (n < 0) Py_FatalError("lost a struct/union!"); s = &builder->ctx.struct_unions[n]; fld = &builder->ctx.fields[s->first_field_index]; /* XXX painfully build all the Python objects that are the args to b_complete_struct_or_union() */ fields = PyList_New(s->num_fields); if (fields == NULL) return -1; for (i = 0; i < s->num_fields; i++, fld++) { _cffi_opcode_t op = fld->field_type_op; int fbitsize = -1; PyObject *f; CTypeDescrObject *ctf; switch (_CFFI_GETOP(op)) { case _CFFI_OP_BITFIELD: assert(fld->field_size >= 0); fbitsize = (int)fld->field_size; /* fall-through */ case _CFFI_OP_NOOP: ctf = realize_c_type(builder, builder->ctx.types, _CFFI_GETARG(op)); break; default: Py_DECREF(fields); PyErr_Format(PyExc_NotImplementedError, "field op=%d", (int)_CFFI_GETOP(op)); return -1; } if (ctf != NULL && fld->field_offset == (size_t)-1) { /* unnamed struct, with field positions and sizes entirely determined by complete_struct_or_union() and not checked. Or, bitfields (field_size >= 0), similarly not checked. */ assert(fld->field_size == (size_t)-1 || fbitsize >= 0); } else if (ctf == NULL || detect_custom_layout(ct, SF_STD_FIELD_POS, ctf->ct_size, fld->field_size, "wrong size for field '", fld->name, "'") < 0) { Py_DECREF(fields); return -1; } f = Py_BuildValue("(sOin)", fld->name, ctf, fbitsize, (Py_ssize_t)fld->field_offset); if (f == NULL) { Py_DECREF(fields); return -1; } PyList_SET_ITEM(fields, i, f); } sflags = 0; if (s->flags & _CFFI_F_CHECK_FIELDS) sflags |= SF_STD_FIELD_POS; if (s->flags & _CFFI_F_PACKED) sflags |= SF_PACKED; args = Py_BuildValue("(OOOnii)", ct, fields, Py_None, (Py_ssize_t)s->size, s->alignment, sflags); Py_DECREF(fields); if (args == NULL) return -1; ct->ct_extra = NULL; ct->ct_flags |= CT_IS_OPAQUE; res = b_complete_struct_or_union(NULL, args); ct->ct_flags &= ~CT_IS_OPAQUE; Py_DECREF(args); if (res == NULL) { ct->ct_extra = builder; return -1; } assert(ct->ct_stuff != NULL); ct->ct_flags &= ~CT_LAZY_FIELD_LIST; Py_DECREF(res); return 1; } else { assert(ct->ct_flags & CT_IS_OPAQUE); return 0; } }