Repository navigation
Corrupt .pyc files stay on disk after failed writes #126606
Copy link
Copy link
Closed
Labels
3.12only security fixesonly security fixes3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-importlibtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Description
Activity
- addedtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
on Nov 8, 2024 can reproduce this on cpython 3.11, git head, and on pypy (I tried on ubuntu). the problem is likely in importlib somewhere.
the problem is
_write_atomicin_bootstrap_external.py:def _write_atomic(path, data, mode=0o666): """Best-effort function to write data to a path atomically. Be prepared to handle a FileExistsError if concurrent writing of the temporary file is attempted.""" import os as _os import _io # id() is used to generate a pseudo-random filename. path_tmp = '{}.{}'.format(path, id(path)) fd = _os.open(path_tmp, _os.O_EXCL | _os.O_CREAT | _os.O_WRONLY, mode & 0o666) try: # We first write data to a temporary file, and then use os.replace() to # perform an atomic rename. with _io.FileIO(fd, 'wb') as file: file.write(data) _os.replace(path_tmp, path) except OSError: try: _os.unlink(path_tmp) except OSError: pass raise
So we should check the result of the write call, and if the length is not equal to that of data, abort the operation.
the use of
FileIO.writecauses the issue, since the docs of that say:write(self, b, /)
Write buffer b to file, return number of bytes written.Only makes one system call, so not all of the data may be written.
The number of bytes actually written is returned. In non-blocking mode,
returns None if the write would block.- addedstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directory3.12only security fixesonly security fixes3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixes
on Nov 9, 2024 Thanks, everyone! This is now fixed in 3.12 to
main.Reacted by Cody Maloney and Kevin Burk@brettcannon thanks a lot Brett! will backport to pypy now.
Reacted by Brett Cannon- added a commit that references this issue
on Nov 28, 2024 - added 4 commits that reference this issue
on Jun 5, 2026
Metadata
Metadata
Assignees
Labels
3.12only security fixesonly security fixes3.13only security fixesonly security fixes3.14bugs and security fixesbugs and security fixesstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytopic-importlibtype-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error
Bug report
Bug description:
If writing a
.pycfile fails (in my case due to a file size limit imposed byulimit), it can leave corrupt data sitting on disk. This causes a crash the second time you run the program, when the interpreter tries to load the corrupt.pycfile instead of the original.pyfile:This was a very hard bug to track down, and it seems like there's a chance to catch this and handle it gracefully. If I do a too-large write myself, I get an
OSError: [Errno 27] File too large, and I'd imagine the interpreter can see something similar. Ideally (in my opinion - feedback appreciated!), the interpreter would notice this and then:sys.dont_write_bytecode = True(this is the workaround I've been using).Here's the code I've been using to test this (
bigfilecan be pretty much anything, but it does seem to have to be part of a module before the interpreter will write a.pycfile for it).Tested in Python 3.10 on OSX and Python 3.12 in an Ubuntu 24 container.
CPython versions tested on:
3.10, 3.12
Operating systems tested on:
Linux, macOS
Linked PRs