Thanks to visit codestin.com
Credit goes to github.com

Skip to content

SL-18830: Fix sporadic notation parse failure with very large input. #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 16, 2023
Merged
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
35 changes: 21 additions & 14 deletions llsd/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,20 +465,27 @@ def _peek(self, num=1, full=True):
# off by 4 bytes to try to point the user at the right spot.
self._error("Invalid length field %d" % num, -4)

got = self._stream.peek(num)
if full and len(got) < num:
# Going right to this error is a little iffy:
# BufferedReader.peek() does not promise to return the requested
# length, but does not clarify the conditions under which it
# returns fewer bytes. If this is an actual problem, we could loop
# until we have the requested length or EOF -- but the loop must
# explicitly seek() past already-peeked data, then reset after.
# https://docs.python.org/3/library/io.html#io.BufferedReader.peek
self._error("Trying to peek past end of stream")

# Interestingly, peek() can also return MORE than requested -- but for
# our purposes (e.g. ord(peek(1))) it's important to constrain it.
return got[:num]
# Instead of using self._stream.peek() at all, use read(num) and reset
# the read pointer. BufferedReader.peek() does not promise to return
# the requested length, but does not clarify the conditions under
# which it returns fewer bytes.
# https://docs.python.org/3/library/io.html#io.BufferedReader.peek
# In practice, we've seen it fail with an input file up over 100Kb:
# peek() returns only part of what we requested, but because we also
# passed full=False (see LLSDNotationParser._get_re()), we didn't
# notice and the parse failed looking for a map delimiter halfway
# through a large decimal integer. read(num), on the other hand,
# promises to return num bytes until actual EOF.
oldpos = self._stream.tell()
try:
got = self._stream.read(num)
if full and len(got) < num:
self._error("Trying to peek past end of stream")

return got

finally:
self._stream.seek(oldpos)

def _error(self, message, offset=0):
oldpos = self._stream.tell()
Expand Down