summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_os.py
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2018-07-31 07:24:54 (GMT)
committerGitHub <noreply@github.com>2018-07-31 07:24:54 (GMT)
commit9d5727326af53ddd91016d98e16ae7cf829caa95 (patch)
tree6d3a41b4f15736bae755debc257e05c4102ba419 /Lib/test/test_os.py
parentf1d36d8efaecd5c84cb35e35119b283f37d83c40 (diff)
downloadcpython-9d5727326af53ddd91016d98e16ae7cf829caa95.zip
cpython-9d5727326af53ddd91016d98e16ae7cf829caa95.tar.gz
cpython-9d5727326af53ddd91016d98e16ae7cf829caa95.tar.bz2
bpo-33871: Fix os.sendfile(), os.writev(), os.readv(), etc. (GH-7931)
* Fix integer overflow in os.readv(), os.writev(), os.preadv() and os.pwritev() and in os.sendfile() with headers or trailers arguments (on BSD-based OSes and MacOS). * Fix sending the part of the file in os.sendfile() on MacOS. Using the trailers argument could cause sending more bytes from the input file than was specified. Thanks Ned Deily for testing on 32-bit MacOS.
Diffstat (limited to 'Lib/test/test_os.py')
-rw-r--r--Lib/test/test_os.py50
1 files changed, 35 insertions, 15 deletions
diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py
index e509188..a140ae0 100644
--- a/Lib/test/test_os.py
+++ b/Lib/test/test_os.py
@@ -2532,12 +2532,14 @@ class SendfileTestServer(asyncore.dispatcher, threading.Thread):
def __init__(self, conn):
asynchat.async_chat.__init__(self, conn)
self.in_buffer = []
+ self.accumulate = True
self.closed = False
self.push(b"220 ready\r\n")
def handle_read(self):
data = self.recv(4096)
- self.in_buffer.append(data)
+ if self.accumulate:
+ self.in_buffer.append(data)
def get_data(self):
return b''.join(self.in_buffer)
@@ -2618,6 +2620,8 @@ class TestSendfile(unittest.TestCase):
not sys.platform.startswith("sunos")
requires_headers_trailers = unittest.skipUnless(SUPPORT_HEADERS_TRAILERS,
'requires headers and trailers support')
+ requires_32b = unittest.skipUnless(sys.maxsize < 2**32,
+ 'test is only meaningful on 32-bit builds')
@classmethod
def setUpClass(cls):
@@ -2648,17 +2652,13 @@ class TestSendfile(unittest.TestCase):
self.server.stop()
self.server = None
- def sendfile_wrapper(self, sock, file, offset, nbytes, headers=[], trailers=[]):
+ def sendfile_wrapper(self, *args, **kwargs):
"""A higher level wrapper representing how an application is
supposed to use sendfile().
"""
- while 1:
+ while True:
try:
- if self.SUPPORT_HEADERS_TRAILERS:
- return os.sendfile(sock, file, offset, nbytes, headers,
- trailers)
- else:
- return os.sendfile(sock, file, offset, nbytes)
+ return os.sendfile(*args, **kwargs)
except OSError as err:
if err.errno == errno.ECONNRESET:
# disconnected
@@ -2749,20 +2749,22 @@ class TestSendfile(unittest.TestCase):
@requires_headers_trailers
def test_headers(self):
total_sent = 0
+ expected_data = b"x" * 512 + b"y" * 256 + self.DATA[:-1]
sent = os.sendfile(self.sockno, self.fileno, 0, 4096,
- headers=[b"x" * 512])
+ headers=[b"x" * 512, b"y" * 256])
+ self.assertLessEqual(sent, 512 + 256 + 4096)
total_sent += sent
offset = 4096
- nbytes = 4096
- while 1:
+ while total_sent < len(expected_data):
+ nbytes = min(len(expected_data) - total_sent, 4096)
sent = self.sendfile_wrapper(self.sockno, self.fileno,
offset, nbytes)
if sent == 0:
break
+ self.assertLessEqual(sent, nbytes)
total_sent += sent
offset += sent
- expected_data = b"x" * 512 + self.DATA
self.assertEqual(total_sent, len(expected_data))
self.client.close()
self.server.wait()
@@ -2778,12 +2780,30 @@ class TestSendfile(unittest.TestCase):
create_file(TESTFN2, file_data)
with open(TESTFN2, 'rb') as f:
- os.sendfile(self.sockno, f.fileno(), 0, len(file_data),
- trailers=[b"1234"])
+ os.sendfile(self.sockno, f.fileno(), 0, 5,
+ trailers=[b"123456", b"789"])
self.client.close()
self.server.wait()
data = self.server.handler_instance.get_data()
- self.assertEqual(data, b"abcdef1234")
+ self.assertEqual(data, b"abcde123456789")
+
+ @requires_headers_trailers
+ @requires_32b
+ def test_headers_overflow_32bits(self):
+ self.server.handler_instance.accumulate = False
+ with self.assertRaises(OSError) as cm:
+ os.sendfile(self.sockno, self.fileno, 0, 0,
+ headers=[b"x" * 2**16] * 2**15)
+ self.assertEqual(cm.exception.errno, errno.EINVAL)
+
+ @requires_headers_trailers
+ @requires_32b
+ def test_trailers_overflow_32bits(self):
+ self.server.handler_instance.accumulate = False
+ with self.assertRaises(OSError) as cm:
+ os.sendfile(self.sockno, self.fileno, 0, 0,
+ trailers=[b"x" * 2**16] * 2**15)
+ self.assertEqual(cm.exception.errno, errno.EINVAL)
@requires_headers_trailers
@unittest.skipUnless(hasattr(os, 'SF_NODISKIO'),