Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ version 1.8.1-dev
+ Fix ``readinto()`` of the private ``isal_zlib._GzipReader`` class, which
wrote into read-only objects such as ``bytes``. It raises ``TypeError`` now.
``igzip.IGzipFile`` was not affected.
+ Fix the ``mtime`` attribute of ``igzip.IGzipFile`` objects in read mode,
which was ``None`` for gzip files with a modification time of 0. It is 0 now,
as in the ``gzip`` module. ``gzip -n``, ``python -m isal.igzip -n``, and
``igzip_threaded`` writers make such files, and so does ``gzip.compress`` by
default on Python 3.14.
+ Fix a crash when there is not enough memory to create an
``igzip_lib.IgzipDecompressor``. It raises ``MemoryError`` now.
+ Fix a crash when there is not enough memory to raise ``BadGzipFile`` for
Expand Down
7 changes: 6 additions & 1 deletion src/isal/isal_zlibmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -1611,6 +1611,9 @@ typedef struct _GzipReaderStruct {
char stream_phase;
char all_bytes_read;
char closed;
/* Set when the first gzip header is read. A modification time of 0 is
valid, so _last_mtime cannot tell whether a header was read. */
char has_last_mtime;
uint32_t _last_mtime;
PyThread_type_lock lock;
struct inflate_state state;
Expand Down Expand Up @@ -1709,6 +1712,7 @@ GzipReader__new__(PyTypeObject *type, PyObject *args, PyObject *kwargs)
self->fp = fp;
self->stream_phase = GzipReader_HEADER;
self->closed = 0;
self->has_last_mtime = 0;
self->_last_mtime = 0;
self->lock = PyThread_allocate_lock();
if (self->lock == NULL) {
Expand Down Expand Up @@ -1869,6 +1873,7 @@ GzipReader_read_into_buffer(GzipReader *self, uint8_t *out_buffer, size_t out_bu
}
uint8_t flags = current_pos[3];
self->_last_mtime = load_u32_le(current_pos + 4);
self->has_last_mtime = 1;
// Skip XFL and header flag
uint8_t *header_cursor = current_pos + 10;
if (flags & FEXTRA) {
Expand Down Expand Up @@ -2280,7 +2285,7 @@ GzipReader_flush(GzipReader *self, PyObject *Py_UNUSED(ignore)) {
static PyObject *
GzipReader_get_last_mtime(GzipReader *self, void *Py_UNUSED(closure))
{
if (self->_last_mtime) {
if (self->has_last_mtime) {
return PyLong_FromUnsignedLong(self->_last_mtime);
}
Py_RETURN_NONE;
Expand Down
9 changes: 9 additions & 0 deletions tests/test_igzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,15 @@ def test_igzip_reader_read_zero():
assert test.read(0) == b""


@pytest.mark.parametrize("mtime", [0, 1, 2**32 - 1])
def test_igzipfile_mtime(mtime):
data = gzip.compress(DATA, mtime=mtime)
with igzip.IGzipFile(fileobj=io.BytesIO(data)) as test:
assert test.mtime is None
assert test.read() == DATA
assert test.mtime == mtime


@pytest.mark.parametrize(["method", "args"], [
("read", ("x",)),
("read", (1, 2)),
Expand Down
Loading