@@ -46,6 +46,7 @@ impl Store {
46
46
47
47
/// Get a module instance by the internal id
48
48
pub fn get_module_instance ( & self , addr : ModuleInstanceAddr ) -> Option < & ModuleInstance > {
49
+ log:: debug!( "existing module instances: {:?}" , self . module_instances. len( ) ) ;
49
50
self . module_instances . get ( addr as usize )
50
51
}
51
52
@@ -180,7 +181,7 @@ impl Store {
180
181
func_addrs : & [ FuncAddr ] ,
181
182
elements : Vec < Element > ,
182
183
idx : ModuleInstanceAddr ,
183
- ) -> Result < Box < [ Addr ] > > {
184
+ ) -> Result < ( Box < [ Addr ] > , Option < Trap > ) > {
184
185
let elem_count = self . data . elements . len ( ) ;
185
186
let mut elem_addrs = Vec :: with_capacity ( elem_count) ;
186
187
for ( i, element) in elements. into_iter ( ) . enumerate ( ) {
@@ -214,15 +215,17 @@ impl Store {
214
215
. copied ( )
215
216
. ok_or_else ( || Error :: Other ( format ! ( "table {} not found for element {}" , table, i) ) ) ?;
216
217
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
222
218
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
+ }
224
227
} else {
225
- log :: error !( "table {} not found" , table) ;
228
+ return Err ( Error :: Other ( format ! ( "table {} not found for element {} " , table, i ) ) ) ;
226
229
}
227
230
228
231
// f. Execute the instruction elm.drop i
@@ -235,7 +238,7 @@ impl Store {
235
238
}
236
239
237
240
// this should be optimized out by the compiler
238
- Ok ( elem_addrs. into_boxed_slice ( ) )
241
+ Ok ( ( elem_addrs. into_boxed_slice ( ) , None ) )
239
242
}
240
243
241
244
/// Add data to the store, returning their addresses in the store
@@ -244,7 +247,7 @@ impl Store {
244
247
mem_addrs : & [ MemAddr ] ,
245
248
datas : Vec < Data > ,
246
249
idx : ModuleInstanceAddr ,
247
- ) -> Result < Box < [ Addr ] > > {
250
+ ) -> Result < ( Box < [ Addr ] > , Option < Trap > ) > {
248
251
let data_count = self . data . datas . len ( ) ;
249
252
let mut data_addrs = Vec :: with_capacity ( data_count) ;
250
253
for ( i, data) in datas. into_iter ( ) . enumerate ( ) {
@@ -268,7 +271,10 @@ impl Store {
268
271
Error :: Other ( format ! ( "memory {} not found for data segment {}" , mem_addr, i) )
269
272
} ) ?;
270
273
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
+ }
272
278
273
279
// drop the data
274
280
continue ;
@@ -281,7 +287,7 @@ impl Store {
281
287
}
282
288
283
289
// this should be optimized out by the compiler
284
- Ok ( data_addrs. into_boxed_slice ( ) )
290
+ Ok ( ( data_addrs. into_boxed_slice ( ) , None ) )
285
291
}
286
292
287
293
pub ( crate ) fn add_global ( & mut self , ty : GlobalType , value : RawWasmValue , idx : ModuleInstanceAddr ) -> Result < Addr > {
0 commit comments