Stream: general

Topic: Linear Memory


view this post on Zulip Minyeong Jeong (Jan 18 2021 at 08:10):

Hi, I don't know if this is the right place to ask questions, but here it goes

I am currently interested in the bound checking of linear memory access of Wasm. Because I am a hardware engineer, I would love to see what architectural aid Wasm can get. So I am looking for the exact code where the bound checking occurs. Any advice where to start? It would be a great help.

view this post on Zulip bjorn3 (Jan 18 2021 at 09:28):

@Minyeong Jeong You can take a look at the expansion of heap_addr: https://github.com/bytecodealliance/wasmtime/blob/5c1d728e3ae8ee7aa329e294999a2c3086b21676/cranelift/codegen/src/legalizer/heap.rs

There are two kinds of heaps: https://github.com/bytecodealliance/wasmtime/blob/5c1d728e3ae8ee7aa329e294999a2c3086b21676/cranelift/codegen/src/ir/heap.rs#L27-L42

Static heaps have a known size. In many cases for wasm it is possible on 64bit systems to simply add the heap address and access offset as the used address without any bound checks. This is because wasm uses 32bit pointers, so reserving a 4GB chunk of memory works. If the wasm heap size is less than 4GB, the rest of this chunk can be explicitly mapped as unreachable, thus causing a catchable SIGSEGV on out of bounds accesses. Static heaps smaller than 4GB and dynamic heaps do need bound checks though.

Standalone JIT-style runtime for WebAssembly, using Cranelift - bytecodealliance/wasmtime
Standalone JIT-style runtime for WebAssembly, using Cranelift - bytecodealliance/wasmtime

view this post on Zulip Minyeong Jeong (Jan 18 2021 at 12:29):

Thank you so much. It was a tremendous help!

view this post on Zulip Minyeong Jeong (Jan 18 2021 at 12:58):

@bjorn3 May I ask another question?

So I get that there are two kinds of heap. Static heap that has a fixed base and some not-yet-allocated pages, and dynamic heap that the base can change. Can you explain when and why you get to use static/dynamic over the other? Is it specific to some usecases? It may be a stupid question, but trying to figure it out!!!

view this post on Zulip bjorn3 (Jan 18 2021 at 13:03):

Static heap is more performant, but requires you to reserve a memory region that has the same size as the maximum heap size. On 32bit systems, this would be a problem as the address space is only 4GB (of which 2GB usable for user programs in most cases) If you don't know in advance exactly how much memory is necessary by the WASM program, you will have to reserve more than the program needs. This memory can then no longer be used by the host or other WASM programs within the same address space. For 64bit systems this is not a problem as 4GB is only a fraction of the address space and only the actually used part of the heap will actually count towards the RAM usage.

view this post on Zulip Minyeong Jeong (Jan 19 2021 at 06:50):

@bjorn3 Thanks agian, got it!!! :grinning:

view this post on Zulip Arne Vogel (Jan 20 2021 at 11:52):

Hi, I have a question about converting a pointer that I get from a wasm module to the real address inside of wasmtime.
I am trying to add threading support to wasmtime. I posted the relevant part of the code below together with a gdb error I get trying to execute it. I am getting Cannot access memory at address which I assume is because the pointer I get from the wasm module is inside of the linear memory and not relative to the real heap which libc::pthread_create expects. So my question is how can I calculate the relative position of the pointer on the heap? I would also appreciate any other feedback. Thanks in advance!

    // wasmtime/crates/wasi-common/src/snapshots/wasi_snapshot_preview1.rs
    fn pthread_create(&self, function: u64) -> Result<u64> {
        unsafe {
            let backptr: usize = function as usize;
            let p: *mut Box<dyn FnOnce()> = backptr as *mut Box<dyn FnOnce()>;
            println!("p: {:?}", p); // -> 0x103a00
            ...
            let _ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _);
        }
    }

    // rust/library/std/src/sys/wasi/thread.rs
    pub unsafe fn new(_stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
        let p: *mut Box<dyn FnOnce()> = Box::into_raw(box p);
        let y: *const i32 = p as *const i32;
        let ptr: usize = y as usize;
        let u64ptr: u64 = ptr as u64;
        println!("ptr: {:#x}", u64ptr); // -> 0x103a00
        let thread: u64 = wasi::pthread_create(u64ptr).unwrap();
    }

    // gdb output
0x0000555556f06993 in <alloc::boxed::Box<F> as core::ops::function::FnOnce<A>>::call_once (
    self=<error reading variable: Cannot access memory at address 0x7ffff55fa780>, args=())
    at /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/alloc/src/boxed.rs:1042
1042    /rustc/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/library/alloc/src/boxed.rs: No such file or directory.

Last updated: Oct 23 2024 at 20:03 UTC