@@ -46,6 +46,7 @@ impl Store {
4646
4747 /// Get a module instance by the internal id
4848 pub fn get_module_instance ( & self , addr : ModuleInstanceAddr ) -> Option < & ModuleInstance > {
49+ log:: debug!( "existing module instances: {:?}" , self . module_instances. len( ) ) ;
4950 self . module_instances . get ( addr as usize )
5051 }
5152
@@ -180,7 +181,7 @@ impl Store {
180181 func_addrs : & [ FuncAddr ] ,
181182 elements : Vec < Element > ,
182183 idx : ModuleInstanceAddr ,
183- ) -> Result < Box < [ Addr ] > > {
184+ ) -> Result < ( Box < [ Addr ] > , Option < Trap > ) > {
184185 let elem_count = self . data . elements . len ( ) ;
185186 let mut elem_addrs = Vec :: with_capacity ( elem_count) ;
186187 for ( i, element) in elements. into_iter ( ) . enumerate ( ) {
@@ -214,15 +215,17 @@ impl Store {
214215 . copied ( )
215216 . ok_or_else ( || Error :: Other ( format ! ( "table {} not found for element {}" , table, i) ) ) ?;
216217
217- // a. Let n be the length of the vector elem[i].init
218- // b. Execute the instruction sequence einstrs
219- // c. Execute the instruction i32.const 0
220- // d. Execute the instruction i32.const n
221- // e. Execute the instruction table.init tableidx i
222218 if let Some ( table) = self . data . tables . get_mut ( table_addr as usize ) {
223- table. borrow_mut ( ) . init ( func_addrs, offset, & init) ?;
219+ // In wasm 2.0, it's possible to call a function that hasn't been instantiated yet,
220+ // when using a partially initialized active element segments.
221+ // This isn't mentioned in the spec, but the "unofficial" testsuite has a test for it:
222+ // https://github.com/WebAssembly/testsuite/blob/5a1a590603d81f40ef471abba70a90a9ae5f4627/linking.wast#L264-L276
223+ // I have NO IDEA why this is allowed, but it is.
224+ if let Err ( Error :: Trap ( trap) ) = table. borrow_mut ( ) . init ( func_addrs, offset, & init) {
225+ return Ok ( ( elem_addrs. into_boxed_slice ( ) , Some ( trap) ) ) ;
226+ }
224227 } else {
225- log :: error !( "table {} not found" , table) ;
228+ return Err ( Error :: Other ( format ! ( "table {} not found for element {} " , table, i ) ) ) ;
226229 }
227230
228231 // f. Execute the instruction elm.drop i
@@ -235,7 +238,7 @@ impl Store {
235238 }
236239
237240 // this should be optimized out by the compiler
238- Ok ( elem_addrs. into_boxed_slice ( ) )
241+ Ok ( ( elem_addrs. into_boxed_slice ( ) , None ) )
239242 }
240243
241244 /// Add data to the store, returning their addresses in the store
@@ -244,7 +247,7 @@ impl Store {
244247 mem_addrs : & [ MemAddr ] ,
245248 datas : Vec < Data > ,
246249 idx : ModuleInstanceAddr ,
247- ) -> Result < Box < [ Addr ] > > {
250+ ) -> Result < ( Box < [ Addr ] > , Option < Trap > ) > {
248251 let data_count = self . data . datas . len ( ) ;
249252 let mut data_addrs = Vec :: with_capacity ( data_count) ;
250253 for ( i, data) in datas. into_iter ( ) . enumerate ( ) {
@@ -268,7 +271,10 @@ impl Store {
268271 Error :: Other ( format ! ( "memory {} not found for data segment {}" , mem_addr, i) )
269272 } ) ?;
270273
271- mem. borrow_mut ( ) . store ( offset as usize , 0 , & data. data ) ?;
274+ // See comment for active element sections in the function above why we need to do this here
275+ if let Err ( Error :: Trap ( trap) ) = mem. borrow_mut ( ) . store ( offset as usize , 0 , & data. data ) {
276+ return Ok ( ( data_addrs. into_boxed_slice ( ) , Some ( trap) ) ) ;
277+ }
272278
273279 // drop the data
274280 continue ;
@@ -281,7 +287,7 @@ impl Store {
281287 }
282288
283289 // this should be optimized out by the compiler
284- Ok ( data_addrs. into_boxed_slice ( ) )
290+ Ok ( ( data_addrs. into_boxed_slice ( ) , None ) )
285291 }
286292
287293 pub ( crate ) fn add_global ( & mut self , ty : GlobalType , value : RawWasmValue , idx : ModuleInstanceAddr ) -> Result < Addr > {
0 commit comments