@@ -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 }
0 commit comments