@@ -153,6 +153,57 @@ impl Default for CryptoVec {
153153 }
154154}
155155
156+ const MAX_CAPACITY : usize = 1usize << ( usize:: BITS - 2 ) ;
157+
158+ #[ cold]
159+ #[ inline( never) ]
160+ #[ allow( clippy:: panic) ]
161+ fn capacity_overflow ( len : usize ) -> ! {
162+ panic ! ( "CryptoVec capacity overflow: {len}" )
163+ }
164+
165+ #[ cold]
166+ #[ inline( never) ]
167+ #[ allow( clippy:: panic) ]
168+ fn length_overflow ( lhs : usize , rhs : usize ) -> ! {
169+ panic ! ( "CryptoVec length overflow: {lhs} + {rhs}" )
170+ }
171+
172+ #[ cold]
173+ #[ inline( never) ]
174+ fn alloc_failed ( layout : std:: alloc:: Layout ) -> ! {
175+ std:: alloc:: handle_alloc_error ( layout)
176+ }
177+
178+ #[ inline]
179+ fn checked_capacity ( len : usize ) -> usize {
180+ if len > MAX_CAPACITY {
181+ capacity_overflow ( len) ;
182+ }
183+ len. next_power_of_two ( )
184+ }
185+
186+ #[ inline]
187+ unsafe fn alloc_zeroed ( capacity : usize ) -> * mut u8 {
188+ debug_assert ! ( capacity > 0 ) ;
189+ let layout = unsafe { std:: alloc:: Layout :: from_size_align_unchecked ( capacity, 1 ) } ;
190+ let p = unsafe { std:: alloc:: alloc_zeroed ( layout) } ;
191+ if p. is_null ( ) {
192+ alloc_failed ( layout) ;
193+ }
194+ let _ = mlock ( p, capacity) ;
195+ p
196+ }
197+
198+ #[ inline]
199+ fn checked_len_sum ( lhs : usize , rhs : usize ) -> usize {
200+ let sum = lhs. wrapping_add ( rhs) ;
201+ if sum < lhs {
202+ length_overflow ( lhs, rhs) ;
203+ }
204+ sum
205+ }
206+
156207impl CryptoVec {
157208 /// Creates a new `CryptoVec`.
158209 pub fn new ( ) -> CryptoVec {
@@ -161,27 +212,27 @@ impl CryptoVec {
161212
162213 /// Creates a new `CryptoVec` with `n` zeros.
163214 pub fn new_zeroed ( size : usize ) -> CryptoVec {
164- unsafe {
165- let capacity = size. next_power_of_two ( ) ;
166- let layout = std:: alloc:: Layout :: from_size_align_unchecked ( capacity, 1 ) ;
167- let p = std:: alloc:: alloc_zeroed ( layout) ;
168- let _ = mlock ( p, capacity) ;
169- CryptoVec { p, capacity, size }
215+ if size == 0 {
216+ return CryptoVec :: default ( ) ;
170217 }
218+
219+ let capacity = checked_capacity ( size) ;
220+ let p = unsafe { alloc_zeroed ( capacity) } ;
221+ CryptoVec { p, capacity, size }
171222 }
172223
173224 /// Creates a new `CryptoVec` with capacity `capacity`.
174225 pub fn with_capacity ( capacity : usize ) -> CryptoVec {
175- unsafe {
176- let capacity = capacity . next_power_of_two ( ) ;
177- let layout = std :: alloc :: Layout :: from_size_align_unchecked ( capacity , 1 ) ;
178- let p = std :: alloc :: alloc_zeroed ( layout ) ;
179- let _ = mlock ( p , capacity) ;
180- CryptoVec {
181- p ,
182- capacity ,
183- size : 0 ,
184- }
226+ if capacity == 0 {
227+ return CryptoVec :: default ( ) ;
228+ }
229+
230+ let capacity = checked_capacity ( capacity) ;
231+ let p = unsafe { alloc_zeroed ( capacity ) } ;
232+ CryptoVec {
233+ p ,
234+ capacity ,
235+ size : 0 ,
185236 }
186237 }
187238
@@ -220,29 +271,21 @@ impl CryptoVec {
220271 } else {
221272 // realloc ! and erase the previous memory.
222273 unsafe {
223- let next_capacity = size . next_power_of_two ( ) ;
274+ let next_capacity = checked_capacity ( size ) ;
224275 let old_ptr = self . p ;
225- let next_layout = std:: alloc:: Layout :: from_size_align_unchecked ( next_capacity, 1 ) ;
226- self . p = std:: alloc:: alloc_zeroed ( next_layout) ;
227- let _ = mlock ( self . p , next_capacity) ;
276+ let next_ptr = alloc_zeroed ( next_capacity) ;
228277
229278 if self . capacity > 0 {
230- std:: ptr:: copy_nonoverlapping ( old_ptr, self . p , self . size ) ;
279+ std:: ptr:: copy_nonoverlapping ( old_ptr, next_ptr , self . size ) ;
231280 zeroize ( old_ptr, self . size ) ;
232281 let _ = munlock ( old_ptr, self . capacity ) ;
233282 let layout = std:: alloc:: Layout :: from_size_align_unchecked ( self . capacity , 1 ) ;
234283 std:: alloc:: dealloc ( old_ptr, layout) ;
235284 }
236285
237- if self . p . is_null ( ) {
238- #[ allow( clippy:: panic) ]
239- {
240- panic ! ( "Realloc failed, pointer = {self:?} {size:?}" )
241- }
242- } else {
243- self . capacity = next_capacity;
244- self . size = size;
245- }
286+ self . p = next_ptr;
287+ self . capacity = next_capacity;
288+ self . size = size;
246289 }
247290 }
248291 }
@@ -262,7 +305,7 @@ impl CryptoVec {
262305 /// Append a new byte at the end of this CryptoVec.
263306 pub fn push ( & mut self , s : u8 ) {
264307 let size = self . size ;
265- self . resize ( size + 1 ) ;
308+ self . resize ( checked_len_sum ( size, 1 ) ) ;
266309 unsafe { * self . p . add ( size) = s }
267310 }
268311
@@ -274,7 +317,8 @@ impl CryptoVec {
274317 mut r : R ,
275318 ) -> Result < usize , std:: io:: Error > {
276319 let cur_size = self . size ;
277- self . resize ( cur_size + n_bytes) ;
320+ let target_size = checked_len_sum ( cur_size, n_bytes) ;
321+ self . resize ( target_size) ;
278322 let s = unsafe { std:: slice:: from_raw_parts_mut ( self . p . add ( cur_size) , n_bytes) } ;
279323 // Resize the buffer to its appropriate size.
280324 match r. read ( s) {
@@ -319,7 +363,7 @@ impl CryptoVec {
319363 /// ```
320364 pub fn resize_mut ( & mut self , n : usize ) -> & mut [ u8 ] {
321365 let size = self . size ;
322- self . resize ( size + n ) ;
366+ self . resize ( checked_len_sum ( size, n ) ) ;
323367 unsafe { std:: slice:: from_raw_parts_mut ( self . p . add ( size) , n) }
324368 }
325369
@@ -331,7 +375,8 @@ impl CryptoVec {
331375 /// ```
332376 pub fn extend ( & mut self , s : & [ u8 ] ) {
333377 let size = self . size ;
334- self . resize ( size + s. len ( ) ) ;
378+ let added = s. len ( ) ;
379+ self . resize ( checked_len_sum ( size, added) ) ;
335380 unsafe {
336381 std:: ptr:: copy_nonoverlapping ( s. as_ptr ( ) , self . p . add ( size) , s. len ( ) ) ;
337382 }
@@ -438,7 +483,7 @@ fn optimization_barrier(dst: *mut u8, size: usize) {
438483
439484#[ cfg( test) ]
440485mod test {
441- use super :: CryptoVec ;
486+ use super :: { CryptoVec , checked_capacity } ;
442487
443488 #[ test]
444489 fn test_new ( ) {
@@ -569,13 +614,39 @@ mod test {
569614 assert ! ( crypto_vec. is_empty( ) ) ;
570615 }
571616
617+ #[ test]
618+ fn test_with_capacity_zero ( ) {
619+ let crypto_vec = CryptoVec :: with_capacity ( 0 ) ;
620+ assert_eq ! ( crypto_vec. size, 0 ) ;
621+ assert_eq ! ( crypto_vec. capacity, 0 ) ;
622+ }
623+
624+ #[ test]
625+ fn test_new_zeroed_zero ( ) {
626+ let crypto_vec = CryptoVec :: new_zeroed ( 0 ) ;
627+ assert_eq ! ( crypto_vec. size, 0 ) ;
628+ assert_eq ! ( crypto_vec. capacity, 0 ) ;
629+ }
630+
572631 #[ test]
573632 fn test_extend ( ) {
574633 let mut crypto_vec = CryptoVec :: new ( ) ;
575634 crypto_vec. extend ( b"test" ) ;
576635 assert_eq ! ( crypto_vec. as_ref( ) , b"test" ) ;
577636 }
578637
638+ #[ test]
639+ #[ should_panic( expected = "CryptoVec capacity overflow" ) ]
640+ fn test_checked_capacity_overflow_panics ( ) {
641+ let _ = checked_capacity ( usize:: MAX ) ;
642+ }
643+
644+ #[ test]
645+ #[ should_panic( expected = "CryptoVec capacity overflow" ) ]
646+ fn test_checked_capacity_rejects_values_above_max_capacity ( ) {
647+ let _ = checked_capacity ( super :: MAX_CAPACITY + 1 ) ;
648+ }
649+
579650 #[ test]
580651 fn test_write_all_from ( ) {
581652 let mut crypto_vec = CryptoVec :: new ( ) ;
0 commit comments