| From f9c6a0549503f00a1ab0ad58a98a30ee99b96770 Mon Sep 17 00:00:00 2001 | |
| From: Leon Anavi <leon.anavi@konsulko.com> | |
| Date: Thu, 9 Jul 2026 11:37:04 +0000 | |
| Subject: [PATCH] Ppmd7/Ppmd8: Fix SIGABRT in OutputBuffer_Grow | |
| The decode loop could abort in OutputBuffer_Grow() when a resumed | |
| decode thread wrote past the current call's max_length. Stop early | |
| once that limit is reached instead of trying to grow the buffer | |
| further. | |
| Also fix Ppmd8Decoder_decode because it never updated needs_input | |
| when input was fully consumed, unlike Ppmd7. | |
| Fixes test_ppmd7_decode_chunks and the equivalent Ppmd8 case, | |
| which previously aborted deterministically partway through decoding | |
| testdata2.ppmd in small chunks. | |
| This work was sponsored by GOVCERT.LU. | |
| Upstream-Status: Pending [https://github.com/miurahr/pyppmd/pull/131/] | |
| Signed-off-by: Leon Anavi <leon.anavi@konsulko.com> | |
| --- | |
| src/ext/_ppmdmodule.c | 16 ++++++++++++++++ | |
| 1 file changed, 16 insertions(+) | |
| diff --git a/src/ext/_ppmdmodule.c b/src/ext/_ppmdmodule.c | |
| index dafa1c5..94f7f18 100644 | |
| --- a/src/ext/_ppmdmodule.c | |
| +++ b/src/ext/_ppmdmodule.c | |
| @@ -531,6 +531,12 @@ Ppmd7Decoder_decode(Ppmd7Decoder *self, PyObject *args, PyObject *kwargs) { | |
| break; | |
| } | |
| if (out->pos == out->size) { | |
| + /* Already reached max_length for this call; stop instead of | |
| + growing (avoids rest<=0 assert in OutputBuffer_Grow) */ | |
| + if (self->blocksOutputBuffer->max_length >= 0 && | |
| + self->blocksOutputBuffer->allocated >= self->blocksOutputBuffer->max_length) { | |
| + break; | |
| + } | |
| if (OutputBuffer_Grow(self->blocksOutputBuffer, out) < 0) { | |
| PyErr_SetString(PyExc_ValueError, "No Memory."); | |
| goto error; | |
| @@ -1276,6 +1282,11 @@ Ppmd8Decoder_decode(Ppmd8Decoder *self, PyObject *args, PyObject *kwargs) { | |
| break; // filled expected | |
| } | |
| if (out->pos == out->size) { | |
| + /* Same guard as for Ppmd7Decoder_decode() above */ | |
| + if (self->blocksOutputBuffer->max_length >= 0 && | |
| + self->blocksOutputBuffer->allocated >= self->blocksOutputBuffer->max_length) { | |
| + break; | |
| + } | |
| if (OutputBuffer_Grow(self->blocksOutputBuffer, out) < 0) { | |
| PyErr_SetString(PyExc_ValueError, "L1586: Unknown status"); | |
| goto error; | |
| @@ -1303,6 +1314,11 @@ Ppmd8Decoder_decode(Ppmd8Decoder *self, PyObject *args, PyObject *kwargs) { | |
| self->in_begin = 0; | |
| self->in_end = 0; | |
| } | |
| + if (self->eof) { | |
| + self->needs_input = False; | |
| + } else { | |
| + self->needs_input = True; | |
| + } | |
| } else { | |
| const size_t data_size = in->size - in->pos; | |
| self->needs_input = False; | |
| -- | |
| 2.47.3 | |