[pypy-commit] cffi release-0.9: hg merge default

arigo noreply at buildbot.pypy.org
Sun May 17 09:59:34 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: release-0.9
Changeset: r2021:fcb2195c0347
Date: 2015-05-17 10:00 +0200
http://bitbucket.org/cffi/cffi/changeset/fcb2195c0347/

Log:	hg merge default

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -3761,9 +3761,10 @@
     for (i=0; i<nb_fields; i++) {
         PyObject *fname;
         CTypeDescrObject *ftype;
-        int fbitsize = -1, falign, do_align, foffset = -1;
-
-        if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|ii:list item",
+        int fbitsize = -1, falign, do_align;
+        Py_ssize_t foffset = -1;
+
+        if (!PyArg_ParseTuple(PyList_GET_ITEM(fields, i), "O!O!|in:list item",
                               &PyText_Type, &fname,
                               &CTypeDescr_Type, &ftype,
                               &fbitsize, &foffset))
@@ -5581,7 +5582,7 @@
 static RETURNTYPE _cffi_to_c_i##SIZE(PyObject *obj) {                   \
     PY_LONG_LONG tmp = _my_PyLong_AsLongLong(obj);                      \
     if ((tmp > (PY_LONG_LONG)((1ULL<<(SIZE-1)) - 1)) ||                 \
-        (tmp < (PY_LONG_LONG)(-(1ULL<<(SIZE-1)))))                      \
+        (tmp < (PY_LONG_LONG)(0ULL-(1ULL<<(SIZE-1)))))                  \
         if (!PyErr_Occurred())                                          \
             return (RETURNTYPE)_convert_overflow(obj, #SIZE "-bit int"); \
     return (RETURNTYPE)tmp;                                             \
diff --git a/c/libffi_msvc/ffi.c b/c/libffi_msvc/ffi.c
--- a/c/libffi_msvc/ffi.c
+++ b/c/libffi_msvc/ffi.c
@@ -119,7 +119,7 @@
       argp += z;
     }
 
-  if (argp - stack > ecif->cif->bytes) 
+  if (argp - stack > (long)ecif->cif->bytes)
     {
       Py_FatalError("FFI BUG: not enough stack space for arguments");
     }
diff --git a/cffi/cparser.py b/cffi/cparser.py
--- a/cffi/cparser.py
+++ b/cffi/cparser.py
@@ -266,7 +266,10 @@
             #
             if decl.name:
                 tp = self._get_type(node, partial_length_ok=True)
-                if self._is_constant_globalvar(node):
+                if tp.is_raw_function:
+                    tp = self._get_type_pointer(tp)
+                    self._declare('function ' + decl.name, tp)
+                elif self._is_constant_globalvar(node):
                     self._declare('constant ' + decl.name, tp)
                 else:
                     self._declare('variable ' + decl.name, tp)
@@ -290,9 +293,13 @@
         assert '__dotdotdot__' not in name.split()
         self._declarations[name] = obj
 
-    def _get_type_pointer(self, type, const=False):
+    def _get_type_pointer(self, type, const=False, declname=None):
         if isinstance(type, model.RawFunctionType):
             return type.as_function_pointer()
+        if (isinstance(type, model.StructOrUnionOrEnum) and
+                type.name.startswith('$') and type.name[1:].isdigit() and
+                type.forcename is None and declname is not None):
+            return model.NamedPointerType(type, declname)
         if const:
             return model.ConstPointerType(type)
         return model.PointerType(type)
@@ -319,7 +326,8 @@
             # pointer type
             const = (isinstance(typenode.type, pycparser.c_ast.TypeDecl)
                      and 'const' in typenode.type.quals)
-            return self._get_type_pointer(self._get_type(typenode.type), const)
+            return self._get_type_pointer(self._get_type(typenode.type), const,
+                                          declname=name)
         #
         if isinstance(typenode, pycparser.c_ast.TypeDecl):
             type = typenode.type
