Skip to content

Commit 0577690

Browse files
committed
Added input validation to DeflaterHuffman unsafe offsetting
1 parent b251c00 commit 0577690

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

src/ImageSharp/Formats/Png/Zlib/DeflaterHuffman.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,20 @@ public bool TallyDist(int distance, int length)
363363
[MethodImpl(InliningOptions.ShortMethod)]
364364
public static short BitReverse(int toReverse)
365365
{
366-
DebugGuard.MustBeLessThan(toReverse & 0xF, Bit4Reverse.Length, nameof(toReverse));
367-
DebugGuard.MustBeLessThan((toReverse >> 4) & 0xF, Bit4Reverse.Length, nameof(toReverse));
368-
DebugGuard.MustBeLessThan((toReverse >> 8) & 0xF, Bit4Reverse.Length, nameof(toReverse));
369-
DebugGuard.MustBeLessThan(toReverse >> 12, Bit4Reverse.Length, nameof(toReverse));
366+
/* Use unsafe offsetting and manually validate the input index to reduce the
367+
* total number of conditional branches. There are two main cases to test here:
368+
* 1. In the first 3, the input value (or some combination of it) is combined
369+
* with & 0xF, which results in a maximum value of 0xF no matter what the
370+
* input value was. That is 15, which is always in range for the target span.
371+
* As a result, no input validation is needed at all in this case.
372+
* 2. There are two cases where the input value might cause an invalid access:
373+
* when it is either negative, or greater than 15 << 12. We can test both
374+
* conditions in a single pass by casting the input value to uint, and checking
375+
* whether that value is lower than 15 << 12. If it was a negative value (2-complement),
376+
* the test will fail as the uint cast will result in a much larger value.
377+
* If the value was simply too high, the test will fail as expected.
378+
* Doing this reduces the total number of index checks from 4 down to just 1. */
379+
Guard.MustBeLessThanOrEqualTo<uint>((uint)toReverse, 15 << 12, nameof(toReverse));
370380

371381
ref byte bit4ReverseRef = ref MemoryMarshal.GetReference(Bit4Reverse);
372382

0 commit comments

Comments
 (0)