13个稳定版本 (5个主要版本)
新 24.0.0 | 2024年8月20日 |
---|---|
23.0.2 | 2024年8月12日 |
23.0.1 | 2024年7月22日 |
22.0.0 | 2024年6月20日 |
19.0.0 | 2024年3月20日 |
#1099 在 WebAssembly
104,608 每月下载量
在 86 个crate中使用 (直接使用4个)
18KB
251 行代码
一个非常简单、统一类型的slab区域,支持释放和重用已释放条目的空间。
slab中空闲条目的列表存储在slab的现有存储中。
示例
use wasmtime_slab::{Id, Slab};
let mut slab = Slab::new();
// Insert some values into the slab.
let rza = slab.alloc("Robert Fitzgerald Diggs");
let gza = slab.alloc("Gary Grice");
let bill = slab.alloc("Bill Gates");
// Allocated elements can be accessed infallibly via indexing (and missing and
// deallocated entries will panic).
assert_eq!(slab[rza], "Robert Fitzgerald Diggs");
// Alternatively, the `get` and `get_mut` methods provide fallible lookup.
if let Some(genius) = slab.get(gza) {
println!("The gza gza genius: {}", genius);
}
if let Some(val) = slab.get_mut(bill) {
*val = "Bill Gates doesn't belong in this set...";
}
// We can remove values from the slab.
slab.dealloc(bill);
// Allocate a new entry.
let bill = slab.alloc("Bill Murray");
使用错误的Id
与Slab
Slab
不会检查用于访问先前分配的值的Id
是否来自当前Slab
实例(而不是不同的Slab
实例)。使用来自不同Slab
的Id
是安全的,但如果使用,将产生无关的值。
如果您希望检查一个Id
是否来自正确的Slab
实例,可以通过将Slab
和Id
包装在额外维护slab实例标识符的类型中来轻松地将该功能分层到这个crate之上。
ABA问题
此Slab
类型不会防止ABA错误,例如以下序列
-
值
A
被分配到slab中,得到idi
。 -
A
被释放,因此与i
相关的条目被添加到slab的空闲列表中。 -
值
B
被分配到 slab 中,复用了i
的关联条目,产生了 idi
。 -
使用 "原始" id
i
访问存储区,期望获取已释放的值A
,但得到了新的值B
。
也就是说,它无法检测和防止内存安全版本的使用后释放(use-after-free)漏洞。
如果您需要保护免受 ABA 漏洞的影响,可以通过将以下类似内容包装在 Slab
上来轻松地在 crate 上层添加该功能
pub struct GenerationalId {
id: wasmtime_slab::Id,
generation: u32,
}
struct GenerationalEntry<T> {
value: T,
generation: u32,
}
pub struct GenerationalSlab<T> {
slab: wasmtime_slab::Slab<GenerationalEntry<T>>,
generation: u32,
}
impl<T> GenerationalSlab<T> {
pub fn alloc(&mut self, value: T) -> GenerationalId {
let generation = self.generation;
let id = self.slab.alloc(GenerationalEntry { value, generation });
GenerationalId { id, generation }
}
pub fn get(&self, id: GenerationalId) -> Option<&T> {
let entry = self.slab.get(id.id)?;
// Check that the entry's generation matches the id's generation,
// else we have an ABA bug. (Alternatively, return `None` instead
// of panicking.)
assert_eq!(id.generation, entry.generation);
Some(&entry.value)
}
pub fn dealloc(&mut self, id: GenerationalId) {
// Check that the entry's generation matches the id's generation,
// else we have an ABA bug. (Alternatively, silently return on
// double-free instead of panicking.)
assert_eq!(id.generation, self.slab[id.id].generation);
self.slab.dealloc(id.id);
// Increment our generation whenever we deallocate so that any new
// value placed in this same entry will have a different generation
// and we can detect ABA bugs.
self.generation += 1;
}
}