Skip to content

Commit 16d3616

Browse files
committed
fix decompress application segfault
1 parent b48831f commit 16d3616

File tree

1 file changed

+53
-53
lines changed

1 file changed

+53
-53
lines changed

src/isal/isal_zlib.pyx

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -373,19 +373,13 @@ cdef class Decompress:
373373
if err != COMP_OK:
374374
check_isal_deflate_rc(err)
375375
self.obuflen = DEF_BUF_SIZE
376-
self.obuf = <unsigned char *>PyMem_Malloc(self.obuflen * sizeof(char))
377376
self.unused_data = b""
378377
self.unconsumed_tail = b""
379378
self.eof = 0
380379
self.is_initialised = 1
381380

382-
def __dealloc__(self):
383-
if self.obuf is not NULL:
384-
PyMem_Free(self.obuf)
385-
386381
def decompress(self, data, Py_ssize_t max_length = 0):
387-
# Initialise output buffer
388-
out = []
382+
389383
cdef Py_ssize_t total_bytes = 0
390384
if max_length > UINT32_MAX:
391385
raise OverflowError("A maximum of 4 GB is allowed for the max "
@@ -395,8 +389,6 @@ cdef class Decompress:
395389
elif max_length < 0:
396390
raise ValueError("max_length can not be smaller than 0")
397391

398-
if data == b"":
399-
data = self.unconsumed_tail
400392
cdef Py_ssize_t total_length = len(data)
401393
if total_length > UINT32_MAX:
402394
# Zlib allows a maximum of 64 KB (16-bit length) and python has
@@ -412,52 +404,60 @@ cdef class Decompress:
412404
cdef unsigned long bytes_written
413405
cdef Py_ssize_t unused_bytes
414406
cdef int err
407+
408+
# Initialise output buffer
409+
cdef unsigned char * obuf = <unsigned char*> PyMem_Malloc(self.obuflen * sizeof(char))
410+
out = []
411+
415412
cdef bint last_round = 0
416-
# This loop reads all the input bytes. If there are no input bytes
417-
# anymore the output is written.
418-
while (self.stream.avail_out == 0
419-
or self.stream.avail_in != 0):
420-
self.stream.next_out = self.obuf # Reset output buffer.
421-
if total_bytes >= max_length:
422-
break
423-
elif total_bytes + self.obuflen >= max_length:
424-
self.stream.avail_out = max_length - total_bytes
425-
# The inflate process may not fill all available bytes so
426-
# we make sure this is the last round.
427-
last_round = 1
428-
else:
429-
self.stream.avail_out = self.obuflen
430-
prev_avail_out = self.stream.avail_out
431-
err = isal_inflate(&self.stream)
432-
if err != ISAL_DECOMP_OK:
433-
# There is some python interacting when possible exceptions
434-
# Are raised. So we remain in pure C code if we check for
435-
# COMP_OK first.
436-
check_isal_inflate_rc(err)
437-
bytes_written = prev_avail_out - self.stream.avail_out
438-
total_bytes += bytes_written
439-
out.append(self.obuf[:bytes_written])
440-
if self.stream.block_state == ISAL_BLOCK_FINISH or last_round:
441-
break
442-
# Save unconsumed input implementation from zlibmodule.c
443-
if self.stream.block_state == ISAL_BLOCK_FINISH:
444-
# The end of the compressed data has been reached. Store the
445-
# leftover input data in self->unused_data.
446-
self.eof = 1
447-
if self.stream.avail_in > 0:
413+
try:
414+
# This loop reads all the input bytes. If there are no input bytes
415+
# anymore the output is written.
416+
while (self.stream.avail_out == 0
417+
or self.stream.avail_in != 0):
418+
self.stream.next_out = obuf # Reset output buffer.
419+
if total_bytes >= max_length:
420+
break
421+
elif total_bytes + self.obuflen >= max_length:
422+
self.stream.avail_out = max_length - total_bytes
423+
# The inflate process may not fill all available bytes so
424+
# we make sure this is the last round.
425+
last_round = 1
426+
else:
427+
self.stream.avail_out = self.obuflen
428+
prev_avail_out = self.stream.avail_out
429+
err = isal_inflate(&self.stream)
430+
if err != ISAL_DECOMP_OK:
431+
# There is some python interacting when possible exceptions
432+
# Are raised. So we remain in pure C code if we check for
433+
# COMP_OK first.
434+
check_isal_inflate_rc(err)
435+
bytes_written = prev_avail_out - self.stream.avail_out
436+
total_bytes += bytes_written
437+
out.append(obuf[:bytes_written])
438+
if self.stream.block_state == ISAL_BLOCK_FINISH or last_round:
439+
break
440+
# Save unconsumed input implementation from zlibmodule.c
441+
if self.stream.block_state == ISAL_BLOCK_FINISH:
442+
# The end of the compressed data has been reached. Store the
443+
# leftover input data in self->unused_data.
444+
self.eof = 1
445+
if self.stream.avail_in > 0:
446+
unused_bytes = self.stream.avail_in
447+
self.unused_data = data[-unused_bytes:]
448+
self.stream.avail_in = 0
449+
if self.stream.avail_in > 0 or self.unconsumed_tail:
450+
# This code handles two distinct cases:
451+
# 1. Output limit was reached. Save leftover input in unconsumed_tail.
452+
# 2. All input data was consumed. Clear unconsumed_tail.
448453
unused_bytes = self.stream.avail_in
449-
self.unused_data = data[-unused_bytes:]
450-
self.stream.avail_in = 0
451-
if self.stream.avail_in > 0 or self.unconsumed_tail:
452-
# This code handles two distinct cases:
453-
# 1. Output limit was reached. Save leftover input in unconsumed_tail.
454-
# 2. All input data was consumed. Clear unconsumed_tail.
455-
unused_bytes = self.stream.avail_in
456-
if unused_bytes == 0:
457-
self.unconsumed_tail = b""
458-
else:
459-
self.unconsumed_tail = data[-unused_bytes:]
460-
return b"".join(out)
454+
if unused_bytes == 0:
455+
self.unconsumed_tail = b""
456+
else:
457+
self.unconsumed_tail = data[-unused_bytes:]
458+
return b"".join(out)
459+
finally:
460+
PyMem_Free(obuf)
461461

462462
def flush(self, Py_ssize_t length = DEF_BUF_SIZE):
463463
if length <= 0:

0 commit comments

Comments
 (0)