Browse Source

Throw for corrupt LZW min code. Add test for deferred clear code

pull/2014/head
James Jackson-South 4 years ago
parent
commit
78e5b6c19d
  1. 7
      ImageSharp.sln
  2. 4
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  3. 26
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  4. 17
      tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
  5. 1
      tests/ImageSharp.Tests/TestImages.cs
  6. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png
  7. 3
      tests/Images/External/ReferenceOutput/GifDecoderTests/IssueDeferredClearCode_Rgba32_bugzilla-55918.png
  8. 3
      tests/Images/Input/Gif/issues/bugzilla-55918.gif

7
ImageSharp.sln

@ -142,6 +142,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gif", "Gif", "{EE3FB0B3-1C3
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{BF8DFDC1-CEE5-4A37-B216-D3085360C776}"
ProjectSection(SolutionItems) = preProject
tests\Images\Input\Gif\issues\bugzilla-55918.gif = tests\Images\Input\Gif\issues\bugzilla-55918.gif
tests\Images\Input\Gif\issues\issue1505_argumentoutofrange.png = tests\Images\Input\Gif\issues\issue1505_argumentoutofrange.png
tests\Images\Input\Gif\issues\issue1530.gif = tests\Images\Input\Gif\issues\issue1530.gif
tests\Images\Input\Gif\issues\issue1668_invalidcolorindex.gif = tests\Images\Input\Gif\issues\issue1668_invalidcolorindex.gif
tests\Images\Input\Gif\issues\issue1962_tiniest_gif_1st.gif = tests\Images\Input\Gif\issues\issue1962_tiniest_gif_1st.gif
tests\Images\Input\Gif\issues\issue2012_drona1.gif = tests\Images\Input\Gif\issues\issue2012_drona1.gif
tests\Images\Input\Gif\issues\issue2012_Stronghold-Crusader-Extreme-Cover.gif = tests\Images\Input\Gif\issues\issue2012_Stronghold-Crusader-Extreme-Cover.gif
tests\Images\Input\Gif\issues\issue403_baddescriptorwidth.gif = tests\Images\Input\Gif\issues\issue403_baddescriptorwidth.gif
tests\Images\Input\Gif\issues\issue405_badappextlength252-2.gif = tests\Images\Input\Gif\issues\issue405_badappextlength252-2.gif
tests\Images\Input\Gif\issues\issue405_badappextlength252.gif = tests\Images\Input\Gif\issues\issue405_badappextlength252.gif

4
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -410,9 +410,9 @@ namespace SixLabors.ImageSharp.Formats.Gif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadFrameIndices(Buffer2D<byte> indices)
{
int dataSize = this.stream.ReadByte();
int minCodeSize = this.stream.ReadByte();
using var lzwDecoder = new LzwDecoder(this.Configuration.MemoryAllocator, this.stream);
lzwDecoder.DecodePixels(dataSize, indices);
lzwDecoder.DecodePixels(minCodeSize, indices);
}
/// <summary>

26
src/ImageSharp/Formats/Gif/LzwDecoder.cs

@ -64,17 +64,22 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary>
/// Decodes and decompresses all pixel indices from the stream.
/// </summary>
/// <param name="dataSize">Size of the data.</param>
/// <param name="minCodeSize">Minimum code size of the data.</param>
/// <param name="pixels">The pixel array to decode to.</param>
public void DecodePixels(int dataSize, Buffer2D<byte> pixels)
public void DecodePixels(int minCodeSize, Buffer2D<byte> pixels)
{
// Calculate the clear code. The value of the clear code is 2 ^ dataSize
int clearCode = 1 << dataSize;
if (clearCode > MaxStackSize)
// Calculate the clear code. The value of the clear code is 2 ^ minCodeSize
int clearCode = 1 << minCodeSize;
// It is possible to specify a larger LZW minimum code size than the palette length in bits
// which may leave a gap in the codes where no colors are assigned.
// http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression
if (minCodeSize < 2 || clearCode > MaxStackSize)
{
// Don't attempt to decode the frame indices.
// The image is most likely corrupted.
return;
// Theoretically we could determine a min code size from the length of the provided
// color palette but we won't bother since the image is most likely corrupted.
ThrowBadMinimumCode();
}
// The resulting index table length.
@ -82,7 +87,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
int height = pixels.Height;
int length = width * height;
int codeSize = dataSize + 1;
int codeSize = minCodeSize + 1;
// Calculate the end code
int endCode = clearCode + 1;
@ -169,7 +174,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (code == clearCode)
{
// Reset the decoder
codeSize = dataSize + 1;
codeSize = minCodeSize + 1;
codeMask = (1 << codeSize) - 1;
availableCode = clearCode + 2;
oldCode = NullCode;
@ -258,5 +263,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.suffix.Dispose();
this.pixelStack.Dispose();
}
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowBadMinimumCode() => throw new InvalidImageContentException("Gif Image does not contain a valid LZW minimum code.");
}
}

17
tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs

@ -277,6 +277,23 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif
[WithFile(TestImages.Gif.Issues.Issue2012BadMinCode, PixelTypes.Rgba32)]
public void Issue2012BadMinCode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
Exception ex = Record.Exception(
() =>
{
using Image<TPixel> image = provider.GetImage();
image.DebugSave(provider);
});
Assert.NotNull(ex);
Assert.Contains("Gif Image does not contain a valid LZW minimum code.", ex.Message);
}
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
[Theory]
[WithFile(TestImages.Gif.Issues.DeferredClearCode, PixelTypes.Rgba32)]
public void IssueDeferredClearCode<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : unmanaged, IPixel<TPixel>
{
using Image<TPixel> image = provider.GetImage();

1
tests/ImageSharp.Tests/TestImages.cs

@ -448,6 +448,7 @@ namespace SixLabors.ImageSharp.Tests
public const string BadAppExtLength = "Gif/issues/issue405_badappextlength252.gif";
public const string BadAppExtLength_2 = "Gif/issues/issue405_badappextlength252-2.gif";
public const string BadDescriptorWidth = "Gif/issues/issue403_baddescriptorwidth.gif";
public const string DeferredClearCode = "Gif/issues/bugzilla-55918.gif";
public const string Issue1505 = "Gif/issues/issue1505_argumentoutofrange.png";
public const string Issue1530 = "Gif/issues/issue1530.gif";
public const string InvalidColorIndex = "Gif/issues/issue1668_invalidcolorindex.gif";

3
tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png

@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:cf4bc93479140b05b25066eb10c33fa9f82c617828a56526d47f5a8c72035ef0
size 1871

3
tests/Images/External/ReferenceOutput/GifDecoderTests/IssueDeferredClearCode_Rgba32_bugzilla-55918.png

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6b33733518b855b25c5e9a1b2f5c93cacf0699a40a459dde795b0ed91a978909
size 12776

3
tests/Images/Input/Gif/issues/bugzilla-55918.gif

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d11148669a093c2e39be62bc3482c5863362d28c03c7f26c5a2386d5de28c339
size 14551
Loading…
Cancel
Save