From 5ce3f10aeea711bb912e948fa5d9f63736df1327 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 9 Jan 2014 14:50:20 +0200 Subject: [PATCH] Issue #20078: Reading malformed zipfiles no longer hangs with 100% CPU consumption. --- Lib/test/test_zipfile.py | 31 +++++++++++++++++++++++++++++++ Lib/zipfile.py | 2 ++ Misc/NEWS | 3 +++ 3 files changed, 36 insertions(+) diff --git a/Lib/test/test_zipfile.py b/Lib/test/test_zipfile.py index ad0c0b7b416..a561d59bc76 100644 --- a/Lib/test/test_zipfile.py +++ b/Lib/test/test_zipfile.py @@ -293,6 +293,36 @@ class AbstractTestsWithSourceFile: buf = fp.read(test_size) self.assertEqual(len(buf), test_size) + def test_truncated_zipfile(self): + fp = io.BytesIO() + with zipfile.ZipFile(fp, mode='w') as zipf: + zipf.writestr('strfile', self.data, compress_type=self.compression) + end_offset = fp.tell() + zipfiledata = fp.getvalue() + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + zipopen.read() + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + while zipopen.read(100): + pass + + fp = io.BytesIO(zipfiledata) + with zipfile.ZipFile(fp) as zipf: + with zipf.open('strfile') as zipopen: + fp.truncate(end_offset - 20) + with self.assertRaises(EOFError): + while zipopen.read1(100): + pass + def tearDown(self): unlink(TESTFN) unlink(TESTFN2) @@ -389,6 +419,7 @@ class StoredTestsWithSourceFile(AbstractTestsWithSourceFile, with zipfile.ZipFile(TESTFN2, "w") as zipfp: self.assertRaises(ValueError, zipfp.write, TESTFN) + @requires_zlib class DeflateTestsWithSourceFile(AbstractTestsWithSourceFile, unittest.TestCase): diff --git a/Lib/zipfile.py b/Lib/zipfile.py index 92c98abe1eb..a1b34147f83 100644 --- a/Lib/zipfile.py +++ b/Lib/zipfile.py @@ -860,6 +860,8 @@ class ZipExtFile(io.BufferedIOBase): data = self._fileobj.read(n) self._compress_left -= len(data) + if not data: + raise EOFError if self._decrypter is not None: data = bytes(map(self._decrypter, data)) diff --git a/Misc/NEWS b/Misc/NEWS index 4ad230af6fe..afe8514fa70 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -36,6 +36,9 @@ Core and Builtins Library ------- +- Issue #20078: Reading malformed zipfiles no longer hangs with 100% CPU + consumption. + - Issue #20113: os.readv() and os.writev() now raise an OSError exception on error instead of returning -1.