Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-133998: Fix gzip file creation when time is out of range #134278

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
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
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. Set
*mtime* to ``0`` to generate a compressed stream that does not depend on
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, then the value ``0`` is used
instead.

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
12 changes: 10 additions & 2 deletions Lib/gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,11 @@ def __init__(self, filename=None, mode=None,

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.
Set mtime to 0 to generate a compressed stream that does not depend on
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, then the value 0 is used
instead.
Comment on lines +191 to +195

Choose a reason for hiding this comment

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

Ditto, see previous comment


"""

Expand All @@ -203,6 +206,9 @@ def __init__(self, filename=None, mode=None,
if mode and 'b' not in mode:
mode += 'b'

if mtime is not None and (mtime < 0 or mtime >= 2**32):
raise ValueError(f'mtime must be in the range 0 through {2**32-1}')

try:
if fileobj is None:
fileobj = self.myfileobj = builtins.open(filename, mode or 'rb')
Expand Down Expand Up @@ -297,6 +303,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
write32u(self.fileobj, int(mtime))
if compresslevel == _COMPRESS_LEVEL_BEST:
xfl = b'\002'
Expand Down
21 changes: 21 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,26 @@ def test_mtime(self):
self.assertEqual(dataRead, data1)
self.assertEqual(fRead.mtime, mtime)

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

def test_metadata(self):
mtime = 123456789

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix ``struct.error`` exception when creating a file with ``gzip.GzipFile()`` if the system time is outside the range 00:00:00 UTC, January 1, 1970 through 06:28:15 UTC, February 7, 2106.

Choose a reason for hiding this comment

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

I think this should also be tweaked since the behaviour of providing an out-of-range mtime has changed

Loading