Commits

Armin Rigo committed fe77462

Accept Python strings or random pointers for a "void *" function argument.

Comments (0)

Files changed (4)

c/_cffi_backend.c

     if (PyBytes_Check(init)) {
         /* from a string: just returning the string here is fine.
            We assume that the C code won't modify the 'char *' data. */
-        if ((ctitem->ct_flags & CT_PRIMITIVE_CHAR) &&
-                (ctitem->ct_size == sizeof(char))) {
+        if (ctptr->ct_flags & CT_CAST_ANYTHING) {
             output_data[0] = PyBytes_AS_STRING(init);
             return 1;
         }
     return result;
 }
 
+static int _testfunc23(char *p)
+{
+    return 1000 * p[0];
+}
+
 static PyObject *b__testfunc(PyObject *self, PyObject *args)
 {
     /* for testing only */
     case 20: f = &_testfunc20; break;
     case 21: f = &_testfunc21; break;
     case 22: f = &_testfunc22; break;
+    case 23: f = &_testfunc23; break;
     default:
         PyErr_SetNone(PyExc_ValueError);
         return NULL;
     if (CData_Check(obj)) {
         return ((CDataObject *)obj)->c_data;
     }
-    _convert_error(obj, "char *", "compatible pointer");
+    _convert_error(obj, "char * or void *", "compatible pointer");
     return NULL;
 }
 
     for i in range(10):
         assert res.a[i] == p1.a[i] - p2.a[i]
 
+def test_call_function_23():
+    BVoid = new_void_type()          # declaring the function as int(void*)
+    BVoidP = new_pointer_type(BVoid)
+    BInt = new_primitive_type("int")
+    BFunc23 = new_function_type((BVoidP,), BInt, False)
+    f = cast(BFunc23, _testfunc(23))
+    res = f(b"foo")
+    assert res == 1000 * ord(b'f')
+
 def test_cannot_pass_struct_with_array_of_length_0():
     BInt = new_primitive_type("int")
     BArray0 = new_array_type(new_pointer_type(BInt), 0)

cffi/vengine_cpy.py

             errvalue = '-1'
         #
         elif isinstance(tp, model.PointerType):
-            if (isinstance(tp.totype, model.PrimitiveType) and
-                    tp.totype.name == 'char'):
+            if ((isinstance(tp.totype, model.PrimitiveType) and
+                    tp.totype.name == 'char') or
+                 isinstance(tp.totype, model.VoidType)):
                 converter = '_cffi_to_c_char_p'
             else:
                 converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('')

testing/test_verify.py

                        "int myfunc(enum foo_e x) { return (int)x; }")
     res = lib2.myfunc("AA")
     assert res == 2
+
+def test_string_to_voidp_arg():
+    ffi = FFI()
+    ffi.cdef("int myfunc(void *);")
+    lib = ffi.verify("int myfunc(void *p) { return ((signed char *)p)[0]; }")
+    res = lib.myfunc(b"hi!")
+    assert res == ord(b"h")
+    p = ffi.new("char[]", b"gah")
+    res = lib.myfunc(p)
+    assert res == ord(b"g")
+    res = lib.myfunc(ffi.cast("void *", p))
+    assert res == ord(b"g")
+    res = lib.myfunc(ffi.cast("int *", p))
+    assert res == ord(b"g")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.