[pypy-commit] pypy default: update to cffi/ba124ec241c1

arigo pypy.commits at gmail.com
Sun Jan 5 09:34:00 EST 2020


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r98446:35b130c4015c
Date: 2020-01-05 14:16 +0100
http://bitbucket.org/pypy/pypy/changeset/35b130c4015c/

Log:	update to cffi/ba124ec241c1

diff --git a/extra_tests/cffi_tests/cffi0/test_ownlib.py b/extra_tests/cffi_tests/cffi0/test_ownlib.py
--- a/extra_tests/cffi_tests/cffi0/test_ownlib.py
+++ b/extra_tests/cffi_tests/cffi0/test_ownlib.py
@@ -372,3 +372,29 @@
         assert s.top == 22
         assert s.right == 33
         assert s.bottom == 44
+
+    def test_dlopen_handle(self):
+        if self.module is None:
+            py.test.skip("fix the auto-generation of the tiny test lib")
+        if sys.platform == 'win32':
+            py.test.skip("uses 'dl' explicitly")
+        if self.__class__.Backend is CTypesBackend:
+            py.test.skip("not for the ctypes backend")
+        backend = self.Backend()
+        ffi1 = FFI(backend=backend)
+        ffi1.cdef("""void *dlopen(const char *filename, int flags);
+                     int dlclose(void *handle);""")
+        lib1 = ffi1.dlopen('dl')
+        handle = lib1.dlopen(self.module.encode(sys.getfilesystemencoding()),
+                             backend.RTLD_LAZY)
+        assert ffi1.typeof(handle) == ffi1.typeof("void *")
+        assert handle
+
+        ffi = FFI(backend=backend)
+        ffi.cdef("""unsigned short foo_2bytes(unsigned short a);""")
+        lib = ffi.dlopen(handle)
+        x = lib.foo_2bytes(1000)
+        assert x == 1042
+
+        err = lib1.dlclose(handle)
+        assert err == 0
diff --git a/extra_tests/cffi_tests/cffi1/test_re_python.py b/extra_tests/cffi_tests/cffi1/test_re_python.py
--- a/extra_tests/cffi_tests/cffi1/test_re_python.py
+++ b/extra_tests/cffi_tests/cffi1/test_re_python.py
@@ -261,3 +261,24 @@
     # based on issue #429
     from re_python_pysrc import ffi
     ffi.new("selfref_ptr_t")
+
+def test_dlopen_handle():
+    import _cffi_backend
+    from re_python_pysrc import ffi
+    if sys.platform == 'win32':
+        py.test.skip("uses 'dl' explicitly")
+    ffi1 = FFI()
+    ffi1.cdef("""void *dlopen(const char *filename, int flags);
+                 int dlclose(void *handle);""")
+    lib1 = ffi1.dlopen('dl')
+    handle = lib1.dlopen(extmod.encode(sys.getfilesystemencoding()),
+                         _cffi_backend.RTLD_LAZY)
+    assert ffi1.typeof(handle) == ffi1.typeof("void *")
+    assert handle
+
+    lib = ffi.dlopen(handle)
+    assert lib.add42(-10) == 32
+    assert type(lib.add42) is _cffi_backend.FFI.CData
+
+    err = lib1.dlclose(handle)
+    assert err == 0
diff --git a/extra_tests/cffi_tests/cffi1/test_recompiler.py b/extra_tests/cffi_tests/cffi1/test_recompiler.py
--- a/extra_tests/cffi_tests/cffi1/test_recompiler.py
+++ b/extra_tests/cffi_tests/cffi1/test_recompiler.py
@@ -349,9 +349,9 @@
     lib = verify(ffi, 'test_verify_exact_field_offset',
                  """struct foo_s { short a; int b; };""")
     e = py.test.raises(ffi.error, ffi.new, "struct foo_s *", [])    # lazily
-    assert str(e.value) == ("struct foo_s: wrong offset for field 'b' (cdef "
-                       'says 0, but C compiler says 4). fix it or use "...;" '
-                       "in the cdef for struct foo_s to make it flexible")
+    assert str(e.value).startswith(
+        "struct foo_s: wrong offset for field 'b' (cdef "
+        'says 0, but C compiler says 4). fix it or use "...;" ')
 
 def test_type_caching():
     ffi1 = FFI(); ffi1.cdef("struct foo_s;")
diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -141,7 +141,11 @@
         linked to a particular library, just like C headers; in the
         library we only look for the actual (untyped) symbols.
         """
-        assert isinstance(name, basestring) or name is None
+        if not (isinstance(name, basestring) or
+                name is None or
+                isinstance(name, self.CData)):
+            raise TypeError("dlopen(name): name must be a file name, None, "
+                            "or an already-opened 'void *' handle")
         with self._lock:
             lib, function_cache = _make_ffi_library(self, name, flags)
             self._function_caches.append(function_cache)
@@ -799,9 +803,9 @@
 
 def _load_backend_lib(backend, name, flags):
     import os
-    if name is None:
-        if sys.platform != "win32":
-            return backend.load_library(None, flags)
+    if not isinstance(name, basestring):
+        if sys.platform != "win32" or name is not None:
+            return backend.load_library(name, flags)
         name = "c"    # Windows: load_library(None) fails, but this works
                       # on Python 2 (backward compatibility hack only)
     first_error = None
@@ -935,7 +939,7 @@
             backendlib.close_lib()
             self.__dict__.clear()
     #
-    if libname is not None:
+    if isinstance(libname, basestring):
         try:
             if not isinstance(libname, str):    # unicode, on Python 2
                 libname = libname.encode('utf-8')
diff --git a/pypy/module/_cffi_backend/cdlopen.py b/pypy/module/_cffi_backend/cdlopen.py
--- a/pypy/module/_cffi_backend/cdlopen.py
+++ b/pypy/module/_cffi_backend/cdlopen.py
@@ -15,10 +15,11 @@
 
     def __init__(self, ffi, w_filename, flags):
         space = ffi.space
-        fname, handle = misc.dlopen_w(space, w_filename, flags)
+        fname, handle, autoclose = misc.dlopen_w(space, w_filename, flags)
         W_LibObject.__init__(self, ffi, fname)
         self.libhandle = handle
-        self.register_finalizer(space)
+        if autoclose:
+            self.register_finalizer(space)
 
     def _finalize_(self):
         h = self.libhandle
diff --git a/pypy/module/_cffi_backend/libraryobj.py b/pypy/module/_cffi_backend/libraryobj.py
--- a/pypy/module/_cffi_backend/libraryobj.py
+++ b/pypy/module/_cffi_backend/libraryobj.py
@@ -18,8 +18,10 @@
 
     def __init__(self, space, w_filename, flags):
         self.space = space
-        self.name, self.handle = misc.dlopen_w(space, w_filename, flags)
-        self.register_finalizer(space)
+        self.name, self.handle, autoclose = (
+            misc.dlopen_w(space, w_filename, flags))
+        if autoclose:
+            self.register_finalizer(space)
 
     def _finalize_(self):
         h = self.handle
diff --git a/pypy/module/_cffi_backend/misc.py b/pypy/module/_cffi_backend/misc.py
--- a/pypy/module/_cffi_backend/misc.py
+++ b/pypy/module/_cffi_backend/misc.py
@@ -8,7 +8,7 @@
 from rpython.rlib.objectmodel import specialize, we_are_translated
 from rpython.rlib.rarithmetic import r_uint, r_ulonglong
 from rpython.rlib.unroll import unrolling_iterable
-from rpython.rlib.rdynload import dlopen, DLOpenError
+from rpython.rlib.rdynload import dlopen, DLOpenError, DLLHANDLE
 from rpython.rtyper.lltypesystem import lltype, llmemory, rffi
 from rpython.translator.tool.cbuild import ExternalCompilationInfo
 
@@ -398,7 +398,26 @@
 # ____________________________________________________________
 
 def dlopen_w(space, w_filename, flags):
-    if WIN32 and space.isinstance_w(w_filename, space.w_unicode):
+    from pypy.module._cffi_backend.cdataobj import W_CData
+    from pypy.module._cffi_backend import ctypeptr
+
+    autoclose = True
+    if isinstance(w_filename, W_CData):
+        # 'flags' ignored in this case
+        w_ctype = w_filename.ctype
+        if (not isinstance(w_ctype, ctypeptr.W_CTypePointer) or
+            not w_ctype.is_void_ptr):
+            raise oefmt(space.w_TypeError,
+                    "dlopen() takes a file name or 'void *' handle, not '%s'",
+                    w_ctype.name)
+        handle = w_filename.unsafe_escaping_ptr()
+        if not handle:
+            raise oefmt(space.w_RuntimeError, "cannot call dlopen(NULL)")
+        fname = w_ctype.extra_repr(handle)
+        handle = rffi.cast(DLLHANDLE, handle)
+        autoclose = False
+        #
+    elif WIN32 and space.isinstance_w(w_filename, space.w_unicode):
         fname = space.text_w(space.repr(w_filename))
         utf8_name = space.utf8_w(w_filename)
         uni_len = space.len_w(w_filename)
@@ -419,4 +438,4 @@
                 handle = dlopen(ll_libname, flags)
             except DLOpenError as e:
                 raise wrap_dlopenerror(space, e, fname)
-    return fname, handle
+    return fname, handle, autoclose
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -308,8 +308,8 @@
             w_FFIError = get_ffi_error(w_ctype.space)
             raise oefmt(w_FFIError,
                     '%s: %s%s%s (cdef says %d, but C compiler says %d).'
-                    ' fix it or use "...;" in the cdef for %s to '
-                    'make it flexible',
+                    ' fix it or use "...;" as the last field in the '
+                    'cdef for %s to make it flexible',
                     w_ctype.name, msg1, msg2, msg3,
                     cdef_value, compiler_value, w_ctype.name)
         w_ctype._custom_field_pos = True
diff --git a/pypy/module/_cffi_backend/test/test_re_python.py b/pypy/module/_cffi_backend/test/test_re_python.py
--- a/pypy/module/_cffi_backend/test/test_re_python.py
+++ b/pypy/module/_cffi_backend/test/test_re_python.py
@@ -75,6 +75,9 @@
         typedef struct bar_s { int x; signed char a[]; } bar_t;
         enum foo_e { AA, BB, CC };
         typedef struct selfref { struct selfref *next; } *selfref_ptr_t;
+
+        void *dlopen(const char *filename, int flags);
+        int dlclose(void *handle);
         """)
         ffi.set_source('re_python_pysrc', None)
         ffi.emit_python_code(str(tmpdir.join('re_python_pysrc.py')))
