@@ -234,6 +234,25 @@ where
234234 }
235235}
236236
237+ /// Caps an untrusted, deserialized element count before it is handed to
238+ /// `with_capacity`, so a hostile length prefix cannot force a huge eager
239+ /// allocation (and its allocation-abort DoS) before a single element has been
240+ /// read. The reservation is limited to `MAX_PREALLOC_BYTES` worth of items; the
241+ /// container still grows to the real length via `push` as elements actually
242+ /// arrive, so well-formed input is unaffected.
243+ #[ cfg( any( feature = "borsh" , feature = "bin-proto" , feature = "serde" ) ) ]
244+ fn cautious_capacity < T > ( len : usize ) -> usize {
245+ // Mirrors serde's `size_hint::cautious`: never trust a wire-provided length
246+ // as an allocation size.
247+ const MAX_PREALLOC_BYTES : usize = 4096 ;
248+ let item_size = core:: mem:: size_of :: < T > ( ) ;
249+ if item_size == 0 {
250+ len
251+ } else {
252+ core:: cmp:: min ( len, MAX_PREALLOC_BYTES / item_size)
253+ }
254+ }
255+
237256#[ cfg( feature = "borsh" ) ]
238257#[ cfg_attr( docs_rs, doc( cfg( feature = "borsh" ) ) ) ]
239258impl < A : Array > borsh:: BorshDeserialize for TinyVec < A >
@@ -244,7 +263,8 @@ where
244263 reader : & mut R ,
245264 ) -> borsh:: io:: Result < Self > {
246265 let len = <usize as borsh:: BorshDeserialize >:: deserialize_reader ( reader) ?;
247- let mut new_tinyvec = Self :: with_capacity ( len) ;
266+ let mut new_tinyvec =
267+ Self :: with_capacity ( cautious_capacity :: < A :: Item > ( len) ) ;
248268
249269 for _ in 0 ..len {
250270 new_tinyvec. push (
@@ -313,7 +333,8 @@ where
313333 {
314334 let item_count =
315335 tag. 0 . try_into ( ) . map_err ( |_| bin_proto:: Error :: TagConvert ) ?;
316- let mut values = Self :: with_capacity ( item_count) ;
336+ let mut values =
337+ Self :: with_capacity ( cautious_capacity :: < A :: Item > ( item_count) ) ;
317338 for _ in 0 ..item_count {
318339 values. push ( bin_proto:: BitDecode :: < _ , _ > :: decode :: < _ , E > ( read, ctx, ( ) ) ?) ;
319340 }
@@ -1951,7 +1972,9 @@ where
19511972 S : SeqAccess < ' de > ,
19521973 {
19531974 let mut new_tinyvec = match seq. size_hint ( ) {
1954- Some ( expected_size) => TinyVec :: with_capacity ( expected_size) ,
1975+ Some ( expected_size) => {
1976+ TinyVec :: with_capacity ( cautious_capacity :: < A :: Item > ( expected_size) )
1977+ }
19551978 None => Default :: default ( ) ,
19561979 } ;
19571980
0 commit comments