[pypy-commit] pypy default: update to cffi/ff25b4e68195

arigo pypy.commits at gmail.com
Mon Mar 11 05:48:14 EDT 2019


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r96269:fd0c6116edcd
Date: 2019-03-11 10:46 +0100
http://bitbucket.org/pypy/pypy/changeset/fd0c6116edcd/

Log:	update to cffi/ff25b4e68195

diff --git a/pypy/module/_cffi_backend/ctypestruct.py b/pypy/module/_cffi_backend/ctypestruct.py
--- a/pypy/module/_cffi_backend/ctypestruct.py
+++ b/pypy/module/_cffi_backend/ctypestruct.py
@@ -238,26 +238,32 @@
         else:
             self.ctype.convert_from_object(cdata, w_ob)
 
+    def add_varsize_length(self, space, itemsize, varsizelength, optvarsize):
+        # returns an updated 'optvarsize' to account for an array of
+        # 'varsizelength' elements, each of size 'itemsize', that starts
+        # at 'self.offset'.
+        try:
+            varsize = ovfcheck(itemsize * varsizelength)
+            size = ovfcheck(self.offset + varsize)
+        except OverflowError:
+            raise oefmt(space.w_OverflowError,
+                        "array size would overflow a ssize_t")
+        assert size >= 0
+        return max(size, optvarsize)
+
     def write_v(self, cdata, w_ob, optvarsize):
         # a special case for var-sized C99 arrays
         from pypy.module._cffi_backend import ctypearray
         ct = self.ctype
+        space = ct.space
         if isinstance(ct, ctypearray.W_CTypeArray) and ct.length < 0:
-            space = ct.space
             w_ob, varsizelength = ct.get_new_array_length(w_ob)
             if optvarsize != -1:
                 # in this mode, the only purpose of this function is to compute
                 # the real size of the structure from a var-sized C99 array
                 assert cdata == lltype.nullptr(rffi.CCHARP.TO)
-                itemsize = ct.ctitem.size
-                try:
-                    varsize = ovfcheck(itemsize * varsizelength)
-                    size = ovfcheck(self.offset + varsize)
-                except OverflowError:
-                    raise oefmt(space.w_OverflowError,
-                                "array size would overflow a ssize_t")
-                assert size >= 0
-                return max(size, optvarsize)
+                return self.add_varsize_length(space, ct.ctitem.size,
+                    varsizelength, optvarsize)
             # if 'value' was only an integer, get_new_array_length() returns
             # w_ob = space.w_None.  Detect if this was the case,
             # and if so, stop here, leaving the content uninitialized
@@ -267,6 +273,12 @@
         #
         if optvarsize == -1:
             self.write(cdata, w_ob)
+        elif (isinstance(ct, W_CTypeStructOrUnion) and ct._with_var_array and
+              not isinstance(w_ob, cdataobj.W_CData)):
+            subsize = ct.size
+            subsize = ct.convert_struct_from_object(
+                lltype.nullptr(rffi.CCHARP.TO), w_ob, subsize)
+            optvarsize = self.add_varsize_length(space, 1, subsize, optvarsize)
         return optvarsize
 
     def convert_bitfield_to_object(self, cdata):
diff --git a/pypy/module/_cffi_backend/newtype.py b/pypy/module/_cffi_backend/newtype.py
--- a/pypy/module/_cffi_backend/newtype.py
+++ b/pypy/module/_cffi_backend/newtype.py
@@ -368,6 +368,16 @@
                 raise oefmt(space.w_TypeError,
                             "field '%s.%s' has ctype '%s' of unknown size",
                             w_ctype.name, fname, ftype.name)
+        elif isinstance(ftype, ctypestruct.W_CTypeStructOrUnion):
+            ftype.force_lazy_struct()
+            # GCC (or maybe C99) accepts var-sized struct fields that are not
+            # the last field of a larger struct.  That's why there is no
+            # check here for "last field": we propagate the flag
+            # '_with_var_array' to any struct that contains either an open-
+            # ended array or another struct that recursively contains an
+            # open-ended array.
+            if ftype._with_var_array:
+                with_var_array = True
         #
         if is_union:
             boffset = 0         # reset each field at offset 0
@@ -419,7 +429,6 @@
                 # a nested anonymous struct or union
                 # note: it seems we only get here with ffi.verify()
                 srcfield2names = {}
-                ftype.force_lazy_struct()
                 for name, srcfld in ftype._fields_dict.items():
                     srcfield2names[srcfld] = name
                 for srcfld in ftype._fields_list:
diff --git a/pypy/module/_cffi_backend/test/_backend_test_c.py b/pypy/module/_cffi_backend/test/_backend_test_c.py
--- a/pypy/module/_cffi_backend/test/_backend_test_c.py
+++ b/pypy/module/_cffi_backend/test/_backend_test_c.py
@@ -3441,6 +3441,15 @@
     assert p.a[1] == 20
     assert p.a[2] == 30
     assert p.a[3] == 0
+    #
+    # struct of struct of varsized array
+    BStruct2 = new_struct_type("bar")
+    complete_struct_or_union(BStruct2, [('head', BInt),
+                                        ('tail', BStruct)])
+    for i in range(2):   # try to detect heap overwrites
+        p = newp(new_pointer_type(BStruct2), [100, [200, list(range(50))]])
+        assert p.tail.y[49] == 49
+
 
 def test_struct_array_no_length_explicit_position():
     BInt = new_primitive_type("int")


More information about the pypy-commit mailing list