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日

#1099WebAssembly

Download history 8428/week @ 2024-04-30 11492/week @ 2024-05-07 14643/week @ 2024-05-14 14947/week @ 2024-05-21 17417/week @ 2024-05-28 16144/week @ 2024-06-04 18958/week @ 2024-06-11 21832/week @ 2024-06-18 22618/week @ 2024-06-25 20554/week @ 2024-07-02 26392/week @ 2024-07-09 23421/week @ 2024-07-16 25877/week @ 2024-07-23 24978/week @ 2024-07-30 23582/week @ 2024-08-06 24883/week @ 2024-08-13

104,608 每月下载量
86 个crate中使用 (直接使用4个)

Apache-2.0 WITH LLVM-exception

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");

使用错误的IdSlab

Slab不会检查用于访问先前分配的值的Id是否来自当前Slab实例(而不是不同的Slab实例)。使用来自不同SlabId是安全的,但如果使用,将产生无关的值。

如果您希望检查一个Id是否来自正确的Slab实例,可以通过将SlabId包装在额外维护slab实例标识符的类型中来轻松地将该功能分层到这个crate之上。

ABA问题

Slab类型不会防止ABA错误,例如以下序列

  • A被分配到slab中,得到id i

  • A被释放,因此与i相关的条目被添加到slab的空闲列表中。

  • B 被分配到 slab 中,复用了 i 的关联条目,产生了 id i

  • 使用 "原始" 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;
    }
}

无运行时依赖