Author: Matti Picus <[email protected]>
Branch: warn-no-ref-kept
Changeset: r2871:ce17083bac2b
Date: 2017-01-23 23:36 +0200
http://bitbucket.org/cffi/cffi/changeset/ce17083bac2b/

Log:    proof-of-concept issue a warning if assigning a dead object to a
        struct field

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -2503,6 +2503,13 @@
 {
     CFieldObject *cf;
     CTypeDescrObject *ct = cd->c_type;
+    if (value && (CDataOwn_Check(value) || Py_TYPE(value) == &CDataGCP_Type) 
&& (value->ob_refcnt == 1))
+    {
+        if (PyErr_WarnEx(PyExc_UserWarning, 
+            "setting a struct field with a non-referenced value, expect 
trouble", 1))
+                return -1;
+    }
+
 
     if (ct->ct_flags & CT_POINTER)
         ct = ct->ct_itemdescr;
diff --git a/testing/cffi0/test_ffi_backend.py 
b/testing/cffi0/test_ffi_backend.py
--- a/testing/cffi0/test_ffi_backend.py
+++ b/testing/cffi0/test_ffi_backend.py
@@ -128,6 +128,27 @@
         alloc5 = ffi.new_allocator(myalloc5)
         py.test.raises(MemoryError, alloc5, "int[5]")
 
+    def test_no_ref_kept(self):
+        import gc, numpy as np
+        ffi = FFI(backend=self.Backend())
+        seen = []
+        def myalloc(size):
+            seen.append(size)
+            return ffi.new("char[]", b"X" * size)
+        def myfree(raw):
+            seen.append(raw)
+        ffi.cdef('typedef struct {char * buf;} vstruct;')
+        alloc = ffi.new_allocator(myalloc, myfree)
+        vstruct = ffi.new('vstruct[1]')
+        b = np.empty(10, dtype='uint8')
+        vstruct[0].buf = ffi.cast('char*', b.ctypes.data)
+        with pytest.warns(UserWarning):
+            vstruct[0].buf = alloc('char[]', chr(100) * 100)
+        for i in range(10):
+            gc.collect()    
+            if len(seen) > 1:
+                break
+        assert len(seen) == 2
 
 class TestBitfield:
     def check(self, source, expected_ofs_y, expected_align, expected_size):
@@ -505,3 +526,5 @@
             py.test.raises(TypeError, cd)
             py.test.raises(TypeError, cd, ffi.NULL)
             py.test.raises(TypeError, cd, ffi.typeof("void *"))
+
+
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to