Skip to content

Commit fe66871

Browse files
authored
Merge pull request #5397 from wiredfool/valgrind_fixes
Valgrind fixes
2 parents 356681f + 75c60bd commit fe66871

17 files changed

+128
-25
lines changed

Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ sdist:
102102
test:
103103
pytest -qq
104104

105+
.PHONY: valgrind
106+
valgrind:
107+
python3 -c "import pytest_valgrind" || pip3 install pytest-valgrind
108+
PYTHONMALLOC=malloc valgrind --suppressions=Tests/oss-fuzz/python.supp --leak-check=no \
109+
--log-file=/tmp/valgrind-output \
110+
python3 -m pytest --no-memcheck -vv --valgrind --valgrind-log=/tmp/valgrind-output
111+
105112
.PHONY: readme
106113
readme:
107114
python3 setup.py --long-description | markdown2 > .long-description.html && open .long-description.html

Tests/conftest.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ def pytest_report_header(config):
1313

1414

1515
def pytest_configure(config):
16+
config.addinivalue_line(
17+
"markers",
18+
"pil_noop_mark: A conditional mark where nothing special happens",
19+
)
20+
1621
# We're marking some tests to ignore valgrind errors and XFAIL them.
1722
# Ensure that the mark is defined
1823
# even in cases where pytest-valgrind isn't installed

Tests/helper.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,21 @@ def skip_unless_feature_version(feature, version_required, reason=None):
173173
return pytest.mark.skipif(version_available < version_required, reason=reason)
174174

175175

176+
def mark_if_feature_version(mark, feature, version_blacklist, reason=None):
177+
if not features.check(feature):
178+
return pytest.mark.pil_noop_mark()
179+
if reason is None:
180+
reason = f"{feature} is {version_blacklist}"
181+
version_required = parse_version(version_blacklist)
182+
version_available = parse_version(features.version(feature))
183+
if (
184+
version_available.major == version_required.major
185+
and version_available.minor == version_required.minor
186+
):
187+
return mark(reason=reason)
188+
return pytest.mark.pil_noop_mark()
189+
190+
176191
@pytest.mark.skipif(sys.platform.startswith("win32"), reason="Requires Unix or macOS")
177192
class PillowLeakTestCase:
178193
# requires unix/macOS

Tests/oss-fuzz/python.supp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
<py3_8_encode_current_locale>
3+
Memcheck:Cond
4+
...
5+
fun:encode_current_locale
6+
}
7+
8+
9+
{
10+
<libtiff_zlib>
11+
Memcheck:Cond
12+
fun:inflate
13+
fun:ZIPDecode
14+
fun:_TIFFReadEncodedTileAndAllocBuffer
15+
...
16+
}

Tests/oss-fuzz/test_fuzzers.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@
22
import sys
33

44
import fuzzers
5+
import packaging
56
import pytest
67

7-
from PIL import Image
8+
from PIL import Image, features
89

910
if sys.platform.startswith("win32"):
1011
pytest.skip("Fuzzer is linux only", allow_module_level=True)
12+
if features.check("libjpeg_turbo"):
13+
version = packaging.version.parse(features.version("libjpeg_turbo"))
14+
if version.major == 2 and version.minor == 0:
15+
pytestmark = pytest.mark.valgrind_known_error(
16+
reason="Known failing with libjpeg_turbo 2.0"
17+
)
1118

1219

1320
@pytest.mark.parametrize(

Tests/test_file_eps.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
assert_image_similar,
99
assert_image_similar_tofile,
1010
hopper,
11+
mark_if_feature_version,
1112
skip_unless_feature,
1213
)
1314

@@ -64,7 +65,9 @@ def test_invalid_file():
6465
EpsImagePlugin.EpsImageFile(invalid_file)
6566

6667

67-
@pytest.mark.valgrind_known_error(reason="Known Failing")
68+
@mark_if_feature_version(
69+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
70+
)
6871
@pytest.mark.skipif(not HAS_GHOSTSCRIPT, reason="Ghostscript not available")
6972
def test_cmyk():
7073
with Image.open("Tests/images/pil_sample_cmyk.eps") as cmyk_image:

Tests/test_file_jpeg.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
djpeg_available,
2525
hopper,
2626
is_win32,
27+
mark_if_feature_version,
2728
skip_unless_feature,
2829
)
2930

@@ -116,7 +117,9 @@ def test(xdpi, ydpi=None):
116117
assert test(100, 200) == (100, 200)
117118
assert test(0) is None # square pixels
118119

119-
@pytest.mark.valgrind_known_error(reason="Known Failing")
120+
@mark_if_feature_version(
121+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
122+
)
120123
def test_icc(self, tmp_path):
121124
# Test ICC support
122125
with Image.open("Tests/images/rgb.jpg") as im1:
@@ -156,7 +159,9 @@ def test(n):
156159
test(ImageFile.MAXBLOCK + 1) # full buffer block plus one byte
157160
test(ImageFile.MAXBLOCK * 4 + 3) # large block
158161

159-
@pytest.mark.valgrind_known_error(reason="Known Failing")
162+
@mark_if_feature_version(
163+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
164+
)
160165
def test_large_icc_meta(self, tmp_path):
161166
# https://github.com/python-pillow/Pillow/issues/148
162167
# Sometimes the meta data on the icc_profile block is bigger than
@@ -423,7 +428,9 @@ def test_ff00_jpeg_header(self):
423428
with Image.open(filename):
424429
pass
425430