diff --git a/cffi/ffiplatform.py b/cffi/ffiplatform.py
--- a/cffi/ffiplatform.py
+++ b/cffi/ffiplatform.py
@@ -1,4 +1,4 @@
-import os
+import sys, os
 
 
 class VerificationError(Exception):
@@ -14,7 +14,17 @@
 LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs',
                       'extra_objects', 'depends']
 
+def _hack_at_distutils():
+    # Windows-only workaround for some configurations: see
+    # https://bugs.python.org/issue23246 (Python 2.7.9)
+    if sys.platform == "win32":
+        try:
+            import setuptools    # for side-effects, patches distutils
+        except ImportError:
+            pass
+
 def get_extension(srcfilename, modname, sources=(), **kwds):
+    _hack_at_distutils()   # *before* the following import
     from distutils.core import Extension
     allsources = [srcfilename]
     allsources.extend(sources)
@@ -37,6 +47,7 @@
 
 def _build(tmpdir, ext):
     # XXX compact but horrible :-(
+    _hack_at_distutils()
     from distutils.core import Distribution
     import distutils.errors
     #
diff --git a/cffi/model.py b/cffi/model.py
--- a/cffi/model.py
+++ b/cffi/model.py
@@ -102,8 +102,26 @@
         'uint32_t':           'i',
         'int64_t':            'i',
         'uint64_t':           'i',
+        'int_least8_t':       'i',
+        'uint_least8_t':      'i',
+        'int_least16_t':      'i',
+        'uint_least16_t':     'i',
+        'int_least32_t':      'i',
+        'uint_least32_t':     'i',
+        'int_least64_t':      'i',
+        'uint_least64_t':     'i',
+        'int_fast8_t':        'i',
+        'uint_fast8_t':       'i',
+        'int_fast16_t':       'i',
+        'uint_fast16_t':      'i',
+        'int_fast32_t':       'i',
+        'uint_fast32_t':      'i',
+        'int_fast64_t':       'i',
+        'uint_fast64_t':      'i',
         'intptr_t':           'i',
         'uintptr_t':          'i',
+        'intmax_t':           'i',
+        'uintmax_t':          'i',
         'ptrdiff_t':          'i',
         'size_t':             'i',
         'ssize_t':            'i',
diff --git a/cffi/vengine_cpy.py b/cffi/vengine_cpy.py
--- a/cffi/vengine_cpy.py
+++ b/cffi/vengine_cpy.py
@@ -141,19 +141,23 @@
     def load_library(self, flags=None):
         # XXX review all usages of 'self' here!
         # import it as a new extension module
-        if hasattr(sys, "getdlopenflags"):
-            previous_flags = sys.getdlopenflags()
+        imp.acquire_lock()
         try:
-            if hasattr(sys, "setdlopenflags") and flags is not None:
-                sys.setdlopenflags(flags)
-            module = imp.load_dynamic(self.verifier.get_module_name(),
-                                      self.verifier.modulefilename)
-        except ImportError as e:
-            error = "importing %r: %s" % (self.verifier.modulefilename, e)
-            raise ffiplatform.VerificationError(error)
+            if hasattr(sys, "getdlopenflags"):
+                previous_flags = sys.getdlopenflags()
+            try:
+                if hasattr(sys, "setdlopenflags") and flags is not None:
+                    sys.setdlopenflags(flags)
+                module = imp.load_dynamic(self.verifier.get_module_name(),
+                                          self.verifier.modulefilename)
+            except ImportError as e:
+                error = "importing %r: %s" % (self.verifier.modulefilename, e)
+                raise ffiplatform.VerificationError(error)
+            finally:
+                if hasattr(sys, "setdlopenflags"):
+                    sys.setdlopenflags(previous_flags)
         finally:
-            if hasattr(sys, "setdlopenflags"):
-                sys.setdlopenflags(previous_flags)
+            imp.release_lock()
         #
         # call loading_cpy_struct() to get the struct layout inferred by
         # the C compiler
diff --git a/cffi/vengine_gen.py b/cffi/vengine_gen.py
--- a/cffi/vengine_gen.py
+++ b/cffi/vengine_gen.py
@@ -149,15 +149,21 @@
         context = 'argument of %s' % name
         arglist = [type.get_c_name(' %s' % arg, context)
                    for type, arg in zip(tp.args, argnames)]
+        tpresult = tp.result
+        if isinstance(tpresult, model.StructOrUnion):
+            arglist.insert(0, tpresult.get_c_name(' *r', context))
+            tpresult = model.void_type
         arglist = ', '.join(arglist) or 'void'
         wrappername = '_cffi_f_%s' % name
         self.export_symbols.append(wrappername)
         funcdecl = ' %s(%s)' % (wrappername, arglist)
         context = 'result of %s' % name
-        prnt(tp.result.get_c_name(funcdecl, context))
+        prnt(tpresult.get_c_name(funcdecl, context))
         prnt('{')
         #
-        if not isinstance(tp.result, model.VoidType):
+        if isinstance(tp.result, model.StructOrUnion):
+            result_code = '*r = '
+        elif not isinstance(tp.result, model.VoidType):
             result_code = 'return '
         else:
             result_code = ''
@@ -174,15 +180,26 @@
         else:
             indirections = []
             base_tp = tp
-            if any(isinstance(typ, model.StructOrUnion) for typ in tp.args):
+            if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args)
+                    or isinstance(tp.result, model.StructOrUnion)):
                 indirect_args = []
                 for i, typ in enumerate(tp.args):
                     if isinstance(typ, model.StructOrUnion):
                         typ = model.PointerType(typ)
                         indirections.append((i, typ))
                     indirect_args.append(typ)
+                indirect_result = tp.result
+                if isinstance(indirect_result, model.StructOrUnion):
+                    if indirect_result.fldtypes is None:
+                        raise TypeError("'%s' is used as result type, "
+                                        "but is opaque" % (
+                                            indirect_result._get_c_name(),))
+                    indirect_result = model.PointerType(indirect_result)
+                    indirect_args.insert(0, indirect_result)
+                    indirections.insert(0, ("result", indirect_result))
+                    indirect_result = model.void_type
                 tp = model.FunctionPtrType(tuple(indirect_args),
-                                           tp.result, tp.ellipsis)
+                                           indirect_result, tp.ellipsis)
             BFunc = self.ffi._get_cached_btype(tp)
             wrappername = '_cffi_f_%s' % name
             newfunction = module.load_function(BFunc, wrappername)
@@ -195,9 +212,16 @@
     def _make_struct_wrapper(self, oldfunc, i, tp, base_tp):
         backend = self.ffi._backend
         BType = self.ffi._get_cached_btype(tp)
-        def newfunc(*args):
-            args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]
-            return oldfunc(*args)
+        if i == "result":
+            ffi = self.ffi
+            def newfunc(*args):
+                res = ffi.new(BType)
+                oldfunc(res, *args)
+                return res[0]
+        else:
+            def newfunc(*args):
+                args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:]
+                return oldfunc(*args)
         newfunc._cffi_base_type = base_tp
         return newfunc
 
diff --git a/doc/source/index.rst b/doc/source/index.rst
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -437,9 +437,9 @@
   types ``TBYTE TCHAR LPCTSTR PCTSTR LPTSTR PTSTR PTBYTE PTCHAR`` are no
   longer automatically defined; see ``ffi.set_unicode()`` below.
 
-* *New in version 0.9:* the other standard integer types from stdint.h,
+* *New in version 0.9.3:* the other standard integer types from stdint.h,
   as long as they map to integers of 1, 2, 4 or 8 bytes.  Larger integers
-  are not supported.
+  are not supported.  (Actually added in version 0.9 but this was buggy.)
 
 .. _`common Windows types`: http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751%28v=vs.85%29.aspx
 
@@ -1078,6 +1078,23 @@
     C.printf("hello, %f\n", ffi.cast("double", 42))
     C.printf("hello, %s\n", ffi.new("char[]", "world"))
 
