@@ -82,7 +82,7 @@ trait Stateful {
8282 fn reset ( & mut self ) ;
8383}
8484
85- #[ derive( Clone ) ]
85+ #[ derive( Clone , Copy , Default ) ]
8686struct Link {
8787 prev : Code ,
8888 byte : u8 ,
@@ -178,9 +178,16 @@ struct Buffer {
178178 write_mark : usize ,
179179}
180180
181+ /// Mask for indexing into fixed-size arrays. Since MAX_ENTRIES = 4096 = 2^12,
182+ /// `idx & MASK` is guaranteed < MAX_ENTRIES. LLVM can prove this for
183+ /// `[T; MAX_ENTRIES]` arrays, eliminating bounds checks. Corrupt `prev`
184+ /// values wrap to a valid index instead of panicking.
185+ const MASK : usize = MAX_ENTRIES - 1 ;
186+
181187struct Table {
182- inner : Vec < Link > ,
183- depths : Vec < u16 > ,
188+ inner : Box < [ Link ; MAX_ENTRIES ] > ,
189+ depths : Box < [ u16 ; MAX_ENTRIES ] > ,
190+ len : usize ,
184191}
185192
186193/// Describes the static parameters for creating a decoder.
@@ -908,7 +915,7 @@ impl<C: CodeBuffer, CgC: CodegenConstants> Stateful for DecodeState<C, CgC> {
908915
909916 debug_assert ! (
910917 // When the table is full, we have a max code above the size switch.
911- self . table. inner . len( ) >= MAX_ENTRIES - usize :: from( self . is_tiff)
918+ self . table. len >= MAX_ENTRIES - usize :: from( self . is_tiff)
912919 // When the code size is 2 we have a bit code: (0, 1, CLS, EOF). Then the
913920 // computed next_code is 4 which already exceeds the bit width from the start.
914921 // Then we will immediately switch code size after this code.
@@ -966,7 +973,7 @@ impl<C: CodeBuffer, CgC: CodegenConstants> Stateful for DecodeState<C, CgC> {
966973 }
967974
968975 // Read the code length and check that we can decode directly into the out slice.
969- let len = self . table . depths [ usize:: from ( read_code) ] ;
976+ let len = self . table . depths [ usize:: from ( read_code) & MASK ] ;
970977
971978 if out. len ( ) < usize:: from ( len) {
972979 break ;
@@ -1031,9 +1038,9 @@ impl<C: CodeBuffer, CgC: CodegenConstants> Stateful for DecodeState<C, CgC> {
10311038 }
10321039
10331040 let required_len = if new_code == self . next_code {
1034- self . table . depths [ usize:: from ( deriv. code ) ] + 1
1041+ self . table . depths [ usize:: from ( deriv. code ) & MASK ] + 1
10351042 } else {
1036- self . table . depths [ usize:: from ( new_code) ]
1043+ self . table . depths [ usize:: from ( new_code) & MASK ]
10371044 } ;
10381045
10391046 // We need the decoded data of the new code if it is the `next_code`. This is the
@@ -1324,7 +1331,7 @@ impl CodeBuffer for LsbBuffer {
13241331 new_bits as u8
13251332 }
13261333 } ;
1327- self . bit_buffer |= u64:: from_be_bytes ( buffer) . swap_bytes ( ) << self . bits ;
1334+ self . bit_buffer |= u64:: from_le_bytes ( buffer) << self . bits ;
13281335 self . bits += new_bits;
13291336 }
13301337
@@ -1397,7 +1404,7 @@ impl Buffer {
13971404 fn fill_reconstruct ( & mut self , table : & Table , code : Code ) -> u8 {
13981405 self . write_mark = 0 ;
13991406 self . read_mark = 0 ;
1400- let depth = table. depths [ usize:: from ( code) ] ;
1407+ let depth = table. depths [ usize:: from ( code) & MASK ] ;
14011408 let mut memory = core:: mem:: replace ( & mut self . bytes , Box :: default ( ) ) ;
14021409
14031410 let out = & mut memory[ ..usize:: from ( depth) ] ;
@@ -1417,89 +1424,88 @@ impl Buffer {
14171424 }
14181425}
14191426
1427+ fn boxed_arr < T : Clone + Default , const N : usize > ( ) -> Box < [ T ; N ] > {
1428+ use core:: convert:: TryInto ;
1429+ vec ! [ T :: default ( ) ; N ]
1430+ . into_boxed_slice ( )
1431+ . try_into ( )
1432+ . ok ( )
1433+ . unwrap ( )
1434+ }
1435+
14201436impl Table {
14211437 fn new ( ) -> Self {
14221438 Table {
1423- inner : Vec :: with_capacity ( MAX_ENTRIES ) ,
1424- depths : Vec :: with_capacity ( MAX_ENTRIES ) ,
1439+ inner : boxed_arr ( ) ,
1440+ depths : boxed_arr ( ) ,
1441+ len : 0 ,
14251442 }
14261443 }
14271444
14281445 fn clear ( & mut self , min_size : u8 ) {
1429- let static_count = usize:: from ( 1u16 << u16:: from ( min_size) ) + 2 ;
1430- self . inner . truncate ( static_count) ;
1431- self . depths . truncate ( static_count) ;
1446+ self . len = usize:: from ( 1u16 << u16:: from ( min_size) ) + 2 ;
14321447 }
14331448
14341449 fn init ( & mut self , min_size : u8 ) {
1435- self . inner . clear ( ) ;
1436- self . depths . clear ( ) ;
1450+ self . len = 0 ;
14371451 for i in 0 ..( 1u16 << u16:: from ( min_size) ) {
1438- self . inner . push ( Link :: base ( i as u8 ) ) ;
1439- self . depths . push ( 1 ) ;
1452+ let idx = self . len & MASK ;
1453+ self . inner [ idx] = Link :: base ( i as u8 ) ;
1454+ self . depths [ idx] = 1 ;
1455+ self . len += 1 ;
1456+ }
1457+ // Clear code + End code: skip writing when the masked index would
1458+ // alias an alphabet entry (happens at min_size=12 where clear=4096
1459+ // wraps to index 0).
1460+ for _ in 0 ..2 {
1461+ if self . len < MAX_ENTRIES {
1462+ let idx = self . len & MASK ;
1463+ self . inner [ idx] = Link :: base ( 0 ) ;
1464+ self . depths [ idx] = 0 ;
1465+ }
1466+ self . len += 1 ;
14401467 }
1441- // Clear code.
1442- self . inner . push ( Link :: base ( 0 ) ) ;
1443- self . depths . push ( 0 ) ;
1444- // End code.
1445- self . inner . push ( Link :: base ( 0 ) ) ;
1446- self . depths . push ( 0 ) ;
14471468 }
14481469
14491470 fn at ( & self , code : Code ) -> & Link {
1450- & self . inner [ usize:: from ( code) ]
1471+ & self . inner [ usize:: from ( code) & MASK ]
14511472 }
14521473
14531474 fn is_empty ( & self ) -> bool {
1454- self . inner . is_empty ( )
1475+ self . len == 0
14551476 }
14561477
14571478 fn is_full ( & self ) -> bool {
1458- self . inner . len ( ) >= MAX_ENTRIES
1479+ self . len >= MAX_ENTRIES
14591480 }
14601481
14611482 fn derive ( & mut self , from : & DerivationBase , byte : u8 ) {
1462- let link = from. derive ( byte) ;
1463- let depth = self . depths [ usize:: from ( from. code ) ] + 1 ;
1464- self . inner . push ( link) ;
1465- self . depths . push ( depth) ;
1483+ let idx = self . len & MASK ;
1484+ let depth = self . depths [ usize:: from ( from. code ) & MASK ] + 1 ;
1485+ self . inner [ idx] = from. derive ( byte) ;
1486+ self . depths [ idx] = depth;
1487+ self . len += 1 ;
14661488 }
14671489
1468- // Derive multiple codes in a row, where each base is guaranteed to already exist.
14691490 fn derive_burst ( & mut self , from : & mut DerivationBase , burst : & [ Code ] , first : & [ u8 ] ) {
1470- let mut depth_of = from. code ;
1471- // Note that false data dependency we want to get rid of!
1472- // TODO: this pushes into a Vec, maybe we can make this cleaner.
1473- for & code in burst {
1474- let depth = self . depths [ usize:: from ( depth_of) ] + 1 ;
1475- self . depths . push ( depth) ;
1476- depth_of = code;
1477- }
1478-
1479- // Llvm tends to be flaky with code layout for the case of requiring an allocation. It's
1480- // not clear if that can occur in practice but it relies on iterator size hint..
1481- let extensions = burst. iter ( ) . zip ( first) ;
1482- self . inner . extend ( extensions. map ( |( & code, & first) | {
1483- let link = from. derive ( first) ;
1491+ for ( & code, & first_byte) in burst. iter ( ) . zip ( first. iter ( ) ) {
1492+ self . derive ( from, first_byte) ;
14841493 from. code = code;
1485- from. first = first;
1486- link
1487- } ) ) ;
1494+ from. first = first_byte;
1495+ }
14881496 }
14891497
14901498 fn reconstruct ( & self , code : Code , out : & mut [ u8 ] ) -> u8 {
14911499 let mut code_iter = code;
1492- let table = & self . inner [ ..=usize:: from ( code) ] ;
1493- let first = table[ usize:: from ( code) ] . first ;
1500+ let first = self . inner [ usize:: from ( code) & MASK ] . first ;
14941501
1495- let len = code_iter;
1502+ // The `& MASK` ensures any prev value (even from corrupt data) maps
1503+ // to a valid array index. This replaces the previous `min(len, prev)`
1504+ // clamp with equivalent safety: no panic, bounded loop, wrong output
1505+ // on corrupt data.
14961506 for ch in out. iter_mut ( ) . rev ( ) {
1497- //(code, cha) = self.table[k as usize];
1498- // Note: This could possibly be replaced with an unchecked array access if
1499- // - value is asserted to be < self.next_code() in push
1500- // - min_size is asserted to be < MAX_CODESIZE
1501- let entry = & table[ usize:: from ( code_iter) ] ;
1502- code_iter = core:: cmp:: min ( len, entry. prev ) ;
1507+ let entry = & self . inner [ usize:: from ( code_iter) & MASK ] ;
1508+ code_iter = entry. prev ;
15031509 * ch = entry. byte ;
15041510 }
15051511
0 commit comments