Wasm Execution Stack vs Linear Memory
WebAssembly (Wasm) utilizes two distinct memory structures during runtime: the function execution stack and the linear memory. This article explains the fundamental differences between these two storage areas, detailing how the execution stack securely manages function execution and local variables while the linear memory provides a mutable, contiguous address space for application data.
The Wasm Function Execution Stack
The execution stack (often referred to as the virtual machine stack) is an implicit, managed storage area used by the WebAssembly runtime to execute instructions. WebAssembly is a stack-based virtual machine, meaning most instructions push values onto this stack or pop values off it to perform operations.
- Purpose: It handles control flow, function arguments, return values, and local variables.
- Security and Isolation: The execution stack is completely managed by the runtime environment and is inaccessible to the WebAssembly program itself. WebAssembly code cannot obtain pointers or references to the stack. This design prevents classic security vulnerabilities like stack smashing, buffer overflows, and unauthorized return address modification.
- Lifetime: Values on the stack exist only during the execution of the active function frame and are discarded automatically when the function returns.
The Linear Memory
Linear memory is a contiguous, sandboxed array of raw bytes that represents the primary heap of a WebAssembly module. It is defined by the module and can grow dynamically during runtime.
- Purpose: It stores complex data structures, strings, arrays, dynamically allocated objects, and any data that needs to persist across multiple function calls.
- Accessibility: Unlike the execution stack, linear memory is directly addressable. WebAssembly instructions can read and write to arbitrary byte offsets within this memory using load and store operations. It is also accessible by the host environment (such as JavaScript in a web browser), allowing data to be shared between the host and the Wasm module.
- Pointers: Languages like C, C++, and Rust compile their pointers directly into integer offsets that reference locations within this linear memory.
Key Differences at a Glance
- Structure: The execution stack is a structured, LIFO (Last-In, First-Out) system managed by the virtual machine. Linear memory is a flat, unstructured, and indexable byte array.
- Addressability: You cannot get the memory address of a variable stored on the execution stack. Conversely, every byte in linear memory has a specific, queryable address (index).
- Safety: The execution stack is inherently safe from memory corruption because Wasm code cannot manipulate stack pointers. Linear memory is mutable and prone to standard memory management bugs (like buffer overflows or use-after-free), though any corruption is securely contained entirely within the limits of the linear memory block.
- Management: The compiler and runtime automatically manage the execution stack. The developer (or the compiled languageās allocator/garbage collector) must manually manage allocations and deallocations within the linear memory.