Skip to content

Commit 5755779

Browse files
Merge pull request #804 from SixLabors/js/fix798
Use bounds checks in Huffman ctr. Fix #798
2 parents 441942b + 93bb373 commit 5755779

File tree

4 files changed

+20
-14
lines changed

4 files changed

+20
-14
lines changed

src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,10 @@ internal unsafe struct HuffmanTable
5050
/// <param name="values">The huffman values</param>
5151
public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLengths, ReadOnlySpan<byte> values)
5252
{
53-
const int Length = 257;
54-
using (IMemoryOwner<short> huffcode = memoryAllocator.Allocate<short>(Length))
53+
// We do some bounds checks in the code here to protect against AccessViolationExceptions
54+
const int HuffCodeLength = 257;
55+
const int MaxSizeLength = HuffCodeLength - 1;
56+
using (IMemoryOwner<short> huffcode = memoryAllocator.Allocate<short>(HuffCodeLength))
5557
{
5658
ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan());
5759
ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths);
@@ -63,7 +65,7 @@ public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLeng
6365
for (short i = 1; i < 17; i++)
6466
{
6567
byte length = Unsafe.Add(ref codeLengthsRef, i);
66-
for (short j = 0; j < length; j++)
68+
for (short j = 0; j < length && x < MaxSizeLength; j++)
6769
{
6870
Unsafe.Add(ref sizesRef, x++) = i;
6971
}
@@ -84,7 +86,7 @@ public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLeng
8486
Unsafe.Add(ref valOffsetRef, k) = (int)(si - code);
8587
if (Unsafe.Add(ref sizesRef, si) == k)
8688
{
87-
while (Unsafe.Add(ref sizesRef, si) == k)
89+
while (Unsafe.Add(ref sizesRef, si) == k && si < HuffCodeLength)
8890
{
8991
Unsafe.Add(ref huffcodeRef, si++) = (short)code++;
9092
}
@@ -100,19 +102,20 @@ public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan<byte> codeLeng
100102

101103
// Generate non-spec lookup tables to speed up decoding.
102104
const int FastBits = ScanDecoder.FastBits;
103-
ref byte fastRef = ref this.Lookahead[0];
104-
Unsafe.InitBlockUnaligned(ref fastRef, 0xFF, 1 << FastBits); // Flag for non-accelerated
105+
ref byte lookaheadRef = ref this.Lookahead[0];
106+
const uint MaxFastLength = 1 << FastBits;
107+
Unsafe.InitBlockUnaligned(ref lookaheadRef, 0xFF, MaxFastLength); // Flag for non-accelerated
105108

106109
for (int i = 0; i < si; i++)
107110
{
108111
int size = Unsafe.Add(ref sizesRef, i);
109112
if (size <= FastBits)
110113
{
111-
int c = Unsafe.Add(ref huffcodeRef, i) << (FastBits - size);
112-
int m = 1 << (FastBits - size);
113-
for (int l = 0; l < m; l++)
114+
int huffCode = Unsafe.Add(ref huffcodeRef, i) << (FastBits - size);
115+
int max = 1 << (FastBits - size);
116+
for (int left = 0; left < max; left++)
114117
{
115-
Unsafe.Add(ref fastRef, c + l) = (byte)i;
118+
Unsafe.Add(ref lookaheadRef, huffCode + left) = (byte)i;
116119
}
117120
}
118121
}

tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Baseline.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@ public void DecodeBaselineJpeg_CriticalEOF_ShouldThrow<TPixel>(TestImageProvider
4646
[Theory]
4747
[WithFile(TestImages.Jpeg.Issues.InvalidJpegThrowsWrongException797, PixelTypes.Rgba32)]
4848
public void LoadingImage_InvalidTagLength_ShouldThrow<TPixel>(TestImageProvider<TPixel> provider)
49-
where TPixel : struct, IPixel<TPixel>
50-
{
51-
Assert.Throws<ImageFormatException>(() => provider.GetImage());
52-
}
49+
where TPixel : struct, IPixel<TPixel> => Assert.Throws<ImageFormatException>(() => provider.GetImage());
50+
51+
[Theory]
52+
[WithFile(TestImages.Jpeg.Issues.AccessViolationException798, PixelTypes.Rgba32)]
53+
public void LoadingImage_BadHuffman_ShouldNotThrow<TPixel>(TestImageProvider<TPixel> provider)
54+
where TPixel : struct, IPixel<TPixel> => Assert.NotNull(provider.GetImage());
5355
}
5456
}

tests/ImageSharp.Tests/TestImages.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ public static class Issues
168168
public const string ExifGetString750Transform = "Jpg/issues/issue750-exif-tranform.jpg";
169169
public const string ExifGetString750Load = "Jpg/issues/issue750-exif-load.jpg";
170170
public const string InvalidJpegThrowsWrongException797 = "Jpg/issues/Issue797-InvalidImage.jpg";
171+
public const string AccessViolationException798 = "Jpg/issues/Issue798-AccessViolationException.jpg";
171172
}
172173

173174
public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray();
381 Bytes
Loading

0 commit comments

Comments
 (0)