Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

V3: Gracefully handle LZW overflows #2880

Open
wants to merge 4 commits into
base: release/3.1.x
Choose a base branch
from

Conversation

JimBobSquarePants
Copy link
Member

Prerequisites

  • I have written a descriptive pull-request title
  • I have verified that there are no overlapping pull-requests open
  • I have verified that I am following the existing coding patterns and practice as demonstrated in the repository. These follow strict Stylecop rules 👮.
  • I have provided test coverage for my change (where applicable)

Description

The issue is caused by using the full capacity of the pixel stack for intermediate pushes without reserving a slot for the final push, which leads to an overflow. By capping out the max index we can skip corrupt blocks.

Fixes #2859

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 3 out of 8 changed files in this pull request and generated no comments.

Files not reviewed (5)
  • tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_A.gif/00.png: Language not supported
  • tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_B.gif/00.png: Language not supported
  • tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_B.gif/01.png: Language not supported
  • tests/Images/Input/Gif/issues/issue_2859_A.gif: Language not supported
  • tests/Images/Input/Gif/issues/issue_2859_B.gif: Language not supported
@@ -204,7 +205,7 @@ public void DecodePixelRow(Span<byte> indices)
this.code = this.oldCode;
}

while (this.code > this.clearCode)
while (this.code > this.clearCode && this.top < maxTop)
Copy link
Member

@antonfirsov antonfirsov Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we are here, can we also un-Unsafe the methods touched?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if we can get the same performance out. We're hitting two separate spans inside a loop which is will definitely incur bounds checks costs.

Copy link
Member

@antonfirsov antonfirsov Feb 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can benchmark that. IMO it was a big mistake to start using Unsafe as default way of indexing things, since it opens us up to security risks and it should be our goal to significantly reduce the amount of Unsafe usage across the codebase. A gain of few percents is not worth the risk, it's better to find algorithmic optimizations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@antonfirsov I've updated the LzwDecoder with the best I could do performance-wise using safe code.

I'm OK with the performance hit given the much-improved security. Given that System.Drawing doesn't actually fully decode the image I'm still happy with the the performance of the decoder.

Target Branch

BenchmarkDotNet=v0.13.0, OS=Windows 10.0.26100
11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores
.NET SDK=9.0.200-preview.0.25057.12
  [Host]     : .NET 7.0.20 (7.0.2024.26716), X64 RyuJIT
  Job-AUXYJW : .NET 6.0.36 (6.0.3624.51421), X64 RyuJIT

Runtime=.NET 6.0  Arguments=/p:DebugType=portable  IterationCount=3
LaunchCount=1  WarmupCount=3
Method TestImage Mean Error StdDev Ratio RatioSD Gen 0 Gen 1 Gen 2 Allocated
'System.Drawing Gif' Gif/rings.gif 294.7 us 100.98 us 5.53 us 1.00 0.00 - - - 168 B
'ImageSharp Gif' Gif/rings.gif 410.6 us 87.95 us 4.82 us 1.39 0.03 0.9766 - - 7,557 B

This PR

Method TestImage Mean Error StdDev Ratio RatioSD Gen 0 Gen 1 Gen 2 Allocated
'System.Drawing Gif' Gif/rings.gif 299.0 us 189.8 us 10.41 us 1.00 0.00 - - - 168 B
'ImageSharp Gif' Gif/rings.gif 486.9 us 153.3 us 8.40 us 1.63 0.06 0.9766 - - 7,715 B

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants