File tree Expand file tree Collapse file tree 9 files changed +65
-21
lines changed
Expand file tree Collapse file tree 9 files changed +65
-21
lines changed Original file line number Diff line number Diff line change @@ -349,23 +349,24 @@ pub struct GcArrayLayout {
349349impl GcArrayLayout {
350350 /// Get the total size of this array for a given length of elements.
351351 #[ inline]
352- pub fn size_for_len ( & self , len : u32 ) -> u32 {
352+ pub fn size_for_len ( & self , len : u32 ) -> Option < u32 > {
353353 self . elem_offset ( len)
354354 }
355355
356356 /// Get the offset of the `i`th element in an array with this layout.
357357 #[ inline]
358- pub fn elem_offset ( & self , i : u32 ) -> u32 {
359- self . base_size + i * self . elem_size
358+ pub fn elem_offset ( & self , i : u32 ) -> Option < u32 > {
359+ let elem_offset = i. checked_mul ( self . elem_size ) ?;
360+ self . base_size . checked_add ( elem_offset)
360361 }
361362
362363 /// Get a `core::alloc::Layout` for an array of this type with the given
363364 /// length.
364- pub fn layout ( & self , len : u32 ) -> Layout {
365- let size = self . size_for_len ( len) ;
365+ pub fn layout ( & self , len : u32 ) -> Option < Layout > {
366+ let size = self . size_for_len ( len) ? ;
366367 let size = usize:: try_from ( size) . unwrap ( ) ;
367368 let align = usize:: try_from ( self . align ) . unwrap ( ) ;
368- Layout :: from_size_align ( size, align) . unwrap ( )
369+ Layout :: from_size_align ( size, align) . ok ( )
369370 }
370371}
371372
Original file line number Diff line number Diff line change @@ -393,22 +393,21 @@ impl ArrayRef {
393393 "attempted to use a `ArrayRefPre` with the wrong store"
394394 ) ;
395395
396- // Type check the elements against the element type.
397- for elem in elems. clone ( ) {
398- elem. ensure_matches_ty ( store, allocator. ty . element_type ( ) . unpack ( ) )
399- . context ( "element type mismatch" ) ?;
400- }
401-
402396 let len = u32:: try_from ( elems. len ( ) ) . unwrap ( ) ;
403397
404- // Allocate the array and write each field value into the appropriate
405- // offset.
398+ // Allocate the array.
406399 let arrayref = store
407400 . require_gc_store_mut ( ) ?
408401 . alloc_uninit_array ( allocator. type_index ( ) , len, allocator. layout ( ) )
409402 . context ( "unrecoverable error when allocating new `arrayref`" ) ?
410403 . map_err ( |n| GcHeapOutOfMemory :: new ( ( ) , n) ) ?;
411404
405+ // Type check the elements against the element type.
406+ for elem in elems. clone ( ) {
407+ elem. ensure_matches_ty ( store, allocator. ty . element_type ( ) . unpack ( ) )
408+ . context ( "element type mismatch" ) ?;
409+ }
410+
412411 // From this point on, if we get any errors, then the array is not
413412 // fully initialized, so we need to eagerly deallocate it before the
414413 // next GC where the collector might try to interpret one of the
Original file line number Diff line number Diff line change @@ -197,6 +197,8 @@ impl StoreOpaque {
197197 Ok ( x) => Ok ( x) ,
198198 Err ( e) => match e. downcast :: < crate :: GcHeapOutOfMemory < T > > ( ) {
199199 Ok ( oom) => {
200+ log:: trace!( "Got GC heap OOM: {oom}" ) ;
201+
200202 let ( value, oom) = oom. take_inner ( ) ;
201203 let bytes_needed = oom. bytes_needed ( ) ;
202204
Original file line number Diff line number Diff line change @@ -1567,7 +1567,7 @@ impl From<TagType> for ExternType {
15671567///
15681568/// This is either a packed 8- or -16 bit integer, or else it is some unpacked
15691569/// Wasm value type.
1570- #[ derive( Clone , Hash ) ]
1570+ #[ derive( Debug , Clone , Hash ) ]
15711571pub enum StorageType {
15721572 /// `i8`, an 8-bit integer.
15731573 I8 ,
Original file line number Diff line number Diff line change @@ -145,7 +145,7 @@ impl VMArrayRef {
145145 ty : & StorageType ,
146146 index : u32 ,
147147 ) -> Val {
148- let offset = layout. elem_offset ( index) ;
148+ let offset = layout. elem_offset ( index) . unwrap ( ) ;
149149 let data = store. unwrap_gc_store_mut ( ) . gc_object_data ( self . as_gc_ref ( ) ) ;
150150 match ty {
151151 StorageType :: I8 => Val :: I32 ( data. read_u8 ( offset) . into ( ) ) ,
@@ -205,7 +205,7 @@ impl VMArrayRef {
205205 ) -> Result < ( ) > {
206206 debug_assert ! ( val. _matches_ty( & store, & ty. unpack( ) ) ?) ;
207207
208- let offset = layout. elem_offset ( index) ;
208+ let offset = layout. elem_offset ( index) . unwrap ( ) ;
209209 let data = store. unwrap_gc_store_mut ( ) . gc_object_data ( self . as_gc_ref ( ) ) ;
210210 match val {
211211 Val :: I32 ( i) if ty. is_i8 ( ) => data. write_i8 ( offset, truncate_i32_to_i8 ( i) ) ,
@@ -319,7 +319,7 @@ impl VMArrayRef {
319319 val : Val ,
320320 ) -> Result < ( ) > {
321321 debug_assert ! ( val. _matches_ty( & store, & ty. unpack( ) ) ?) ;
322- let offset = layout. elem_offset ( index) ;
322+ let offset = layout. elem_offset ( index) . unwrap ( ) ;
323323 let gcstore = store. require_gc_store_mut ( ) ?;
324324 match val {
325325 Val :: I32 ( i) if ty. is_i8 ( ) => gcstore
Original file line number Diff line number Diff line change @@ -414,7 +414,7 @@ impl DrcHeap {
414414 let info = match gc_layout {
415415 GcLayout :: Array ( l) => {
416416 if l. elems_are_gc_refs {
417- debug_assert_eq ! ( l. elem_offset( 0 ) , GC_REF_ARRAY_ELEMS_OFFSET , ) ;
417+ debug_assert_eq ! ( l. elem_offset( 0 ) , Some ( GC_REF_ARRAY_ELEMS_OFFSET ) ) ;
418418 }
419419 TraceInfo :: Array {
420420 gc_ref_elems : l. elems_are_gc_refs ,
@@ -1070,9 +1070,12 @@ unsafe impl GcHeap for DrcHeap {
10701070 length : u32 ,
10711071 layout : & GcArrayLayout ,
10721072 ) -> Result < Result < VMArrayRef , u64 > > {
1073+ let layout = layout
1074+ . layout ( length)
1075+ . ok_or_else ( || format_err ! ( "allocation size too large" ) ) ?;
10731076 let gc_ref = match self . alloc_raw (
10741077 VMGcHeader :: from_kind_and_index ( VMGcKind :: ArrayRef , ty) ,
1075- layout. layout ( length ) ,
1078+ layout,
10761079 ) ? {
10771080 Err ( n) => return Ok ( Err ( n) ) ,
10781081 Ok ( gc_ref) => gc_ref,
Original file line number Diff line number Diff line change @@ -307,9 +307,12 @@ unsafe impl GcHeap for NullHeap {
307307 length : u32 ,
308308 layout : & GcArrayLayout ,
309309 ) -> Result < Result < VMArrayRef , u64 > > {
310+ let layout = layout
311+ . layout ( length)
312+ . ok_or_else ( || format_err ! ( "allocation size too large" ) ) ?;
310313 self . alloc (
311314 VMGcHeader :: from_kind_and_index ( VMGcKind :: ArrayRef , ty) ,
312- layout. layout ( length ) ,
315+ layout,
313316 )
314317 . map ( |r| {
315318 r. map ( |r| {
Original file line number Diff line number Diff line change 1+ use crate :: ErrorExt ;
2+
13use super :: gc_store;
24use wasmtime:: * ;
35
@@ -876,3 +878,22 @@ fn instantiate_with_array_global() -> Result<()> {
876878
877879 Ok ( ( ) )
878880}
881+
882+ #[ test]
883+ fn issue_13034_array_layout_overflow ( ) -> Result < ( ) > {
884+ for ( storage, len, val) in [
885+ ( StorageType :: I8 , u32:: MAX , Val :: I32 ( 0 ) ) ,
886+ ( StorageType :: I8 , u32:: MAX - 1 , Val :: I32 ( 0 ) ) ,
887+ ( StorageType :: I16 , u32:: MAX / 2 , Val :: I32 ( 0 ) ) ,
888+ ( ValType :: I32 . into ( ) , u32:: MAX / 4 , Val :: I32 ( 0 ) ) ,
889+ ( ValType :: I64 . into ( ) , u32:: MAX / 8 , Val :: I32 ( 0 ) ) ,
890+ ] {
891+ log:: trace!( "Testing [{storage}; {len}]" ) ;
892+ let mut store = gc_store ( ) ?;
893+ let array_ty = ArrayType :: new ( store. engine ( ) , FieldType :: new ( Mutability :: Const , storage) ) ;
894+ let pre = ArrayRefPre :: new ( & mut store, array_ty) ;
895+ let err = ArrayRef :: new ( & mut store, & pre, & val, len) . unwrap_err ( ) ;
896+ err. assert_contains ( "allocation size too large" ) ;
897+ }
898+ Ok ( ( ) )
899+ }
Original file line number Diff line number Diff line change 1+ ;; ! gc = true
2+
3+ (module
4+ (type $i32_array (array (mut i32 )))
5+
6+ (global $arr (mut (ref null $i32_array )) (ref.null $i32_array ))
7+
8+ (func (export " run" )
9+ (global.set $arr
10+ (array.new $i32_array (i32.const 0 ) (i32.const 1073741817 ))
11+ )
12+ )
13+ )
14+
15+ (assert_trap (invoke " run" ) " allocation size too large" )
You can’t perform that action at this time.
0 commit comments