Skip to content

gh-156434: Update entry offsets only after moving them in repack() - #156435

Open
fedonman wants to merge 4 commits into
python:mainfrom
fedonman:fix-zipfile-repack-rollback
Open

fedonman wants to merge 4 commits into
python:mainfrom
fedonman:fix-zipfile-repack-rollback

Conversation

@fedonman

@fedonman fedonman commented Aug 26, 2026 •

Copy link
Copy Markdown
Contributor

_ZipRepacker.repack() set each entry's header_offset before moving its bytes, so after a failed move a later close() wrote a central directory pointing at data that was never moved. Each offset is now set only after that entry has been moved, so entries that finished moving or were never touched stay readable.

_ZipRepacker.repack() updates ZipInfo.header_offset for each member
before moving that member's bytes, so a failing _copy_bytes() left the
in-memory offsets describing a layout that was never written.  remove()
has already set _didModify, so a later close() committed a central
directory built from those offsets, and the archive became unreadable
even though the caller had handled the error.

ZipFile.repack() now snapshots the offsets of the surviving and the
removed entries and restores them if the repack raises.  The copy only
ever moves data to lower offsets, so a partial move never overwrites
its own source and the archive falls back to the state of a remove()
with no repack().

Copilot AI left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Oops, I've triggered Copilot review by mistake, but since it left a valid comment, just shortening the general review message. @m-aciek

Comment thread Lib/zipfile/__init__.py Resolved
Restoring every offset after a failed repack() is wrong once an entry
has been moved over its old position: the restored offset then points
at overwritten data.  Instead, set each entry's header_offset only
after its bytes have been copied, so entries that finished moving or
were never touched stay readable.

This also drops the list(removed) copy, which was only needed because
the rollback read removed a second time.
@fedonman fedonman changed the title gh-156434: Restore entry offsets when repack() fails gh-156434: Update entry offsets only after moving them in repack() Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ZipFile.close() writes wrong offsets after a failed repack()

3 participants