Skip to content

Commit 8c22e58

Browse files
authored
mpk: Fix index used when purging a module in the pooling allocator (#12910)
This commit fixes an issue with the pooling allocator when MPK is enabled, which is off-by-default at compile time. When a module is dropped all remaining images are purged from the pooling allocator, but the purging logic mistakenly used the wrong kind of index during purging which led to corruption of the pooling allocator itself. This fixes the logic and adds regression tests showcasing the issue as well.
1 parent 0dbb6f3 commit 8c22e58

3 files changed

Lines changed: 57 additions & 2 deletions

File tree

crates/wasmtime/src/runtime/vm/instance/allocator/pooling/memory_pool.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,7 +507,7 @@ impl MemoryPool {
507507
// associated with a module (not just module and memory). The latter
508508
// would require care to make sure that its maintenance wouldn't be too
509509
// expensive for normal allocation/free operations.
510-
for stripe in &self.stripes {
510+
for (stripe_index, stripe) in self.stripes.iter().enumerate() {
511511
for i in 0..self.memories_per_instance {
512512
use wasmtime_environ::EntityRef;
513513
let memory_index = DefinedMemoryIndex::new(i);
@@ -522,7 +522,8 @@ impl MemoryPool {
522522
// If anything fails then the slot will be in an "unknown"
523523
// state which means that on next use it'll be remapped with
524524
// anonymous memory.
525-
let index = MemoryAllocationIndex(id.0);
525+
let index = StripedAllocationIndex(id.0)
526+
.as_unstriped_slot_index(stripe_index, self.stripes.len());
526527
if let Ok(mut slot) = self.take_memory_image_slot(index) {
527528
if slot.remove_image().is_ok() {
528529
self.return_memory_image_slot(index, Some(slot));

tests/all/pooling_allocator.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,3 +1456,41 @@ fn memory_reset_if_instantiation_fails() -> Result<()> {
14561456

14571457
Ok(())
14581458
}
1459+
1460+
#[test]
1461+
fn purge_module_with_mpk() -> Result<()> {
1462+
if !wasmtime::PoolingAllocationConfig::are_memory_protection_keys_available() {
1463+
println!("skipping test; mpk is not supported");
1464+
return Ok(());
1465+
}
1466+
1467+
let mut pool = crate::small_pool_config();
1468+
pool.total_memories(2)
1469+
.memory_protection_keys(Enabled::Yes)
1470+
.max_memory_protection_keys(2);
1471+
let mut config = Config::new();
1472+
config.allocation_strategy(InstanceAllocationStrategy::Pooling(pool));
1473+
let engine = Engine::new(&config)?;
1474+
1475+
// Create a module and instantiate it in stripe 0.
1476+
let m1 = Module::new(&engine, "(module (memory 1))")?;
1477+
let mut store = Store::new(&engine, ());
1478+
Instance::new(&mut store, &m1, &[])?;
1479+
1480+
// Create and instantiate a module in stripe 1. Note that the store is
1481+
// immediately destroyed here after instantiation. That should leave the
1482+
// linear memory slot available for re-instantiation.
1483+
{
1484+
let m2 = Module::new(&engine, "(module (memory 1))")?;
1485+
Instance::new(&mut Store::new(&engine, ()), &m2, &[])?;
1486+
1487+
// ... drop `m2` here which will purge it and should remove the warm
1488+
// slot left for the module. Nothing should get corrupted...
1489+
}
1490+
1491+
// Drop the outer store here which will clean up the rest of the
1492+
// instance/etc.
1493+
drop(store);
1494+
1495+
Ok(())
1496+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
;; Small test case to create a module in one thread, drop another module in
2+
;; another thread, then drop the first module in the original thread. This
3+
;; historically exposed an issue with MPK and using striped indices correctly
4+
;; when purging modules from the pooling allocator.
5+
6+
(module
7+
(memory 1)
8+
(data (i32.const 0) "\2a\00\00\00")
9+
(func (export "load") (result i32)
10+
i32.const 0
11+
i32.load))
12+
13+
(assert_return (invoke "load") (i32.const 42))
14+
15+
(thread $t1 (module (memory 1)))
16+
(wait $t1)

0 commit comments

Comments
 (0)