@@ -29,7 +29,7 @@ impl<'data, T: Pod> PodSlice<'data, T> {
29
29
}
30
30
let ( length, data) = data. split_at ( LENGTH_SIZE ) ;
31
31
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 ) ?;
33
33
let data = pod_slice_from_bytes ( data) ?;
34
34
Ok ( Self { length, data } )
35
35
}
@@ -70,7 +70,7 @@ impl<'data, T: Pod> PodSliceMut<'data, T> {
70
70
if init {
71
71
* length = 0 . into ( ) ;
72
72
}
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 ) ?;
74
74
let data = pod_slice_from_bytes_mut ( data) ?;
75
75
Ok ( Self {
76
76
length,
@@ -109,22 +109,30 @@ impl<'data, T: Pod> PodSliceMut<'data, T> {
109
109
}
110
110
}
111
111
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 > ( ) ;
114
114
let max_len = data_len
115
- . checked_div ( size )
115
+ . checked_div ( item_size )
116
116
. 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 {
119
127
if max_len == 0 {
120
128
// Size of T is greater than buffer size
121
- Err ( PodSliceError :: BufferTooSmall . into ( ) )
129
+ Err ( PodSliceError :: BufferTooSmall ) ?
122
130
} else {
123
- Err ( PodSliceError :: BufferTooLarge . into ( ) )
131
+ Err ( PodSliceError :: BufferTooLarge ) ?
124
132
}
125
- } else {
126
- Ok ( max_len)
127
133
}
134
+
135
+ Ok ( max_len)
128
136
}
129
137
130
138
#[ cfg( test) ]
@@ -171,9 +179,11 @@ mod tests {
171
179
172
180
#[ test]
173
181
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 ] ) ;
177
187
let err = PodSlice :: < TestStruct > :: unpack ( & pod_slice_bytes)
178
188
. err ( )
179
189
. unwrap ( ) ;
@@ -184,6 +194,32 @@ mod tests {
184
194
) ;
185
195
}
186
196
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
+
187
223
#[ test]
188
224
fn test_pod_slice_buffer_too_small ( ) {
189
225
// 1 `TestStruct` + length = 37 bytes
@@ -199,6 +235,31 @@ mod tests {
199
235
) ;
200
236
}
201
237
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
+
202
263
#[ test]
203
264
fn test_pod_slice_mut ( ) {
204
265
// slice can fit 2 `TestStruct`
0 commit comments