self.assertEqual(rawio.read(2), None)
self.assertEqual(rawio.read(2), b"")
+ def test_RawIOBase_read_bounds_checking(self):
+ # Make sure a `.readinto` call which returns a value outside
+ # (0, len(buffer)) raises.
+ class Misbehaved(self.RawIOBase):
+ def __init__(self, readinto_return) -> None:
+ self._readinto_return = readinto_return
+ def readinto(self, b):
+ return self._readinto_return
+
+ with self.assertRaises(ValueError) as cm:
+ Misbehaved(2).read(1)
+ self.assertEqual(str(cm.exception), "readinto returned 2 outside buffer size 1")
+ for bad_size in (2147483647, sys.maxsize, -1, -1000):
+ with self.assertRaises(ValueError):
+ Misbehaved(bad_size).read()
+
def test_types_have_dict(self):
test = (
self.IOBase(),
return res;
}
- n = PyNumber_AsSsize_t(res, PyExc_ValueError);
+ Py_ssize_t bytes_filled = PyNumber_AsSsize_t(res, PyExc_ValueError);
Py_DECREF(res);
- if (n == -1 && PyErr_Occurred()) {
+ if (bytes_filled == -1 && PyErr_Occurred()) {
Py_DECREF(b);
return NULL;
}
+ if (bytes_filled < 0 || bytes_filled > n) {
+ Py_DECREF(b);
+ PyErr_Format(PyExc_ValueError,
+ "readinto returned %zd outside buffer size %zd",
+ bytes_filled, n);
+ return NULL;
+ }
- res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), n);
+ res = PyBytes_FromStringAndSize(PyByteArray_AsString(b), bytes_filled);
Py_DECREF(b);
return res;
}