Title: zipfile should catch ValueError as well as OSError to detect bad seek calls
Type: Stage:
Components: Library (Lib) Versions: Python 3.11
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: FFY00, iritkatriel, llllllllll
Priority: normal Keywords:

Created on 2017-02-07 03:14 by llllllllll, last changed 2021-05-24 18:42 by FFY00.

Messages (3)
msg287185 - (view) Author: Joe Jevnik (llllllllll) * Date: 2017-02-07 03:14
In only OSError is checked to see if seek fails:

def _EndRecData64(fpin, offset, endrec):
    Read the ZIP64 end-of-archive records and use that to update endrec
    try: - sizeEndCentDir64Locator, 2)
    except OSError:
        # If the seek fails, the file is not large enough to contain a ZIP64
        # end-of-archive record, so just return the end record we were given.
        return endrec

I belive that this should also catch ValueError so that other file-like objects may be passed to ZipFile. The particular case I ran into was passing an mmap object:

$ python
sys.version_info(major=3, minor=6, micro=0, releaselevel='final', serial=0)
Traceback (most recent call last):
  File "", line 34, in <module>
    with mmap_shared_raw_zipfile( as zf:
  File "/usr/lib64/python3.6/", line 82, in __enter__
    return next(self.gen)
  File "", line 23, in mmap_shared_raw_zipfile
    ZipFile(mm) as zf:
  File "/usr/lib64/python3.6/", line 1100, in __init__
  File "/usr/lib64/python3.6/", line 1163, in _RealGetContents
    endrec = _EndRecData(fp)
  File "/usr/lib64/python3.6/", line 264, in _EndRecData
    return _EndRecData64(fpin, -sizeEndCentDir, endrec)
  File "/usr/lib64/python3.6/", line 196, in _EndRecData64 - sizeEndCentDir64Locator, 2)
ValueError: seek out of range
from contextlib import contextmanager
import mmap
import sys
from tempfile import NamedTemporaryFile
from zipfile import ZipFile


def mmap_shared_raw_zipfile(path):
    """Open a zipfile with mmap shared so the data can be shared in multiple

    path : str
        The path the zipfile to open.

    The context manager returns a :class:`zipfile.ZipFile` on enter.
    with open(path) as f, \
            mmap.mmap(f.fileno(), 0, mmap.MAP_SHARED, mmap.PROT_READ) as mm, \
            ZipFile(mm) as zf:
        yield zf

with NamedTemporaryFile() as f:
    ZipFile(f, mode='w').close()

with NamedTemporaryFile() as f:
    ZipFile(f, mode='w').close()
    with mmap_shared_raw_zipfile( as zf:
msg393314 - (view) Author: Irit Katriel (iritkatriel) * (Python committer) Date: 2021-05-09 10:27
Maybe a better option is to change mmap's seek() to raise an OSError, because it's supposed to behave like a file object.
msg394263 - (view) Author: Filipe LaĆ­ns (FFY00) * (Python triager) Date: 2021-05-24 18:42
That would not stay true to its meaning. AFAIK there are no implied exceptions in file objects. Given the meaning of ValueError, I'd say it is appropriate here.
Date User Action Args
2021-05-24 18:42:06FFY00setnosy: + FFY00
messages: + msg394263
2021-05-09 10:27:50iritkatrielsetnosy: + iritkatriel

messages: + msg393314
versions: + Python 3.11, - Python 3.6
2017-02-07 03:14:05llllllllllcreate