diff --git a/lib/matplotlib/testing/conftest.py b/lib/matplotlib/testing/conftest.py index 04f6e7048b26..a93f705af092 100644 --- a/lib/matplotlib/testing/conftest.py +++ b/lib/matplotlib/testing/conftest.py @@ -26,6 +26,8 @@ def mpl_test_settings(request): assert len(backend_marker.args) == 1, \ "Marker 'backend' must specify 1 backend." backend, = backend_marker.args + skip_on_importerror = backend_marker.kwargs.get( + 'skip_on_importerror', False) prev_backend = matplotlib.get_backend() style = '_classic_test' # Default of cleanup and image_comparison too. @@ -45,7 +47,7 @@ def mpl_test_settings(request): except ImportError as exc: # Should only occur for the cairo backend tests, if neither # pycairo nor cairocffi are installed. - if 'cairo' in backend.lower(): + if 'cairo' in backend.lower() or skip_on_importerror: pytest.skip("Failed to switch to backend {} ({})." .format(backend, exc)) else: diff --git a/lib/matplotlib/tests/test_backend_tk.py b/lib/matplotlib/tests/test_backend_tk.py new file mode 100644 index 000000000000..18ffcb40a0b1 --- /dev/null +++ b/lib/matplotlib/tests/test_backend_tk.py @@ -0,0 +1,28 @@ +import pytest +import numpy as np +from matplotlib import pyplot as plt + + +@pytest.mark.backend('TkAgg', skip_on_importerror=True) +def test_blit(): + from matplotlib.backends import _tkagg + def evil_blit(photoimage, aggimage, offsets, bboxptr): + data = np.asarray(aggimage) + height, width = data.shape[:2] + dataptr = (height, width, data.ctypes.data) + _tkagg.blit( + photoimage.tk.interpaddr(), str(photoimage), dataptr, offsets, + bboxptr) + + fig, ax = plt.subplots() + for bad_boxes in ((-1, 2, 0, 2), + (2, 0, 0, 2), + (1, 6, 0, 2), + (0, 2, -1, 2), + (0, 2, 2, 0), + (0, 2, 1, 6)): + with pytest.raises(ValueError): + evil_blit(fig.canvas._tkphoto, + np.ones((4, 4, 4)), + (0, 1, 2, 3), + bad_boxes) diff --git a/src/_tkagg.cpp b/src/_tkagg.cpp index 760b4b0efd84..2e5167ac8ff5 100644 --- a/src/_tkagg.cpp +++ b/src/_tkagg.cpp @@ -67,6 +67,11 @@ static PyObject *mpl_tk_blit(PyObject *self, PyObject *args) PyErr_SetString(PyExc_ValueError, "Failed to extract Tk_PhotoHandle"); goto exit; } + if (0 > y1 || y1 > y2 || y2 > height || 0 > x1 || x1 > x2 || x2 > width) { + PyErr_SetString(PyExc_ValueError, "Attempting to draw out of bounds"); + goto exit; + } + block.pixelPtr = data_ptr + 4 * ((height - y2) * width + x1); block.width = x2 - x1; block.height = y2 - y1;