|
| 1 | +# Deterministic Wasm Execution |
| 2 | + |
| 3 | +The WebAssembly language is *mostly* deterministic, but there are a few places |
| 4 | +where non-determinism slips in. This page documents how to use Wasmtime to |
| 5 | +execute Wasm programs fully deterministically, even when the Wasm language spec |
| 6 | +allows for non-determinism. |
| 7 | + |
| 8 | +## Make Sure All Imports are Deterministic |
| 9 | + |
| 10 | +Do not give Wasm programs access to non-deterministic host functions. |
| 11 | + |
| 12 | +When using WASI, use |
| 13 | +[`wasi-virt`](https://github.com/bytecodealliance/WASI-Virt) to virtualize |
| 14 | +non-deterministic APIs like clocks and file systems. |
| 15 | + |
| 16 | +## Enable IEEE-754 `NaN` canonicalization |
| 17 | + |
| 18 | +Some Wasm opcodes can result in `NaN` (not-a-number) values. The IEEE-754 spec |
| 19 | +defines a whole range of `NaN` values and the Wasm spec does not require that |
| 20 | +Wasm always generates any particular `NaN` value, it could be any one of |
| 21 | +them. This non-determinism can then be observed by the Wasm program by storing |
| 22 | +the `NaN` value to memory or bitcasting it to an integer. Therefore, Wasmtime |
| 23 | +can be configured to canonicalize all `NaN`s into a particular, canonical `NaN` |
| 24 | +value. The downside is that this adds overhead to Wasm's floating-point |
| 25 | +instructions. |
| 26 | + |
| 27 | +See |
| 28 | +[wasmtime::Config::cranelift_nan_canonicalization](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.cranelift_nan_canonicalization) |
| 29 | +for more details. |
| 30 | + |
| 31 | +## Make the Relaxed SIMD Proposal Deterministic |
| 32 | + |
| 33 | +The relaxed SIMD proposal gives Wasm programs access to SIMD operations that |
| 34 | +cannot be made to execute both identically and performantly across different |
| 35 | +architecures. The proposal gave up determinism across different achitectures in |
| 36 | +order to maintain portable performance. |
| 37 | + |
| 38 | +At the cost of worse runtime performance, Wasmtime can deterministically execute |
| 39 | +this proposal's instructions. See |
| 40 | +[wasmtime::Config::relaxed_simd_deterministic](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.relaxed_simd_deterministic) |
| 41 | +for more details. |
| 42 | + |
| 43 | +Alternatively, you can simply disable the proposal completely. See |
| 44 | +[`wasmtime::Config::wasm_relaxed_simd`](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.wasm_relaxed_simd) |
| 45 | +for more details. |
| 46 | + |
| 47 | +## Handling Non-Deterministic Memory and Table Growth |
| 48 | + |
| 49 | +All WebAssembly memories and tables have an associated minimum, or initial, size |
| 50 | +and an optional maximum size. When the maximum size is not present, that means |
| 51 | +"unlimited". If a memory or table is already at its maximum size, then attempts |
| 52 | +to grow them will always fail. If they are below their maximum size, however, |
| 53 | +then the `memory.grow` and `table.grow` instructions are allowed to |
| 54 | +non-deterministicaly succeed or fail (for example, when the host system does not |
| 55 | +have enough memory available to satisfy that growth). |
| 56 | + |
| 57 | +You can make this deterministic in a variety of ways: |
| 58 | + |
| 59 | +* Disallow Wasm programs that use memories and tables via a |
| 60 | + [limiter](https://docs.rs/wasmtime/latest/wasmtime/struct.Store.html#method.limiter) |
| 61 | + that rejects non-zero-sized memories and tables. |
| 62 | + |
| 63 | +* Use a [custom memory |
| 64 | + creator](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.with_host_memory) |
| 65 | + that allocates the maximum size up front so that growth will either always |
| 66 | + succeed or fail before the program has begun execution. |
| 67 | + |
| 68 | +* Use [the `wasmparser` crate](https://crates.io/crates/wasmparser) to write a |
| 69 | + little validator program that rejects Wasm modules that use |
| 70 | + `{memory,table}.grow` instructions or alternatively rejects memories and |
| 71 | + tables that do not have a maximum size equal to their minimum size (which, |
| 72 | + again, means that their allocation must happen completely up front, and if |
| 73 | + allocation fails, it will have failed before the Wasm program began |
| 74 | + executing). |
| 75 | + |
| 76 | +## Use Deterministic Interruption, If Any |
| 77 | + |
| 78 | +If you are making Wasm execution interruptible, use [deterministic fuel-based |
| 79 | +interruption](./examples-interrupting-wasm.html#deterministic-fuel) rather than |
| 80 | +non-deterministic epoch-based interruption. |
0 commit comments