[pypy-commit] cffi cffi-1.0: ffi.dlclose(). Global variables.

arigo noreply at buildbot.pypy.org
Sat May 16 14:25:26 CEST 2015


Author: Armin Rigo <arigo at tunes.org>
Branch: cffi-1.0
Changeset: r2014:f077a8aeded1
Date: 2015-05-16 14:26 +0200
http://bitbucket.org/cffi/cffi/changeset/f077a8aeded1/

Log:	ffi.dlclose(). Global variables.

diff --git a/c/cdlopen.c b/c/cdlopen.c
--- a/c/cdlopen.c
+++ b/c/cdlopen.c
@@ -73,23 +73,27 @@
 static PyObject *ffi_dlclose(PyObject *self, PyObject *args)
 {
     LibObject *lib;
+    void *libhandle;
     if (!PyArg_ParseTuple(args, "O!", &Lib_Type, &lib))
         return NULL;
 
-    if (lib->l_libhandle == NULL) {
+    libhandle = lib->l_libhandle;
+    lib->l_libhandle = NULL;
+
+    if (libhandle == NULL) {
         PyErr_Format(FFIError, "library '%s' is already closed "
                      "or was not created with ffi.dlopen()",
-                     PyText_AS_UTF8(lib->l_libhandle));
+                     PyText_AS_UTF8(lib->l_libname));
         return NULL;
     }
 
-    if (cdlopen_close(lib->l_libname, lib->l_libhandle) < 0)
-        return NULL;
-
     /* Clear the dict to force further accesses to do cdlopen_fetch()
        again, and fail because the library was closed. */
     PyDict_Clear(lib->l_dict);
 
+    if (cdlopen_close(lib->l_libname, libhandle) < 0)
+        return NULL;
+
     Py_INCREF(Py_None);
     return Py_None;
 }
diff --git a/c/lib_obj.c b/c/lib_obj.c
--- a/c/lib_obj.c
+++ b/c/lib_obj.c
@@ -139,6 +139,7 @@
         return NULL;
     }
     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;
@@ -250,6 +251,7 @@
         if (ct == NULL)
             return NULL;
 
+        assert(g->address);
         assert(ct->ct_size > 0);
         data = alloca(ct->ct_size);
         ((void(*)(char*))g->address)(data);
@@ -272,20 +274,22 @@
             x = NULL;
         }
         else {
-            x = make_global_var(ct, g->address);
+            void *address = g->address;
+            if (address == NULL) {
+                /* for dlopen() style */
+                address = cdlopen_fetch(lib->l_libname, lib->l_libhandle, s);
+            }
+            x = make_global_var(ct, address);
         }
         Py_DECREF(ct);
         break;
 
-    case _CFFI_OP_DLOPEN:
+    case _CFFI_OP_DLOPEN_FUNC:
     {
-        /* For dlopen(): the function or global variable of the given
-           'name'.  We use dlsym() to get the address of something in
-           the dynamic library, which we interpret as being exactly of
-           the specified type.  If this type is a function (not a
-           function pointer), then we assume it is a regular function
-           in the dynamic library; otherwise, we assume it is a global
-           variable.
+        /* 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);
@@ -298,10 +302,8 @@
         if (ct1 == NULL)
             return NULL;
 
-        if (CTypeDescr_Check(ct1))
-            x = make_global_var((CTypeDescrObject *)ct1, address);
-        else
-            x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1));
+        assert(!CTypeDescr_Check(ct1));   /* must be a function */
+        x = new_simple_cdata(address, unwrap_fn_as_fnptr(ct1));
 
         Py_DECREF(ct1);
         break;
diff --git a/cffi/cffi_opcode.py b/cffi/cffi_opcode.py
--- a/cffi/cffi_opcode.py
+++ b/cffi/cffi_opcode.py
@@ -51,7 +51,7 @@
 OP_CONSTANT        = 29
 OP_CONSTANT_INT    = 31
 OP_GLOBAL_VAR      = 33
-OP_DLOPEN          = 35
+OP_DLOPEN_FUNC     = 35
 
 PRIM_VOID          = 0
 PRIM_BOOL          = 1
diff --git a/cffi/parse_c_type.h b/cffi/parse_c_type.h
--- a/cffi/parse_c_type.h
+++ b/cffi/parse_c_type.h
@@ -24,7 +24,7 @@
 #define _CFFI_OP_CONSTANT       29
 #define _CFFI_OP_CONSTANT_INT   31
 #define _CFFI_OP_GLOBAL_VAR     33
-#define _CFFI_OP_DLOPEN         35
+#define _CFFI_OP_DLOPEN_FUNC    35
 
 #define _CFFI_PRIM_VOID          0
 #define _CFFI_PRIM_BOOL          1
diff --git a/cffi/recompiler.py b/cffi/recompiler.py
--- a/cffi/recompiler.py
+++ b/cffi/recompiler.py
@@ -706,7 +706,7 @@
         type_index = self._typesdict[tp.as_raw_function()]
         numargs = len(tp.args)
         if self.target_is_python:
-            meth_kind = OP_DLOPEN
+            meth_kind = OP_DLOPEN_FUNC
         elif numargs == 0:
             meth_kind = OP_CPYTHON_BLTN_N   # 'METH_NOARGS'
         elif numargs == 1:
diff --git a/testing/cffi1/test_dlopen.py b/testing/cffi1/test_dlopen.py
--- a/testing/cffi1/test_dlopen.py
+++ b/testing/cffi1/test_dlopen.py
@@ -1,5 +1,5 @@
 import py
-from cffi import FFI, VerificationError
+from cffi import FFI, VerificationError, CDefError
 from cffi.recompiler import make_py_source
 from testing.udir import udir
 
@@ -29,6 +29,23 @@
         "the value of constant 'BB' (only integer constants are "
         "supported, and only if their value are specified in the cdef)")
 
