@@ -3589,15 +3589,29 @@ where
35893589 offset : u8 ,
35903590 len : u8 ,
35913591 ) -> Result < Vec < Self > , ControllerError > {
3592- let end = offset + len;
3592+ let offset = u16:: from ( offset) ;
3593+ let len = u16:: from ( len) ;
3594+ let end = offset. checked_add ( len) . expect ( "offset and len are u8s" ) ;
35933595 ( offset..end)
35943596 . step_by ( usize:: from ( Self :: SIZE ) )
35953597 . map ( |new_offset| {
3598+ // The addition used to find the bounds of this range is done
3599+ // with u16s, so the new offset could be larger than a u8. Check
3600+ // that it fits first. If not, we've stepped past the end of the
3601+ // valid range. Use u8::MAX here, and let the call to
3602+ // build_one() fail with the right error type.
3603+ let offset = new_offset. try_into ( ) . unwrap_or ( u8:: MAX ) ;
3604+
35963605 // The length is up to SIZE, or the remainder of the entire
35973606 // operation, whichever is smaller.
3598- let remainder = end - new_offset;
3599- let new_len = Self :: SIZE . min ( remainder) ;
3600- Self :: build_one ( page, new_offset, new_len)
3607+ let remainder =
3608+ end. checked_sub ( new_offset) . expect ( "new_offset <= end" ) ;
3609+ let new_len = u16:: from ( Self :: SIZE )
3610+ . min ( remainder)
3611+ . try_into ( )
3612+ . expect ( "min of SIZE and rem must be a u8" ) ;
3613+
3614+ Self :: build_one ( page, offset, new_len)
36013615 } )
36023616 . collect ( )
36033617 }
@@ -3664,6 +3678,7 @@ mod tests {
36643678 use transceiver_controller:: Identifier ;
36653679 use transceiver_controller:: IdentifierResult ;
36663680 use transceiver_controller:: ReadResult ;
3681+ use transceiver_controller:: TransceiverError ;
36673682
36683683 fn logger ( ) -> Logger {
36693684 let decorator =
@@ -5049,4 +5064,82 @@ mod tests {
50495064 } ;
50505065 assert_eq ! ( data, expected_data) ;
50515066 }
5067+
5068+ #[ test]
5069+ fn handle_large_op_at_the_end_of_lower_page ( ) {
5070+ let offset = 112 ;
5071+ let len = 16 ;
5072+ let page = mgmt:: cmis:: Page :: Lower ;
5073+ let read_args = mgmt:: MemoryRead :: build_many ( page, offset, len) . expect (
5074+ "Should handle offset / len reads to the end of the lower page" ,
5075+ ) ;
5076+ assert_eq ! ( read_args. len( ) , 2 ) ;
5077+ assert ! ( read_args. iter( ) . all( |rd| rd. len( ) == len / 2 ) ) ;
5078+ }
5079+
5080+ #[ test]
5081+ fn handle_large_op_at_the_end_of_upper_page ( ) {
5082+ let offset = 240 ;
5083+ let len = 16 ;
5084+ let page = mgmt:: cmis:: Page :: Upper (
5085+ mgmt:: cmis:: UpperPage :: new_unbanked ( 0 ) . unwrap ( ) ,
5086+ ) ;
5087+ let read_args = mgmt:: MemoryRead :: build_many ( page, offset, len) . expect (
5088+ "Should handle offset / len reads to the end of the upper page" ,
5089+ ) ;
5090+ assert_eq ! ( read_args. len( ) , 2 ) ;
5091+ assert ! ( read_args. iter( ) . all( |rd| rd. len( ) == len / 2 ) ) ;
5092+ }
5093+
5094+ #[ test]
5095+ fn fail_if_large_op_reads_past_the_end_of_the_lower_page ( ) {
5096+ let offset = 112 ;
5097+ let len = 18 ;
5098+ let page = mgmt:: cmis:: Page :: Lower ;
5099+ let err = mgmt:: MemoryRead :: build_many ( page, offset, len)
5100+ . expect_err ( "Should fail rather than panicking" ) ;
5101+ assert ! ( matches!(
5102+ err,
5103+ ControllerError :: Transceiver ( TransceiverError :: Mgmt (
5104+ mgmt:: Error :: InvalidMemoryAccess { .. }
5105+ ) )
5106+ ) ) ;
5107+
5108+ let len = u8:: MAX ;
5109+ let err = mgmt:: MemoryRead :: build_many ( page, offset, len)
5110+ . expect_err ( "Should fail rather than panicking" ) ;
5111+ assert ! ( matches!(
5112+ err,
5113+ ControllerError :: Transceiver ( TransceiverError :: Mgmt (
5114+ mgmt:: Error :: InvalidMemoryAccess { .. }
5115+ ) )
5116+ ) ) ;
5117+ }
5118+
5119+ #[ test]
5120+ fn fail_if_large_op_reads_past_the_end_of_the_upper_page ( ) {
5121+ let offset = 240 ;
5122+ let len = 19 ;
5123+ let page = mgmt:: cmis:: Page :: Upper (
5124+ mgmt:: cmis:: UpperPage :: new_unbanked ( 0 ) . unwrap ( ) ,
5125+ ) ;
5126+ let err = mgmt:: MemoryRead :: build_many ( page, offset, len)
5127+ . expect_err ( "Should fail rather than panicking" ) ;
5128+ assert ! ( matches!(
5129+ err,
5130+ ControllerError :: Transceiver ( TransceiverError :: Mgmt (
5131+ mgmt:: Error :: InvalidMemoryAccess { .. }
5132+ ) )
5133+ ) ) ;
5134+
5135+ let len = u8:: MAX ;
5136+ let err = mgmt:: MemoryRead :: build_many ( page, offset, len)
5137+ . expect_err ( "Should fail rather than panicking" ) ;
5138+ assert ! ( matches!(
5139+ err,
5140+ ControllerError :: Transceiver ( TransceiverError :: Mgmt (
5141+ mgmt:: Error :: InvalidMemoryAccess { .. }
5142+ ) )
5143+ ) ) ;
5144+ }
50525145}
0 commit comments