Skip to content

reading truncated png can segfault python #9256

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

Closed
anntzer opened this issue Sep 30, 2017 · 6 comments
Closed

reading truncated png can segfault python #9256

anntzer opened this issue Sep 30, 2017 · 6 comments
Milestone

Comments

@anntzer
Copy link
Contributor

anntzer commented Sep 30, 2017

Bug report

Bug summary

Reading a truncated png file can segfault the process.

Code for reproduction

from pylab import *
rcdefaults()
savefig("test.png")
buf = open("test.png", "rb").read()
open("test.png", "wb").write(buf[:20])  # truncate to first 20 bytes
imread("test.png")

Actual outcome

Fatal Python error: Segmentation fault

Current thread 0x00007f3638e8a540 (most recent call first):
  File "/usr/lib/python3.6/site-packages/matplotlib/image.py", line 1298 in imread
  File "/usr/lib/python3.6/site-packages/matplotlib/pyplot.py", line 2314 in imread
  File "test.py", line 6 in <module>
[1]    12789 segmentation fault (core dumped)  python test.py

Expected outcome

Some exception is raised.

(To be honest I'm not fully convinced there's a much of a benefit in shipping our own png wrappers rather than, say, relying on PIL throughout.)

Matplotlib version

  • Operating System: Arch Linux
  • Matplotlib Version: 2.0.2 and master
  • Python Version: 3.6
  • Jupyter Version (if applicable): NA
  • Other Libraries: NA
@tacaswell tacaswell added this to the 2.1.1 (next bug fix release) milestone Oct 1, 2017
@tacaswell
Copy link
Member

attn @mdboom

@tacaswell
Copy link
Member

Related to #5495

Does not segfault on python2

23:18 $ python /tmp/test.py 
libpng error: Read Error
Traceback (most recent call last):
  File "/tmp/test.py", line 8, in <module>
    imread("test.png")
  File "/home/tcaswell/src/p/matplotlib/lib/matplotlib/pyplot.py", line 2233, in imread
    return _imread(*args, **kwargs)
  File "/home/tcaswell/src/p/matplotlib/lib/matplotlib/image.py", line 1300, in imread
    return handler(fd)
RuntimeError: Error setting jump

It looks like it is segfaulting in cpython, not our code

(gdb) run /tmp/test.py 
Starting program: /home/tcaswell/mc3/envs/bleeding/bin/python /tmp/test.py
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
PyBytes_AsStringAndSize (obj=obj@entry=0x0, s=s@entry=0x7fffffffd098, len=len@entry=0x7fffffffd0a0) at Objects/bytesobject.c:1301
1301        if (!PyBytes_Check(obj)) {

I think I have a fix for this....

tacaswell added a commit to tacaswell/matplotlib that referenced this issue Oct 1, 2017
 - be more paranoid in _read_png_data about failed reads and check for
   exceptions after both calls to it
 - in read_png_data kick the png error handling
 - only override the exception in the body of `setjmp` handler if
   there is not already one set

closes matplotlib#9256
@Kojoley
Copy link
Member

Kojoley commented Oct 8, 2017

(To be honest I'm not fully convinced there's a much of a benefit in shipping our own png wrappers rather than, say, relying on PIL throughout.)

Me too, because it requires zlib and libpng build dependencies with zero benefits. I tried to replace _png with a PIL wrappper, but have not fully done it https://github.com/Kojoley/matplotlib/tree/use-pil .
IIRC the main problem is strange 16bit images handling by PIL.

@WeatherGod
Copy link
Member

WeatherGod commented Oct 9, 2017 via email

@Kojoley
Copy link
Member

Kojoley commented Oct 9, 2017

Our PNG wrapper, IIRC, allows us to pass file-like objects (e.g., StringIO,
GzipFile) to the PNG writing and reading library... (or am I getting that
mixed up with our truetype wrapper?)

PIL perfectly does this too, it would be no.1 feature request if it were not.

import io
from PIL import Image, ImageDraw
text = "Hello, PIL!!!"
color = (0, 0, 120)
im = Image.new('RGB', (100, 50), color)
imd = ImageDraw.Draw(im)
imd.text((10, 20), text)
buf = io.BytesIO()
im.save(buf, format='png')
assert buf.getvalue()[1:4] == b'PNG'

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
plt.imshow(Image.open(buf))
plt.show()

@tacaswell
Copy link
Member

closed by #9257

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants