Pillow/Tests/test_decompression_bomb.py
2024-06-09 15:16:17 +10:00

113 lines
3.6 KiB
Python

from __future__ import annotations
import pytest
from PIL import Image
from .helper import hopper
TEST_FILE = "Tests/images/hopper.ppm"
ORIGINAL_LIMIT = Image.MAX_IMAGE_PIXELS
class TestDecompressionBomb:
def teardown_method(self) -> None:
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
def test_no_warning_small_file(self) -> None:
# Implicit assert: no warning.
# A warning would cause a failure.
with Image.open(TEST_FILE):
pass
def test_no_warning_no_limit(self) -> None:
# Arrange
# Turn limit off
Image.MAX_IMAGE_PIXELS = None
assert Image.MAX_IMAGE_PIXELS is None
# Act / Assert
# Implicit assert: no warning.
# A warning would cause a failure.
with Image.open(TEST_FILE):
pass
def test_warning(self) -> None:
# Set limit to trigger warning on the test file
Image.MAX_IMAGE_PIXELS = 128 * 128 - 1
assert Image.MAX_IMAGE_PIXELS == 128 * 128 - 1
with pytest.warns(Image.DecompressionBombWarning):
with Image.open(TEST_FILE):
pass
def test_exception(self) -> None:
# Set limit to trigger exception on the test file
Image.MAX_IMAGE_PIXELS = 64 * 128 - 1
assert Image.MAX_IMAGE_PIXELS == 64 * 128 - 1
with pytest.raises(Image.DecompressionBombError):
with Image.open(TEST_FILE):
pass
def test_exception_ico(self) -> None:
with pytest.raises(Image.DecompressionBombError):
with Image.open("Tests/images/decompression_bomb.ico"):
pass
def test_exception_gif(self) -> None:
with pytest.raises(Image.DecompressionBombError):
with Image.open("Tests/images/decompression_bomb.gif"):
pass
def test_exception_gif_extents(self) -> None:
with Image.open("Tests/images/decompression_bomb_extents.gif") as im:
with pytest.raises(Image.DecompressionBombError):
im.seek(1)
def test_exception_gif_zero_width(self) -> None:
# Set limit to trigger exception on the test file
Image.MAX_IMAGE_PIXELS = 4 * 64 * 128
assert Image.MAX_IMAGE_PIXELS == 4 * 64 * 128
with pytest.raises(Image.DecompressionBombError):
with Image.open("Tests/images/zero_width.gif"):
pass
def test_exception_bmp(self) -> None:
with pytest.raises(Image.DecompressionBombError):
with Image.open("Tests/images/bmp/b/reallybig.bmp"):
pass
class TestDecompressionCrop:
@classmethod
def setup_class(cls) -> None:
width, height = 128, 128
Image.MAX_IMAGE_PIXELS = height * width * 4 - 1
@classmethod
def teardown_class(cls) -> None:
Image.MAX_IMAGE_PIXELS = ORIGINAL_LIMIT
def test_enlarge_crop(self) -> None:
# Crops can extend the extents, therefore we should have the
# same decompression bomb warnings on them.
with hopper() as src:
box = (0, 0, src.width * 2, src.height * 2)
with pytest.warns(Image.DecompressionBombWarning):
src.crop(box)
def test_crop_decompression_checks(self) -> None:
im = Image.new("RGB", (100, 100))
for value in ((-9999, -9999, -9990, -9990), (-999, -999, -990, -990)):
assert im.crop(value).size == (9, 9)
with pytest.warns(Image.DecompressionBombWarning):
im.crop((-160, -160, 99, 99))
with pytest.raises(Image.DecompressionBombError):
im.crop((-99909, -99990, 99999, 99999))