| 266 | #[test] |
| 267 | #[cfg_attr(miri, ignore)] |
| 268 | fn test_memory_size_accessibility() -> Result<()> { |
| 269 | const NUM_GROW_OPS: usize = 1000; |
| 270 | let wat = r#"(module |
| 271 | (import "env" "memory" (memory $memory 1 1000 shared)) |
| 272 | (func (export "probe_last_available") (result i32) |
| 273 | (local $last_address i32) |
| 274 | (local.set $last_address (i32.sub (i32.mul (memory.size) (i32.const 0x10000)) (i32.const 4))) |
| 275 | (i32.load $memory (local.get $last_address)) |
| 276 | ) |
| 277 | )"#; |
| 278 | |
| 279 | let Some(engine) = engine() else { |
| 280 | return Ok(()); |
| 281 | }; |
| 282 | let module = Module::new(&engine, wat)?; |
| 283 | let shared_memory = SharedMemory::new(&engine, MemoryType::shared(1, NUM_GROW_OPS as u32))?; |
| 284 | let done = Arc::new(AtomicBool::new(false)); |
| 285 | |
| 286 | let grow_memory = shared_memory.clone(); |
| 287 | let grow_thread = std::thread::spawn(move || { |
| 288 | for i in 0..NUM_GROW_OPS { |
| 289 | if grow_memory.grow(1).is_err() { |
| 290 | println!("stopping at grow operation #{i}"); |
| 291 | break; |
| 292 | } |
| 293 | } |
| 294 | }); |
| 295 | |
| 296 | let probe_memory = shared_memory.clone(); |
| 297 | let probe_done = done.clone(); |
| 298 | let probe_thread = std::thread::spawn(move || { |
| 299 | let mut store = Store::new(&engine, ()); |
| 300 | let instance = Instance::new(&mut store, &module, &[probe_memory.into()]).unwrap(); |
| 301 | let probe_fn = instance |
| 302 | .get_typed_func::<(), i32>(&mut store, "probe_last_available") |
| 303 | .unwrap(); |
| 304 | while !probe_done.load(Ordering::SeqCst) { |
| 305 | let value = probe_fn.call(&mut store, ()).unwrap() as u32; |
| 306 | assert_eq!(value, 0); |
| 307 | } |
| 308 | }); |
| 309 | |
| 310 | grow_thread.join().unwrap(); |
| 311 | done.store(true, Ordering::SeqCst); |
| 312 | probe_thread.join().unwrap(); |
| 313 | |
| 314 | Ok(()) |
| 315 | } |
| 316 | |
| 317 | #[test] |
| 318 | fn create_shared_memory_through_memory() -> Result<()> { |