From 1178365e6ffa5ddac3a50bfa2ab0e6d387b122d5 Mon Sep 17 00:00:00 2001 From: Vladislav Glinkin Date: Tue, 29 Sep 2026 17:27:32 +0300 Subject: [PATCH] Discard compressed input buffer on backward gzip seek --- CHANGELOG.rst | 2 ++ src/isal/isal_zlibmodule.c | 4 ++++ tests/test_seek_buffer_reset.py | 30 ++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 tests/test_seek_buffer_reset.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b8471793..37edd493 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -11,6 +11,8 @@ Changelog version 1.8.1-dev ----------------- + Restore PyPy wheel builds. ++ Fix backward seeking in igzip files by discarding buffered compressed data + when rewinding the underlying file. version 1.8.0 ----------------- diff --git a/src/isal/isal_zlibmodule.c b/src/isal/isal_zlibmodule.c index 3a280ec8..fe779176 100644 --- a/src/isal/isal_zlibmodule.c +++ b/src/isal/isal_zlibmodule.c @@ -1918,6 +1918,10 @@ GzipReader_seek(GzipReader *self, PyObject *args, PyObject *kwargs) if (seek_result == NULL) { return NULL; } + Py_DECREF(seek_result); + /* Discard compressed data buffered before rewinding the file. */ + self->current_pos = self->input_buffer; + self->buffer_end = self->input_buffer; self->stream_phase = GzipReader_HEADER; self->_pos = 0; self->all_bytes_read = 0; diff --git a/tests/test_seek_buffer_reset.py b/tests/test_seek_buffer_reset.py new file mode 100644 index 00000000..023ec86f --- /dev/null +++ b/tests/test_seek_buffer_reset.py @@ -0,0 +1,30 @@ +"""Force backward seeks past the outer buffer and through the raw reader.""" +import gzip +import io +import random + +from isal import igzip + +import pytest + + +@pytest.mark.parametrize('writer', [gzip.compress, igzip.compress]) +@pytest.mark.parametrize('random_data', [False, True]) +def test_backward_seek_discards_compressed_buffer(writer, random_data): + data = (random.Random(42).randbytes(1048576) if random_data + else b'hello world' * 100000) + with igzip.open(io.BytesIO(writer(data)), 'rb') as reader: + for offset in (12345, 0, 750000, 10, 32768, 0): + assert reader.seek(offset) == offset + assert reader.read(400) == data[offset:offset+400] + reader.seek(0) + assert reader.read() == data + + +@pytest.mark.parametrize('size', [110, 8192, 32768]) +def test_raw_reader_backward_seek(size): + data = random.Random(42).randbytes(size) + reader = igzip._GzipReader(io.BytesIO(gzip.compress(data))) + assert reader.read(1) == data[:1] + assert reader.seek(0) == 0 + assert reader.readall() == data