Bug report
Summary
ZipFile.testzip() can incorrectly report that an archive is valid when an earlier member is corrupt and a later member has the same filename. The method iterates over all ZipInfo objects, but opens each one by filename instead of by its ZipInfo instance. Filename lookup selects the last duplicate, so earlier duplicates are checked against the wrong archive entry.
Minimal Reproducer
import io
import struct
import zipfile
buffer = io.BytesIO()
with zipfile.ZipFile(buffer, "w") as zf:
zf.writestr("duplicate.txt", b"corrupt me")
zf.writestr("duplicate.txt", b"valid data")
raw = bytearray(buffer.getvalue())
# Corrupt the payload of the first duplicate only.
with zipfile.ZipFile(io.BytesIO(raw)) as zf:
first = zf.infolist()[0]
name_length, extra_length = struct.unpack_from(
"<HH", raw, first.header_offset + 26
)
data_offset = (
first.header_offset + zipfile.sizeFileHeader +
name_length + extra_length
)
raw[data_offset] ^= 1
with zipfile.ZipFile(io.BytesIO(raw)) as zf:
first = zf.infolist()[0]
try:
zf.read(first)
except zipfile.BadZipFile:
print("The first duplicate is corrupt")
print(zf.testzip())
Observed output:
The first duplicate is corrupt
None
testzip() should return "duplicate.txt".
Expected Behavior
Every member in infolist() should be validated individually. For duplicate names, testzip() should preserve the identity of each ZipInfo object and open the entry with:
Rather than:
self.open(zinfo.filename, "r")
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs
Bug report
Summary
ZipFile.testzip()can incorrectly report that an archive is valid when an earlier member is corrupt and a later member has the same filename. The method iterates over allZipInfoobjects, but opens each one by filename instead of by itsZipInfoinstance. Filename lookup selects the last duplicate, so earlier duplicates are checked against the wrong archive entry.Minimal Reproducer
Observed output:
testzip()should return"duplicate.txt".Expected Behavior
Every member in
infolist()should be validated individually. For duplicate names,testzip()should preserve the identity of eachZipInfoobject and open the entry with:Rather than:
CPython versions tested on:
CPython main branch
Operating systems tested on:
Linux
Linked PRs