Skip to content

Commit ed3f389

Browse files
committed
python: Fix segv on unpacking from stream.
1 parent 5dbf2f5 commit ed3f389

File tree

1 file changed

+24
-15
lines changed

1 file changed

+24
-15
lines changed

msgpack/_msgpack.pyx

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,8 @@ cdef class Unpacker(object):
229229
cdef char* buf
230230
cdef size_t buf_size, buf_head, buf_tail
231231
cdef object file_like
232-
cdef int read_size
232+
cdef object file_like_read
233+
cdef Py_ssize_t read_size
233234
cdef bint use_list
234235
cdef object object_hook
235236

@@ -239,12 +240,16 @@ cdef class Unpacker(object):
239240
def __dealloc__(self):
240241
free(self.buf);
241242

242-
def __init__(self, file_like=None, int read_size=0, bint use_list=0,
243+
def __init__(self, file_like=None, Py_ssize_t read_size=0, bint use_list=0,
243244
object object_hook=None, object list_hook=None):
244245
if read_size == 0:
245246
read_size = 1024*1024
246247
self.use_list = use_list
247248
self.file_like = file_like
249+
if file_like:
250+
self.file_like_read = file_like.read
251+
if not PyCallable_Check(self.file_like_read):
252+
raise ValueError("`file_like.read` must be a callable.")
248253
self.read_size = read_size
249254
self.buf = <char*>malloc(read_size)
250255
self.buf_size = read_size
@@ -265,6 +270,9 @@ cdef class Unpacker(object):
265270
def feed(self, object next_bytes):
266271
cdef char* buf
267272
cdef Py_ssize_t buf_len
273+
if self.file_like is not None:
274+
raise AssertionError(
275+
"unpacker.feed() is not be able to use with`file_like`.")
268276
PyObject_AsReadBuffer(next_bytes, <const_void_ptr*>&buf, &buf_len)
269277
self.append_buffer(buf, buf_len)
270278

@@ -298,7 +306,7 @@ cdef class Unpacker(object):
298306
# prepare self.buf from file_like
299307
cdef fill_buffer(self):
300308
if self.file_like is not None:
301-
next_bytes = self.file_like.read(self.read_size)
309+
next_bytes = self.file_like_read(self.read_size)
302310
if next_bytes:
303311
self.append_buffer(PyBytes_AsString(next_bytes),
304312
PyBytes_Size(next_bytes))
@@ -308,18 +316,19 @@ cdef class Unpacker(object):
308316
cpdef unpack(self):
309317
"""unpack one object"""
310318
cdef int ret
311-
self.fill_buffer()
312-
ret = template_execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head)
313-
if ret == 1:
314-
o = template_data(&self.ctx)
315-
template_init(&self.ctx)
316-
return o
317-
elif ret == 0:
318-
if self.file_like is not None:
319-
return self.unpack()
320-
raise StopIteration, "No more unpack data."
321-
else:
322-
raise ValueError, "Unpack failed."
319+
while 1:
320+
ret = template_execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head)
321+
if ret == 1:
322+
o = template_data(&self.ctx)
323+
template_init(&self.ctx)
324+
return o
325+
elif ret == 0:
326+
if self.file_like is not None:
327+
self.fill_buffer()
328+
continue
329+
raise StopIteration("No more unpack data.")
330+
else:
331+
raise ValueError("Unpack failed: error = %d" % (ret,))
323332

324333
def __iter__(self):
325334
return UnpackIterator(self)

0 commit comments

Comments
 (0)