Browse Source

Prevent zigzag overflow. Fix #922

af/merge-core
James Jackson-South 7 years ago
parent
commit
4f76e3b49c
  1. 45
      src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs
  2. 44
      tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs

45
src/ImageSharp/Formats/Jpeg/Components/ZigZag.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
@ -19,30 +19,37 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary> /// <summary>
/// Copy of <see cref="Unzig"/> in a value type /// Copy of <see cref="Unzig"/> in a value type
/// </summary> /// </summary>
public fixed byte Data[64]; public fixed byte Data[64 + 16];
/// <summary> /// <summary>
/// <para>
/// Unzig maps from the zigzag ordering to the natural ordering. For example, /// Unzig maps from the zigzag ordering to the natural ordering. For example,
/// unzig[3] is the column and row of the fourth element in zigzag order. The /// unzig[3] is the column and row of the fourth element in zigzag order. The
/// value is 16, which means first column (16%8 == 0) and third row (16/8 == 2). /// value is 16, which means first column (16%8 == 0) and third row (16/8 == 2).
/// </para>
/// <para>
/// When reading corrupted data, the Huffman decoders could attempt
/// to reference an entry beyond the end of this array (if the decoded
/// zero run length reaches past the end of the block). To prevent
/// wild stores without adding an inner-loop test, we put some extra
/// "63"s after the real entries. This will cause the extra coefficient
/// to be stored in location 63 of the block, not somewhere random.
/// The worst case would be a run-length of 15, which means we need 16
/// fake entries.
/// </para>
/// </summary> /// </summary>
private static readonly byte[] Unzig = private static readonly byte[] Unzig =
{ {
0, 0, 1, 8, 16, 9, 2, 3, 10,
1, 8, 17, 24, 32, 25, 18, 11, 4, 5,
16, 9, 2, 12, 19, 26, 33, 40, 48, 41, 34,
3, 10, 17, 24, 27, 20, 13, 6, 7, 14, 21, 28,
32, 25, 18, 11, 4, 35, 42, 49, 56, 57, 50, 43, 36,
5, 12, 19, 26, 33, 40, 29, 22, 15, 23, 30, 37, 44, 51,
48, 41, 34, 27, 20, 13, 6, 58, 59, 52, 45, 38, 31, 39, 46,
7, 14, 21, 28, 35, 42, 49, 56, 53, 60, 61, 54, 47, 55, 62, 63,
57, 50, 43, 36, 29, 22, 15, 63, 63, 63, 63, 63, 63, 63, 63, // Extra entries for safety in decoder
23, 30, 37, 44, 51, 58, 63, 63, 63, 63, 63, 63, 63, 63
59, 52, 45, 38, 31,
39, 46, 53, 60,
61, 54, 47,
55, 62,
63
}; };
/// <summary> /// <summary>
@ -68,7 +75,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{ {
ZigZag result = default; ZigZag result = default;
byte* unzigPtr = result.Data; byte* unzigPtr = result.Data;
Marshal.Copy(Unzig, 0, (IntPtr)unzigPtr, 64); Marshal.Copy(Unzig, 0, (IntPtr)unzigPtr, 64 + 16);
return result; return result;
} }
@ -87,4 +94,4 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return result; return result;
} }
} }
} }

44
tests/ImageSharp.Tests/Formats/Jpg/ZigZagTests.cs

@ -0,0 +1,44 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Components;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
public class ZigZagTests
{
[Fact]
public void ZigZagCanHandleAllPossibleCoefficients()
{
// Mimic the behaviour of the huffman scan decoder using all possible byte values
short[] block = new short[64];
var zigzag = ZigZag.CreateUnzigTable();
for (int h = 0; h < 255; h++)
{
for (int i = 1; i < 64; i++)
{
int s = h;
int r = s >> 4;
s &= 15;
if (s != 0)
{
i += r;
block[zigzag[i++]] = (short)s;
}
else
{
if (r == 0)
{
break;
}
i += 16;
}
}
}
}
}
}
Loading…
Cancel
Save