Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parser for PNG fails when fed halfway through zTXt chunk #318

Closed
vytisb opened this issue Aug 13, 2013 · 8 comments

Comments

Projects
None yet
3 participants
@vytisb
Copy link
Contributor

commented Aug 13, 2013

It raises zlib.error, which is never caught.

I solved it locally with the following:

--- a/PIL/PngImagePlugin.py
+++ b/PIL/PngImagePlugin.py
@@ -310,7 +310,10 @@ class PngStream(ChunkStream):
         if comp_method != 0:
             raise SyntaxError("Unknown compression method %s in zTXt chunk" % comp_method)
         import zlib
-        v = zlib.decompress(v[1:])
+        try:
+            v = zlib.decompress(v[1:])
+        except zlib.error as e:
+            raise IOError("zlib error: " + e.message)

         if bytes is not str:
             k = k.decode('latin-1', 'strict')
@wiredfool

This comment has been minimized.

Copy link
Member

commented Aug 13, 2013

Do you have a sample image that triggers the error?

@vytisb

This comment has been minimized.

Copy link
Contributor Author

commented Aug 13, 2013

I made up an image and inserted a zTXt chunk at the beginning:
pillow318.png

Code that triggers the error:

from PIL import ImageFile
p = ImageFile.Parser()
with open('pillow318.png', 'rb') as f:
    p.feed(f.read(64))

The last line raises a zlib.error:

Traceback (most recent call last):
  File "<pyshell#108>", line 2, in <module>
    p.feed(f.read(64))
  File "C:\Python27\lib\site-packages\PIL\ImageFile.py", line 372, in feed
    im = Image.open(fp)
  File "C:\Python27\lib\site-packages\PIL\Image.py", line 2001, in open
    return factory(fp, filename)
  File "C:\Python27\lib\site-packages\PIL\ImageFile.py", line 94, in __init__
    self._open()
  File "C:\Python27\lib\site-packages\PIL\PngImagePlugin.py", line 357, in _open
    s = self.png.call(cid, pos, len)
  File "C:\Python27\lib\site-packages\PIL\PngImagePlugin.py", line 118, in call
    return getattr(self, "chunk_" + cid.decode('ascii'))(pos, len)
  File "C:\Python27\lib\site-packages\PIL\PngImagePlugin.py", line 314, in chunk_zTXt
    v = zlib.decompress(v[1:])
error: Error -5 while decompressing data: incomplete or truncated stream

Btw, Image.open() opens the file just fine.

@d-schmidt

This comment has been minimized.

Copy link
Contributor

commented Aug 14, 2013

open() just reads some header data and does not load the image. Image.open(yourbrokenimage.png).load() should trigger the error too.

+1 for wrapping the zlib error in a proper IOError.
What effect has ImageFile.LOAD_TRUNCATED_IMAGES = True?

@vytisb

This comment has been minimized.

Copy link
Contributor Author

commented Aug 14, 2013

The image itself is valid. I forgot to mention that load() also works fine.
The problem occurs when you don't have the whole file (as is the case of Parser).

LOAD_TRUNCATED_IMAGES doesn't change anything.

I have looked through other chunk handlers and it seems that similar errors are caught and ignored. So, for consistency, maybe it is better not to wrap it into a IOError, but skip the chunk completely?

@d-schmidt

This comment has been minimized.

Copy link
Contributor

commented Aug 14, 2013

zTXt stores text, skipping it sounds reasonable.

@wiredfool

This comment has been minimized.

Copy link
Member

commented Aug 14, 2013

So, if I understand this correctly, if you feed the stream parser a partial chunk of compressed data, it barfs with an internal error rather than the IoError that the rest of the code throws if there's a similar error. I assume that if you manage to feed the parser an entire chunk, it decides it correctly?

@vytisb

This comment has been minimized.

Copy link
Contributor Author

commented Aug 19, 2013

@wiredfool, that is correct.
Except for IOError part.

Here's an updated patch, with error handling consistent with chunk_tEXt() (uncompressed text data):

--- a/PIL/PngImagePlugin.py
+++ b/PIL/PngImagePlugin.py
@@ -305,12 +305,18 @@ class PngStream(ChunkStream):

         # compressed text
         s = ImageFile._safe_read(self.fp, len)
-        k, v = s.split(b"\0", 1)
+        try:
+            k, v = s.split(b"\0", 1)
+        except ValueError:
+            k = s; v = b""
         comp_method = i8(v[0])
         if comp_method != 0:
             raise SyntaxError("Unknown compression method %s in zTXt chunk" % comp_method)
         import zlib
-        v = zlib.decompress(v[1:])
+        try:
+            v = zlib.decompress(v[1:])
+        except zlib.error:
+            v = b""

         if bytes is not str:
             k = k.decode('latin-1', 'strict')
@wiredfool

This comment has been minimized.

Copy link
Member

commented Aug 19, 2013

Ok. Looks reasonable to me. Can you package it in a pull request with a test case including the upthread image?

wiredfool added a commit that referenced this issue Aug 21, 2013

Merge pull request #321 from vytisb/master
Fix for #318: Catch truncated zTXt chunk errors when decoding PNG images.

@wiredfool wiredfool closed this Aug 21, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.