diff --git a/Tests/test_file_bmp.py b/Tests/test_file_bmp.py index bfe24e0007d..f214fd6bda1 100644 --- a/Tests/test_file_bmp.py +++ b/Tests/test_file_bmp.py @@ -147,6 +147,25 @@ def test_rle8(): im.load() +@pytest.mark.parametrize( + "file_name,length", + ( + # EOF immediately after the header + ("Tests/images/hopper_rle8.bmp", 1078), + # EOF during delta + ("Tests/images/bmp/q/pal8rletrns.bmp", 3670), + # EOF when reading data in absolute mode + ("Tests/images/bmp/g/pal8rle.bmp", 1064), + ), +) +def test_rle8_eof(file_name, length): + with open(file_name, "rb") as fp: + data = fp.read(length) + with Image.open(io.BytesIO(data)) as im: + with pytest.raises(ValueError): + im.load() + + def test_offset(): # This image has been hexedited # to exclude the palette size from the pixel data offset diff --git a/src/PIL/BmpImagePlugin.py b/src/PIL/BmpImagePlugin.py index 7221d7f065e..7e7e742cd74 100644 --- a/src/PIL/BmpImagePlugin.py +++ b/src/PIL/BmpImagePlugin.py @@ -283,8 +283,11 @@ def decode(self, buffer): data = bytearray() x = 0 while len(data) < self.state.xsize * self.state.ysize: - num_pixels = self.fd.read(1)[0] + pixels = self.fd.read(1) byte = self.fd.read(1) + if not pixels or not byte: + break + num_pixels = pixels[0] if num_pixels: # encoded mode if x + num_pixels > self.state.xsize: @@ -303,12 +306,18 @@ def decode(self, buffer): break elif byte[0] == 2: # delta + bytes_read = self.fd.read(2) + if len(bytes_read) < 2: + break right, up = self.fd.read(2) data += b"\x00" * (right + up * self.state.xsize) x = len(data) % self.state.xsize else: # absolute mode - data += self.fd.read(byte[0]) + bytes_read = self.fd.read(byte[0]) + data += bytes_read + if len(bytes_read) < byte[0]: + break x += byte[0] # align to 16-bit word boundary