[pypy-commit] cffi default: Decided to fix ffi.sizeof() too. Update the documentation.

arigo pypy.commits at gmail.com
Thu Oct 27 11:21:55 EDT 2016


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r2800:5ef556ba98f2
Date: 2016-10-27 17:21 +0200
http://bitbucket.org/cffi/cffi/changeset/5ef556ba98f2/

Log:	Decided to fix ffi.sizeof() too. Update the documentation.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -5492,8 +5492,11 @@
 
         if (cd->c_type->ct_flags & CT_ARRAY)
             size = get_array_length(cd) * cd->c_type->ct_itemdescr->ct_size;
-        else
-            size = cd->c_type->ct_size;
+        else {
+            size = _cdata_var_byte_size(cd);
+            if (size < 0)
+                size = cd->c_type->ct_size;
+        }
     }
     else if (CTypeDescr_Check(arg)) {
         size = ((CTypeDescrObject *)arg)->ct_size;
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -3202,6 +3202,7 @@
         assert len(p.y) == 3
         assert len(p[0].y) == 3
         assert len(buffer(p)) == sizeof(BInt) * 4
+        assert sizeof(p[0]) == sizeof(BInt) * 4
         plist.append(p)
     for i in range(20):
         p = plist[i]
@@ -3220,6 +3221,7 @@
         sizeof(BStruct) + 3 * sizeof(BInt),)
     assert repr(p[0]) == "<cdata 'foo' owning %d bytes>" % (
         sizeof(BStruct) + 3 * sizeof(BInt),)
+    assert sizeof(p[0]) == sizeof(BStruct) + 3 * sizeof(BInt)
     #
     # from a non-owning pointer, we can't get the length
     q = cast(new_pointer_type(BStruct), p)
@@ -3229,6 +3231,7 @@
     py.test.raises(TypeError, len, q[0].y)
     assert typeof(q.y) is BIntP
     assert typeof(q[0].y) is BIntP
+    assert sizeof(q[0]) == sizeof(BStruct)
     #
     # error cases
     py.test.raises(IndexError, "p.y[4]")
diff --git a/doc/source/ref.rst b/doc/source/ref.rst
--- a/doc/source/ref.rst
+++ b/doc/source/ref.rst
@@ -141,7 +141,8 @@
    into a struct over a socket, rewriting the contents of mystruct[0]
 
 Remember that like in C, you can use ``array + index`` to get the pointer
-to the index'th item of an array.
+to the index'th item of an array.  (In C you might more naturally write
+``&array[index]``, but that is equivalent.)
 
 The returned object is not a built-in buffer nor memoryview object,
 because these objects' API changes too much across Python versions.
@@ -255,6 +256,14 @@
 argument in bytes.  The argument can be either a C type, or a cdata object,
 like in the equivalent ``sizeof`` operator in C.
 
+For ``array = ffi.new("T[]", n)``, then ``ffi.sizeof(array)`` returns
+``n * ffi.sizeof("T")``.  *New in version 1.9:* Similar rules apply for
+structures with aa variable-sized array at the end.  More precisely, if
+``p`` was returned by ``ffi.new("struct foo *", ...)``, then
+``ffi.sizeof(p[0])`` now returns the total allocated size.  In previous
+versions, it used to just return ``ffi.sizeof(ffi.typeof(p[0]))``, which
+is the size of the structure ignoring the variable-sized part.
+
 **ffi.alignof("C type")**: return the natural alignment size in bytes of
 the argument.  Corresponds to the ``__alignof__`` operator in GCC.
 
diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst
--- a/doc/source/whatsnew.rst
+++ b/doc/source/whatsnew.rst
@@ -3,8 +3,18 @@
 ======================
 
 
-v1.8.4
-======
+v1.9
+====
+
+* Structs with variable-sized arrays as their last field: now we track
+  the length of the array after ``ffi.new()`` is called, just like we
+  always tracked the length of ``ffi.new("int[]", 42)``.  This lets us
+  detect out-of-range accesses to array items.  This also lets us
+  display a better ``repr()``, and have the total size returned by
+  ``ffi.sizeof()`` and ``ffi.buffer()``.  Previously both functions
+  would return a result based on the size of the declared structure
+  type, with an assumed empty array.  (Thanks andrew for starting this
+  refactoring.)
 
 * Add support in ``cdef()/set_source()`` for unspecified-length arrays
   in typedefs: ``typedef int foo_t[...];``.  It was already supported
@@ -17,6 +27,16 @@
   enum has size ``int`` is a 99%-safe bet.  (But not 100%, so it stays
   as a warning.)
 
+* Fix leaks in the code handling ``FILE *`` arguments.  In CPython 3
+  there is a remaining issue that is hard to fix: if you pass a Python
+  file object to a ``FILE *`` argument, then ``os.dup()`` is used and
+  the new file descriptor is only closed when the GC reclaims the Python
+  file object---and not at the earlier time when you call ``close()``,
+  which only closes the original file descriptor.  If this is an issue,
+  you should avoid this automatic convertion of Python file objects:
+  instead, explicitly manipulate file descriptors and call ``fdopen()``
+  from C (...via cffi).
+
 
 v1.8.3
 ======
diff --git a/testing/cffi0/test_verify.py b/testing/cffi0/test_verify.py
--- a/testing/cffi0/test_verify.py
+++ b/testing/cffi0/test_verify.py
@@ -591,10 +591,15 @@
     ffi.verify("struct foo_s { int x; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 1 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')   # the same in C
+    assert ffi.sizeof(ffi.typeof(s[0])) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
+    # ^^^ explanation: if you write in C: "char x[5];", then
+    # "sizeof(ax" will evaluate to 5.  The behavior above is
+    # a generalization of that to "struct foo_s[len(a)=5] x;"
+    # if you could do that in C.
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 5 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 1 * ffi.sizeof('int')
@@ -609,10 +614,10 @@
     ffi.verify("struct foo_s { int x, y; int a[]; };")
     assert ffi.sizeof('struct foo_s') == 2 * ffi.sizeof('int')
     s = ffi.new("struct foo_s *", [424242, 4])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == 0
     s = ffi.new("struct foo_s *", [424242, [-40, -30, -20, -10]])
-    assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')
+    assert ffi.sizeof(s[0]) == 6 * ffi.sizeof('int')
     assert s.a[3] == -10
     s = ffi.new("struct foo_s *")
     assert ffi.sizeof(s[0]) == 2 * ffi.sizeof('int')


More information about the pypy-commit mailing list