From 7623294cb76b23d63df2858df71072721bf409cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lars=20Gust=C3=A4bel?= Date: Sun, 22 Mar 2009 20:48:03 +0000 Subject: [PATCH] Issue #5068: Fixed the tarfile._BZ2Proxy.read() method that would loop forever on incomplete input. That caused tarfile.open() to hang when used with mode 'r' or 'r:bz2' and a fileobj argument that contained no data or partial bzip2 compressed data. (backported from r70523) --- Lib/tarfile.py | 9 ++++----- Lib/test/test_tarfile.py | 25 ++++++++++++++++++++++++- Misc/NEWS | 14 ++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Lib/tarfile.py b/Lib/tarfile.py index 5ad096dbf36..8b477fe76e7 100644 --- a/Lib/tarfile.py +++ b/Lib/tarfile.py @@ -594,12 +594,11 @@ class _BZ2Proxy(object): b = [self.buf] x = len(self.buf) while x < size: - try: - raw = self.fileobj.read(self.blocksize) - data = self.bz2obj.decompress(raw) - b.append(data) - except EOFError: + raw = self.fileobj.read(self.blocksize) + if not raw: break + data = self.bz2obj.decompress(raw) + b.append(data) x += len(data) self.buf = "".join(b) diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py index a9797aeb992..f8e8ddb59ee 100644 --- a/Lib/test/test_tarfile.py +++ b/Lib/test/test_tarfile.py @@ -751,6 +751,29 @@ if bz2: class ReadFileobjTestBzip2(ReadFileobjTest): comp = "bz2" + class PartialReadTestBzip2(unittest.TestCase): + # Issue5068: The _BZ2Proxy.read() method loops forever + # on an empty or partial bzipped file. + + def _test_partial_input(self, mode): + class MyStringIO(StringIO.StringIO): + hit_eof = False + def read(self, n): + if self.hit_eof: + raise AssertionError("infinite loop detected in tarfile.open()") + self.hit_eof = self.pos == self.len + return StringIO.StringIO.read(self, n) + + data = bz2.compress(tarfile.TarInfo("foo").tobuf()) + for x in range(len(data) + 1): + tarfile.open(fileobj=MyStringIO(data[:x]), mode=mode) + + def test_partial_input(self): + self._test_partial_input("r") + + def test_partial_input_bz2(self): + self._test_partial_input("r:bz2") + # If importing gzip failed, discard the Gzip TestCases. if not gzip: del ReadTestGzip @@ -811,7 +834,7 @@ def test_main(): WriteTestBzip2, WriteStreamTestBzip2, ReadDetectTestBzip2, ReadDetectFileobjTestBzip2, ReadAsteriskTestBzip2, ReadStreamAsteriskTestBzip2, - ReadFileobjTestBzip2 + ReadFileobjTestBzip2, PartialReadTestBzip2 ]) try: test_support.run_unittest(*tests) diff --git a/Misc/NEWS b/Misc/NEWS index 2cd62527aa9..6b256b6ef07 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -4,6 +4,20 @@ Python News (editors: check NEWS.help for information about editing NEWS using ReST.) +What's New in Python 2.5.5? +=========================== + +*Release date: XX-XXX-20XX* + +Library +------- + +- Issue #5068: Fixed the tarfile._BZ2Proxy.read() method that would loop + forever on incomplete input. That caused tarfile.open() to hang when used + with mode 'r' or 'r:bz2' and a fileobj argument that contained no data or + partial bzip2 compressed data. + + What's New in Python 2.5.4? ===========================