Skip to content

Commit ec79a2f

Browse files
Merge pull request #3069 from SixLabors/js/v4-fix-3067
Throw explicit InvalidImageContentException when BMP BPP is invalid.
2 parents fea3df9 + 128d6f9 commit ec79a2f

3 files changed

Lines changed: 48 additions & 8 deletions

File tree

src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,30 +131,35 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
131131
try
132132
{
133133
int bytesPerColorMapEntry = this.ReadImageHeaders(stream, out bool inverted, out byte[] palette);
134+
ushort bitsPerPixel = this.infoHeader.BitsPerPixel;
134135

135136
image = new Image<TPixel>(this.configuration, this.infoHeader.Width, this.infoHeader.Height, this.metadata);
136137

137138
Buffer2D<TPixel> pixels = image.GetRootFramePixelBuffer();
138139

139140
switch (this.infoHeader.Compression)
140141
{
141-
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 32 && this.bmpMetadata.InfoHeaderType is BmpInfoHeaderType.WinVersion3:
142+
case BmpCompression.RGB when bitsPerPixel is 32 && this.bmpMetadata.InfoHeaderType is BmpInfoHeaderType.WinVersion3:
142143
this.ReadRgb32Slow(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
143144

144145
break;
145-
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 32:
146+
147+
case BmpCompression.RGB when bitsPerPixel is 32:
146148
this.ReadRgb32Fast(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
147149

148150
break;
149-
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 24:
151+
152+
case BmpCompression.RGB when bitsPerPixel is 24:
150153
this.ReadRgb24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
151154

152155
break;
153-
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is 16:
156+
157+
case BmpCompression.RGB when bitsPerPixel is 16:
154158
this.ReadRgb16(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
155159

156160
break;
157-
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is <= 8 && this.processedAlphaMask:
161+
162+
case BmpCompression.RGB when bitsPerPixel is > 0 and <= 8 && this.processedAlphaMask:
158163
this.ReadRgbPaletteWithAlphaMask(
159164
stream,
160165
pixels,
@@ -166,7 +171,8 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
166171
inverted);
167172

168173
break;
169-
case BmpCompression.RGB when this.infoHeader.BitsPerPixel is <= 8:
174+
175+
case BmpCompression.RGB when bitsPerPixel is > 0 and <= 8:
170176
this.ReadRgbPalette(
171177
stream,
172178
pixels,
@@ -179,6 +185,10 @@ protected override Image<TPixel> Decode<TPixel>(BufferedReadStream stream, Cance
179185

180186
break;
181187

188+
case BmpCompression.RGB when bitsPerPixel is <= 0 or > 32:
189+
BmpThrowHelper.ThrowInvalidImageContentException($"Invalid bits per pixel: {bitsPerPixel}");
190+
break;
191+
182192
case BmpCompression.RLE24:
183193
this.ReadRle24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted);
184194

tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,4 +571,27 @@ public void BmpDecoder_ThrowsException_Issue2696<TPixel>(TestImageProvider<TPixe
571571
});
572572
Assert.IsType<InvalidMemoryOperationException>(ex.InnerException);
573573
}
574+
575+
[Fact]
576+
public void BmpDecoder_ThrowsException_Issue3067()
577+
{
578+
// Construct minimal BMP with bitsPerPixel = 0
579+
byte[] bmp = new byte[54];
580+
bmp[0] = (byte)'B';
581+
bmp[1] = (byte)'M';
582+
BitConverter.GetBytes(54).CopyTo(bmp, 2);
583+
BitConverter.GetBytes(54).CopyTo(bmp, 10);
584+
BitConverter.GetBytes(40).CopyTo(bmp, 14);
585+
BitConverter.GetBytes(1).CopyTo(bmp, 18);
586+
BitConverter.GetBytes(1).CopyTo(bmp, 22);
587+
BitConverter.GetBytes((short)1).CopyTo(bmp, 26);
588+
BitConverter.GetBytes((short)0).CopyTo(bmp, 28); // bitsPerPixel = 0
589+
590+
using MemoryStream stream = new(bmp);
591+
592+
Assert.Throws<InvalidImageContentException>(() =>
593+
{
594+
using Image image = BmpDecoder.Instance.Decode(DecoderOptions.Default, stream);
595+
});
596+
}
574597
}

tests/ImageSharp.Tests/Formats/Icon/Ico/IcoDecoderTests.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,19 @@ public void Bpp8Test(TestImageProvider<Rgba32> provider)
204204
}
205205

206206
[Theory]
207-
[WithFile(InvalidAll, PixelTypes.Rgba32)]
208207
[WithFile(InvalidBpp, PixelTypes.Rgba32)]
208+
public void InvalidThrows_InvalidImageContentException(TestImageProvider<Rgba32> provider)
209+
=> Assert.Throws<InvalidImageContentException>(() =>
210+
{
211+
using Image<Rgba32> image = provider.GetImage(IcoDecoder.Instance);
212+
});
213+
214+
[Theory]
215+
[WithFile(InvalidAll, PixelTypes.Rgba32)]
209216
[WithFile(InvalidCompression, PixelTypes.Rgba32)]
210217
[WithFile(InvalidRLE4, PixelTypes.Rgba32)]
211218
[WithFile(InvalidRLE8, PixelTypes.Rgba32)]
212-
public void InvalidTest(TestImageProvider<Rgba32> provider)
219+
public void InvalidThows_NotSupportedException(TestImageProvider<Rgba32> provider)
213220
=> Assert.Throws<NotSupportedException>(() =>
214221
{
215222
using Image<Rgba32> image = provider.GetImage(IcoDecoder.Instance);

0 commit comments

Comments
 (0)