Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r3283:f34ec7d90cd6
Date: 2019-07-23 06:37 +0200
http://bitbucket.org/cffi/cffi/changeset/f34ec7d90cd6/

Log:    Issue #413

        Test and "fix" for a corner case: now it gives a RuntimeError with a
        message, instead of a C-level infinite recursion

diff --git a/c/realize_c_type.c b/c/realize_c_type.c
--- a/c/realize_c_type.c
+++ b/c/realize_c_type.c
@@ -413,19 +413,12 @@
 }
 
 static PyObject *
-realize_c_type_or_func(builder_c_t *builder,
-                        _cffi_opcode_t opcodes[], int index)
+realize_c_type_or_func_now(builder_c_t *builder, _cffi_opcode_t op,
+                           _cffi_opcode_t opcodes[], int index)
 {
     PyObject *x, *y, *z;
-    _cffi_opcode_t op = opcodes[index];
     Py_ssize_t length = -1;
 
-    if ((((uintptr_t)op) & 1) == 0) {
-        x = (PyObject *)op;
-        Py_INCREF(x);
-        return x;
-    }
-
     switch (_CFFI_GETOP(op)) {
 
     case _CFFI_OP_PRIMITIVE:
@@ -638,11 +631,40 @@
         break;
     }
 
+    case 255:    /* recursion detection */
+        PyErr_Format(PyExc_RuntimeError,
+            "found a situation in which we try to build a type recursively.  "
+            "This is known to occur e.g. in ``struct s { void(*callable)"
+            "(struct s); }''.  Please report if you get this error and "
+            "really need support for your case.");
+        return NULL;
+
     default:
         PyErr_Format(PyExc_NotImplementedError, "op=%d", (int)_CFFI_GETOP(op));
         return NULL;
     }
 
+    return x;
+}
+
+static PyObject *
+realize_c_type_or_func(builder_c_t *builder,
+                        _cffi_opcode_t opcodes[], int index)
+{
+    PyObject *x;
+     _cffi_opcode_t op = opcodes[index];
+
+    if ((((uintptr_t)op) & 1) == 0) {
+        x = (PyObject *)op;
+        Py_INCREF(x);
+        return x;
+    }
+
+    opcodes[index] = (_cffi_opcode_t)255;   /* recursion detection */
+    x = realize_c_type_or_func_now(builder, op, opcodes, index);
+    if (opcodes[index] == (_cffi_opcode_t)255)
+        opcodes[index] = op;
+
     if (x != NULL && opcodes == builder->ctx.types && opcodes[index] != x) {
         assert((((uintptr_t)x) & 1) == 0);
         assert((((uintptr_t)opcodes[index]) & 1) == 1);
@@ -650,7 +672,7 @@
         opcodes[index] = x;
     }
     return x;
-};
+}
 
 static CTypeDescrObject *
 realize_c_func_return_type(builder_c_t *builder,
diff --git a/testing/cffi1/test_recompiler.py b/testing/cffi1/test_recompiler.py
--- a/testing/cffi1/test_recompiler.py
+++ b/testing/cffi1/test_recompiler.py
@@ -2412,3 +2412,15 @@
     a = ffi.new("struct A *")
     assert ffi.sizeof(a[0]) == ffi.sizeof("unsigned")
     assert ffi.sizeof(b[0]) == ffi.sizeof(a[0])
+
+def test_struct_with_func_with_struct_arg():
+    ffi = FFI()
+    ffi.cdef("""struct BinaryTree {
+            int (* CompareKey)(struct BinaryTree tree);
+        };""")
+    lib = verify(ffi, "test_struct_with_func_with_struct_arg", """
+        struct BinaryTree {
+            int (* CompareKey)(struct BinaryTree tree);
+        };
+    """)
+    py.test.raises(RuntimeError, ffi.new, "struct BinaryTree *")
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to