Skip to content

Commit 9bc89f2

Browse files
committed
Issue #21932: os.read() now uses a :c:func:Py_ssize_t type instead of
:c:type:`int` for the size to support reading more than 2 GB at once. On Windows, the size is truncted to INT_MAX. As any call to os.read(), the OS may read less bytes than the number of requested bytes.
1 parent ead5431 commit 9bc89f2

File tree

3 files changed

+37
-6
lines changed

3 files changed

+37
-6
lines changed

Lib/test/test_os.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
import _winapi
4444
except ImportError:
4545
_winapi = None
46+
try:
47+
from _testcapi import INT_MAX
48+
except ImportError:
49+
INT_MAX = 2 ** 31 - 1
4650

4751
from test.script_helper import assert_python_ok
4852

@@ -119,6 +123,21 @@ def test_read(self):
119123
self.assertEqual(type(s), bytes)
120124
self.assertEqual(s, b"spam")
121125

126+
def test_large_read(self):
127+
with open(support.TESTFN, "wb") as fp:
128+
fp.write(b'test')
129+
self.addCleanup(support.unlink, support.TESTFN)
130+
131+
# Issue #21932: Make sure that os.read() does not raise an
132+
# OverflowError for size larger than INT_MAX
133+
size = INT_MAX + 10
134+
with open(support.TESTFN, "rb") as fp:
135+
data = os.read(fp.fileno(), size)
136+
137+
# The test does not try to read more than 2 GB at once because the
138+
# operating system is free to return less bytes than requested.
139+
self.assertEqual(data, b'test')
140+
122141
def test_write(self):
123142
# os.write() accepts bytes- and buffer-like objects but not strings
124143
fd = os.open(support.TESTFN, os.O_CREAT | os.O_WRONLY)

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,11 @@ Core and Builtins
108108
Library
109109
-------
110110

111+
- Issue #21932: os.read() now uses a :c:func:`Py_ssize_t` type instead of
112+
:c:type:`int` for the size to support reading more than 2 GB at once. On
113+
Windows, the size is truncted to INT_MAX. As any call to os.read(), the OS
114+
may read less bytes than the number of requested bytes.
115+
111116
- Issue #21942: Fixed source file viewing in pydoc's server mode on Windows.
112117

113118
- Issue #11259: asynchat.async_chat().set_terminator() now raises a ValueError

Modules/posixmodule.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7989,24 +7989,31 @@ Read a file descriptor.");
79897989
static PyObject *
79907990
posix_read(PyObject *self, PyObject *args)
79917991
{
7992-
int fd, size;
7992+
int fd;
7993+
Py_ssize_t size;
79937994
Py_ssize_t n;
79947995
PyObject *buffer;
7995-
if (!PyArg_ParseTuple(args, "ii:read", &fd, &size))
7996+
if (!PyArg_ParseTuple(args, "in:read", &fd, &size))
79967997
return NULL;
7998+
if (!_PyVerify_fd(fd))
7999+
return posix_error();
8000+
#ifdef MS_WINDOWS
8001+
if (size > INT_MAX)
8002+
size = INT_MAX;
8003+
#endif
79978004
if (size < 0) {
79988005
errno = EINVAL;
79998006
return posix_error();
80008007
}
80018008
buffer = PyBytes_FromStringAndSize((char *)NULL, size);
80028009
if (buffer == NULL)
80038010
return NULL;
8004-
if (!_PyVerify_fd(fd)) {
8005-
Py_DECREF(buffer);
8006-
return posix_error();
8007-
}
80088011
Py_BEGIN_ALLOW_THREADS
8012+
#ifdef MS_WINDOWS
8013+
n = read(fd, PyBytes_AS_STRING(buffer), (int)size);
8014+
#else
80098015
n = read(fd, PyBytes_AS_STRING(buffer), size);
8016+
#endif
80108017
Py_END_ALLOW_THREADS
80118018
if (n < 0) {
80128019
Py_DECREF(buffer);

0 commit comments

Comments
 (0)