Skip to content

gzip: cannot create file if mtime > 2106-02-07T06:28:15 #133998

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
huwcbjones opened this issue May 14, 2025 · 5 comments
Open

gzip: cannot create file if mtime > 2106-02-07T06:28:15 #133998

huwcbjones opened this issue May 14, 2025 · 5 comments
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error

Comments

@huwcbjones
Copy link

huwcbjones commented May 14, 2025

Bug report

Bug description:

We had a VM where ntp went very wonky and ended up thinking it was the year 2141!
Trying to write a gzip file with the system clock greater than 2106-02-07T06:28:15 results in a struct error because we tried to cram a 64-bit int into a 32 bit field (which won't work).

I wouldn't expect the gzip module to explode in this case, I'd expect it to set the MTIME to 0.
RFC 1952 (if that's at all relevant these days) states

MTIME = 0 means no time stamp is available

MWE

Only tested this on macOS on 3.13.2, but from a cursory glance, the mtime handling hasn't changed in over a decade.

>>> import gzip
>>> gzip.GzipFile("/dev/null", "w", mtime=2**32+1)
Traceback (most recent call last):
  File "<python-input-3>", line 1, in <module>
    gzip.GzipFile("/dev/null", "w", mtime=2**32+1)
    ~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/gzip.py", line 237, in __init__
    self._write_gzip_header(compresslevel)
    ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/gzip.py", line 281, in _write_gzip_header
    write32u(self.fileobj, int(mtime))
    ~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/local/lib/python3.13/gzip.py", line 77, in write32u
    output.write(struct.pack("<L", value))
                 ~~~~~~~~~~~^^^^^^^^^^^^^
struct.error: 'L' format requires 0 <= number <= 4294967295

Proposed Patch

I'd naïvely fix it with this patch

diff --git a/Lib/gzip.py b/Lib/gzip.py
index c00f51858de..29345de4659 100644
--- a/Lib/gzip.py
+++ b/Lib/gzip.py
@@ -297,6 +297,8 @@ def _write_gzip_header(self, compresslevel):
         mtime = self._write_mtime
         if mtime is None:
             mtime = time.time()
+        if mtime > 4294967295:
+            mtime = 0
         write32u(self.fileobj, int(mtime))
         if compresslevel == _COMPRESS_LEVEL_BEST:
             xfl = b'\002'

CPython versions tested on:

3.13

Operating systems tested on:

macOS

Linked PRs

@huwcbjones huwcbjones added the type-bug An unexpected behavior, bug, or error label May 14, 2025
@ZeroIntensity ZeroIntensity added the stdlib Python modules in the Lib dir label May 14, 2025
@StanFromIreland
Copy link
Contributor

It is consistent with the specification, I am +1 for setting it to 0. This will have to be documented.

@adang1345
Copy link
Contributor

I'm at the PyCon US sprints right now, and I decided to give this issue a shot. I have made a pull request.

@StanFromIreland
Copy link
Contributor

@adang1345 In the future please ask before using someones idea, they may want to open the pr themselves.

@huwcbjones
Copy link
Author

@adang1345 , in this case I'd be 108 before this issue could cause any noticeable problems.
Whether I make it that far or not, I think my care levels would be quite low, so feel free to fix this!

@serhiy-storchaka
Copy link
Member

From the changelog for the GNU gzip 1.9 (2018-01-07):

When converting from system-dependent time_t format to the 32-bit
unsigned MTIME format used in gzip files, if a timestamp does not
fit gzip now substitutes zero instead of the timestamp's low-order
32 bits, as per Internet RFC 1952. When converting from MTIME to
time_t format, if a timestamp does not fit gzip now warns and
substitutes the nearest in-range value instead of crashing or
silently substituting an implementation-defined value (typically,
the timestamp's low-order bits). This affects timestamps before
1970 and after 2106, and timestamps after 2038 on platforms with
32-bit signed time_t. [bug present since the beginning]

So replacing the mtime outside of the valid range with 0 looks the most preferable solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir type-bug An unexpected behavior, bug, or error
Projects
Status: No status
Development

No branches or pull requests

5 participants