@@ -29,7 +29,7 @@ impl<'data, T: Pod> PodSlice<'data, T> {
2929 }
3030 let ( length, data) = data. split_at ( LENGTH_SIZE ) ;
3131 let length = pod_from_bytes :: < PodU32 > ( length) ?;
32- let _max_length = max_len_for_type :: < T > ( data. len ( ) ) ?;
32+ let _max_length = max_len_for_type :: < T > ( data. len ( ) , u32 :: from ( * length ) as usize ) ?;
3333 let data = pod_slice_from_bytes ( data) ?;
3434 Ok ( Self { length, data } )
3535 }
@@ -70,7 +70,7 @@ impl<'data, T: Pod> PodSliceMut<'data, T> {
7070 if init {
7171 * length = 0 . into ( ) ;
7272 }
73- let max_length = max_len_for_type :: < T > ( data. len ( ) ) ?;
73+ let max_length = max_len_for_type :: < T > ( data. len ( ) , u32 :: from ( * length ) as usize ) ?;
7474 let data = pod_slice_from_bytes_mut ( data) ?;
7575 Ok ( Self {
7676 length,
@@ -109,22 +109,30 @@ impl<'data, T: Pod> PodSliceMut<'data, T> {
109109 }
110110}
111111
112- fn max_len_for_type < T > ( data_len : usize ) -> Result < usize , ProgramError > {
113- let size : usize = std:: mem:: size_of :: < T > ( ) ;
112+ fn max_len_for_type < T > ( data_len : usize , length_val : usize ) -> Result < usize , ProgramError > {
113+ let item_size = std:: mem:: size_of :: < T > ( ) ;
114114 let max_len = data_len
115- . checked_div ( size )
115+ . checked_div ( item_size )
116116 . ok_or ( PodSliceError :: CalculationFailure ) ?;
117- // check that it isn't over or under allocated
118- if max_len. saturating_mul ( size) != data_len {
117+
118+ // Make sure the max length that can be stored in the buffer isn't less
119+ // than the length value.
120+ if max_len < length_val {
121+ Err ( PodSliceError :: BufferTooSmall ) ?
122+ }
123+
124+ // Make sure the buffer is cleanly divisible by `size_of::<T>`; not over or
125+ // under allocated.
126+ if max_len. saturating_mul ( item_size) != data_len {
119127 if max_len == 0 {
120128 // Size of T is greater than buffer size
121- Err ( PodSliceError :: BufferTooSmall . into ( ) )
129+ Err ( PodSliceError :: BufferTooSmall ) ?
122130 } else {
123- Err ( PodSliceError :: BufferTooLarge . into ( ) )
131+ Err ( PodSliceError :: BufferTooLarge ) ?
124132 }
125- } else {
126- Ok ( max_len)
127133 }
134+
135+ Ok ( max_len)
128136}
129137
130138#[ cfg( test) ]
@@ -171,9 +179,11 @@ mod tests {
171179
172180 #[ test]
173181 fn test_pod_slice_buffer_too_large ( ) {
174- // 1 `TestStruct` + length = 37 bytes
175- // we pass 38 to trigger BufferTooLarge
176- let pod_slice_bytes = [ 1 ; 38 ] ;
182+ // Length is 1. We pass one test struct with 6 trailing bytes to
183+ // trigger BufferTooLarge.
184+ let data_len = LENGTH_SIZE + std:: mem:: size_of :: < TestStruct > ( ) + 6 ;
185+ let mut pod_slice_bytes = vec ! [ 1 ; data_len] ;
186+ pod_slice_bytes[ 0 ..4 ] . copy_from_slice ( & [ 1 , 0 , 0 , 0 ] ) ;
177187 let err = PodSlice :: < TestStruct > :: unpack ( & pod_slice_bytes)
178188 . err ( )
179189 . unwrap ( ) ;
@@ -184,6 +194,32 @@ mod tests {
184194 ) ;
185195 }
186196
197+ #[ test]
198+ fn test_pod_slice_buffer_larger_than_length_value ( ) {
199+ // If the buffer is longer than the u32 length value declares, it
200+ // should still unpack successfully, as long as the length of the rest
201+ // of the buffer can be divided by `size_of::<T>`.
202+ let length: u32 = 12 ;
203+ let length_le = length. to_le_bytes ( ) ;
204+
205+ // First set up the data to have room for extra items.
206+ let data_len = PodSlice :: < TestStruct > :: size_of ( length as usize + 2 ) . unwrap ( ) ;
207+ let mut data = vec ! [ 0 ; data_len] ;
208+
209+ // Now write the bogus length - which is smaller - into the first 4
210+ // bytes.
211+ data[ ..LENGTH_SIZE ] . copy_from_slice ( & length_le) ;
212+
213+ let pod_slice = PodSlice :: < TestStruct > :: unpack ( & data) . unwrap ( ) ;
214+ let pod_slice_len = u32:: from ( * pod_slice. length ) ;
215+ let data = pod_slice. data ( ) ;
216+ let data_vec = data. to_vec ( ) ;
217+
218+ assert_eq ! ( pod_slice_len, length) ;
219+ assert_eq ! ( data. len( ) , length as usize ) ;
220+ assert_eq ! ( data_vec. len( ) , length as usize ) ;
221+ }
222+
187223 #[ test]
188224 fn test_pod_slice_buffer_too_small ( ) {
189225 // 1 `TestStruct` + length = 37 bytes
@@ -199,6 +235,31 @@ mod tests {
199235 ) ;
200236 }
201237
238+ #[ test]
239+ fn test_pod_slice_buffer_shorter_than_length_value ( ) {
240+ // If the buffer is shorter than the u32 length value declares, we
241+ // should get a BufferTooSmall error.
242+ let length: u32 = 12 ;
243+ let length_le = length. to_le_bytes ( ) ;
244+ for num_items in 0 ..length {
245+ // First set up the data to have `num_elements` items.
246+ let data_len = PodSlice :: < TestStruct > :: size_of ( num_items as usize ) . unwrap ( ) ;
247+ let mut data = vec ! [ 0 ; data_len] ;
248+
249+ // Now write the bogus length - which is larger - into the first 4
250+ // bytes.
251+ data[ ..LENGTH_SIZE ] . copy_from_slice ( & length_le) ;
252+
253+ // Expect an error on unpacking.
254+ let err = PodSlice :: < TestStruct > :: unpack ( & data) . err ( ) . unwrap ( ) ;
255+ assert_eq ! (
256+ err,
257+ PodSliceError :: BufferTooSmall . into( ) ,
258+ "Expected an `PodSliceError::BufferTooSmall` error"
259+ ) ;
260+ }
261+ }
262+
202263 #[ test]
203264 fn test_pod_slice_mut ( ) {
204265 // slice can fit 2 `TestStruct`
0 commit comments