How to set max memory limit in wasm

1. background

In my case, i want to limit the max memory that the *.wasm file can use, if it reached the limit, it can crash by OOM.

2. what i have tried

i build the *.rs file to *.wasm file by the command cargo build --target wasm32-wasi

now, i decompiled wasm.wasm to wat file by command wasm2wat wasm.wasm -o a, and the memory segment in the file as follows:

(memory (;0;) 19) means the init memory is 19 pages, size is 65536 * 19 bytes, and no max memory limit, which means it can grow memory as needed.

i tried to set max memory limit as follows:
when i build by the command cargo build --target wasm32-wasi --initial-memory=65536 --max-memory=65536

i got a error:

error: Found argument '--initial-memory' which wasn't expected, or isn't valid in this context

when i build by the command cargo build --target wasm32-wasi --max-memory=65536

i got a error:

error: Found argument '--max-memory' which wasn't expected, or isn't valid in this context

3. my question

in my opinion, if i can modified the memory segment from (memory (;0;) 19) to (memory (;0;) 19 20).

when the memory used by the wasm file reached 20 pages, it will be crashed by OOM

is there any idea about how to achieve this?

1 Like

Are you talking about stack or heap memory?

in my case, i want to use wasm in production env, so it's better for me to limit both stack and heap memory.

besides memory, i also want to limit the max cpu cycle used by wasm file, maybe this is more difficult than limit max memory, any idea about this?

The last time I checked is about a year ago.

Back then at least, stack space could not be altered, which made sure I had to rework an application I was working on to prevent stack overflows.

As for limiting heap space, other than with VMs or containers (both of which are Rust-agnostic) I'm not aware of any way to limit that on any platform.

Thanks for your reply.

i found the wasm file build by rust contains the memory segment, which is (memory (;0;) 19),
In my opinion, maybe we just need add a build flag, eg. --max-page=20, then, when we build rust file to wasm file, the compiler just modify (memory (;0;) 19) to (memory (;0;) 19 20), and this will crashed when the memory reached 20 pages.

What confuses me is why the rust compiler doesn't set max page size in the memory segment and doesn't provide other method to update this?

It's likely because without the explicit cooperation of the various WASM VMs, you can put whatever you want in the wasm file, and it will simply be ignored. The easiest way to ensure such cooperation is by getting it into the WASM spec, but even that doesn't seem to be exactly easy.

i directly edit the wat file and modified the memory segment to (memory (;0;) 1 1), which means the init memory is 1 page and the max is 2 page,

now i compiled the wat file to wasm file by the command wat2wasm a -o a.wasm and run it by wasmtime

i got the error as follows

Error: failed to run main module `a.wasm`
Caused by:
    0: failed to invoke command default
    1: wasm trap: out of bounds memory access

it indeed what i want to see.

and i checked the WebAssembly spec, it has the max limit:

i think if wasm doesn't support limit cpu and memory resource, it's dangerous to load multiple wasm instance in one wasm runtime in production env

I just checked the spec myself. Indeed it does seem to support putting limits on memory sizes.
However, it does not seem to support limiting cpu time.

1 Like

--initial-memory and --max-memory are arguments for the linker. Try `cargo rustc --target wasm32-wasi -- -Clink-arg=--initial-memory=65536 -Clink-arg=--max-memory=65536

2 Likes

I don't know of a way to tell the Rust compiler to generate a .wasm file with the memory limit set.

However, I would suggest you to enforce this on the runtime level. If you are using wasmtime, you can embed their runtime into a wrapper app and control memory & CPU usage precisely. This way you don't even need to trust the value in the .wasm file you are running.

If you don't feel like providing your runtime, lunatic even allows you to write rust code that compiles to wasm and then loads other .wasm files dynamically with specific memory/cpu/syscalls constraints. You can even run just a closure from the currently executing .wasm file in a separate "process" (wasm instance), with specific memory and CPU constraints.

Btw. When compiling to wasm, Rust uses a shadow-stack on the wasm heap that will eat part of your heap memory. You can configure how big this stack is with a flag (I think it's actually a LLVM flag and I can't remember it now). You need to account for this too if you are setting a small wasm page size (like ~20).

2 Likes

thanks! it really works!

thanks for your suggestion, I am studying the lunatic project. :smiley:

Normally this will be enforced by your WebAssembly runtime and not by the compiler/linker.

Wasmer has an in-depth example of limiting memory and wasmtime lets you customise linear memory's behaviour with Config::with_host_memory().

2 Likes