[pypy-commit] pypy refactor-buffer-api: fix validation of buffer writability

bdkearns noreply at buildbot.pypy.org
Thu Apr 24 03:27:56 CEST 2014


Author: Brian Kearns <bdkearns at gmail.com>
Branch: refactor-buffer-api
Changeset: r70911:ac02d8345ef9
Date: 2014-04-23 21:06 -0400
http://bitbucket.org/pypy/pypy/changeset/ac02d8345ef9/

Log:	fix validation of buffer writability

diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -5,7 +5,7 @@
 from rpython.rlib import jit, types
 from rpython.rlib.debug import make_sure_not_resized
 from rpython.rlib.objectmodel import (we_are_translated, newlist_hint,
-     compute_unique_id)
+     compute_unique_id, specialize)
 from rpython.rlib.signature import signature
 from rpython.rlib.rarithmetic import r_uint, SHRT_MIN, SHRT_MAX, \
     INT_MIN, INT_MAX, UINT_MAX
@@ -1369,6 +1369,11 @@
     BUF_FULL_RO = 1
     BUF_CONTIG = 2
     BUF_CONTIG_RO = 3
+    BUF_WRITABLE = 4
+
+    def check_buf_flags(self, flags, readonly):
+        if flags & self.BUF_WRITABLE == self.BUF_WRITABLE and readonly:
+            raise oefmt(self.w_BufferError, "Object is not writable.")
 
     def buffer_w(self, w_obj, flags):
         # New buffer interface, returns a buffer based on flags (PyObject_GetBuffer)
@@ -1402,6 +1407,26 @@
             raise oefmt(self.w_TypeError,
                         "expected a character buffer object")
 
+    def _getarg_error(self, expected, w_obj):
+        raise oefmt(self.w_TypeError, "must be %s, not %T", expected, w_obj)
+
+    @specialize.arg(1)
+    def getarg_w(self, code, w_obj):
+        if code == 'w*':
+            try:
+                try:
+                    return w_obj.buffer_w(self, self.BUF_WRITABLE)
+                except OperationError:
+                    self._getarg_error("read-write buffer", w_obj)
+            except TypeError:
+                pass
+            try:
+                return w_obj.writebuf_w(self)
+            except TypeError:
+                self._getarg_error("read-write buffer", w_obj)
+        else:
+            assert False
+
     # XXX rename these/replace with code more like CPython getargs for buffers
     def bufferstr_w(self, w_obj):
         # Directly returns an interp-level str.  Note that if w_obj is a
diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -80,7 +80,7 @@
         self._unsupportedoperation(space, "detach")
 
     def readinto_w(self, space, w_buffer):
-        rwbuffer = space.buffer_w(w_buffer, space.BUF_CONTIG)
+        rwbuffer = space.getarg_w('w*', w_buffer)
         length = rwbuffer.getlength()
         w_data = space.call_method(self, "read", space.wrap(length))
 
diff --git a/pypy/module/_io/interp_bytesio.py b/pypy/module/_io/interp_bytesio.py
--- a/pypy/module/_io/interp_bytesio.py
+++ b/pypy/module/_io/interp_bytesio.py
@@ -41,7 +41,7 @@
 
     def readinto_w(self, space, w_buffer):
         self._check_closed(space)
-        rwbuffer = space.buffer_w(w_buffer, space.BUF_CONTIG)
+        rwbuffer = space.getarg_w('w*', w_buffer)
         size = rwbuffer.getlength()
 
         output = self.read(size)
diff --git a/pypy/module/_io/interp_fileio.py b/pypy/module/_io/interp_fileio.py
--- a/pypy/module/_io/interp_fileio.py
+++ b/pypy/module/_io/interp_fileio.py
@@ -366,7 +366,7 @@
     def readinto_w(self, space, w_buffer):
         self._check_closed(space)
         self._check_readable(space)
-        rwbuffer = space.buffer_w(w_buffer, space.BUF_CONTIG)
+        rwbuffer = space.getarg_w('w*', w_buffer)
         length = rwbuffer.getlength()
         try:
             buf = os.read(self.fd, length)
diff --git a/pypy/module/_io/test/test_bufferedio.py b/pypy/module/_io/test/test_bufferedio.py
--- a/pypy/module/_io/test/test_bufferedio.py
+++ b/pypy/module/_io/test/test_bufferedio.py
@@ -139,6 +139,8 @@
         raw = _io.FileIO(self.tmpfile)
         f = _io.BufferedReader(raw)
         assert f.readinto(a) == 5
+        exc = raises(TypeError, f.readinto, memoryview(b"hello"))
+        assert str(exc.value) == "must be read-write buffer, not memoryview"
         f.close()
         assert a == 'a\nb\ncxxxxx'
 
diff --git a/pypy/module/_io/test/test_bytesio.py b/pypy/module/_io/test/test_bytesio.py
--- a/pypy/module/_io/test/test_bytesio.py
+++ b/pypy/module/_io/test/test_bytesio.py
@@ -97,6 +97,8 @@
         a2 = bytearray('testing')
         assert b.readinto(a1) == 1
         assert b.readinto(a2) == 4
+        exc = raises(TypeError, b.readinto, memoryview(b"hello"))
+        assert str(exc.value) == "must be read-write buffer, not memoryview"
         b.close()
         assert a1 == "h"
         assert a2 == "elloing"
diff --git a/pypy/module/_io/test/test_fileio.py b/pypy/module/_io/test/test_fileio.py
--- a/pypy/module/_io/test/test_fileio.py
+++ b/pypy/module/_io/test/test_fileio.py
@@ -135,6 +135,8 @@
         a = bytearray('x' * 10)
         f = _io.FileIO(self.tmpfile, 'r+')
         assert f.readinto(a) == 10
+        exc = raises(TypeError, f.readinto, memoryview(b"hello"))
+        assert str(exc.value) == "must be read-write buffer, not memoryview"
         f.close()
         assert a == 'a\nb\nc\0\0\0\0\0'
         #
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -443,6 +443,7 @@
         return self._value
 
     def buffer_w(self, space, flags):
+        space.check_buf_flags(flags, True)
         return StringBuffer(self._value)
 
     def readbuf_w(self, space):
diff --git a/pypy/objspace/std/memoryobject.py b/pypy/objspace/std/memoryobject.py
--- a/pypy/objspace/std/memoryobject.py
+++ b/pypy/objspace/std/memoryobject.py
@@ -34,16 +34,17 @@
     an interp-level buffer.
     """
 
-    def __init__(self, buf):
+    def __init__(self, obj, buf):
         assert isinstance(buf, Buffer)
+        self.obj = obj
         self.buf = buf
 
     def buffer_w(self, space, flags):
-        return self.buf
+        return space.buffer_w(self.obj, flags)
 
     @staticmethod
     def descr_new_memoryview(space, w_subtype, w_object):
-        return W_MemoryView(space.buffer_w(w_object, space.BUF_FULL_RO))
+        return W_MemoryView(w_object, space.buffer_w(w_object, space.BUF_FULL_RO))
 
     def _make_descr__cmp(name):
         def descr__cmp(self, space, w_other):
@@ -86,7 +87,7 @@
         if size < 0:
             size = 0
         buf = SubBuffer(self.buf, start, size)
-        return W_MemoryView(buf)
+        return W_MemoryView(self.obj, buf)
 
     def descr_tobytes(self, space):
         return space.wrap(self.as_str())


More information about the pypy-commit mailing list