Kaydet (Commit) 37d3ff14 authored tarafından Nadeem Vawda's avatar Nadeem Vawda

#15546: Fix {GzipFile,LZMAFile}.read1()'s handling of pathological input data.

üst 9c92a691
...@@ -385,7 +385,10 @@ class GzipFile(io.BufferedIOBase): ...@@ -385,7 +385,10 @@ class GzipFile(io.BufferedIOBase):
return b'' return b''
try: try:
self._read() # For certain input data, a single call to _read() may not return
# any data. In this case, retry until we get some data or reach EOF.
while self.extrasize <= 0:
self._read()
except EOFError: except EOFError:
pass pass
if size < 0 or size > self.extrasize: if size < 0 or size > self.extrasize:
......
...@@ -204,29 +204,31 @@ class LZMAFile(io.BufferedIOBase): ...@@ -204,29 +204,31 @@ class LZMAFile(io.BufferedIOBase):
# Fill the readahead buffer if it is empty. Returns False on EOF. # Fill the readahead buffer if it is empty. Returns False on EOF.
def _fill_buffer(self): def _fill_buffer(self):
if self._buffer: # Depending on the input data, our call to the decompressor may not
return True # return any data. In this case, try again after reading another block.
while True:
if self._decompressor.unused_data: if self._buffer:
rawblock = self._decompressor.unused_data return True
else:
rawblock = self._fp.read(_BUFFER_SIZE) if self._decompressor.unused_data:
rawblock = self._decompressor.unused_data
if not rawblock:
if self._decompressor.eof:
self._mode = _MODE_READ_EOF
self._size = self._pos
return False
else: else:
raise EOFError("Compressed file ended before the " rawblock = self._fp.read(_BUFFER_SIZE)
"end-of-stream marker was reached")
if not rawblock:
# Continue to next stream. if self._decompressor.eof:
if self._decompressor.eof: self._mode = _MODE_READ_EOF
self._decompressor = LZMADecompressor(**self._init_args) self._size = self._pos
return False
else:
raise EOFError("Compressed file ended before the "
"end-of-stream marker was reached")
# Continue to next stream.
if self._decompressor.eof:
self._decompressor = LZMADecompressor(**self._init_args)
self._buffer = self._decompressor.decompress(rawblock) self._buffer = self._decompressor.decompress(rawblock)
return True
# Read data until EOF. # Read data until EOF.
# If return_data is false, consume the data without returning it. # If return_data is false, consume the data without returning it.
...@@ -284,11 +286,14 @@ class LZMAFile(io.BufferedIOBase): ...@@ -284,11 +286,14 @@ class LZMAFile(io.BufferedIOBase):
return self._read_block(size) return self._read_block(size)
def read1(self, size=-1): def read1(self, size=-1):
"""Read up to size uncompressed bytes with at most one read """Read up to size uncompressed bytes, while trying to avoid
from the underlying stream. making multiple reads from the underlying stream.
Returns b"" if the file is at EOF. Returns b"" if the file is at EOF.
""" """
# Usually, read1() calls _fp.read() at most once. However, sometimes
# this does not give enough data for the decompressor to make progress.
# In this case we make multiple reads, to avoid returning b"".
self._check_can_read() self._check_can_read()
if (size == 0 or self._mode == _MODE_READ_EOF or if (size == 0 or self._mode == _MODE_READ_EOF or
not self._fill_buffer()): not self._fill_buffer()):
......
...@@ -77,6 +77,9 @@ Core and Builtins ...@@ -77,6 +77,9 @@ Core and Builtins
Library Library
------- -------
- Issue #15546: Fix handling of pathological input data in the read1() method of
the BZ2File, GzipFile and LZMAFile classes.
- Issue #13052: Fix IDLE crashing when replace string in Search/Replace dialog - Issue #13052: Fix IDLE crashing when replace string in Search/Replace dialog
ended with '\'. Patch by Roger Serwy. ended with '\'. Patch by Roger Serwy.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment