From a13609516ce1f8cf0c1fd5d5463adc7e9220edec Mon Sep 17 00:00:00 2001 From: Andrew Murray Date: Mon, 30 Dec 2024 15:21:57 +1100 Subject: [PATCH] Check that _fp type is not DeferredError before use --- src/PIL/DcxImagePlugin.py | 3 +++ src/PIL/FliImagePlugin.py | 3 +++ src/PIL/GifImagePlugin.py | 3 +++ src/PIL/ImImagePlugin.py | 3 +++ src/PIL/Image.py | 2 +- src/PIL/MpoImagePlugin.py | 5 +++++ src/PIL/PngImagePlugin.py | 3 +++ src/PIL/PsdImagePlugin.py | 5 +++++ src/PIL/SpiderImagePlugin.py | 3 +++ src/PIL/TiffImagePlugin.py | 4 +++- 10 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/PIL/DcxImagePlugin.py b/src/PIL/DcxImagePlugin.py index f67f27d73bb..aea661b9cb6 100644 --- a/src/PIL/DcxImagePlugin.py +++ b/src/PIL/DcxImagePlugin.py @@ -24,6 +24,7 @@ from . import Image from ._binary import i32le as i32 +from ._util import DeferredError from .PcxImagePlugin import PcxImageFile MAGIC = 0x3ADE68B1 # QUIZ: what's this value, then? @@ -66,6 +67,8 @@ def _open(self) -> None: def seek(self, frame: int) -> None: if not self._seek_check(frame): return + if isinstance(self._fp, DeferredError): + raise self._fp.ex self.frame = frame self.fp = self._fp self.fp.seek(self._offset[frame]) diff --git a/src/PIL/FliImagePlugin.py b/src/PIL/FliImagePlugin.py index b534b30ab83..7c5bfeefa1b 100644 --- a/src/PIL/FliImagePlugin.py +++ b/src/PIL/FliImagePlugin.py @@ -22,6 +22,7 @@ from ._binary import i16le as i16 from ._binary import i32le as i32 from ._binary import o8 +from ._util import DeferredError # # decoder @@ -134,6 +135,8 @@ def seek(self, frame: int) -> None: self._seek(f) def _seek(self, frame: int) -> None: + if isinstance(self._fp, DeferredError): + raise self._fp.ex if frame == 0: self.__frame = -1 self._fp.seek(self.__rewind) diff --git a/src/PIL/GifImagePlugin.py b/src/PIL/GifImagePlugin.py index 47022d58436..2c48c747be7 100644 --- a/src/PIL/GifImagePlugin.py +++ b/src/PIL/GifImagePlugin.py @@ -45,6 +45,7 @@ from ._binary import i16le as i16 from ._binary import o8 from ._binary import o16le as o16 +from ._util import DeferredError if TYPE_CHECKING: from . import _imaging @@ -167,6 +168,8 @@ def seek(self, frame: int) -> None: raise EOFError(msg) from e def _seek(self, frame: int, update_image: bool = True) -> None: + if isinstance(self._fp, DeferredError): + raise self._fp.ex if frame == 0: # rewind self.__offset = 0 diff --git a/src/PIL/ImImagePlugin.py b/src/PIL/ImImagePlugin.py index b4215a0b1e5..2209177dce1 100644 --- a/src/PIL/ImImagePlugin.py +++ b/src/PIL/ImImagePlugin.py @@ -31,6 +31,7 @@ from typing import IO, Any from . import Image, ImageFile, ImagePalette +from ._util import DeferredError # -------------------------------------------------------------------- # Standard tags @@ -290,6 +291,8 @@ def is_animated(self) -> bool: def seek(self, frame: int) -> None: if not self._seek_check(frame): return + if isinstance(self._fp, DeferredError): + raise self._fp.ex self.frame = frame diff --git a/src/PIL/Image.py b/src/PIL/Image.py index dff3d063b13..653195c8d3d 100644 --- a/src/PIL/Image.py +++ b/src/PIL/Image.py @@ -604,7 +604,7 @@ def __enter__(self): return self def _close_fp(self): - if getattr(self, "_fp", False): + if getattr(self, "_fp", False) and not isinstance(self._fp, DeferredError): if self._fp != self.fp: self._fp.close() self._fp = DeferredError(ValueError("Operation on closed image")) diff --git a/src/PIL/MpoImagePlugin.py b/src/PIL/MpoImagePlugin.py index 71f89a09a85..ea792e2fa0d 100644 --- a/src/PIL/MpoImagePlugin.py +++ b/src/PIL/MpoImagePlugin.py @@ -32,6 +32,7 @@ TiffImagePlugin, ) from ._binary import o32le +from ._util import DeferredError def _save(im: Image.Image, fp: IO[bytes], filename: str | bytes) -> None: @@ -125,11 +126,15 @@ def _after_jpeg_open(self, mpheader: dict[int, Any] | None = None) -> None: self.readonly = 1 def load_seek(self, pos: int) -> None: + if isinstance(self._fp, DeferredError): + raise self._fp.ex self._fp.seek(pos) def seek(self, frame: int) -> None: if not self._seek_check(frame): return + if isinstance(self._fp, DeferredError): + raise self._fp.ex self.fp = self._fp self.offset = self.__mpoffsets[frame] diff --git a/src/PIL/PngImagePlugin.py b/src/PIL/PngImagePlugin.py index 4b97992a31f..b44cf96652a 100644 --- a/src/PIL/PngImagePlugin.py +++ b/src/PIL/PngImagePlugin.py @@ -48,6 +48,7 @@ from ._binary import o8 from ._binary import o16be as o16 from ._binary import o32be as o32 +from ._util import DeferredError if TYPE_CHECKING: from . import _imaging @@ -869,6 +870,8 @@ def seek(self, frame: int) -> None: def _seek(self, frame: int, rewind: bool = False) -> None: assert self.png is not None + if isinstance(self._fp, DeferredError): + raise self._fp.ex self.dispose: _imaging.ImagingCore | None dispose_extent = None diff --git a/src/PIL/PsdImagePlugin.py b/src/PIL/PsdImagePlugin.py index 8ff5e39088a..fe6a5723e7d 100644 --- a/src/PIL/PsdImagePlugin.py +++ b/src/PIL/PsdImagePlugin.py @@ -27,6 +27,7 @@ from ._binary import i32be as i32 from ._binary import si16be as si16 from ._binary import si32be as si32 +from ._util import DeferredError MODES = { # (photoshop mode, bits) -> (pil mode, required channels) @@ -148,6 +149,8 @@ def layers( ) -> list[tuple[str, str, tuple[int, int, int, int], list[ImageFile._Tile]]]: layers = [] if self._layers_position is not None: + if isinstance(self._fp, DeferredError): + raise self._fp.ex self._fp.seek(self._layers_position) _layer_data = io.BytesIO(ImageFile._safe_read(self._fp, self._layers_size)) layers = _layerinfo(_layer_data, self._layers_size) @@ -167,6 +170,8 @@ def is_animated(self) -> bool: def seek(self, layer: int) -> None: if not self._seek_check(layer): return + if isinstance(self._fp, DeferredError): + raise self._fp.ex # seek to given layer (1..max) try: diff --git a/src/PIL/SpiderImagePlugin.py b/src/PIL/SpiderImagePlugin.py index 3a87d009adc..3bd3510faa0 100644 --- a/src/PIL/SpiderImagePlugin.py +++ b/src/PIL/SpiderImagePlugin.py @@ -40,6 +40,7 @@ from typing import IO, TYPE_CHECKING, Any, cast from . import Image, ImageFile +from ._util import DeferredError def isInt(f: Any) -> int: @@ -178,6 +179,8 @@ def seek(self, frame: int) -> None: raise EOFError(msg) if not self._seek_check(frame): return + if isinstance(self._fp, DeferredError): + raise self._fp.ex self.stkoffset = self.hdrlen + frame * (self.hdrlen + self.imgbytes) self.fp = self._fp self.fp.seek(self.stkoffset) diff --git a/src/PIL/TiffImagePlugin.py b/src/PIL/TiffImagePlugin.py index 16c521bea25..585bbc38bbf 100644 --- a/src/PIL/TiffImagePlugin.py +++ b/src/PIL/TiffImagePlugin.py @@ -58,7 +58,7 @@ from ._binary import o8 from ._deprecate import deprecate from ._typing import StrOrBytesPath -from ._util import is_path +from ._util import DeferredError, is_path from .TiffTags import TYPES if TYPE_CHECKING: @@ -1212,6 +1212,8 @@ def seek(self, frame: int) -> None: self._im = None def _seek(self, frame: int) -> None: + if isinstance(self._fp, DeferredError): + raise self._fp.ex self.fp = self._fp while len(self._frame_pos) <= frame: