[pypy-commit] cffi default: More Windows support for ffi.dlopen(), this time the out-of-line version

arigo pypy.commits at gmail.com
Fri Feb 16 05:23:22 EST 2018


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r3100:5448f4eca09c
Date: 2018-02-16 11:22 +0100
http://bitbucket.org/cffi/cffi/changeset/5448f4eca09c/

Log:	More Windows support for ffi.dlopen(), this time the out-of-line
	version

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -4145,49 +4145,56 @@
     dl_methods,                         /* tp_methods */
 };
 
-static PyObject *b_load_library(PyObject *self, PyObject *args)
-{
-    char *filename_or_null, *printable_filename;
-    PyObject *s = NULL;
+static void *b_do_dlopen(PyObject *args, char **p_printable_filename,
+                         PyObject **p_temp)
+{
+    /* Logic to call the correct version of dlopen().  Returns NULL in case of error.
+       Otherwise, '*p_printable_filename' will point to a printable char version of
+       the filename (maybe utf-8-encoded).  '*p_temp' will be set either to NULL or
+       to a temporary object that must be freed after looking at printable_filename.
+    */
     void *handle;
-    DynLibObject *dlobj = NULL;
+    char *filename_or_null;
     int flags = 0;
-
+    *p_temp = NULL;
+    
     if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) {
         PyObject *dummy;
         if (!PyArg_ParseTuple(args, "|Oi:load_library",
                               &dummy, &flags))
             return NULL;
         filename_or_null = NULL;
-        printable_filename = "<None>";
+        *p_printable_filename = "<None>";
     }
     else
     {
-        printable_filename = NULL;
-        s = PyObject_Repr(PyTuple_GET_ITEM(args, 0));
-        if (s != NULL) {
-            printable_filename = PyText_AsUTF8(s);
-        }
-        if (printable_filename == NULL) {
-            PyErr_Clear();
-            printable_filename = "?";
-        }
-
+        PyObject *s = PyTuple_GET_ITEM(args, 0);
 #ifdef MS_WIN32
+        Py_UNICODE *filenameW;
+        if (PyArg_ParseTuple(args, "u|i:load_library", &filenameW, &flags))
         {
-            Py_UNICODE *filenameW;
-            if (PyArg_ParseTuple(args, "u|i:load_library", &filenameW, &flags))
-            {
-                handle = dlopenW(filenameW);
-                goto got_handle;
-            }
-            PyErr_Clear();
-        }
+#if PY_MAJOR_VERSION < 3
+            s = PyUnicode_AsUTF8String(s);
+            if (s == NULL)
+                return NULL;
+            *p_temp = s;
+#endif
+            *p_printable_filename = PyText_AsUTF8(s);
+            if (*p_printable_filename == NULL)
+                return NULL;
+
+            handle = dlopenW(filenameW);
+            goto got_handle;
+        }
+        PyErr_Clear();
 #endif
         if (!PyArg_ParseTuple(args, "et|i:load_library",
-            Py_FileSystemDefaultEncoding, &filename_or_null,
-            &flags))
-            goto error;
+                     Py_FileSystemDefaultEncoding, &filename_or_null, &flags))
+            return NULL;
+
+        *p_printable_filename = PyText_AsUTF8(s);
+        if (*p_printable_filename == NULL)
+            return NULL;
     }
     if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
         flags |= RTLD_NOW;
@@ -4199,10 +4206,23 @@
 #endif
     if (handle == NULL) {
         const char *error = dlerror();
-        PyErr_Format(PyExc_OSError, "cannot load library %s: %s",
-                     printable_filename, error);
+        PyErr_Format(PyExc_OSError, "cannot load library '%s': %s",
+                     *p_printable_filename, error);
+        return NULL;
+    }
+    return handle;
+}
+
+static PyObject *b_load_library(PyObject *self, PyObject *args)
+{
+    char *printable_filename;
+    PyObject *temp;
+    void *handle;
+    DynLibObject *dlobj = NULL;
+
+    handle = b_do_dlopen(args, &printable_filename, &temp);
+    if (handle == NULL)
         goto error;
-    }
 
     dlobj = PyObject_New(DynLibObject, &dl_type);
     if (dlobj == NULL) {
@@ -4211,9 +4231,9 @@
     }
     dlobj->dl_handle = handle;
     dlobj->dl_name = strdup(printable_filename);