+Note that if you are using ``dlopen()``, the function declaration in the
+``cdef()`` must match the original one in C exactly, as usual --- in
+particular, if this function is variadic in C, then its ``cdef()``
+declaration must also be variadic.  You cannot declare it in the
+``cdef()`` with fixed arguments instead, even if you plan to only call
+it with these argument types.  The reason is that some architectures
+have a different calling convention depending on whether the function
+signature is fixed or not.  (On x86-64, the difference can sometimes be
+seen in PyPy's JIT-generated code if some arguments are ``double``.)
+
+Note that the function signature ``int foo();`` is interpreted by CFFI
+as equivalent to ``int foo(void);``.  This differs from the C standard,
+in which ``int foo();`` is really like ``int foo(...);`` and can be
+called with any arguments.  (This feature of C is a pre-C89 relic: the
+arguments cannot be accessed at all in the body of ``foo()`` without
+relying on compiler-specific extensions.)
+
 
 Callbacks
 ---------
@@ -1260,7 +1277,8 @@
 buffer interface.  This is the opposite of ``ffi.buffer()``.  It gives
 a (read-write) reference to the existing data, not a copy; for this
 reason, and for PyPy compatibility, it does not work with the built-in
-types str or unicode or bytearray.  It is meant to be used on objects
+types str or unicode or bytearray (or buffers/memoryviews on them).
+It is meant to be used on objects
 containing large quantities of raw data, like ``array.array`` or numpy
 arrays.  It supports both the old buffer API (in Python 2.x) and the
 new memoryview API.  The original object is kept alive (and, in case
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -19,7 +19,7 @@
         p = subprocess.Popen([pkg_config, option, 'libffi'],
                              stdout=subprocess.PIPE)
     except OSError as e:
-        if e.errno != errno.ENOENT:
+        if e.errno not in [errno.ENOENT, errno.EACCES]:
             raise
     else:
         t = p.stdout.read().decode().strip()
@@ -109,11 +109,14 @@
     use_pkg_config()
     ask_supports_thread()
 
+if 'freebsd' in sys.platform:
+    include_dirs.append('/usr/local/include')
+
 
 if __name__ == '__main__':
     from setuptools import setup, Extension
     ext_modules = []
-    if '__pypy__' not in sys.modules:
+    if '__pypy__' not in sys.builtin_module_names:
         ext_modules.append(Extension(
             name='_cffi_backend',
             include_dirs=include_dirs,
@@ -162,5 +165,8 @@
             'Programming Language :: Python :: 3',
             'Programming Language :: Python :: 3.2',
             'Programming Language :: Python :: 3.3',
+            'Programming Language :: Python :: 3.4',
+            'Programming Language :: Python :: Implementation :: CPython',
+            'Programming Language :: Python :: Implementation :: PyPy',
         ],
     )
diff --git a/setup_base.py b/setup_base.py
--- a/setup_base.py
+++ b/setup_base.py
@@ -8,7 +8,7 @@
 if __name__ == '__main__':
     from distutils.core import setup
     from distutils.extension import Extension
-    standard = '__pypy__' not in sys.modules
+    standard = '__pypy__' not in sys.builtin_module_names
     setup(packages=['cffi'],
           requires=['pycparser'],
           ext_modules=[Extension(name = '_cffi_backend',
diff --git a/testing/backend_tests.py b/testing/backend_tests.py
--- a/testing/backend_tests.py
+++ b/testing/backend_tests.py
@@ -1388,6 +1388,17 @@
         assert p.c == 14
         assert p.d == 14
 
+    def test_nested_field_offset_align(self):
+        ffi = FFI(backend=self.Backend())
+        ffi.cdef("""
+            struct foo_s {
+                struct { int a; char b; };
+                union { char c; };
+            };
+        """)
+        assert ffi.offsetof("struct foo_s", "c") == 2 * SIZE_OF_INT
+        assert ffi.sizeof("struct foo_s") == 3 * SIZE_OF_INT
+
     def test_nested_anonymous_union(self):
         ffi = FFI(backend=self.Backend())
         ffi.cdef("""
@@ -1692,5 +1703,3 @@
         assert lib.DOT_HEX == 0x100
         assert lib.DOT_HEX2 == 0x10
         assert lib.DOT_UL == 1000
-
-
diff --git a/testing/test_ctypes.py b/testing/test_ctypes.py
--- a/testing/test_ctypes.py
+++ b/testing/test_ctypes.py
@@ -28,6 +28,9 @@
     def test_nested_anonymous_struct(self):
         py.test.skip("ctypes backend: not supported: nested anonymous struct")
 
+    def test_nested_field_offset_align(self):
+        py.test.skip("ctypes backend: not supported: nested anonymous struct")
+
     def test_nested_anonymous_union(self):
         py.test.skip("ctypes backend: not supported: nested anonymous union")
 
diff --git a/testing/test_ffi_backend.py b/testing/test_ffi_backend.py
--- a/testing/test_ffi_backend.py
+++ b/testing/test_ffi_backend.py
@@ -222,3 +222,57 @@
         assert ffi.typeof(c) is ffi.typeof("char[]")
         ffi.cast("unsigned short *", c)[1] += 500
         assert list(a) == [10000, 20500, 30000]
+
+    def test_all_primitives(self):
+        ffi = FFI()
+        for name in [
+            "char",
+            "short",
+            "int",
+            "long",
+            "long long",
+            "signed char",
+            "unsigned char",
+            "unsigned short",
+            "unsigned int",
+            "unsigned long",
+            "unsigned long long",
+            "float",
+            "double",
+            "long double",
+            "wchar_t",
+            "_Bool",
+            "int8_t",
+            "uint8_t",
+            "int16_t",
+            "uint16_t",
+            "int32_t",
+            "uint32_t",
+            "int64_t",
+            "uint64_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",
+            "intptr_t",
+            "uintptr_t",
+            "intmax_t",
+            "uintmax_t",
+            "ptrdiff_t",
+            "size_t",
+            "ssize_t",
+            ]:
+            x = ffi.sizeof(name)
+            assert 1 <= x <= 16
diff --git a/testing/test_function.py b/testing/test_function.py
--- a/testing/test_function.py
+++ b/testing/test_function.py
@@ -292,7 +292,6 @@
         assert ffi.string(a) == b'4.4.4.4'
 
     def test_function_typedef(self):
-        py.test.skip("using really obscure C syntax")
         ffi = FFI(backend=self.Backend())
         ffi.cdef("""
             typedef double func_t(double);
diff --git a/testing/test_verify.py b/testing/test_verify.py
--- a/testing/test_verify.py
+++ b/testing/test_verify.py
@@ -657,9 +657,9 @@
     # case the 'static' is completely ignored.
     ffi.cdef("static const int AA, BB, CC, DD;")
     lib = ffi.verify("#define AA 42\n"
-                     "#define BB (-43)\n"
-                     "#define CC (22*2)\n"
-                     "#define DD ((unsigned int)142)\n")
+                     "#define BB (-43)   // blah\n"
+                     "#define CC (22*2)  /* foobar */\n"
+                     "#define DD ((unsigned int)142)  /* foo\nbar */\n")
     assert lib.AA == 42
     assert lib.BB == -43
     assert lib.CC == 44
@@ -1197,6 +1197,15 @@
     """)
     assert lib.foo_func(lib.BB) == lib.BB == 2
 
+def test_function_typedef():
+    ffi = FFI()
+    ffi.cdef("""
+        typedef double func_t(double);
+        func_t sin;
+    """)
+    lib = ffi.verify('#include <math.h>', libraries=lib_m)
+    assert lib.sin(1.23) == math.sin(1.23)
+
 def test_callback_calling_convention():
     py.test.skip("later")
     if sys.platform != 'win32':
@@ -1217,11 +1226,11 @@
     xxx
 
 def test_opaque_integer_as_function_result():
-    import platform
-    if platform.machine().startswith('sparc'):
-        py.test.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
-    elif platform.machine() == 'mips64' and sys.maxsize > 2**32:
-        py.test.skip('Segfaults on mips64el')
+    #import platform
+    #if platform.machine().startswith('sparc'):
+    #    py.test.skip('Breaks horribly on sparc (SIGILL + corrupted stack)')
+    #elif platform.machine() == 'mips64' and sys.maxsize > 2**32:
+    #    py.test.skip('Segfaults on mips64el')
     # XXX bad abuse of "struct { ...; }".  It only works a bit by chance
     # anyway.  XXX think about something better :-(
     ffi = FFI()
@@ -1236,11 +1245,45 @@
     h = lib.foo()
     assert ffi.sizeof(h) == ffi.sizeof("short")
 
+def test_return_partial_struct():
+    ffi = FFI()
+    ffi.cdef("""
+        typedef struct { int x; ...; } foo_t;
+        foo_t foo(void);
+    """)
+    lib = ffi.verify("""
+        typedef struct { int y, x; } foo_t;
+        foo_t foo(void) { foo_t r = { 45, 81 }; return r; }
+    """)
+    h = lib.foo()
+    assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
+    assert h.x == 81
+
+def test_take_and_return_partial_structs():
+    ffi = FFI()
+    ffi.cdef("""
+        typedef struct { int x; ...; } foo_t;
+        foo_t foo(foo_t, foo_t);
+    """)
+    lib = ffi.verify("""
+        typedef struct { int y, x; } foo_t;
+        foo_t foo(foo_t a, foo_t b) {
+            foo_t r = { 100, a.x * 5 + b.x * 7 };
+            return r;
+        }
+    """)
+    args = ffi.new("foo_t[3]")
+    args[0].x = 1000
+    args[2].x = -498
+    h = lib.foo(args[0], args[2])
+    assert ffi.sizeof(h) == 2 * ffi.sizeof("int")
+    assert h.x == 1000 * 5 - 498 * 7
+
 def test_cannot_name_struct_type():
     ffi = FFI()
-    ffi.cdef("typedef struct { int x; } *sp; void foo(sp);")
+    ffi.cdef("typedef struct { int x; } **sp; void foo(sp);")
     e = py.test.raises(VerificationError, ffi.verify,
-                       "typedef struct { int x; } *sp; void foo(sp);")
+                       "typedef struct { int x; } **sp; void foo(sp x) { }")
     assert 'in argument of foo: unknown type name' in str(e.value)
 
 def test_dont_check_unnamable_fields():
@@ -1637,9 +1680,8 @@
     e = py.test.raises(TypeError, ffi.verify,
                        "typedef struct { int x; } foo_t; "
                        "foo_t myfunc(void) { foo_t x = { 42 }; return x; }")
-    assert str(e.value) in [
-        "function myfunc: 'foo_t' is used as result type, but is opaque",
-        "function myfunc: result type 'foo_t' is opaque"]
+    assert str(e.value) == (
+        "function myfunc: 'foo_t' is used as result type, but is opaque")
 
 def test_include():
     ffi1 = FFI()
@@ -1667,6 +1709,17 @@
     res = lib2.myfunc(lib2.AA)
     assert res == 2
 
+def test_named_pointer_as_argument():
+    ffi = FFI()
+    ffi.cdef("typedef struct { int x; } *mystruct_p;\n"
+             "mystruct_p ff5a(mystruct_p);")
+    lib = ffi.verify("typedef struct { int x; } *mystruct_p;\n"
+                     "mystruct_p ff5a(mystruct_p p) { p->x += 40; return p; }")
+    p = ffi.new("mystruct_p", [-2])
+    q = lib.ff5a(p)
+    assert q == p
+    assert p.x == 38
+
 def test_enum_size():
     cases = [('123',           4, 4294967295),
              ('4294967295U',   4, 4294967295),


More information about the pypy-commit mailing list