@@ -96,6 +99,11 @@
             return fix_path
         """)
 
+        cls.w_dl_libpath = space.w_None
+        if sys.platform != 'win32':
+            import ctypes.util
+            cls.w_dl_libpath = space.wrap(ctypes.util.find_library('dl'))
+
     def teardown_method(self, meth):
         self.space.appexec([], """():
             import sys
@@ -244,3 +252,22 @@
         self.fix_path()
         from re_python_pysrc import ffi
         ffi.new("selfref_ptr_t")
+
+    def test_dlopen_handle(self):
+        import _cffi_backend, sys
+        self.fix_path()
+        from re_python_pysrc import ffi
+        if self.dl_libpath is None:
+            py.test.skip("uses 'dl' explicitly")
+        lib1 = ffi.dlopen(self.dl_libpath)
+        handle = lib1.dlopen(self.extmod.encode(sys.getfilesystemencoding()),
+                             _cffi_backend.RTLD_LAZY)
+        assert ffi.typeof(handle) == ffi.typeof("void *")
+        assert handle
+
+        lib = ffi.dlopen(handle)
+        assert lib.add42(-10) == 32
+        assert type(lib.add42) is _cffi_backend.FFI.CData
+
+        err = lib1.dlclose(handle)
+        assert err == 0
diff --git a/pypy/module/_cffi_backend/test/test_recompiler.py b/pypy/module/_cffi_backend/test/test_recompiler.py
--- a/pypy/module/_cffi_backend/test/test_recompiler.py
+++ b/pypy/module/_cffi_backend/test/test_recompiler.py
@@ -343,9 +343,9 @@
             'test_verify_exact_field_offset',
             """struct foo_s { short a; int b; };""")
         e = raises(ffi.error, ffi.new, "struct foo_s *", [])    # lazily
-        assert str(e.value) == ("struct foo_s: wrong offset for field 'b' (cdef "
-                           'says 0, but C compiler says 4). fix it or use "...;" '
-                           "in the cdef for struct foo_s to make it flexible")
+        assert str(e.value).startswith(
+            "struct foo_s: wrong offset for field 'b' (cdef "
+            'says 0, but C compiler says 4). fix it or use "...;" ')
 
     def test_type_caching(self):
         ffi1, lib1 = self.prepare(


More information about the pypy-commit mailing list