Commits

Armin Rigo committed 419181f

Test and fix for an obscure case that raised SystemError instead of
the proper TypeError.

  • Participants
  • Parent commits a8283f7

Comments (0)

Files changed (2)

File c/_cffi_backend.c

         /* then enough room for the result --- which means at least
            sizeof(ffi_arg), according to the ffi docs */
         i = fb->rtype->size;
-        if (i < sizeof(ffi_arg))
+        if (i < (Py_ssize_t)sizeof(ffi_arg))
             i = sizeof(ffi_arg);
         exchange_offset += i;
     }
     /* work work work around a libffi irregularity: for integer return
        types we have to fill at least a complete 'ffi_arg'-sized result
        buffer. */
-    if (ctype->ct_size < sizeof(ffi_arg)) {
+    if (ctype->ct_size < (Py_ssize_t)sizeof(ffi_arg)) {
+        if (ctype->ct_flags & CT_VOID) {
+            if (pyobj == Py_None) {
+                return 0;
+            }
+            else {
+                PyErr_SetString(PyExc_TypeError,
+                    "callback with the return type 'void' must return None");
+                return -1;
+            }
+        }
         if ((ctype->ct_flags & (CT_PRIMITIVE_SIGNED | CT_IS_ENUM))
                 == CT_PRIMITIVE_SIGNED) {
             PY_LONG_LONG value;
     py_res = PyEval_CallObject(py_ob, py_args);
     if (py_res == NULL)
         goto error;
-
-    if (SIGNATURE(1)->ct_size > 0) {
-        if (convert_from_object_fficallback(result, SIGNATURE(1), py_res) < 0)
-            goto error;
-    }
-    else if (py_res != Py_None) {
-        PyErr_SetString(PyExc_TypeError, "callback with the return type 'void'"
-                                         " must return None");
+    if (convert_from_object_fficallback(result, SIGNATURE(1), py_res) < 0)
         goto error;
-    }
  done:
     Py_XDECREF(py_args);
     Py_XDECREF(py_res);
 
     ctresult = (CTypeDescrObject *)PyTuple_GET_ITEM(ct->ct_stuff, 1);
     size = ctresult->ct_size;
-    if (ctresult->ct_flags & (CT_PRIMITIVE_CHAR | CT_PRIMITIVE_SIGNED |
-                              CT_PRIMITIVE_UNSIGNED)) {
-        if (size < sizeof(ffi_arg))
-            size = sizeof(ffi_arg);
-    }
-    else if (size < 0) {
-        size = 0;
-    }
+    if (size < (Py_ssize_t)sizeof(ffi_arg))
+        size = sizeof(ffi_arg);
     py_rawerr = PyString_FromStringAndSize(NULL, size);
     if (py_rawerr == NULL)
         return NULL;
     assert s.a == -10
     assert s.b == 1E-42
 
+def test_callback_returning_void():
+    BVoid = new_void_type()
+    BFunc = new_function_type((), BVoid, False)
+    def cb():
+        seen.append(42)
+    f = callback(BFunc, cb)
+    seen = []
+    f()
+    assert seen == [42]
+    py.test.raises(TypeError, callback, BFunc, cb, -42)
+
 def test_enum_type():
     BEnum = new_enum_type("foo", (), ())
     assert repr(BEnum) == "<ctype 'enum foo'>"