+def test_invalid_global_constant_2():
+    ffi = FFI()
+    ffi.cdef("static const float BB = 12;")
+    target = udir.join('test_invalid_global_constants_2.py')
+    e = py.test.raises(VerificationError, make_py_source, ffi,
+                       'test_invalid_global_constants_2', str(target))
+    assert str(e.value) == (
+        "ffi.dlopen() will not be able to figure out "
+        "the value of constant 'BB' (only integer constants are "
+        "supported, and only if their value are specified in the cdef)")
+
+def test_invalid_global_constant_3():
+    ffi = FFI()
+    e = py.test.raises(CDefError, ffi.cdef, "#define BB 12.34")
+    assert str(e.value).startswith(
+        "only supports one of the following syntax:")
+
 def test_invalid_dotdotdot_in_macro():
     ffi = FFI()
     ffi.cdef("#define FOO ...")
@@ -176,3 +193,17 @@
     target = udir.join('test_array_overflow.py')
     py.test.raises(OverflowError, make_py_source,
                    ffi, 'test_array_overflow', str(target))
+
+def test_global_var():
+    ffi = FFI()
+    ffi.cdef("int myglob;")
+    target = udir.join('test_global_var.py')
+    assert make_py_source(ffi, 'test_global_var', str(target))
+    assert target.read() == r"""# auto-generated file
+import _cffi_backend
+
+ffi = _cffi_backend.FFI(b'test_global_var',
+    _types = b'\x00\x00\x07\x01',
+    _globals = (b'\x00\x00\x00\x21myglob',0,),
+)
+"""
diff --git a/testing/cffi1/test_re_python.py b/testing/cffi1/test_re_python.py
--- a/testing/cffi1/test_re_python.py
+++ b/testing/cffi1/test_re_python.py
@@ -12,6 +12,7 @@
     #define BIGPOS 420000000000L
     #define BIGNEG -420000000000L
     int add42(int x) { return x + 42; }
+    int globalvar42 = 1234;
     struct foo_s;
     typedef struct bar_s { int x; signed char a[]; } bar_t;
     enum foo_e { AA, BB, CC };
@@ -32,6 +33,7 @@
     #define BIGPOS 420000000000L
     #define BIGNEG -420000000000L
     int add42(int);
+    int globalvar42;
     struct foo_s;
     typedef struct bar_s { int x; signed char a[]; } bar_t;
     enum foo_e { AA, BB, CC };
@@ -54,9 +56,21 @@
     assert ffi.integer_const('BIGNEG') == -420000000000
 
 def test_function():
+    import _cffi_backend
     from re_python_pysrc import ffi
     lib = ffi.dlopen(extmod)
     assert lib.add42(-10) == 32
+    assert type(lib.add42) is _cffi_backend.FFI.CData
+
+def test_dlclose():
+    import _cffi_backend
+    from re_python_pysrc import ffi
+    lib = ffi.dlopen(extmod)
+    ffi.dlclose(lib)
+    e = py.test.raises(ffi.error, ffi.dlclose, lib)
+    assert str(e.value) == (
+        "library '%s' is already closed or was not created with ffi.dlopen()"
+        % (extmod,))
 
 def test_constant_via_lib():
     from re_python_pysrc import ffi
@@ -103,3 +117,13 @@
     #
     p = ffi.new("bar_t *", [5, "foobar"])
     assert p.a[4] == ord('a')
+
+def test_global_var():
+    from re_python_pysrc import ffi
+    lib = ffi.dlopen(extmod)
+    assert lib.globalvar42 == 1234
+    p = ffi.addressof(lib, 'globalvar42')
+    lib.globalvar42 += 5
+    assert p[0] == 1239
+    p[0] -= 1
+    assert lib.globalvar42 == 1238


More information about the pypy-commit mailing list