Skip to content
Next Next commit
gh-133998: Fix gzip file creation when time is out of range
  • Loading branch information
adang1345 committed May 19, 2025
commit 64681af6c69ec52a76ef64877ae56851ccab5f8e
9 changes: 6 additions & 3 deletions Doc/library/gzip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,12 @@ The module defines the following items:
is no compression. The default is ``9``.

The optional *mtime* argument is the timestamp requested by gzip. The time
is in Unix format, i.e., seconds since 00:00:00 UTC, January 1, 1970.
If *mtime* is omitted or ``None``, the current time is used. Use *mtime* = 0
to generate a compressed stream that does not depend on creation time.
is in Unix format, i.e., seconds since *00:00:00 UTC, January 1, 1970*.
Comment thread
adang1345 marked this conversation as resolved.
Outdated
Use *mtime* = ``0`` to generate a compressed stream that does not depend on
Comment thread
adang1345 marked this conversation as resolved.
Outdated
creation time. If *mtime* is omitted or ``None``, the current time is used;
however, if the current time is outside the range
*00:00:00 UTC, January 1, 1970* through *06:28:15 UTC, February 7, 2106*,
Comment thread
adang1345 marked this conversation as resolved.
Outdated
then the value ``0`` is used instead.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs are slightly wrong now that GzipFile.__init__ will raise a ValueError if the specified value is out of range.
I know you've documented it in the docstring for __init__, but I think it's worth clarifying here since we're already in the area.

See below for the :attr:`mtime` attribute that is set when decompressing.

Expand Down
2 changes: 2 additions & 0 deletions Lib/gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ def _write_gzip_header(self, compresslevel):
mtime = self._write_mtime
if mtime is None:
mtime = time.time()
if mtime < 0 or mtime >= 2**32:
mtime = 0
Comment thread
adang1345 marked this conversation as resolved.
Outdated
write32u(self.fileobj, int(mtime))
if compresslevel == _COMPRESS_LEVEL_BEST:
xfl = b'\002'
Expand Down
22 changes: 22 additions & 0 deletions Lib/test/test_gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import unittest
import warnings
from subprocess import PIPE, Popen
from unittest import mock
from test.support import catch_unraisable_exception
from test.support import import_helper
from test.support import os_helper
Expand Down Expand Up @@ -351,6 +352,27 @@ def test_mtime(self):
self.assertEqual(dataRead, data1)
self.assertEqual(fRead.mtime, mtime)

def test_mtime_out_of_range(self):
# exception should be raised when mtime<0 or mtime>=2**32 and is
# explicitly specified
with self.assertRaises(Exception):
with gzip.GzipFile(self.filename, 'w', mtime=-1) as fWrite:
pass
with self.assertRaises(Exception):
with gzip.GzipFile(self.filename, 'w', mtime=2**32) as fWrite:
pass

# mtime should be set to 0 when time.time() is out of range and mtime is
# not explicitly given
for mtime in (-1, 2**32):
with mock.patch('time.time', return_value=float(mtime)):
with gzip.GzipFile(self.filename, 'w') as fWrite:
fWrite.write(data1)
with gzip.GzipFile(self.filename) as fRead:
fRead.read()
self.assertEqual(fRead.mtime, 0)

Comment thread
adang1345 marked this conversation as resolved.

def test_metadata(self):
mtime = 123456789

Expand Down