From 7217552ebf7f0b15beb4a0d0f5d6b5695563dc31 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Tue, 11 Feb 2020 17:24:38 +0100 Subject: [PATCH] Add tests for discontiguous buffers for gif --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 3 ++ src/ImageSharp/Formats/Gif/GifDecoder.cs | 16 +++++++- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 7 +++- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 ++ src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 3 ++ .../Formats/Gif/GifDecoderTests.cs | 40 +++++++++++++++++++ .../Formats/Gif/GifEncoderTests.cs | 10 ++++- 7 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 960c2ecd22..fdd371f547 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -114,6 +114,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.options = options; } + /// + /// Gets the dimensions of the image. + /// public Size Dimensions => new Size(this.infoHeader.Width, this.infoHeader.Height); /// diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index 7691ec1aa5..24e3d88261 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -1,7 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.IO; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -27,7 +29,19 @@ namespace SixLabors.ImageSharp.Formats.Gif where TPixel : struct, IPixel { var decoder = new GifDecoderCore(configuration, this); - return decoder.Decode(stream); + + try + { + return decoder.Decode(stream); + } + catch (InvalidMemoryOperationException ex) + { + Size dims = decoder.Dimensions; + + // TODO: use InvalidImageContentException here, if we decide to define it + // https://github.com/SixLabors/ImageSharp/issues/1110 + throw new ImageFormatException($"Can not decode image. Failed to allocate buffers for possibly degenerate dimensions: {dims.Width}x{dims.Height}.", ex); + } } /// diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 98dbddb481..bc508cba74 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -86,10 +86,15 @@ namespace SixLabors.ImageSharp.Formats.Gif public bool IgnoreMetadata { get; internal set; } /// - /// Gets the decoding mode for multi-frame images + /// Gets the decoding mode for multi-frame images. /// public FrameDecodingMode DecodingMode { get; } + /// + /// Gets the dimensions of the image. + /// + public Size Dimensions => new Size(this.imageDescriptor.Width, this.imageDescriptor.Height); + private MemoryAllocator MemoryAllocator => this.configuration.MemoryAllocator; /// diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index ff75e4290f..2701bd2a74 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -132,6 +132,9 @@ namespace SixLabors.ImageSharp.Formats.Png this.ignoreMetadata = options.IgnoreMetadata; } + /// + /// Gets the dimensions of the image. + /// public Size Dimensions => new Size(this.header.Width, this.header.Height); /// diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 1717df63b6..6768f4db30 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -61,6 +61,9 @@ namespace SixLabors.ImageSharp.Formats.Tga this.options = options; } + /// + /// Gets the dimensions of the image. + /// public Size Dimensions => new Size(this.fileHeader.Width, this.fileHeader.Height); /// diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 99dc2d06da..ea244f68ab 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -4,10 +4,14 @@ using System; using System.Collections.Generic; using System.IO; +using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Tga; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using Xunit; @@ -163,5 +167,41 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif } } } + + [Theory] + [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] + [WithFile(TestImages.Gif.Kumin, PixelTypes.Rgba32)] + public void GifDecoder_DegenerateMemoryRequest_ShouldTranslateTo_ImageFormatException(TestImageProvider provider) + where TPixel : struct, IPixel + { + provider.LimitAllocatorBufferCapacity().InPixels(10); + ImageFormatException ex = Assert.Throws(provider.GetImage); + Assert.IsType(ex.InnerException); + } + + [Theory] + [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] + [WithFile(TestImages.Gif.Kumin, PixelTypes.Rgba32)] + public void GifDecoder_CanDecode_WithLimitedAllocatorBufferCapacity(TestImageProvider provider) + where TPixel : struct, IPixel + { + static void RunTest(string providerDump, string nonContiguousBuffersStr) + { + TestImageProvider provider = BasicSerializer.Deserialize>(providerDump); + + provider.LimitAllocatorBufferCapacity().InPixels(100); + + using Image image = provider.GetImage(new GifDecoder()); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } + + string providerDump = BasicSerializer.Serialize(provider); + RemoteExecutor.Invoke( + RunTest, + providerDump, + "Disco") + .Dispose(); + } } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index fe1faa5aed..4c710cdb2e 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -26,10 +26,16 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif }; [Theory] - [WithTestPatternImages(100, 100, TestPixelTypes)] - public void EncodeGeneratedPatterns(TestImageProvider provider) + [WithTestPatternImages(100, 100, TestPixelTypes, false)] + [WithTestPatternImages(100, 100, TestPixelTypes, false)] + public void EncodeGeneratedPatterns(TestImageProvider provider, bool limitAllocationBuffer) where TPixel : struct, IPixel { + if (limitAllocationBuffer) + { + provider.LimitAllocatorBufferCapacity().InPixels(100); + } + using (Image image = provider.GetImage()) { var encoder = new GifEncoder