Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions construct/lib/bitstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,13 @@ def read(self, count=None):
newdata = self.substream.read(128*1024)
except BlockingIOError:
newdata = None
if not newdata:
if newdata is None:
# non-blocking stream has no data ready yet, keep polling
sleep(0)
continue
if not newdata:
# empty bytes signal end of file, stop reading
break
self.rwbuffer += newdata
data = self.rwbuffer[startsat-self.moved:endsat-self.moved]
self.offset += count
Expand All @@ -109,10 +113,18 @@ def write(self, data):
startsat = self.offset
endsat = startsat + len(data)
while self.moved + len(self.rwbuffer) < startsat:
newdata = self.substream.read(128*1024)
self.rwbuffer += newdata
if not newdata:
try:
newdata = self.substream.read(128*1024)
except BlockingIOError:
newdata = None
if newdata is None:
# non-blocking stream has no data ready yet, keep polling
sleep(0)
continue
if not newdata:
# empty bytes signal end of file, stop reading
break
self.rwbuffer += newdata
self.rwbuffer = self.rwbuffer[:startsat-self.moved] + data + self.rwbuffer[endsat-self.moved:]
self.offset = endsat
if self.tailcutoff is not None and self.moved < self.offset - self.tailcutoff:
Expand Down
9 changes: 9 additions & 0 deletions tests/lib/test_bitstream.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,12 @@ def test_rebuffered():
assert bstream.read(50) == data[at:at+50]
jumpback = random.randrange(1, 19)
assert bstream.seek(-jumpback, 1)

def test_rebuffered_reading_past_eof():
# reading past end of stream must raise, not hang forever (issue #988)
bstream = RebufferedBytesIO(io.BytesIO(b"abc"))
assert bstream.read(3) == b"abc"
assert raises(bstream.read, 1) == IOError

bstream = RebufferedBytesIO(io.BytesIO(b"abc"))
assert raises(bstream.read, 5) == IOError