Skip to content

Commit bed5513

Browse files
committed
Improve madvise-failure logic in the pooling allocator
In bytecodealliance#12888 the failure of `madvise` or `mmap` was improved to be handled in the pooling allocator but this only accounted for linear memories rather than tables as well. This meant that if `madvise` or `mmap` failed it could be possible to have the previous contents of one table leak over to the next. There's no known actual situation in which this would happen (`madvise` and `mmap` failing is mostly theoretical) but this seems best to fix nonetheless.
1 parent b2fd5de commit bed5513

File tree

2 files changed

+40
-8
lines changed

2 files changed

+40
-8
lines changed

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,16 +177,15 @@ impl DecommitQueue {
177177
// Second, restore the various entities to their associated pools' free
178178
// lists. This is safe, and they are ready for reuse, now that their
179179
// memory regions have been decommitted.
180-
//
181-
// Note that for memory images the images are all dropped here and
182-
// ignored if any decommits failed. This signifies how the state of the
183-
// slot is unknown and needs to be paved over in the future. Also note
184-
// that `bytes_resident` is probably too low, but there's no other
185-
// precise way to know, so it's left here as-is and it'll get reset when
186-
// the slot is reused.
187180
let mut deallocated_any = false;
188181
for (allocation_index, image, bytes_resident) in self.memories {
189182
deallocated_any = true;
183+
// Note that for memory images the images are all dropped here and
184+
// ignored if any decommits failed. This signifies how the state of the
185+
// slot is unknown and needs to be paved over in the future. Also note
186+
// that `bytes_resident` is probably too low, but there's no other
187+
// precise way to know, so it's left here as-is and it'll get reset when
188+
// the slot is reused.
190189
let image = if decommit_succeeded {
191190
Some(image)
192191
} else {
@@ -197,8 +196,16 @@ impl DecommitQueue {
197196
.deallocate(allocation_index, image, bytes_resident);
198197
}
199198
}
200-
for (allocation_index, table, bytes_resident) in self.tables {
199+
for (allocation_index, mut table, bytes_resident) in self.tables {
201200
deallocated_any = true;
201+
// Like with memories, if any decommit failed then we need to
202+
// ensure that tables are still in a defined state. Unlike memories
203+
// which track this via images tables are always assumed to be
204+
// all-null on returning to the allocator. If the OS couldn't do it
205+
// then manually do it ourselves here.
206+
if !decommit_succeeded {
207+
table.manually_memset_zeros();
208+
}
202209
unsafe {
203210
pool.tables
204211
.deallocate(allocation_index, table, bytes_resident);

crates/wasmtime/src/runtime/vm/table.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,6 +1131,31 @@ impl Table {
11311131
}
11321132
}
11331133
}
1134+
1135+
/// Manually resets all table elements to a null bit pattern.
1136+
///
1137+
/// Used in the pooling allocator when `madvise` fails to reset pages back
1138+
/// to their original contents. In such a situation the previous contents of
1139+
/// the table are unknown so this resets them all to defined values.
1140+
pub fn manually_memset_zeros(&mut self) {
1141+
match self.element_type() {
1142+
TableElementType::Func => {
1143+
let (funcrefs, _lazy_init) = self.funcrefs_mut();
1144+
funcrefs.fill(MaybeTaggedFuncRef(None));
1145+
}
1146+
TableElementType::GcRef => {
1147+
// Note that this explicitly contains no barriers as all table
1148+
// GC elements should already have been dropped before returning
1149+
// the table back to the pool.
1150+
for r in self.gc_refs_mut() {
1151+
*r = None;
1152+
}
1153+
}
1154+
TableElementType::Cont => {
1155+
self.contrefs_mut().fill(None);
1156+
}
1157+
}
1158+
}
11341159
}
11351160

11361161
// The default table representation is an empty funcref table that cannot grow.

0 commit comments

Comments
 (0)