Skip to content

Commit 5f00fd0

Browse files
committed
Fix parsing RS-separated streams
Fix the parsing loop to use the proper interface, thus fixing parsing RS-separated streams (RFC 7464). Without this, the program would abort on assertion failure, like this: python3: src/jv_parse.c:684: jv_parser_set_buf: Assertion `(p->curr_buf == 0 || p->curr_buf_pos == p->curr_buf_length) && "previous buffer not exhausted"' failed.
1 parent ed1646e commit 5f00fd0

File tree

2 files changed

+76
-10
lines changed

2 files changed

+76
-10
lines changed

jq.pyx

+9-10
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ cdef extern from "jv.h":
4343
jv_parser* jv_parser_new(int)
4444
void jv_parser_free(jv_parser*)
4545
void jv_parser_set_buf(jv_parser*, const char*, int, int)
46+
int jv_parser_remaining(jv_parser*)
4647
jv jv_parser_next(jv_parser*)
4748

4849

@@ -171,11 +172,11 @@ cdef class _JSONParser(object):
171172
"""
172173
cdef jv value
173174
while True:
174-
# If we have no bytes to parse
175-
if self._bytes is None:
176-
# Ready some more
175+
# If the parser has no buffer set/left
176+
if not jv_parser_remaining(self._parser):
177+
# Supply it with some bytes
177178
self._ready_next_bytes()
178-
# Parse whatever we've readied, if any
179+
# Get next value from the parser
179180
value = jv_parser_next(self._parser)
180181
if jv_is_valid(value):
181182
if self._packed:
@@ -189,12 +190,10 @@ cdef class _JSONParser(object):
189190
message = jv_string_value(error_message).decode("utf8")
190191
jv_free(error_message)
191192
raise JSONParseError(message)
192-
else:
193-
jv_free(value)
194-
# If we didn't ready any bytes
195-
if self._bytes is None:
196-
raise StopIteration
197-
self._bytes = None
193+
jv_free(value)
194+
# If we supplied no bytes last time
195+
if self._bytes is None:
196+
raise StopIteration
198197

199198
cdef bint _ready_next_bytes(self) except 1:
200199
cdef char* cbytes

tests/jq_tests.py

+67
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,58 @@ def unicode_strings_can_be_used_as_input():
177177
)
178178

179179

180+
@istest
181+
def record_separator_character_accepted_in_input():
182+
assert_equal(
183+
[],
184+
list(jq.compile(".").input(text='\x1e'))
185+
)
186+
assert_equal(
187+
[],
188+
list(jq.compile(".").input(text='\x1e\x1e'))
189+
)
190+
assert_equal(
191+
[{}],
192+
list(jq.compile(".").input(text='\x1e{}'))
193+
)
194+
assert_equal(
195+
[{}],
196+
list(jq.compile(".").input(text='\x1e\x1e{}'))
197+
)
198+
assert_equal(
199+
[{}],
200+
list(jq.compile(".").input(text='{}\x1e'))
201+
)
202+
assert_equal(
203+
[{}],
204+
list(jq.compile(".").input(text='{}\x1e\x1e'))
205+
)
206+
assert_equal(
207+
[{}],
208+
list(jq.compile(".").input(text='\x1e{}\x1e'))
209+
)
210+
assert_equal(
211+
[{},[]],
212+
list(jq.compile(".").input(text='{}\x1e[]'))
213+
)
214+
assert_equal(
215+
[{},[]],
216+
list(jq.compile(".").input(text='{}\x1e\x1e[]'))
217+
)
218+
assert_equal(
219+
[{},[]],
220+
list(jq.compile(".").input(text='\x1e{}\x1e[]'))
221+
)
222+
assert_equal(
223+
[{},[]],
224+
list(jq.compile(".").input(text='{}\x1e[]\x1e'))
225+
)
226+
assert_equal(
227+
[{},[]],
228+
list(jq.compile(".").input(text='\x1e{}\x1e[]\x1e'))
229+
)
230+
231+
180232
@istest
181233
def unicode_strings_can_be_used_as_programs():
182234
assert_equal(
@@ -204,6 +256,21 @@ def parse_json_all_inputs_accepted():
204256
assert_equal(True, next(jq.parse_json(text=b"true")))
205257
assert_equal(True, next(jq.parse_json(text_iter=iter([b"true"]))))
206258

259+
@istest
260+
def parse_json_record_separator_character_accepted():
261+
assert_equal([], list(jq.parse_json(text='\x1e')))
262+
assert_equal([], list(jq.parse_json(text='\x1e\x1e')))
263+
assert_equal([{}], list(jq.parse_json(text='\x1e{}')))
264+
assert_equal([{}], list(jq.parse_json(text='\x1e\x1e{}')))
265+
assert_equal([{}], list(jq.parse_json(text='{}\x1e')))
266+
assert_equal([{}], list(jq.parse_json(text='{}\x1e\x1e')))
267+
assert_equal([{}], list(jq.parse_json(text='\x1e{}\x1e')))
268+
assert_equal([{},[]], list(jq.parse_json(text='{}\x1e[]')))
269+
assert_equal([{},[]], list(jq.parse_json(text='{}\x1e\x1e[]')))
270+
assert_equal([{},[]], list(jq.parse_json(text='\x1e{}\x1e[]')))
271+
assert_equal([{},[]], list(jq.parse_json(text='{}\x1e[]\x1e')))
272+
assert_equal([{},[]], list(jq.parse_json(text='\x1e{}\x1e[]\x1e')))
273+
207274
@istest
208275
def parse_json_file_works():
209276
fp = io.StringIO('{"abc": "def"}')

0 commit comments

Comments
 (0)