Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 080d0f8

Browse files
authored
Merge pull request #9257 from tacaswell/fix_png_segfault
FIX: segfault on truncated png
2 parents ba79e99 + 6ebcb11 commit 080d0f8

File tree

2 files changed

+69
-28
lines changed

2 files changed

+69
-28
lines changed

lib/matplotlib/tests/test_png.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,15 @@
22
unicode_literals)
33

44
import six
5-
5+
from six import BytesIO
66
import glob
77
import os
8-
98
import numpy as np
9+
import pytest
1010

1111
from matplotlib.testing.decorators import image_comparison
1212
from matplotlib import pyplot as plt
1313
import matplotlib.cm as cm
14-
1514
import sys
1615
on_win = (sys.platform == 'win32')
1716

@@ -46,3 +45,28 @@ def test_imread_png_uint16():
4645

4746
assert (img.dtype == np.uint16)
4847
assert np.sum(img.flatten()) == 134184960
48+
49+
50+
def test_truncated_file(tmpdir):
51+
d = tmpdir.mkdir('test')
52+
fname = str(d.join('test.png'))
53+
fname_t = str(d.join('test_truncated.png'))
54+
plt.savefig(fname)
55+
with open(fname, 'rb') as fin:
56+
buf = fin.read()
57+
with open(fname_t, 'wb') as fout:
58+
fout.write(buf[:20])
59+
60+
with pytest.raises(Exception):
61+
plt.imread(fname_t)
62+
63+
64+
def test_truncated_buffer():
65+
b = BytesIO()
66+
plt.savefig(b)
67+
b.seek(0)
68+
b2 = BytesIO(b.read(20))
69+
b2.seek(0)
70+
71+
with pytest.raises(Exception):
72+
plt.imread(b2)

src/_png.cpp

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -194,18 +194,18 @@ static PyObject *Py_write_png(PyObject *self, PyObject *args, PyObject *kwds)
194194

195195
switch (channels) {
196196
case 1:
197-
png_color_type = PNG_COLOR_TYPE_GRAY;
198-
break;
197+
png_color_type = PNG_COLOR_TYPE_GRAY;
198+
break;
199199
case 3:
200-
png_color_type = PNG_COLOR_TYPE_RGB;
201-
break;
200+
png_color_type = PNG_COLOR_TYPE_RGB;
201+
break;
202202
case 4:
203-
png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
204-
break;
203+
png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
204+
break;
205205
default:
206206
PyErr_SetString(PyExc_ValueError,
207-
"Buffer must be an NxMxD array with D in 1, 3, 4 "
208-
"(grayscale, RGB, RGBA)");
207+
"Buffer must be an NxMxD array with D in 1, 3, 4 "
208+
"(grayscale, RGB, RGBA)");
209209
goto exit;
210210
}
211211

@@ -349,20 +349,20 @@ static PyObject *Py_write_png(PyObject *self, PyObject *args, PyObject *kwds)
349349
sig_bit.alpha = 0;
350350
switch (png_color_type) {
351351
case PNG_COLOR_TYPE_GRAY:
352-
sig_bit.gray = 8;
353-
sig_bit.red = 0;
354-
sig_bit.green = 0;
355-
sig_bit.blue = 0;
356-
break;
352+
sig_bit.gray = 8;
353+
sig_bit.red = 0;
354+
sig_bit.green = 0;
355+
sig_bit.blue = 0;
356+
break;
357357
case PNG_COLOR_TYPE_RGB_ALPHA:
358-
sig_bit.alpha = 8;
359-
// fall through
358+
sig_bit.alpha = 8;
359+
// fall through
360360
case PNG_COLOR_TYPE_RGB:
361-
sig_bit.gray = 0;
362-
sig_bit.red = 8;
363-
sig_bit.green = 8;
364-
sig_bit.blue = 8;
365-
break;
361+
sig_bit.gray = 0;
362+
sig_bit.red = 8;
363+
sig_bit.green = 8;
364+
sig_bit.blue = 8;
365+
break;
366366
default:
367367
PyErr_SetString(PyExc_RuntimeError, "internal error, bad png_color_type");
368368
goto exit;
@@ -408,13 +408,21 @@ static void _read_png_data(PyObject *py_file_obj, png_bytep data, png_size_t len
408408
Py_ssize_t bufflen;
409409
if (read_method) {
410410
result = PyObject_CallFunction(read_method, (char *)"i", length);
411-
if (PyBytes_AsStringAndSize(result, &buffer, &bufflen) == 0) {
412-
if (bufflen == (Py_ssize_t)length) {
413-
memcpy(data, buffer, length);
411+
if (result) {
412+
if (PyBytes_AsStringAndSize(result, &buffer, &bufflen) == 0) {
413+
if (bufflen == (Py_ssize_t)length) {
414+
memcpy(data, buffer, length);
415+
} else {
416+
PyErr_SetString(PyExc_IOError, "read past end of file");
417+
}
414418
} else {
415-
PyErr_SetString(PyExc_IOError, "read past end of file");
419+
PyErr_SetString(PyExc_IOError, "failed to copy buffer");
416420
}
421+
} else {
422+
PyErr_SetString(PyExc_IOError, "failed to read file");
417423
}
424+
425+
418426
}
419427
Py_XDECREF(read_method);
420428
Py_XDECREF(result);
@@ -424,6 +432,10 @@ static void read_png_data(png_structp png_ptr, png_bytep data, png_size_t length
424432
{
425433
PyObject *py_file_obj = (PyObject *)png_get_io_ptr(png_ptr);
426434
_read_png_data(py_file_obj, data, length);
435+
if (PyErr_Occurred()) {
436+
png_error(png_ptr, "failed to read file");
437+
}
438+
427439
}
428440

429441
static PyObject *_read_png(PyObject *filein, bool float_result)
@@ -481,6 +493,9 @@ static PyObject *_read_png(PyObject *filein, bool float_result)
481493
}
482494
Py_XDECREF(read_method);
483495
_read_png_data(py_file, header, 8);
496+
if (PyErr_Occurred()) {
497+
goto exit;
498+
}
484499
}
485500

486501
if (png_sig_cmp(header, 0, 8)) {
@@ -503,7 +518,9 @@ static PyObject *_read_png(PyObject *filein, bool float_result)
503518
}
504519

505520
if (setjmp(png_jmpbuf(png_ptr))) {
506-
PyErr_SetString(PyExc_RuntimeError, "Error setting jump");
521+
if (!PyErr_Occurred()) {
522+
PyErr_SetString(PyExc_RuntimeError, "error setting jump");
523+
}
507524
goto exit;
508525
}
509526

0 commit comments

Comments
 (0)