426-
@pytest.mark.valgrind_known_error(reason="Known Failing")
431+
@mark_if_feature_version(
432+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
433+
)
427434
def test_truncated_jpeg_should_read_all_the_data(self):
428435
filename = "Tests/images/truncated_jpeg.jpg"
429436
ImageFile.LOAD_TRUNCATED_IMAGES = True
@@ -442,7 +449,9 @@ def test_truncated_jpeg_throws_oserror(self):
442449
with pytest.raises(OSError):
443450
im.load()
444451

445-
@pytest.mark.valgrind_known_error(reason="Known Failing")
452+
@mark_if_feature_version(
453+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
454+
)
446455
def test_qtables(self, tmp_path):
447456
def _n_qtables_helper(n, test_file):
448457
with Image.open(test_file) as im:
@@ -726,7 +735,9 @@ def test_invalid_exif(self):
726735
# OSError for unidentified image.
727736
assert im.info.get("dpi") == (72, 72)
728737

729-
@pytest.mark.valgrind_known_error(reason="Known Failing")
738+
@mark_if_feature_version(
739+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
740+
)
730741
def test_exif_x_resolution(self, tmp_path):
731742
with Image.open("Tests/images/flower.jpg") as im:
732743
exif = im.getexif()
@@ -757,7 +768,9 @@ def test_ifd_offset_exif(self):
757768
# Act / Assert
758769
assert im._getexif()[306] == "2017:03:13 23:03:09"
759770

760-
@pytest.mark.valgrind_known_error(reason="Backtrace in Python Core")
771+
@mark_if_feature_version(
772+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
773+
)
761774
def test_photoshop(self):
762775
with Image.open("Tests/images/photoshop-200dpi.jpg") as im:
763776
assert im.info["photoshop"][0x03ED] == {

Tests/test_file_libtiff.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
assert_image_similar,
1818
assert_image_similar_tofile,
1919
hopper,
20+
mark_if_feature_version,
2021
skip_unless_feature,
2122
)
2223

@@ -822,13 +823,17 @@ def test_strip_cmyk_16l_jpeg(self):
822823
with Image.open(infile) as im:
823824
assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
824825

825-
@pytest.mark.valgrind_known_error(reason="Known Failing")
826+
@mark_if_feature_version(
827+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
828+
)
826829
def test_strip_ycbcr_jpeg_2x2_sampling(self):
827830
infile = "Tests/images/tiff_strip_ycbcr_jpeg_2x2_sampling.tif"
828831
with Image.open(infile) as im:
829832
assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5)
830833

831-
@pytest.mark.valgrind_known_error(reason="Known Failing")
834+
@mark_if_feature_version(
835+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
836+
)
832837
def test_strip_ycbcr_jpeg_1x1_sampling(self):
833838
infile = "Tests/images/tiff_strip_ycbcr_jpeg_1x1_sampling.tif"
834839
with Image.open(infile) as im:
@@ -839,13 +844,17 @@ def test_tiled_cmyk_jpeg(self):
839844
with Image.open(infile) as im:
840845
assert_image_similar_tofile(im, "Tests/images/pil_sample_cmyk.jpg", 0.5)
841846

842-
@pytest.mark.valgrind_known_error(reason="Known Failing")
847+
@mark_if_feature_version(
848+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
849+
)
843850
def test_tiled_ycbcr_jpeg_1x1_sampling(self):
844851
infile = "Tests/images/tiff_tiled_ycbcr_jpeg_1x1_sampling.tif"
845852
with Image.open(infile) as im:
846853
assert_image_equal_tofile(im, "Tests/images/flower2.jpg")
847854

848-
@pytest.mark.valgrind_known_error(reason="Known Failing")
855+
@mark_if_feature_version(
856+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
857+
)
849858
def test_tiled_ycbcr_jpeg_2x2_sampling(self):
850859
infile = "Tests/images/tiff_tiled_ycbcr_jpeg_2x2_sampling.tif"
851860
with Image.open(infile) as im:

Tests/test_file_pdf.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from PIL import Image, PdfParser
1010

11-
from .helper import hopper
11+
from .helper import hopper, mark_if_feature_version
1212

1313

1414
def helper_save_as_pdf(tmp_path, mode, **kwargs):
@@ -85,7 +85,9 @@ def test_unsupported_mode(tmp_path):
8585
im.save(outfile)
8686

8787

88-
@pytest.mark.valgrind_known_error(reason="Known Failing")
88+
@mark_if_feature_version(
89+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
90+
)
8991
def test_save_all(tmp_path):
9092
# Single frame image
9193
helper_save_as_pdf(tmp_path, "RGB", save_all=True)

Tests/test_file_png.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
hopper,
1414
is_big_endian,
1515
is_win32,
16+
mark_if_feature_version,
1617
skip_unless_feature,
1718
)
1819

@@ -679,7 +680,9 @@ def test_exif_save(self, tmp_path):
679680
exif = reloaded._getexif()
680681
assert exif[274] == 1
681682

682-
@pytest.mark.valgrind_known_error(reason="Known Failing")
683+
@mark_if_feature_version(
684+
pytest.mark.valgrind_known_error, "libjpeg_turbo", "2.0", reason="Known Failing"
685+
)
683686
def test_exif_from_jpg(self, tmp_path):
684687
with Image.open("Tests/images/pil_sample_rgb.jpg") as im:
685688
test_file = str(tmp_path / "temp.png")

0 commit comments

Comments
 (0)