Hello community, here is the log from the commit of package python3-cffi for openSUSE:Factory checked in at 2015-06-16 14:05:39 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python3-cffi (Old) and /work/SRC/openSUSE:Factory/.python3-cffi.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python3-cffi" Changes: -------- --- /work/SRC/openSUSE:Factory/python3-cffi/python3-cffi.changes 2015-06-02 10:04:07.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.python3-cffi.new/python3-cffi.changes 2015-06-16 14:05:59.000000000 +0200 @@ -1,0 +2,18 @@ +Mon Jun 15 02:13:07 UTC 2015 - a...@gmx.de + +- update to version 1.1.2: + * ffi.gc(): fixed a race condition in multithreaded programs + introduced in 1.1.1 + +- changes from version 1.1.1: + * Out-of-line mode: ffi.string(), ffi.buffer() and ffi.getwinerror() + didn't accept their arguments as keyword arguments, unlike their + in-line mode equivalent. (It worked in PyPy.) + * Out-of-line ABI mode: documented a restriction of ffi.dlopen() + when compared to the in-line mode. + * ffi.gc(): when called several times with equal pointers, it was + accidentally registering only the last destructor, or even none at + all depending on details. (It was correctly registering all of + them only in PyPy, and only with the out-of-line FFIs.) + +------------------------------------------------------------------- Old: ---- cffi-1.1.0.tar.gz New: ---- cffi-1.1.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python3-cffi.spec ++++++ --- /var/tmp/diff_new_pack.eQaebf/_old 2015-06-16 14:06:00.000000000 +0200 +++ /var/tmp/diff_new_pack.eQaebf/_new 2015-06-16 14:06:00.000000000 +0200 @@ -17,7 +17,7 @@ Name: python3-cffi -Version: 1.1.0 +Version: 1.1.2 Release: 0 Summary: Foreign Function Interface for Python calling C code License: MIT ++++++ cffi-1.1.0.tar.gz -> cffi-1.1.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/PKG-INFO new/cffi-1.1.2/PKG-INFO --- old/cffi-1.1.0/PKG-INFO 2015-05-30 21:48:01.000000000 +0200 +++ new/cffi-1.1.2/PKG-INFO 2015-06-09 12:04:16.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.1.0 +Version: 1.1.2 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/_cffi_backend.c new/cffi-1.1.2/c/_cffi_backend.c --- old/cffi-1.1.0/c/_cffi_backend.c 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/c/_cffi_backend.c 2015-06-09 12:04:10.000000000 +0200 @@ -5158,12 +5158,14 @@ return PyText_FromStringAndSize(s, namelen + replacelen); } -static PyObject *b_string(PyObject *self, PyObject *args) +static PyObject *b_string(PyObject *self, PyObject *args, PyObject *kwds) { CDataObject *cd; Py_ssize_t maxlen = -1; - if (!PyArg_ParseTuple(args, "O!|n:string", - &CData_Type, &cd, &maxlen)) + static char *keywords[] = {"cdata", "maxlen", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:string", keywords, + &CData_Type, &cd, &maxlen)) return NULL; if (cd->c_type->ct_itemdescr != NULL && @@ -5246,12 +5248,14 @@ return NULL; } -static PyObject *b_buffer(PyObject *self, PyObject *args) +static PyObject *b_buffer(PyObject *self, PyObject *args, PyObject *kwds) { CDataObject *cd; Py_ssize_t size = -1; - if (!PyArg_ParseTuple(args, "O!|n:buffer", - &CData_Type, &cd, &size)) + static char *keywords[] = {"cdata", "size", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|n:buffer", keywords, + &CData_Type, &cd, &size)) return NULL; if (cd->c_type->ct_flags & CT_POINTER) { @@ -5351,6 +5355,12 @@ return NULL; } x = (PyObject *)(raw + 42); + if (Py_REFCNT(x) <= 0) { + Py_FatalError("ffi.from_handle() detected that the address passed " + "points to garbage. If it is really the result of " + "ffi.new_handle(), then the Python object has already " + "been garbage collected"); + } Py_INCREF(x); return x; } @@ -5790,15 +5800,15 @@ {"typeoffsetof", b_typeoffsetof, METH_VARARGS}, {"rawaddressof", b_rawaddressof, METH_VARARGS}, {"getcname", b_getcname, METH_VARARGS}, - {"string", b_string, METH_VARARGS}, - {"buffer", b_buffer, METH_VARARGS}, + {"string", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS}, + {"buffer", (PyCFunction)b_buffer, METH_VARARGS | METH_KEYWORDS}, {"get_errno", b_get_errno, METH_NOARGS}, {"set_errno", b_set_errno, METH_O}, {"newp_handle", b_newp_handle, METH_VARARGS}, {"from_handle", b_from_handle, METH_O}, {"from_buffer", b_from_buffer, METH_VARARGS}, #ifdef MS_WIN32 - {"getwinerror", b_getwinerror, METH_VARARGS}, + {"getwinerror", (PyCFunction)b_getwinerror, METH_VARARGS | METH_KEYWORDS}, #endif {"_get_types", b__get_types, METH_NOARGS}, {"_testfunc", b__testfunc, METH_VARARGS}, @@ -6053,7 +6063,7 @@ if (v == NULL || PyModule_AddObject(m, "_C_API", v) < 0) INITERROR; - v = PyText_FromString("1.1.0"); + v = PyText_FromString("1.1.2"); if (v == NULL || PyModule_AddObject(m, "__version__", v) < 0) INITERROR; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/cgc.c new/cffi-1.1.2/c/cgc.c --- old/cffi-1.1.0/c/cgc.c 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/c/cgc.c 2015-06-09 12:04:07.000000000 +0200 @@ -2,79 +2,121 @@ /* translated to C from cffi/gc_weakref.py */ -static PyObject *const_name_pop; - -static PyObject *gc_wref_remove(PyObject *ffi_wref_data, PyObject *arg) +static PyObject *gc_wref_remove(PyObject *ffi_wref_tup, PyObject *key) { - PyObject *destructor, *cdata, *x; - PyObject *res = PyObject_CallMethodObjArgs(ffi_wref_data, - const_name_pop, arg, NULL); - if (res == NULL) - return NULL; - - assert(PyTuple_Check(res)); - destructor = PyTuple_GET_ITEM(res, 0); - cdata = PyTuple_GET_ITEM(res, 1); - x = PyObject_CallFunctionObjArgs(destructor, cdata, NULL); - Py_DECREF(res); - if (x == NULL) - return NULL; - Py_DECREF(x); - - Py_INCREF(Py_None); - return Py_None; + FFIObject *ffi; + PyObject *indexobj, *destructor, *cdata, *freelist, *result; + Py_ssize_t index; + + /* here, tup is a 4-tuple (ffi, destructor, cdata, index) */ + if (!PyTuple_Check(ffi_wref_tup)) + goto oops; /* should never occur */ + + ffi = (FFIObject *)PyTuple_GET_ITEM(ffi_wref_tup, 0); + destructor = PyTuple_GET_ITEM(ffi_wref_tup, 1); + cdata = PyTuple_GET_ITEM(ffi_wref_tup, 2); + indexobj = PyTuple_GET_ITEM(ffi_wref_tup, 3); + + index = PyInt_AsSsize_t(indexobj); + if (index < 0) + goto oops; /* should never occur */ + + /* assert gc_wrefs[index] is key */ + if (PyList_GET_ITEM(ffi->gc_wrefs, index) != key) + goto oops; /* should never occur */ + + /* gc_wrefs[index] = freelist */ + /* transfer ownership of 'freelist' to 'gc_wrefs[index]' */ + freelist = ffi->gc_wrefs_freelist; + PyList_SET_ITEM(ffi->gc_wrefs, index, freelist); + + /* freelist = index */ + ffi->gc_wrefs_freelist = indexobj; + Py_INCREF(indexobj); + + /* destructor(cdata) */ + result = PyObject_CallFunctionObjArgs(destructor, cdata, NULL); + + Py_DECREF(key); /* free the reference that was in 'gc_wrefs[index]' */ + return result; + + oops: + PyErr_SetString(PyExc_SystemError, "cgc: internal inconsistency"); + /* random leaks may follow */ + return NULL; } static PyMethodDef remove_callback = { "gc_wref_remove", (PyCFunction)gc_wref_remove, METH_O }; -static PyObject *gc_weakrefs_build(FFIObject *ffi, CDataObject *cd, +static PyObject *gc_weakrefs_build(FFIObject *ffi, CDataObject *cdata, PyObject *destructor) { - PyObject *new_cdata, *ref = NULL, *tup = NULL; + PyObject *new_cdata, *ref = NULL, *tup = NULL, *remove_fn = NULL; + Py_ssize_t index; + PyObject *datalist; if (ffi->gc_wrefs == NULL) { /* initialize */ - PyObject *data; - - if (const_name_pop == NULL) { - const_name_pop = PyText_InternFromString("pop"); - if (const_name_pop == NULL) - return NULL; - } - data = PyDict_New(); - if (data == NULL) - return NULL; - ffi->gc_wrefs = PyCFunction_New(&remove_callback, data); - Py_DECREF(data); - if (ffi->gc_wrefs == NULL) + datalist = PyList_New(0); + if (datalist == NULL) return NULL; + ffi->gc_wrefs = datalist; + assert(ffi->gc_wrefs_freelist == NULL); + ffi->gc_wrefs_freelist = Py_None; + Py_INCREF(Py_None); } - new_cdata = do_cast(cd->c_type, (PyObject *)cd); + /* new_cdata = self.ffi.cast(typeof(cdata), cdata) */ + new_cdata = do_cast(cdata->c_type, (PyObject *)cdata); if (new_cdata == NULL) goto error; - ref = PyWeakref_NewRef(new_cdata, ffi->gc_wrefs); - if (ref == NULL) + /* if freelist is None: */ + datalist = ffi->gc_wrefs; + if (ffi->gc_wrefs_freelist == Py_None) { + /* index = len(gc_wrefs) */ + index = PyList_GET_SIZE(datalist); + /* gc_wrefs.append(None) */ + if (PyList_Append(datalist, Py_None) < 0) + goto error; + tup = Py_BuildValue("OOOn", ffi, destructor, cdata, index); + } + else { + /* index = freelist */ + index = PyInt_AsSsize_t(ffi->gc_wrefs_freelist); + if (index < 0) + goto error; /* should not occur */ + tup = PyTuple_Pack(4, ffi, destructor, cdata, ffi->gc_wrefs_freelist); + } + if (tup == NULL) goto error; - tup = PyTuple_Pack(2, destructor, cd); - if (tup == NULL) + remove_fn = PyCFunction_New(&remove_callback, tup); + if (remove_fn == NULL) goto error; - /* the 'self' of the function 'gc_wrefs' is actually the data dict */ - if (PyDict_SetItem(PyCFunction_GET_SELF(ffi->gc_wrefs), ref, tup) < 0) + ref = PyWeakref_NewRef(new_cdata, remove_fn); + if (ref == NULL) goto error; + /* freelist = gc_wrefs[index] (which is None if we just did append(None)) */ + /* transfer ownership of 'datalist[index]' into gc_wrefs_freelist */ + Py_DECREF(ffi->gc_wrefs_freelist); + ffi->gc_wrefs_freelist = PyList_GET_ITEM(datalist, index); + /* gc_wrefs[index] = ref */ + /* transfer ownership of 'ref' into 'datalist[index]' */ + PyList_SET_ITEM(datalist, index, ref); + Py_DECREF(remove_fn); Py_DECREF(tup); - Py_DECREF(ref); + return new_cdata; error: Py_XDECREF(new_cdata); Py_XDECREF(ref); Py_XDECREF(tup); + Py_XDECREF(remove_fn); return NULL; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/ffi_obj.c new/cffi-1.1.2/c/ffi_obj.c --- old/cffi-1.1.0/c/ffi_obj.c 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/c/ffi_obj.c 2015-06-09 12:04:07.000000000 +0200 @@ -23,7 +23,7 @@ struct FFIObject_s { PyObject_HEAD - PyObject *gc_wrefs; + PyObject *gc_wrefs, *gc_wrefs_freelist; struct _cffi_parse_info_s info; char ctx_is_static, ctx_is_nonempty; builder_c_t types_builder; @@ -51,6 +51,7 @@ return NULL; } ffi->gc_wrefs = NULL; + ffi->gc_wrefs_freelist = NULL; ffi->info.ctx = &ffi->types_builder.ctx; ffi->info.output = internal_output; ffi->info.output_size = FFI_COMPLEXITY_OUTPUT; @@ -63,6 +64,7 @@ { PyObject_GC_UnTrack(ffi); Py_XDECREF(ffi->gc_wrefs); + Py_XDECREF(ffi->gc_wrefs_freelist); free_builder_c(&ffi->types_builder, ffi->ctx_is_static); @@ -140,6 +142,38 @@ #define ACCEPT_ALL (ACCEPT_STRING | ACCEPT_CTYPE | ACCEPT_CDATA) #define CONSIDER_FN_AS_FNPTR 8 +static CTypeDescrObject *_ffi_bad_type(FFIObject *ffi, char *input_text) +{ + size_t length = strlen(input_text); + char *extra; + + if (length > 500) { + extra = ""; + } + else { + char *p; + size_t i, num_spaces = ffi->info.error_location; + extra = alloca(length + num_spaces + 4); + p = extra; + *p++ = '\n'; + for (i = 0; i < length; i++) { + if (' ' <= input_text[i] && input_text[i] < 0x7f) + *p++ = input_text[i]; + else if (input_text[i] == '\t' || input_text[i] == '\n') + *p++ = ' '; + else + *p++ = '?'; + } + *p++ = '\n'; + memset(p, ' ', num_spaces); + p += num_spaces; + *p++ = '^'; + *p++ = 0; + } + PyErr_Format(FFIError, "%s%s", ffi->info.error_message, extra); + return NULL; +} + static CTypeDescrObject *_ffi_type(FFIObject *ffi, PyObject *arg, int accept) { @@ -153,15 +187,9 @@ if (x == NULL) { char *input_text = PyText_AS_UTF8(arg); int err, index = parse_c_type(&ffi->info, input_text); - if (index < 0) { - size_t num_spaces = ffi->info.error_location; - char *spaces = alloca(num_spaces + 1); - memset(spaces, ' ', num_spaces); - spaces[num_spaces] = '\0'; - PyErr_Format(FFIError, "%s\n%s\n%s^", ffi->info.error_message, - input_text, spaces); - return NULL; - } + if (index < 0) + return _ffi_bad_type(ffi, input_text); + x = realize_c_type_or_func(&ffi->types_builder, ffi->info.output, index); if (x == NULL) @@ -774,7 +802,7 @@ static PyMethodDef ffi_methods[] = { {"addressof", (PyCFunction)ffi_addressof, METH_VARARGS, ffi_addressof_doc}, {"alignof", (PyCFunction)ffi_alignof, METH_O, ffi_alignof_doc}, - {"buffer", (PyCFunction)ffi_buffer, METH_VARARGS, ffi_buffer_doc}, + {"buffer", (PyCFunction)ffi_buffer, METH_VKW, ffi_buffer_doc}, {"callback", (PyCFunction)ffi_callback, METH_VKW, ffi_callback_doc}, {"cast", (PyCFunction)ffi_cast, METH_VARARGS, ffi_cast_doc}, {"dlclose", (PyCFunction)ffi_dlclose, METH_VARARGS, ffi_dlclose_doc}, @@ -784,14 +812,14 @@ {"gc", (PyCFunction)ffi_gc, METH_VKW, ffi_gc_doc}, {"getctype", (PyCFunction)ffi_getctype, METH_VKW, ffi_getctype_doc}, #ifdef MS_WIN32 - {"getwinerror",(PyCFunction)ffi_getwinerror,METH_VARARGS, ffi_getwinerror_doc}, + {"getwinerror",(PyCFunction)ffi_getwinerror,METH_VKW, ffi_getwinerror_doc}, #endif {"integer_const",(PyCFunction)ffi_int_const,METH_VKW, ffi_int_const_doc}, {"new", (PyCFunction)ffi_new, METH_VKW, ffi_new_doc}, {"new_handle", (PyCFunction)ffi_new_handle, METH_O, ffi_new_handle_doc}, {"offsetof", (PyCFunction)ffi_offsetof, METH_VARARGS, ffi_offsetof_doc}, {"sizeof", (PyCFunction)ffi_sizeof, METH_O, ffi_sizeof_doc}, - {"string", (PyCFunction)ffi_string, METH_VARARGS, ffi_string_doc}, + {"string", (PyCFunction)ffi_string, METH_VKW, ffi_string_doc}, {"typeof", (PyCFunction)ffi_typeof, METH_O, ffi_typeof_doc}, {NULL} }; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/lib_obj.c new/cffi-1.1.2/c/lib_obj.c --- old/cffi-1.1.0/c/lib_obj.c 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/c/lib_obj.c 2015-06-09 12:04:07.000000000 +0200 @@ -300,7 +300,7 @@ case _CFFI_OP_GLOBAL_VAR: { /* global variable of the exact type specified here */ - size_t g_size = (size_t)g->size_or_direct_fn; + 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) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/misc_win32.h new/cffi-1.1.2/c/misc_win32.h --- old/cffi-1.1.0/c/misc_win32.h 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/c/misc_win32.h 2015-06-09 12:04:07.000000000 +0200 @@ -82,14 +82,15 @@ } #if PY_MAJOR_VERSION >= 3 -static PyObject *b_getwinerror(PyObject *self, PyObject *args) +static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) { int err = -1; int len; WCHAR *s_buf = NULL; /* Free via LocalFree */ PyObject *v, *message; + static char *keywords[] = {"code", NULL}; - if (!PyArg_ParseTuple(args, "|i", &err)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) return NULL; if (err == -1) { @@ -129,7 +130,7 @@ return v; } #else -static PyObject *b_getwinerror(PyObject *self, PyObject *args) +static PyObject *b_getwinerror(PyObject *self, PyObject *args, PyObject *kwds) { int err = -1; int len; @@ -137,8 +138,9 @@ char *s_buf = NULL; /* Free via LocalFree */ char s_small_buf[28]; /* Room for "Windows Error 0xFFFFFFFF" */ PyObject *v; + static char *keywords[] = {"code", NULL}; - if (!PyArg_ParseTuple(args, "|i", &err)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", keywords, &err)) return NULL; if (err == -1) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/realize_c_type.c new/cffi-1.1.2/c/realize_c_type.c --- old/cffi-1.1.0/c/realize_c_type.c 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/c/realize_c_type.c 2015-06-09 12:04:07.000000000 +0200 @@ -60,7 +60,7 @@ static void free_builder_c(builder_c_t *builder, int ctx_is_static) { if (!ctx_is_static) { - int i; + size_t i; const void *mem[] = {builder->ctx.types, builder->ctx.globals, builder->ctx.struct_unions, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/c/test_c.py new/cffi-1.1.2/c/test_c.py --- old/cffi-1.1.0/c/test_c.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/c/test_c.py 2015-06-09 12:04:10.000000000 +0200 @@ -3346,4 +3346,4 @@ def test_version(): # this test is here mostly for PyPy - assert __version__ == "1.1.0" + assert __version__ == "1.1.2" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/__init__.py new/cffi-1.1.2/cffi/__init__.py --- old/cffi-1.1.0/cffi/__init__.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/cffi/__init__.py 2015-06-09 12:04:10.000000000 +0200 @@ -4,8 +4,8 @@ from .api import FFI, CDefError, FFIError from .ffiplatform import VerificationError, VerificationMissing -__version__ = "1.1.0" -__version_info__ = (1, 1, 0) +__version__ = "1.1.2" +__version_info__ = (1, 1, 2) # The verifier module file names are based on the CRC32 of a string that # contains the following version number. It may be older than __version__ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/gc_weakref.py new/cffi-1.1.2/cffi/gc_weakref.py --- old/cffi-1.1.0/cffi/gc_weakref.py 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/cffi/gc_weakref.py 2015-06-09 12:04:07.000000000 +0200 @@ -2,18 +2,23 @@ class GcWeakrefs(object): - # code copied and adapted from WeakKeyDictionary. - def __init__(self, ffi): self.ffi = ffi - self.data = data = {} - def remove(k): - destructor, cdata = data.pop(k) - destructor(cdata) - self.remove = remove + self.data = {} + self.nextindex = 0 def build(self, cdata, destructor): # make a new cdata of the same type as the original one new_cdata = self.ffi.cast(self.ffi._backend.typeof(cdata), cdata) - self.data[ref(new_cdata, self.remove)] = destructor, cdata + # + def remove(key): + # careful, this function is not protected by any lock + old_key = self.data.pop(index) + assert old_key is key + destructor(cdata) + # + key = ref(new_cdata, remove) + index = self.nextindex + self.nextindex = index + 1 # we're protected by the lock here + self.data[index] = key return new_cdata diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/recompiler.py new/cffi-1.1.2/cffi/recompiler.py --- old/cffi-1.1.0/cffi/recompiler.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/cffi/recompiler.py 2015-06-09 12:04:10.000000000 +0200 @@ -775,7 +775,8 @@ try: if ftype.is_integer_type() or fbitsize >= 0: # accept all integers, but complain on float or double - prnt(' (void)((p->%s) << 1);' % fname) + prnt(" (void)((p->%s) << 1); /* check that '%s.%s' is " + "an integer */" % (fname, cname, fname)) continue # only accept exactly the type declared, except that '[]' # is interpreted as a '*' and so will match any array length. @@ -949,7 +950,7 @@ prnt('{') prnt(' int n = (%s) <= 0;' % (name,)) prnt(' *o = (unsigned long long)((%s) << 0);' - ' /* check that we get an integer */' % (name,)) + ' /* check that %s is an integer */' % (name, name)) if check_value is not None: if check_value > 0: check_value = '%dU' % (check_value,) @@ -1088,8 +1089,9 @@ self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) def _emit_bytecode_UnknownIntegerType(self, tp, index): - s = '_cffi_prim_int(sizeof(%s), (((%s)-1) << 0) <= 0)' % ( - tp.name, tp.name) + s = ('_cffi_prim_int(sizeof(%s), (\n' + ' ((%s)-1) << 0 /* check that %s is an integer type */\n' + ' ) <= 0)' % (tp.name, tp.name, tp.name)) self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) def _emit_bytecode_RawFunctionType(self, tp, index): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/setuptools_ext.py new/cffi-1.1.2/cffi/setuptools_ext.py --- old/cffi-1.1.0/cffi/setuptools_ext.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/cffi/setuptools_ext.py 2015-06-09 12:04:07.000000000 +0200 @@ -18,7 +18,9 @@ # __init__.py files may already try to import the file that # we are generating. with open(filename) as f: - code = compile(f.read(), filename, 'exec') + src = f.read() + src += '\n' # Python 2.6 compatibility + code = compile(src, filename, 'exec') exec(code, glob, glob) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi/vengine_gen.py new/cffi-1.1.2/cffi/vengine_gen.py --- old/cffi-1.1.0/cffi/vengine_gen.py 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/cffi/vengine_gen.py 2015-06-09 12:04:07.000000000 +0200 @@ -402,12 +402,16 @@ else: assert tp is not None assert check_value is None - prnt(tp.get_c_name(' %s(void)' % funcname, name),) - prnt('{') if category == 'var': ampersand = '&' else: ampersand = '' + extra = '' + if category == 'const' and isinstance(tp, model.StructOrUnion): + extra = 'const *' + ampersand = '&' + prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) + prnt('{') prnt(' return (%s%s);' % (ampersand, name)) prnt('}') prnt() @@ -436,9 +440,14 @@ value += (1 << (8*self.ffi.sizeof(BLongLong))) else: assert check_value is None - BFunc = self.ffi._typeof_locked(tp.get_c_name('(*)(void)', name))[0] + fntypeextra = '(*)(void)' + if isinstance(tp, model.StructOrUnion): + fntypeextra = '*' + fntypeextra + BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] function = module.load_function(BFunc, funcname) value = function() + if isinstance(tp, model.StructOrUnion): + value = value[0] return value def _loaded_gen_constant(self, tp, name, module, library): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/cffi.egg-info/PKG-INFO new/cffi-1.1.2/cffi.egg-info/PKG-INFO --- old/cffi-1.1.0/cffi.egg-info/PKG-INFO 2015-05-30 21:48:01.000000000 +0200 +++ new/cffi-1.1.2/cffi.egg-info/PKG-INFO 2015-06-09 12:04:15.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: cffi -Version: 1.1.0 +Version: 1.1.2 Summary: Foreign Function Interface for Python calling C code. Home-page: http://cffi.readthedocs.org Author: Armin Rigo, Maciej Fijalkowski diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/cdef.rst new/cffi-1.1.2/doc/source/cdef.rst --- old/cffi-1.1.0/doc/source/cdef.rst 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/doc/source/cdef.rst 2015-06-09 12:04:10.000000000 +0200 @@ -278,6 +278,18 @@ needed. (Alternatively, the out-of-line FFIs have a method ``ffi.dlclose(lib)``.) +.. _dlopen-note: + +Note: the old version of ``ffi.dlopen()`` from the in-line ABI mode +tries to use ``ctypes.util.find_library()`` if it cannot directly find +the library. The newer out-of-line ``ffi.dlopen()`` no longer does it +automatically; it simply passes the argument it receives to the +underlying ``dlopen()`` or ``LoadLibrary()`` function. If needed, it +is up to you to use ``ctypes.util.find_library()`` or any other way to +look for the library's filename. This also means that +``ffi.dlopen(None)`` no longer work on Windows; try instead +``ffi.dlopen(ctypes.util.find_library('c'))``. + ffi.set_source(): preparing out-of-line modules ----------------------------------------------- @@ -375,7 +387,7 @@ * *New in version 1.1:* integer types: the syntax "``typedef int... foo_t;``" declares the type ``foo_t`` as an integer type - whose exact size and signness is not specified. The compiler will + whose exact size and signedness is not specified. The compiler will figure it out. (Note that this requires ``set_source()``; it does not work with ``verify()``.) The ``int...`` can be replaced with ``long...`` or ``unsigned long long...`` or any other primitive diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/conf.py new/cffi-1.1.2/doc/source/conf.py --- old/cffi-1.1.0/doc/source/conf.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/doc/source/conf.py 2015-06-09 12:04:10.000000000 +0200 @@ -47,7 +47,7 @@ # The short X.Y version. version = '1.1' # The full version, including alpha/beta/rc tags. -release = '1.1.0' +release = '1.1.2' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/installation.rst new/cffi-1.1.2/doc/source/installation.rst --- old/cffi-1.1.0/doc/source/installation.rst 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/doc/source/installation.rst 2015-06-09 12:04:10.000000000 +0200 @@ -51,7 +51,7 @@ Download and Installation: -* http://pypi.python.org/packages/source/c/cffi/cffi-1.1.0.tar.gz +* http://pypi.python.org/packages/source/c/cffi/cffi-1.1.2.tar.gz - Or grab the most current version by following the instructions below. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/overview.rst new/cffi-1.1.2/doc/source/overview.rst --- old/cffi-1.1.0/doc/source/overview.rst 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/doc/source/overview.rst 2015-06-09 12:04:07.000000000 +0200 @@ -82,9 +82,21 @@ from _simple_example import ffi - lib = ffi.dlopen(None) # or path to a library + lib = ffi.dlopen(None) # Unix: open the standard C library + #import ctypes.util # or, try this on Windows: + #lib = ffi.dlopen(ctypes.util.find_library("c")) + lib.printf(b"hi there, number %d\n", ffi.cast("int", 2)) +Note that this ``ffi.dlopen()``, unlike the one from in-line mode, +does not invoke any additional magic to locate the library: it must be +a path name (with or without a directory), as required by the C +``dlopen()`` or ``LoadLibrary()`` functions. This means that +``ffi.dlopen("libfoo.so")`` is ok, but ``ffi.dlopen("foo")`` is not. +In the latter case, you could replace it with +``ffi.dlopen(ctypes.util.find_library("foo"))``. Also, None is only +recognized on Unix to open the standard C library. + For distribution purposes, remember that there is a new ``_simple_example.py`` file generated. You can either include it statically within your project's source files, or, with Setuptools, @@ -202,6 +214,13 @@ .. _struct: http://docs.python.org/library/struct.html .. _array: http://docs.python.org/library/array.html +This example also admits an out-of-line equivalent. It is similar to +`Out-of-line example (ABI level, out-of-line)`_ above, but without any +call to ``ffi.dlopen()``. In the main program, you write ``from +_simple_example import ffi`` and then the same content as the in-line +example above starting from the line ``image = ffi.new("pixel_t[]", +800*600)``. + .. _performance: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/doc/source/whatsnew.rst new/cffi-1.1.2/doc/source/whatsnew.rst --- old/cffi-1.1.0/doc/source/whatsnew.rst 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/doc/source/whatsnew.rst 2015-06-09 12:04:10.000000000 +0200 @@ -3,11 +3,36 @@ ====================== +1.1.2 +===== + +* ``ffi.gc()``: fixed a race condition in multithreaded programs + introduced in 1.1.1 + + +1.1.1 +===== + +* Out-of-line mode: ``ffi.string()``, ``ffi.buffer()`` and + ``ffi.getwinerror()`` didn't accept their arguments as keyword + arguments, unlike their in-line mode equivalent. (It worked in PyPy.) + +* Out-of-line ABI mode: documented a restriction__ of ``ffi.dlopen()`` + when compared to the in-line mode. + +* ``ffi.gc()``: when called several times with equal pointers, it was + accidentally registering only the last destructor, or even none at + all depending on details. (It was correctly registering all of them + only in PyPy, and only with the out-of-line FFIs.) + +.. __: cdef.html#dlopen-note + + 1.1.0 ===== * Out-of-line API mode: we can now declare integer types with - ``typedef int... foo_t;``. The exact size and signness of ``foo_t`` + ``typedef int... foo_t;``. The exact size and signedness of ``foo_t`` is figured out by the compiler. * Out-of-line API mode: we can now declare multidimensional arrays diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/setup.py new/cffi-1.1.2/setup.py --- old/cffi-1.1.0/setup.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/setup.py 2015-06-09 12:04:10.000000000 +0200 @@ -144,7 +144,7 @@ `Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_ """, - version='1.1.0', + version='1.1.2', packages=['cffi'] if cpython else [], package_data={'cffi': ['_cffi_include.h', 'parse_c_type.h']} if cpython else {}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi0/backend_tests.py new/cffi-1.1.2/testing/cffi0/backend_tests.py --- old/cffi-1.1.0/testing/cffi0/backend_tests.py 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi0/backend_tests.py 2015-06-09 12:04:07.000000000 +0200 @@ -1457,6 +1457,63 @@ import gc; gc.collect(); gc.collect(); gc.collect() assert seen == [1] + def test_gc_2(self): + ffi = FFI(backend=self.Backend()) + p = ffi.new("int *", 123) + seen = [] + q1 = ffi.gc(p, lambda p: seen.append(1)) + q2 = ffi.gc(q1, lambda p: seen.append(2)) + import gc; gc.collect() + assert seen == [] + del q1, q2 + import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect() + assert seen == [2, 1] + + def test_gc_3(self): + ffi = FFI(backend=self.Backend()) + p = ffi.new("int *", 123) + r = ffi.new("int *", 123) + seen = [] + seen_r = [] + q1 = ffi.gc(p, lambda p: seen.append(1)) + s1 = ffi.gc(r, lambda r: seen_r.append(4)) + q2 = ffi.gc(q1, lambda p: seen.append(2)) + s2 = ffi.gc(s1, lambda r: seen_r.append(5)) + q3 = ffi.gc(q2, lambda p: seen.append(3)) + import gc; gc.collect() + assert seen == [] + assert seen_r == [] + del q1, q2, q3, s2, s1 + import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect() + assert seen == [3, 2, 1] + assert seen_r == [5, 4] + + def test_gc_4(self): + ffi = FFI(backend=self.Backend()) + p = ffi.new("int *", 123) + seen = [] + q1 = ffi.gc(p, lambda p: seen.append(1)) + q2 = ffi.gc(q1, lambda p: seen.append(2)) + q3 = ffi.gc(q2, lambda p: seen.append(3)) + import gc; gc.collect() + assert seen == [] + del q1, q3 # q2 remains, and has a hard ref to q1 + import gc; gc.collect(); gc.collect(); gc.collect() + assert seen == [3] + + def test_gc_finite_list(self): + ffi = FFI(backend=self.Backend()) + p = ffi.new("int *", 123) + keepalive = [] + for i in range(10): + keepalive.append(ffi.gc(p, lambda p: None)) + assert len(ffi.gc_weakrefs.data) == i + 1 #should be a private attr + del keepalive[:] + import gc; gc.collect(); gc.collect() + for i in range(10): + keepalive.append(ffi.gc(p, lambda p: None)) + assert len(ffi.gc_weakrefs.data) == 10 + def test_CData_CType(self): ffi = FFI(backend=self.Backend()) assert isinstance(ffi.cast("int", 0), ffi.CData) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi0/test_verify.py new/cffi-1.1.2/testing/cffi0/test_verify.py --- old/cffi-1.1.0/testing/cffi0/test_verify.py 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi0/test_verify.py 2015-06-09 12:04:07.000000000 +0200 @@ -2227,3 +2227,11 @@ ffi.cdef("static const int FOO = 123;") e = py.test.raises(VerificationError, ffi.verify, "#define FOO 124") assert str(e.value).endswith("FOO has the real value 124, not 123") + +def test_const_struct_global(): + ffi = FFI() + ffi.cdef("typedef struct { int x; ...; } T; const T myglob;") + lib = ffi.verify("typedef struct { double y; int x; } T;" + "const T myglob = { 0.1, 42 };") + assert ffi.typeof(lib.myglob) == ffi.typeof("T") + assert lib.myglob.x == 42 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi0/test_zintegration.py new/cffi-1.1.2/testing/cffi0/test_zintegration.py --- old/cffi-1.1.0/testing/cffi0/test_zintegration.py 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi0/test_zintegration.py 2015-06-09 12:04:07.000000000 +0200 @@ -1,5 +1,4 @@ import py, os, sys, shutil -import imp import subprocess from testing.udir import udir @@ -15,28 +14,12 @@ except OSError as e: py.test.skip("Cannot execute virtualenv: %s" % (e,)) - try: - deepcopy = os.symlink - except: - import shutil, errno - def deepcopy(src, dst): - try: - shutil.copytree(src, dst) - except OSError as e: - if e.errno in (errno.ENOTDIR, errno.EINVAL): - shutil.copy(src, dst) - else: - print('got errno') - print(e.errno) - print('not') - print(errno.ENOTDIR) - raise - site_packages = None for dirpath, dirnames, filenames in os.walk(str(tmpdir)): if os.path.basename(dirpath) == 'site-packages': site_packages = dirpath break + paths = "" if site_packages: try: from cffi import _pycparser @@ -49,15 +32,22 @@ pass else: modules += ('ply',) # needed for older versions of pycparser + paths = [] for module in modules: - target = imp.find_module(module)[1] - deepcopy(target, os.path.join(site_packages, - os.path.basename(target))) - return tmpdir + target = __import__(module, None, None, []) + src = os.path.abspath(target.__file__) + for end in ['__init__.pyc', '__init__.pyo', '__init__.py']: + if src.lower().endswith(end): + src = src[:-len(end)-1] + break + paths.append(os.path.dirname(src)) + paths = os.pathsep.join(paths) + return tmpdir, paths SNIPPET_DIR = py.path.local(__file__).join('..', 'snippets') -def really_run_setup_and_program(dirname, venv_dir, python_snippet): +def really_run_setup_and_program(dirname, venv_dir_and_paths, python_snippet): + venv_dir, paths = venv_dir_and_paths def remove(dir): dir = str(SNIPPET_DIR.join(dirname, dir)) shutil.rmtree(dir, ignore_errors=True) @@ -75,9 +65,11 @@ else: bindir = 'bin' vp = str(venv_dir.join(bindir).join('python')) - subprocess.check_call((vp, 'setup.py', 'clean')) - subprocess.check_call((vp, 'setup.py', 'install')) - subprocess.check_call((vp, str(python_f))) + env = os.environ.copy() + env['PYTHONPATH'] = paths + subprocess.check_call((vp, 'setup.py', 'clean'), env=env) + subprocess.check_call((vp, 'setup.py', 'install'), env=env) + subprocess.check_call((vp, str(python_f)), env=env) finally: os.chdir(olddir) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_ffi_obj.py new/cffi-1.1.2/testing/cffi1/test_ffi_obj.py --- old/cffi-1.1.0/testing/cffi1/test_ffi_obj.py 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi1/test_ffi_obj.py 2015-06-09 12:04:07.000000000 +0200 @@ -1,4 +1,4 @@ -import py +import py, sys import _cffi_backend as _cffi1_backend @@ -65,6 +65,7 @@ ffi = _cffi1_backend.FFI() p = ffi.new("char[]", init=b"foobar\x00baz") assert ffi.string(p) == b"foobar" + assert ffi.string(cdata=p, maxlen=3) == b"foo" def test_ffi_errno(): # xxx not really checking errno, just checking that we can read/write it @@ -157,11 +158,19 @@ assert str(e.value) == ("undefined struct/union name\n" "struct never_heard_of_s\n" " ^") + e = py.test.raises(ffi.error, ffi.cast, "\t\n\x01\x1f~\x7f\x80\xff", 0) + marks = "?" if sys.version_info < (3,) else "??" + assert str(e.value) == ("identifier expected\n" + " ??~?%s%s\n" + " ^" % (marks, marks)) + e = py.test.raises(ffi.error, ffi.cast, "X" * 600, 0) + assert str(e.value) == ("undefined type name") def test_ffi_buffer(): ffi = _cffi1_backend.FFI() a = ffi.new("signed char[]", [5, 6, 7]) assert ffi.buffer(a)[:] == b'\x05\x06\x07' + assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06' def test_ffi_from_buffer(): import array @@ -178,3 +187,11 @@ ffi = _cffi1_backend.FFI() assert isinstance(ffi.cast("int", 42), CData) assert isinstance(ffi.typeof("int"), CType) + +def test_ffi_getwinerror(): + if sys.platform != "win32": + py.test.skip("for windows") + ffi = _cffi1_backend.FFI() + n = (1 << 29) + 42 + code, message = ffi.getwinerror(code=n) + assert code == n diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_new_ffi_1.py new/cffi-1.1.2/testing/cffi1/test_new_ffi_1.py --- old/cffi-1.1.0/testing/cffi1/test_new_ffi_1.py 2015-05-30 21:45:20.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi1/test_new_ffi_1.py 2015-06-09 12:04:07.000000000 +0200 @@ -32,7 +32,9 @@ struct ab { int a, b; }; struct abc { int a, b, c; }; - enum foq { A0, B0, CC0, D0 }; + /* don't use A0, B0, CC0, D0 because termios.h might be included + and it has its own #defines for these names */ + enum foq { cffiA0, cffiB0, cffiCC0, cffiD0 }; enum bar { A1, B1=-2, CC1, D1, E1 }; enum baz { A2=0x1000, B2=0x2000 }; enum foo2 { A3, B3, C3, D3 }; @@ -878,9 +880,9 @@ def test_enum(self): # enum foq { A0, B0, CC0, D0 }; - assert ffi.string(ffi.cast("enum foq", 0)) == "A0" - assert ffi.string(ffi.cast("enum foq", 2)) == "CC0" - assert ffi.string(ffi.cast("enum foq", 3)) == "D0" + assert ffi.string(ffi.cast("enum foq", 0)) == "cffiA0" + assert ffi.string(ffi.cast("enum foq", 2)) == "cffiCC0" + assert ffi.string(ffi.cast("enum foq", 3)) == "cffiD0" assert ffi.string(ffi.cast("enum foq", 4)) == "4" # enum bar { A1, B1=-2, CC1, D1, E1 }; assert ffi.string(ffi.cast("enum bar", 0)) == "A1" @@ -1407,6 +1409,47 @@ import gc; gc.collect(); gc.collect(); gc.collect() assert seen == [1] + def test_gc_2(self): + p = ffi.new("int *", 123) + seen = [] + q1 = ffi.gc(p, lambda p: seen.append(1)) + q2 = ffi.gc(q1, lambda p: seen.append(2)) + import gc; gc.collect() + assert seen == [] + del q1, q2 + import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect() + assert seen == [2, 1] + + def test_gc_3(self): + p = ffi.new("int *", 123) + r = ffi.new("int *", 123) + seen = [] + seen_r = [] + q1 = ffi.gc(p, lambda p: seen.append(1)) + s1 = ffi.gc(r, lambda r: seen_r.append(4)) + q2 = ffi.gc(q1, lambda p: seen.append(2)) + s2 = ffi.gc(s1, lambda r: seen_r.append(5)) + q3 = ffi.gc(q2, lambda p: seen.append(3)) + import gc; gc.collect() + assert seen == [] + assert seen_r == [] + del q1, q2, q3, s2, s1 + import gc; gc.collect(); gc.collect(); gc.collect(); gc.collect() + assert seen == [3, 2, 1] + assert seen_r == [5, 4] + + def test_gc_4(self): + p = ffi.new("int *", 123) + seen = [] + q1 = ffi.gc(p, lambda p: seen.append(1)) + q2 = ffi.gc(q1, lambda p: seen.append(2)) + q3 = ffi.gc(q2, lambda p: seen.append(3)) + import gc; gc.collect() + assert seen == [] + del q1, q3 # q2 remains, and has a hard ref to q1 + import gc; gc.collect(); gc.collect(); gc.collect() + assert seen == [3] + def test_CData_CType(self): assert isinstance(ffi.cast("int", 0), ffi.CData) assert isinstance(ffi.new("int *"), ffi.CData) @@ -1533,8 +1576,8 @@ assert p.a == -52525 # p = ffi.cast("enum foq", 2) - assert ffi.string(p) == "CC0" - assert ffi2.sizeof("char[CC0]") == 2 + assert ffi.string(p) == "cffiCC0" + assert ffi2.sizeof("char[cffiCC0]") == 2 # p = ffi.new("anon_foo_t *", [-52526]) assert p.a == -52526 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_re_python.py new/cffi-1.1.2/testing/cffi1/test_re_python.py --- old/cffi-1.1.0/testing/cffi1/test_re_python.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi1/test_re_python.py 2015-06-09 12:04:07.000000000 +0200 @@ -7,6 +7,7 @@ def setup_module(mod): SRC = """ + #include <string.h> #define FOOBAR (-42) static const int FOOBAZ = -43; #define BIGPOS 420000000000L @@ -53,6 +54,7 @@ struct foo_s; typedef struct bar_s { int x; signed char a[]; } bar_t; enum foo_e { AA, BB, CC }; + int strlen(const char *); """) ffi.set_source('re_python_pysrc', None) ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py'))) @@ -81,10 +83,20 @@ def test_function_with_varargs(): import _cffi_backend from re_python_pysrc import ffi - lib = ffi.dlopen(extmod) + lib = ffi.dlopen(extmod, 0) assert lib.add43(45, ffi.cast("int", -5)) == 45 assert type(lib.add43) is _cffi_backend.FFI.CData +def test_dlopen_none(): + import _cffi_backend + from re_python_pysrc import ffi + name = None + if sys.platform == 'win32': + import ctypes.util + name = ctypes.util.find_msvcrt() + lib = ffi.dlopen(name) + assert lib.strlen(b"hello") == 5 + def test_dlclose(): import _cffi_backend from re_python_pysrc import ffi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_recompiler.py new/cffi-1.1.2/testing/cffi1/test_recompiler.py --- old/cffi-1.1.0/testing/cffi1/test_recompiler.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi1/test_recompiler.py 2015-06-09 12:04:10.000000000 +0200 @@ -992,3 +992,13 @@ ffi.typeof('function_t*') lib.function(ffi.NULL) # assert did not crash + +def test_alignment_of_longlong(): + ffi = FFI() + x1 = ffi.alignof('unsigned long long') + assert x1 in [4, 8] + ffi.cdef("struct foo_s { unsigned long long x; };") + lib = verify(ffi, 'test_alignment_of_longlong', + "struct foo_s { unsigned long long x; };") + assert ffi.alignof('unsigned long long') == x1 + assert ffi.alignof('struct foo_s') == x1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_verify1.py new/cffi-1.1.2/testing/cffi1/test_verify1.py --- old/cffi-1.1.0/testing/cffi1/test_verify1.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi1/test_verify1.py 2015-06-09 12:04:07.000000000 +0200 @@ -2117,25 +2117,19 @@ try: ffi1 = FFI() ffi1.cdef("int foo_verify_dlopen_flags;") - - sys.setdlopenflags(ffi1.RTLD_GLOBAL | ffi1.RTLD_LAZY) + sys.setdlopenflags(ffi1.RTLD_GLOBAL | ffi1.RTLD_NOW) lib1 = ffi1.verify("int foo_verify_dlopen_flags;") - lib2 = get_second_lib() - - lib1.foo_verify_dlopen_flags = 42 - assert lib2.foo_verify_dlopen_flags == 42 - lib2.foo_verify_dlopen_flags += 1 - assert lib1.foo_verify_dlopen_flags == 43 finally: sys.setdlopenflags(old) -def get_second_lib(): - # Hack, using modulename makes the test fail ffi2 = FFI() - ffi2.cdef("int foo_verify_dlopen_flags;") - lib2 = ffi2.verify("int foo_verify_dlopen_flags;", - flags=ffi2.RTLD_GLOBAL | ffi2.RTLD_LAZY) - return lib2 + ffi2.cdef("int *getptr(void);") + lib2 = ffi2.verify(""" + extern int foo_verify_dlopen_flags; + static int *getptr(void) { return &foo_verify_dlopen_flags; } + """) + p = lib2.getptr() + assert ffi1.addressof(lib1, 'foo_verify_dlopen_flags') == p def test_consider_not_implemented_function_type(): ffi = FFI() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/cffi-1.1.0/testing/cffi1/test_zdist.py new/cffi-1.1.2/testing/cffi1/test_zdist.py --- old/cffi-1.1.0/testing/cffi1/test_zdist.py 2015-05-30 21:45:50.000000000 +0200 +++ new/cffi-1.1.2/testing/cffi1/test_zdist.py 2015-06-09 12:04:07.000000000 +0200 @@ -29,13 +29,17 @@ if hasattr(self, 'saved_cwd'): os.chdir(self.saved_cwd) - def run(self, args): + def run(self, args, cwd=None): env = os.environ.copy() - newpath = self.rootdir - if 'PYTHONPATH' in env: - newpath += os.pathsep + env['PYTHONPATH'] - env['PYTHONPATH'] = newpath - subprocess.check_call([self.executable] + args, env=env) + # a horrible hack to prevent distutils from finding ~/.pydistutils.cfg + # (there is the --no-user-cfg option, but not in Python 2.6...) + env['HOME'] = '/this/path/does/not/exist' + if cwd is None: + newpath = self.rootdir + if 'PYTHONPATH' in env: + newpath += os.pathsep + env['PYTHONPATH'] + env['PYTHONPATH'] = newpath + subprocess.check_call([self.executable] + args, cwd=cwd, env=env) def _prepare_setuptools(self): if hasattr(TestDist, '_setuptools_ready'): @@ -44,8 +48,7 @@ import setuptools except ImportError: py.test.skip("setuptools not found") - subprocess.check_call([self.executable, 'setup.py', 'egg_info'], - cwd=self.rootdir) + self.run(['setup.py', 'egg_info'], cwd=self.rootdir) TestDist._setuptools_ready = True def check_produced_files(self, content, curdir=None):