diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ec3ebfa1dc..ddd43f7966 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -25,7 +25,7 @@ jobs: sdk-preview: true runtime: -x64 codecov: false - - os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable + - os: macos-26 framework: net7.0 sdk: 7.0.x sdk-preview: true @@ -48,7 +48,7 @@ jobs: sdk: 6.0.x runtime: -x64 codecov: false - - os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable + - os: macos-26 framework: net6.0 sdk: 6.0.x runtime: -x64 @@ -69,8 +69,20 @@ jobs: - name: Install libgdi+, which is required for tests running on ubuntu if: ${{ contains(matrix.options.os, 'ubuntu') }} run: | - sudo apt-get update - sudo apt-get -y install libgdiplus libgif-dev libglib2.0-dev libcairo2-dev libtiff-dev libexif-dev + sudo apt-get update + sudo apt-get -y install libgdiplus libgif-dev libglib2.0-dev libcairo2-dev libtiff-dev libexif-dev + + - name: Install libgdi+, which is required for tests running on macos + if: ${{ contains(matrix.options.os, 'macos-26') }} + run: | + brew update + brew install mono-libgdiplus + # Create symlinks to make libgdiplus discoverable + sudo mkdir -p /usr/local/lib + sudo ln -sf $(brew --prefix)/lib/libgdiplus.dylib /usr/local/lib/libgdiplus.dylib + # Verify installation + ls -la $(brew --prefix)/lib/libgdiplus* || echo "libgdiplus not found in brew prefix" + ls -la /usr/local/lib/libgdiplus* || echo "libgdiplus not found in /usr/local/lib" - name: Git Config shell: bash diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 5dc30575d5..3ac7e803ea 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -126,7 +126,10 @@ protected override Image Decode(BufferedReadStream stream, Cance switch (this.infoHeader.Compression) { case BmpCompression.RGB: - if (this.infoHeader.BitsPerPixel == 32) + + ushort bitsPerPixel = this.infoHeader.BitsPerPixel; + + if (bitsPerPixel == 32) { if (this.bmpMetadata.InfoHeaderType == BmpInfoHeaderType.WinVersion3) { @@ -137,15 +140,15 @@ protected override Image Decode(BufferedReadStream stream, Cance this.ReadRgb32Fast(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); } } - else if (this.infoHeader.BitsPerPixel == 24) + else if (bitsPerPixel == 24) { this.ReadRgb24(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); } - else if (this.infoHeader.BitsPerPixel == 16) + else if (bitsPerPixel == 16) { this.ReadRgb16(stream, pixels, this.infoHeader.Width, this.infoHeader.Height, inverted); } - else if (this.infoHeader.BitsPerPixel <= 8) + else if (bitsPerPixel is > 0 and <= 8) { this.ReadRgbPalette( stream, @@ -153,10 +156,14 @@ protected override Image Decode(BufferedReadStream stream, Cance palette, this.infoHeader.Width, this.infoHeader.Height, - this.infoHeader.BitsPerPixel, + bitsPerPixel, bytesPerColorMapEntry, inverted); } + else + { + BmpThrowHelper.ThrowInvalidImageContentException($"Invalid bits per pixel: {bitsPerPixel}"); + } break; diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 1ce794e44b..80e3061205 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -570,4 +570,27 @@ public void BmpDecoder_ThrowsException_Issue2696(TestImageProvider(ex.InnerException); } + + [Fact] + public void BmpDecoder_ThrowsException_Issue3067() + { + // Construct minimal BMP with bitsPerPixel = 0 + byte[] bmp = new byte[54]; + bmp[0] = (byte)'B'; + bmp[1] = (byte)'M'; + BitConverter.GetBytes(54).CopyTo(bmp, 2); + BitConverter.GetBytes(54).CopyTo(bmp, 10); + BitConverter.GetBytes(40).CopyTo(bmp, 14); + BitConverter.GetBytes(1).CopyTo(bmp, 18); + BitConverter.GetBytes(1).CopyTo(bmp, 22); + BitConverter.GetBytes((short)1).CopyTo(bmp, 26); + BitConverter.GetBytes((short)0).CopyTo(bmp, 28); // bitsPerPixel = 0 + + using MemoryStream stream = new(bmp); + + InvalidImageContentException ex = Assert.Throws(() => + { + using Image image = BmpDecoder.Instance.Decode(DecoderOptions.Default, stream); + }); + } }