-
+ 
  error:
-    Py_XDECREF(s);
+    Py_XDECREF(temp);
     return (PyObject *)dlobj;
 }
 
diff --git a/c/cdlopen.c b/c/cdlopen.c
--- a/c/cdlopen.c
+++ b/c/cdlopen.c
@@ -40,35 +40,18 @@
 
 static PyObject *ffi_dlopen(PyObject *self, PyObject *args)
 {
-    char *filename_or_null, *printable_filename;
+    char *modname;
+    PyObject *temp, *result = NULL;
     void *handle;
-    int flags = 0;
 
-    if (PyTuple_GET_SIZE(args) == 0 || PyTuple_GET_ITEM(args, 0) == Py_None) {
-        PyObject *dummy;
-        if (!PyArg_ParseTuple(args, "|Oi:load_library",
-                              &dummy, &flags))
-            return NULL;
-        filename_or_null = NULL;
+    handle = b_do_dlopen(args, &modname, &temp);
+    if (handle != NULL)
+    {
+        result = (PyObject *)lib_internal_new((FFIObject *)self,
+                                              modname, handle);
     }
-    else if (!PyArg_ParseTuple(args, "et|i:load_library",
-                          Py_FileSystemDefaultEncoding, &filename_or_null,
-                          &flags))
-        return NULL;
-
-    if ((flags & (RTLD_NOW | RTLD_LAZY)) == 0)
-        flags |= RTLD_NOW;
-    printable_filename = filename_or_null ? filename_or_null : "<None>";
-
-    handle = dlopen(filename_or_null, flags);
-    if (handle == NULL) {
-        const char *error = dlerror();
-        PyErr_Format(PyExc_OSError, "cannot load library '%s': %s",
-                     printable_filename, error);
-        return NULL;
-    }
-    return (PyObject *)lib_internal_new((FFIObject *)self,
-                                        printable_filename, handle);
+    Py_XDECREF(temp);
+    return result;
 }
 
 static PyObject *ffi_dlclose(PyObject *self, PyObject *args)
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
@@ -1,8 +1,9 @@
-import sys
+import sys, os
 import py
 from cffi import FFI
 from cffi import recompiler, ffiplatform, VerificationMissing
 from testing.udir import udir
+from testing.support import u
 
 
 def setup_module(mod):
@@ -35,6 +36,13 @@
                         'globalconst42', 'globalconsthello']
     )
     outputfilename = ffiplatform.compile(str(tmpdir), ext)
+    if sys.platform == "win32":
+        # test with a non-ascii char
+        outputfn1 = outputfilename
+        ofn, oext = os.path.splitext(outputfn1)
+        outputfilename = ofn + (u+'\u03be') + oext
+        #print(repr(outputfn1) + ' ==> ' + repr(outputfilename))
+        os.rename(outputfn1, outputfilename)
     mod.extmod = outputfilename
     mod.tmpdir = tmpdir
     #
@@ -107,12 +115,16 @@
     from re_python_pysrc import ffi
     lib = ffi.dlopen(extmod)
     ffi.dlclose(lib)
+    if type(extmod) is not str:   # unicode, on python 2
+        str_extmod = extmod.encode('utf-8')
+    else:
+        str_extmod = extmod
     e = py.test.raises(ffi.error, ffi.dlclose, lib)
     assert str(e.value).startswith(
-        "library '%s' is already closed" % (extmod,))
+        "library '%s' is already closed" % (str_extmod,))
     e = py.test.raises(ffi.error, getattr, lib, 'add42')
     assert str(e.value) == (
-        "library '%s' has been closed" % (extmod,))
+        "library '%s' has been closed" % (str_extmod,))
 
 def test_constant_via_lib():
     from re_python_pysrc import ffi


More information about the pypy-commit mailing list