diff options
author | olegts <olegts@yandex-team.ru> | 2022-02-10 16:48:22 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:48:22 +0300 |
commit | 30983fb2586f6904aaf6a5d6ef2b445cbaec1f44 (patch) | |
tree | 3e86334ffd140d7ccfa0aa79386a6cf51b5b1e46 /contrib/python/cffi/c/lib_obj.c | |
parent | 9525b12aeec0b37aae9be1712d3d1031a235118f (diff) | |
download | ydb-30983fb2586f6904aaf6a5d6ef2b445cbaec1f44.tar.gz |
Restoring authorship annotation for <olegts@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/python/cffi/c/lib_obj.c')
-rw-r--r-- | contrib/python/cffi/c/lib_obj.c | 1340 |
1 files changed, 670 insertions, 670 deletions
diff --git a/contrib/python/cffi/c/lib_obj.c b/contrib/python/cffi/c/lib_obj.c index 38bf3d5510..d253f5613a 100644 --- a/contrib/python/cffi/c/lib_obj.c +++ b/contrib/python/cffi/c/lib_obj.c @@ -1,166 +1,166 @@ - -/* A Lib object is what is in the "lib" attribute of a C extension - module originally created by recompile(). - - A Lib object is special in the sense that it has a custom - __getattr__ which returns C globals, functions and constants. The - original idea was to raise AttributeError for anything else, even - attrs like '__class__', but it breaks various things; now, standard - attrs are returned, but in the unlikely case where a user cdef()s - the same name, then the standard attr is hidden (and the various - things like introspection might break). - - A Lib object has got a reference to the _cffi_type_context_s - structure, which is used to create lazily the objects returned by - __getattr__. -*/ - -struct CPyExtFunc_s { - PyMethodDef md; - void *direct_fn; - int type_index; - char doc[1]; -}; - -struct LibObject_s { - PyObject_HEAD - builder_c_t *l_types_builder; /* same as the one on the ffi object */ - PyObject *l_dict; /* content, built lazily */ - PyObject *l_libname; /* some string that gives the name of the lib */ - FFIObject *l_ffi; /* reference back to the ffi object */ - void *l_libhandle; /* the dlopen()ed handle, if any */ + +/* A Lib object is what is in the "lib" attribute of a C extension + module originally created by recompile(). + + A Lib object is special in the sense that it has a custom + __getattr__ which returns C globals, functions and constants. The + original idea was to raise AttributeError for anything else, even + attrs like '__class__', but it breaks various things; now, standard + attrs are returned, but in the unlikely case where a user cdef()s + the same name, then the standard attr is hidden (and the various + things like introspection might break). + + A Lib object has got a reference to the _cffi_type_context_s + structure, which is used to create lazily the objects returned by + __getattr__. +*/ + +struct CPyExtFunc_s { + PyMethodDef md; + void *direct_fn; + int type_index; + char doc[1]; +}; + +struct LibObject_s { + PyObject_HEAD + builder_c_t *l_types_builder; /* same as the one on the ffi object */ + PyObject *l_dict; /* content, built lazily */ + PyObject *l_libname; /* some string that gives the name of the lib */ + FFIObject *l_ffi; /* reference back to the ffi object */ + void *l_libhandle; /* the dlopen()ed handle, if any */ int l_auto_close; /* if we must dlclose() this handle */ -}; - -static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x) -{ - PyObject *y; - LibObject *lo; - PyCFunctionObject *fo; - - if (!PyCFunction_Check(x)) - return NULL; - y = PyCFunction_GET_SELF(x); - if (!LibObject_Check(y)) - return NULL; - - fo = (PyCFunctionObject *)x; - lo = (LibObject *)y; - if (lo->l_libname != fo->m_module) - return NULL; - - return (struct CPyExtFunc_s *)(fo->m_ml); -} - -static PyObject *_cpyextfunc_type(LibObject *lib, struct CPyExtFunc_s *exf) -{ - PyObject *tuple, *result; - tuple = realize_c_type_or_func(lib->l_types_builder, - lib->l_types_builder->ctx.types, - exf->type_index); - if (tuple == NULL) - return NULL; - - /* 'tuple' is a tuple of length 1 containing the real CT_FUNCTIONPTR - object */ - result = PyTuple_GetItem(tuple, 0); - Py_XINCREF(result); - Py_DECREF(tuple); - return result; -} - -static PyObject *_cpyextfunc_type_index(PyObject *x) -{ - struct CPyExtFunc_s *exf; - LibObject *lib; - - assert(PyErr_Occurred()); - exf = _cpyextfunc_get(x); - if (exf == NULL) - return NULL; /* still the same exception is set */ - - PyErr_Clear(); - - lib = (LibObject *)PyCFunction_GET_SELF(x); - return _cpyextfunc_type(lib, exf); -} - -static void cdlopen_close_ignore_errors(void *libhandle); /* forward */ +}; + +static struct CPyExtFunc_s *_cpyextfunc_get(PyObject *x) +{ + PyObject *y; + LibObject *lo; + PyCFunctionObject *fo; + + if (!PyCFunction_Check(x)) + return NULL; + y = PyCFunction_GET_SELF(x); + if (!LibObject_Check(y)) + return NULL; + + fo = (PyCFunctionObject *)x; + lo = (LibObject *)y; + if (lo->l_libname != fo->m_module) + return NULL; + + return (struct CPyExtFunc_s *)(fo->m_ml); +} + +static PyObject *_cpyextfunc_type(LibObject *lib, struct CPyExtFunc_s *exf) +{ + PyObject *tuple, *result; + tuple = realize_c_type_or_func(lib->l_types_builder, + lib->l_types_builder->ctx.types, + exf->type_index); + if (tuple == NULL) + return NULL; + + /* 'tuple' is a tuple of length 1 containing the real CT_FUNCTIONPTR + object */ + result = PyTuple_GetItem(tuple, 0); + Py_XINCREF(result); + Py_DECREF(tuple); + return result; +} + +static PyObject *_cpyextfunc_type_index(PyObject *x) +{ + struct CPyExtFunc_s *exf; + LibObject *lib; + + assert(PyErr_Occurred()); + exf = _cpyextfunc_get(x); + if (exf == NULL) + return NULL; /* still the same exception is set */ + + PyErr_Clear(); + + lib = (LibObject *)PyCFunction_GET_SELF(x); + return _cpyextfunc_type(lib, exf); +} + +static void cdlopen_close_ignore_errors(void *libhandle); /* forward */ static void *cdlopen_fetch(PyObject *libname, void *libhandle, const char *symbol); - -static void lib_dealloc(LibObject *lib) -{ + +static void lib_dealloc(LibObject *lib) +{ PyObject_GC_UnTrack(lib); if (lib->l_auto_close) cdlopen_close_ignore_errors(lib->l_libhandle); - Py_DECREF(lib->l_dict); - Py_DECREF(lib->l_libname); - Py_DECREF(lib->l_ffi); - PyObject_GC_Del(lib); -} - -static int lib_traverse(LibObject *lib, visitproc visit, void *arg) -{ - Py_VISIT(lib->l_dict); - Py_VISIT(lib->l_libname); - Py_VISIT(lib->l_ffi); - return 0; -} - -static PyObject *lib_repr(LibObject *lib) -{ - return PyText_FromFormat("<Lib object for '%.200s'>", - PyText_AS_UTF8(lib->l_libname)); -} - -static PyObject *lib_build_cpython_func(LibObject *lib, - const struct _cffi_global_s *g, - const char *s, int flags) -{ - /* First make sure the argument types and return type are really - built. The C extension code can then assume that they are, - by calling _cffi_type(). - */ - PyObject *result = NULL; - CTypeDescrObject **pfargs = NULL; - CTypeDescrObject *fresult; - Py_ssize_t nargs = 0; - struct CPyExtFunc_s *xfunc; - int i, type_index = _CFFI_GETARG(g->type_op); - _cffi_opcode_t *opcodes = lib->l_types_builder->ctx.types; - static const char *const format = ";\n\nCFFI C function from %s.lib"; + Py_DECREF(lib->l_dict); + Py_DECREF(lib->l_libname); + Py_DECREF(lib->l_ffi); + PyObject_GC_Del(lib); +} + +static int lib_traverse(LibObject *lib, visitproc visit, void *arg) +{ + Py_VISIT(lib->l_dict); + Py_VISIT(lib->l_libname); + Py_VISIT(lib->l_ffi); + return 0; +} + +static PyObject *lib_repr(LibObject *lib) +{ + return PyText_FromFormat("<Lib object for '%.200s'>", + PyText_AS_UTF8(lib->l_libname)); +} + +static PyObject *lib_build_cpython_func(LibObject *lib, + const struct _cffi_global_s *g, + const char *s, int flags) +{ + /* First make sure the argument types and return type are really + built. The C extension code can then assume that they are, + by calling _cffi_type(). + */ + PyObject *result = NULL; + CTypeDescrObject **pfargs = NULL; + CTypeDescrObject *fresult; + Py_ssize_t nargs = 0; + struct CPyExtFunc_s *xfunc; + int i, type_index = _CFFI_GETARG(g->type_op); + _cffi_opcode_t *opcodes = lib->l_types_builder->ctx.types; + static const char *const format = ";\n\nCFFI C function from %s.lib"; const char *libname = PyText_AS_UTF8(lib->l_libname); - struct funcbuilder_s funcbuilder; - - /* return type: */ - fresult = realize_c_func_return_type(lib->l_types_builder, opcodes, - type_index); - if (fresult == NULL) - goto error; - - /* argument types: */ - /* 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. */ - i = type_index + 1; - while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) - i++; - pfargs = alloca(sizeof(CTypeDescrObject *) * (i - type_index - 1)); - i = type_index + 1; - while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) { - CTypeDescrObject *ct = realize_c_type(lib->l_types_builder, opcodes, i); - if (ct == NULL) - goto error; - pfargs[nargs++] = ct; - i++; - } - - memset(&funcbuilder, 0, sizeof(funcbuilder)); - if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) - goto error; - + struct funcbuilder_s funcbuilder; + + /* return type: */ + fresult = realize_c_func_return_type(lib->l_types_builder, opcodes, + type_index); + if (fresult == NULL) + goto error; + + /* argument types: */ + /* 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. */ + i = type_index + 1; + while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) + i++; + pfargs = alloca(sizeof(CTypeDescrObject *) * (i - type_index - 1)); + i = type_index + 1; + while (_CFFI_GETOP(opcodes[i]) != _CFFI_OP_FUNCTION_END) { + CTypeDescrObject *ct = realize_c_type(lib->l_types_builder, opcodes, i); + if (ct == NULL) + goto error; + pfargs[nargs++] = ct; + i++; + } + + memset(&funcbuilder, 0, sizeof(funcbuilder)); + if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) + goto error; + /* The few bytes of memory we allocate here appear to leak, but this is not a real leak. Indeed, CPython never unloads its C extension modules. There is only one PyMem_Malloc() per real @@ -169,157 +169,157 @@ static PyObject *lib_build_cpython_func(LibObject *lib, global variable generated for each CPYTHON_BLTN defined in the C extension, and the effect would be the same (but a bit more complicated). - */ - xfunc = PyMem_Malloc(sizeof(struct CPyExtFunc_s) + - funcbuilder.nb_bytes + - strlen(format) + strlen(libname)); - if (xfunc == NULL) { - PyErr_NoMemory(); - goto error; - } - memset((char *)xfunc, 0, sizeof(struct CPyExtFunc_s)); - assert(g->address); - xfunc->md.ml_meth = (PyCFunction)g->address; - xfunc->md.ml_flags = flags; - xfunc->md.ml_name = g->name; - xfunc->md.ml_doc = xfunc->doc; - xfunc->direct_fn = g->size_or_direct_fn; - xfunc->type_index = type_index; - - /* build the docstring */ - funcbuilder.bufferp = xfunc->doc; - if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) - goto error; - sprintf(funcbuilder.bufferp - 1, format, libname); - /* done building the docstring */ - - result = PyCFunction_NewEx(&xfunc->md, (PyObject *)lib, lib->l_libname); - /* fall-through */ - error: - Py_XDECREF(fresult); - while (nargs > 0) { - --nargs; - Py_DECREF(pfargs[nargs]); - } - return result; -} - -static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name, - int recursion) -{ - /* does not return a new reference! */ - PyObject *x; - int index; - const struct _cffi_global_s *g; - CTypeDescrObject *ct; - builder_c_t *types_builder = lib->l_types_builder; + */ + xfunc = PyMem_Malloc(sizeof(struct CPyExtFunc_s) + + funcbuilder.nb_bytes + + strlen(format) + strlen(libname)); + if (xfunc == NULL) { + PyErr_NoMemory(); + goto error; + } + memset((char *)xfunc, 0, sizeof(struct CPyExtFunc_s)); + assert(g->address); + xfunc->md.ml_meth = (PyCFunction)g->address; + xfunc->md.ml_flags = flags; + xfunc->md.ml_name = g->name; + xfunc->md.ml_doc = xfunc->doc; + xfunc->direct_fn = g->size_or_direct_fn; + xfunc->type_index = type_index; + + /* build the docstring */ + funcbuilder.bufferp = xfunc->doc; + if (fb_build_name(&funcbuilder, g->name, pfargs, nargs, fresult, 0) < 0) + goto error; + sprintf(funcbuilder.bufferp - 1, format, libname); + /* done building the docstring */ + + result = PyCFunction_NewEx(&xfunc->md, (PyObject *)lib, lib->l_libname); + /* fall-through */ + error: + Py_XDECREF(fresult); + while (nargs > 0) { + --nargs; + Py_DECREF(pfargs[nargs]); + } + return result; +} + +static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name, + int recursion) +{ + /* does not return a new reference! */ + PyObject *x; + int index; + const struct _cffi_global_s *g; + CTypeDescrObject *ct; + builder_c_t *types_builder = lib->l_types_builder; const char *s = PyText_AsUTF8(name); - if (s == NULL) - return NULL; - - index = search_in_globals(&types_builder->ctx, s, strlen(s)); - if (index < 0) { - - if (types_builder->included_libs != NULL) { - Py_ssize_t i; - PyObject *included_ffis = types_builder->included_ffis; - PyObject *included_libs = types_builder->included_libs; - - if (recursion > 100) { - PyErr_SetString(PyExc_RuntimeError, - "recursion overflow in ffi.include() delegations"); - return NULL; - } - - for (i = 0; i < PyTuple_GET_SIZE(included_libs); i++) { - LibObject *lib1; - - lib1 = (LibObject *)PyTuple_GET_ITEM(included_libs, i); - if (lib1 != NULL) { - x = PyDict_GetItem(lib1->l_dict, name); - if (x != NULL) { - Py_INCREF(x); - goto found; - } - x = lib_build_and_cache_attr(lib1, name, recursion + 1); - if (x != NULL) { - Py_INCREF(x); - goto found; - } - } - else { - FFIObject *ffi1; - - ffi1 = (FFIObject *)PyTuple_GetItem(included_ffis, i); - if (ffi1 == NULL) - return NULL; - x = ffi_fetch_int_constant(ffi1, s, recursion + 1); - if (x != NULL) - goto found; - } - if (PyErr_Occurred()) - return NULL; - } - } - - if (recursion > 0) - return NULL; /* no error set, continue looking elsewhere */ - - PyErr_Format(PyExc_AttributeError, - "cffi library '%.200s' has no function, constant " - "or global variable named '%.200s'", - PyText_AS_UTF8(lib->l_libname), s); - return NULL; - } - - g = &types_builder->ctx.globals[index]; - - switch (_CFFI_GETOP(g->type_op)) { - - case _CFFI_OP_CPYTHON_BLTN_V: - x = lib_build_cpython_func(lib, g, s, METH_VARARGS); - break; - - case _CFFI_OP_CPYTHON_BLTN_N: - x = lib_build_cpython_func(lib, g, s, METH_NOARGS); - break; - - case _CFFI_OP_CPYTHON_BLTN_O: - x = lib_build_cpython_func(lib, g, s, METH_O); - break; - - case _CFFI_OP_CONSTANT_INT: - case _CFFI_OP_ENUM: - { - /* a constant integer whose value, in an "unsigned long long", - is obtained by calling the function at g->address */ - x = realize_global_int(types_builder, index); - break; - } - - case _CFFI_OP_CONSTANT: - case _CFFI_OP_DLOPEN_CONST: - { - /* a constant which is not of integer type */ - char *data; - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - - if (ct->ct_size <= 0) { - PyErr_Format(FFIError, "constant '%s' is of type '%s', " - "whose size is not known", s, ct->ct_name); - return NULL; - } - if (g->address == NULL) { - /* for dlopen() style */ - assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_DLOPEN_CONST); - data = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (data == NULL) - return NULL; - } - else { + if (s == NULL) + return NULL; + + index = search_in_globals(&types_builder->ctx, s, strlen(s)); + if (index < 0) { + + if (types_builder->included_libs != NULL) { + Py_ssize_t i; + PyObject *included_ffis = types_builder->included_ffis; + PyObject *included_libs = types_builder->included_libs; + + if (recursion > 100) { + PyErr_SetString(PyExc_RuntimeError, + "recursion overflow in ffi.include() delegations"); + return NULL; + } + + for (i = 0; i < PyTuple_GET_SIZE(included_libs); i++) { + LibObject *lib1; + + lib1 = (LibObject *)PyTuple_GET_ITEM(included_libs, i); + if (lib1 != NULL) { + x = PyDict_GetItem(lib1->l_dict, name); + if (x != NULL) { + Py_INCREF(x); + goto found; + } + x = lib_build_and_cache_attr(lib1, name, recursion + 1); + if (x != NULL) { + Py_INCREF(x); + goto found; + } + } + else { + FFIObject *ffi1; + + ffi1 = (FFIObject *)PyTuple_GetItem(included_ffis, i); + if (ffi1 == NULL) + return NULL; + x = ffi_fetch_int_constant(ffi1, s, recursion + 1); + if (x != NULL) + goto found; + } + if (PyErr_Occurred()) + return NULL; + } + } + + if (recursion > 0) + return NULL; /* no error set, continue looking elsewhere */ + + PyErr_Format(PyExc_AttributeError, + "cffi library '%.200s' has no function, constant " + "or global variable named '%.200s'", + PyText_AS_UTF8(lib->l_libname), s); + return NULL; + } + + g = &types_builder->ctx.globals[index]; + + switch (_CFFI_GETOP(g->type_op)) { + + case _CFFI_OP_CPYTHON_BLTN_V: + x = lib_build_cpython_func(lib, g, s, METH_VARARGS); + break; + + case _CFFI_OP_CPYTHON_BLTN_N: + x = lib_build_cpython_func(lib, g, s, METH_NOARGS); + break; + + case _CFFI_OP_CPYTHON_BLTN_O: + x = lib_build_cpython_func(lib, g, s, METH_O); + break; + + case _CFFI_OP_CONSTANT_INT: + case _CFFI_OP_ENUM: + { + /* a constant integer whose value, in an "unsigned long long", + is obtained by calling the function at g->address */ + x = realize_global_int(types_builder, index); + break; + } + + case _CFFI_OP_CONSTANT: + case _CFFI_OP_DLOPEN_CONST: + { + /* a constant which is not of integer type */ + char *data; + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + + if (ct->ct_size <= 0) { + PyErr_Format(FFIError, "constant '%s' is of type '%s', " + "whose size is not known", s, ct->ct_name); + return NULL; + } + if (g->address == NULL) { + /* for dlopen() style */ + assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_DLOPEN_CONST); + data = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); + if (data == NULL) + return NULL; + } + else { /* The few bytes of memory we allocate here appear to leak, but this is not a real leak. Indeed, CPython never unloads its C extension modules. There is only one PyMem_Malloc() per real @@ -334,218 +334,218 @@ static PyObject *lib_build_and_cache_attr(LibObject *lib, PyObject *name, cases; but there is no point and it only makes the remaining less-common cases more suspicious. */ - assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT); - data = PyMem_Malloc(ct->ct_size); - if (data == NULL) { - PyErr_NoMemory(); - return NULL; - } - ((void(*)(char*))g->address)(data); - } - x = convert_to_object(data, ct); - Py_DECREF(ct); - break; - } - - case _CFFI_OP_GLOBAL_VAR: - { - /* global variable of the exact type specified here - (nowadays, only used by the ABI mode or backward - compatibility; see _CFFI_OP_GLOBAL_VAR_F for the API mode) - */ - Py_ssize_t g_size = (Py_ssize_t)g->size_or_direct_fn; - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - if (g_size != ct->ct_size && g_size != 0 && ct->ct_size > 0) { - PyErr_Format(FFIError, - "global variable '%.200s' should be %zd bytes " - "according to the cdef, but is actually %zd", - s, ct->ct_size, g_size); - x = NULL; - } - else { - void *address = g->address; - if (address == NULL) { - /* for dlopen() style */ - address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (address == NULL) - return NULL; - } - x = make_global_var(name, ct, address, NULL); - } - Py_DECREF(ct); - break; - } - - case _CFFI_OP_GLOBAL_VAR_F: - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - x = make_global_var(name, ct, NULL, (gs_fetch_addr_fn)g->address); - Py_DECREF(ct); - break; - - case _CFFI_OP_DLOPEN_FUNC: - { - /* For dlopen(): the function of the given 'name'. We use - dlsym() to get the address of something in the dynamic - library, which we interpret as being exactly a function of - the specified type. - */ - PyObject *ct1; - void *address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); - if (address == NULL) - return NULL; - - ct1 = realize_c_type_or_func(types_builder, - types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct1 == NULL) - return NULL; - - assert(!CTypeDescr_Check(ct1)); /* must be a function */ - x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1)); - - Py_DECREF(ct1); - break; - } - - case _CFFI_OP_EXTERN_PYTHON: - /* for reading 'lib.bar' where bar is declared with extern "Python" */ - ct = realize_c_type(types_builder, types_builder->ctx.types, - _CFFI_GETARG(g->type_op)); - if (ct == NULL) - return NULL; - x = convert_to_object((char *)&g->size_or_direct_fn, ct); - Py_DECREF(ct); - break; - - default: - PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d", - (int)_CFFI_GETOP(g->type_op)); - return NULL; - } - - found: - if (x != NULL) { - int err = PyDict_SetItem(lib->l_dict, name, x); - Py_DECREF(x); - if (err < 0) /* else there is still one ref left in the dict */ - return NULL; - } - return x; -} - -#define LIB_GET_OR_CACHE_ADDR(x, lib, name, error) \ - do { \ - x = PyDict_GetItem(lib->l_dict, name); \ - if (x == NULL) { \ - x = lib_build_and_cache_attr(lib, name, 0); \ - if (x == NULL) { \ - error; \ - } \ - } \ - } while (0) - -static PyObject *_lib_dir1(LibObject *lib, int ignore_global_vars) -{ - const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; - int i, count = 0, total = lib->l_types_builder->ctx.num_globals; - PyObject *s, *lst = PyList_New(total); - if (lst == NULL) - return NULL; - - for (i = 0; i < total; i++) { - if (ignore_global_vars) { - int op = _CFFI_GETOP(g[i].type_op); - if (op == _CFFI_OP_GLOBAL_VAR || op == _CFFI_OP_GLOBAL_VAR_F) - continue; - } - s = PyText_FromString(g[i].name); - if (s == NULL) - goto error; - PyList_SET_ITEM(lst, count, s); - count++; - } - if (PyList_SetSlice(lst, count, total, NULL) < 0) - goto error; - return lst; - - error: - Py_DECREF(lst); - return NULL; -} - -static PyObject *_lib_dict(LibObject *lib) -{ - const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; - int i, total = lib->l_types_builder->ctx.num_globals; - PyObject *name, *x, *d = PyDict_New(); - if (d == NULL) - return NULL; - - for (i = 0; i < total; i++) { - name = PyText_FromString(g[i].name); - if (name == NULL) - goto error; - - LIB_GET_OR_CACHE_ADDR(x, lib, name, goto error); - - if (PyDict_SetItem(d, name, x) < 0) - goto error; - Py_DECREF(name); - } - return d; - - error: - Py_XDECREF(name); - Py_DECREF(d); - return NULL; -} - -static PyObject *lib_getattr(LibObject *lib, PyObject *name) -{ + assert(_CFFI_GETOP(g->type_op) == _CFFI_OP_CONSTANT); + data = PyMem_Malloc(ct->ct_size); + if (data == NULL) { + PyErr_NoMemory(); + return NULL; + } + ((void(*)(char*))g->address)(data); + } + x = convert_to_object(data, ct); + Py_DECREF(ct); + break; + } + + case _CFFI_OP_GLOBAL_VAR: + { + /* global variable of the exact type specified here + (nowadays, only used by the ABI mode or backward + compatibility; see _CFFI_OP_GLOBAL_VAR_F for the API mode) + */ + Py_ssize_t g_size = (Py_ssize_t)g->size_or_direct_fn; + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + if (g_size != ct->ct_size && g_size != 0 && ct->ct_size > 0) { + PyErr_Format(FFIError, + "global variable '%.200s' should be %zd bytes " + "according to the cdef, but is actually %zd", + s, ct->ct_size, g_size); + x = NULL; + } + else { + void *address = g->address; + if (address == NULL) { + /* for dlopen() style */ + address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); + if (address == NULL) + return NULL; + } + x = make_global_var(name, ct, address, NULL); + } + Py_DECREF(ct); + break; + } + + case _CFFI_OP_GLOBAL_VAR_F: + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + x = make_global_var(name, ct, NULL, (gs_fetch_addr_fn)g->address); + Py_DECREF(ct); + break; + + case _CFFI_OP_DLOPEN_FUNC: + { + /* For dlopen(): the function of the given 'name'. We use + dlsym() to get the address of something in the dynamic + library, which we interpret as being exactly a function of + the specified type. + */ + PyObject *ct1; + void *address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s); + if (address == NULL) + return NULL; + + ct1 = realize_c_type_or_func(types_builder, + types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct1 == NULL) + return NULL; + + assert(!CTypeDescr_Check(ct1)); /* must be a function */ + x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1)); + + Py_DECREF(ct1); + break; + } + + case _CFFI_OP_EXTERN_PYTHON: + /* for reading 'lib.bar' where bar is declared with extern "Python" */ + ct = realize_c_type(types_builder, types_builder->ctx.types, + _CFFI_GETARG(g->type_op)); + if (ct == NULL) + return NULL; + x = convert_to_object((char *)&g->size_or_direct_fn, ct); + Py_DECREF(ct); + break; + + default: + PyErr_Format(PyExc_NotImplementedError, "in lib_build_attr: op=%d", + (int)_CFFI_GETOP(g->type_op)); + return NULL; + } + + found: + if (x != NULL) { + int err = PyDict_SetItem(lib->l_dict, name, x); + Py_DECREF(x); + if (err < 0) /* else there is still one ref left in the dict */ + return NULL; + } + return x; +} + +#define LIB_GET_OR_CACHE_ADDR(x, lib, name, error) \ + do { \ + x = PyDict_GetItem(lib->l_dict, name); \ + if (x == NULL) { \ + x = lib_build_and_cache_attr(lib, name, 0); \ + if (x == NULL) { \ + error; \ + } \ + } \ + } while (0) + +static PyObject *_lib_dir1(LibObject *lib, int ignore_global_vars) +{ + const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; + int i, count = 0, total = lib->l_types_builder->ctx.num_globals; + PyObject *s, *lst = PyList_New(total); + if (lst == NULL) + return NULL; + + for (i = 0; i < total; i++) { + if (ignore_global_vars) { + int op = _CFFI_GETOP(g[i].type_op); + if (op == _CFFI_OP_GLOBAL_VAR || op == _CFFI_OP_GLOBAL_VAR_F) + continue; + } + s = PyText_FromString(g[i].name); + if (s == NULL) + goto error; + PyList_SET_ITEM(lst, count, s); + count++; + } + if (PyList_SetSlice(lst, count, total, NULL) < 0) + goto error; + return lst; + + error: + Py_DECREF(lst); + return NULL; +} + +static PyObject *_lib_dict(LibObject *lib) +{ + const struct _cffi_global_s *g = lib->l_types_builder->ctx.globals; + int i, total = lib->l_types_builder->ctx.num_globals; + PyObject *name, *x, *d = PyDict_New(); + if (d == NULL) + return NULL; + + for (i = 0; i < total; i++) { + name = PyText_FromString(g[i].name); + if (name == NULL) + goto error; + + LIB_GET_OR_CACHE_ADDR(x, lib, name, goto error); + + if (PyDict_SetItem(d, name, x) < 0) + goto error; + Py_DECREF(name); + } + return d; + + error: + Py_XDECREF(name); + Py_DECREF(d); + return NULL; +} + +static PyObject *lib_getattr(LibObject *lib, PyObject *name) +{ const char *p; - PyObject *x; - LIB_GET_OR_CACHE_ADDR(x, lib, name, goto missing); - - if (GlobSupport_Check(x)) { - return read_global_var((GlobSupportObject *)x); - } - Py_INCREF(x); - return x; - - missing: + PyObject *x; + LIB_GET_OR_CACHE_ADDR(x, lib, name, goto missing); + + if (GlobSupport_Check(x)) { + return read_global_var((GlobSupportObject *)x); + } + Py_INCREF(x); + return x; + + missing: /*** ATTRIBUTEERROR IS SET HERE ***/ - p = PyText_AsUTF8(name); - if (p == NULL) - return NULL; - if (strcmp(p, "__all__") == 0) { - PyErr_Clear(); - return _lib_dir1(lib, 1); - } - if (strcmp(p, "__dict__") == 0) { - PyErr_Clear(); - return _lib_dict(lib); - } - if (strcmp(p, "__class__") == 0) { - PyErr_Clear(); - x = (PyObject *)&PyModule_Type; - /* ^^^ used to be Py_TYPE(lib). But HAAAAAACK! That makes - help() behave correctly. I couldn't find a more reasonable - way. Urgh. */ - Py_INCREF(x); - return x; - } - /* this hack is for Python 3.5, and also to give a more - module-like behavior */ - if (strcmp(p, "__name__") == 0) { - PyErr_Clear(); - return PyText_FromFormat("%s.lib", PyText_AS_UTF8(lib->l_libname)); - } + p = PyText_AsUTF8(name); + if (p == NULL) + return NULL; + if (strcmp(p, "__all__") == 0) { + PyErr_Clear(); + return _lib_dir1(lib, 1); + } + if (strcmp(p, "__dict__") == 0) { + PyErr_Clear(); + return _lib_dict(lib); + } + if (strcmp(p, "__class__") == 0) { + PyErr_Clear(); + x = (PyObject *)&PyModule_Type; + /* ^^^ used to be Py_TYPE(lib). But HAAAAAACK! That makes + help() behave correctly. I couldn't find a more reasonable + way. Urgh. */ + Py_INCREF(x); + return x; + } + /* this hack is for Python 3.5, and also to give a more + module-like behavior */ + if (strcmp(p, "__name__") == 0) { + PyErr_Clear(); + return PyText_FromFormat("%s.lib", PyText_AS_UTF8(lib->l_libname)); + } #if PY_MAJOR_VERSION >= 3 if (strcmp(p, "__loader__") == 0 || strcmp(p, "__spec__") == 0) { /* some more module-like behavior hacks */ @@ -554,163 +554,163 @@ static PyObject *lib_getattr(LibObject *lib, PyObject *name) return Py_None; } #endif - return NULL; -} - -static int lib_setattr(LibObject *lib, PyObject *name, PyObject *val) -{ - PyObject *x; - LIB_GET_OR_CACHE_ADDR(x, lib, name, return -1); - - if (val == NULL) { - PyErr_SetString(PyExc_AttributeError, "C attribute cannot be deleted"); - return -1; - } - - if (GlobSupport_Check(x)) { - return write_global_var((GlobSupportObject *)x, val); - } - - PyErr_Format(PyExc_AttributeError, - "cannot write to function or constant '%.200s'", - PyText_Check(name) ? PyText_AS_UTF8(name) : "?"); - return -1; -} - -static PyObject *lib_dir(PyObject *self, PyObject *noarg) -{ - return _lib_dir1((LibObject *)self, 0); -} - -static PyMethodDef lib_methods[] = { - {"__dir__", lib_dir, METH_NOARGS}, - {NULL, NULL} /* sentinel */ -}; - -static PyTypeObject Lib_Type = { - PyVarObject_HEAD_INIT(NULL, 0) + return NULL; +} + +static int lib_setattr(LibObject *lib, PyObject *name, PyObject *val) +{ + PyObject *x; + LIB_GET_OR_CACHE_ADDR(x, lib, name, return -1); + + if (val == NULL) { + PyErr_SetString(PyExc_AttributeError, "C attribute cannot be deleted"); + return -1; + } + + if (GlobSupport_Check(x)) { + return write_global_var((GlobSupportObject *)x, val); + } + + PyErr_Format(PyExc_AttributeError, + "cannot write to function or constant '%.200s'", + PyText_Check(name) ? PyText_AS_UTF8(name) : "?"); + return -1; +} + +static PyObject *lib_dir(PyObject *self, PyObject *noarg) +{ + return _lib_dir1((LibObject *)self, 0); +} + +static PyMethodDef lib_methods[] = { + {"__dir__", lib_dir, METH_NOARGS}, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject Lib_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.Lib", - sizeof(LibObject), - 0, - (destructor)lib_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)lib_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc)lib_getattr, /* tp_getattro */ - (setattrofunc)lib_setattr, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - 0, /* tp_doc */ - (traverseproc)lib_traverse, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - lib_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - offsetof(LibObject, l_dict), /* tp_dictoffset */ -}; - + sizeof(LibObject), + 0, + (destructor)lib_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)lib_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + (getattrofunc)lib_getattr, /* tp_getattro */ + (setattrofunc)lib_setattr, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)lib_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + lib_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + offsetof(LibObject, l_dict), /* tp_dictoffset */ +}; + static LibObject *lib_internal_new(FFIObject *ffi, const char *module_name, void *dlopen_libhandle, int auto_close) -{ - LibObject *lib; - PyObject *libname, *dict; - - libname = PyText_FromString(module_name); - if (libname == NULL) - goto err1; - - dict = PyDict_New(); - if (dict == NULL) - goto err2; - - lib = (LibObject *)PyType_GenericAlloc(&Lib_Type, 0); - if (lib == NULL) - goto err3; - - lib->l_types_builder = &ffi->types_builder; - lib->l_dict = dict; - lib->l_libname = libname; - Py_INCREF(ffi); - lib->l_ffi = ffi; - lib->l_libhandle = dlopen_libhandle; +{ + LibObject *lib; + PyObject *libname, *dict; + + libname = PyText_FromString(module_name); + if (libname == NULL) + goto err1; + + dict = PyDict_New(); + if (dict == NULL) + goto err2; + + lib = (LibObject *)PyType_GenericAlloc(&Lib_Type, 0); + if (lib == NULL) + goto err3; + + lib->l_types_builder = &ffi->types_builder; + lib->l_dict = dict; + lib->l_libname = libname; + Py_INCREF(ffi); + lib->l_ffi = ffi; + lib->l_libhandle = dlopen_libhandle; lib->l_auto_close = auto_close; - return lib; - - err3: - Py_DECREF(dict); - err2: - Py_DECREF(libname); - err1: + return lib; + + err3: + Py_DECREF(dict); + err2: + Py_DECREF(libname); + err1: if (auto_close) cdlopen_close_ignore_errors(dlopen_libhandle); - return NULL; -} - -static PyObject *address_of_global_var(PyObject *args) -{ - LibObject *lib; - PyObject *x, *o_varname; - char *varname; - - if (!PyArg_ParseTuple(args, "O!s", &Lib_Type, &lib, &varname)) - return NULL; - - /* rebuild a string from 'varname', to do typechecks and to force - a unicode back to a plain string (on python 2) */ - o_varname = PyText_FromString(varname); - if (o_varname == NULL) - return NULL; - - LIB_GET_OR_CACHE_ADDR(x, lib, o_varname, goto error); - Py_DECREF(o_varname); - if (GlobSupport_Check(x)) { - return cg_addressof_global_var((GlobSupportObject *)x); - } - else { - struct CPyExtFunc_s *exf = _cpyextfunc_get(x); - if (exf != NULL) { /* an OP_CPYTHON_BLTN: '&func' returns a cdata */ - PyObject *ct; - if (exf->direct_fn == NULL) { - Py_INCREF(x); /* backward compatibility */ - return x; - } - ct = _cpyextfunc_type(lib, exf); - if (ct == NULL) - return NULL; - x = new_simple_cdata(exf->direct_fn, (CTypeDescrObject *)ct); - Py_DECREF(ct); - return x; - } - if (CData_Check(x) && /* a constant functionptr cdata: 'f == &f' */ - (((CDataObject *)x)->c_type->ct_flags & CT_FUNCTIONPTR) != 0) { - Py_INCREF(x); - return x; - } - else { - PyErr_Format(PyExc_AttributeError, - "cannot take the address of the constant '%.200s'", - varname); - return NULL; - } - } - - error: - Py_DECREF(o_varname); - return NULL; -} + return NULL; +} + +static PyObject *address_of_global_var(PyObject *args) +{ + LibObject *lib; + PyObject *x, *o_varname; + char *varname; + + if (!PyArg_ParseTuple(args, "O!s", &Lib_Type, &lib, &varname)) + return NULL; + + /* rebuild a string from 'varname', to do typechecks and to force + a unicode back to a plain string (on python 2) */ + o_varname = PyText_FromString(varname); + if (o_varname == NULL) + return NULL; + + LIB_GET_OR_CACHE_ADDR(x, lib, o_varname, goto error); + Py_DECREF(o_varname); + if (GlobSupport_Check(x)) { + return cg_addressof_global_var((GlobSupportObject *)x); + } + else { + struct CPyExtFunc_s *exf = _cpyextfunc_get(x); + if (exf != NULL) { /* an OP_CPYTHON_BLTN: '&func' returns a cdata */ + PyObject *ct; + if (exf->direct_fn == NULL) { + Py_INCREF(x); /* backward compatibility */ + return x; + } + ct = _cpyextfunc_type(lib, exf); + if (ct == NULL) + return NULL; + x = new_simple_cdata(exf->direct_fn, (CTypeDescrObject *)ct); + Py_DECREF(ct); + return x; + } + if (CData_Check(x) && /* a constant functionptr cdata: 'f == &f' */ + (((CDataObject *)x)->c_type->ct_flags & CT_FUNCTIONPTR) != 0) { + Py_INCREF(x); + return x; + } + else { + PyErr_Format(PyExc_AttributeError, + "cannot take the address of the constant '%.200s'", + varname); + return NULL; + } + } + + error: + Py_DECREF(o_varname); + return NULL; +} |