wasmedge-hs-0.17.1.0: examples/Stress/WasmBytecode.hs
{-# LANGUAGE ImportQualifiedPost #-}
{- |
Module : WasmBytecode
Description : Pre-compiled binary WebAssembly modules for stress testing and verification
Copyright : (c) 2026 Tushar Adhatrao
License : MIT
Stability : experimental
This module provides standard, validated WASM binaries encoded as 'ByteString's.
These bytecodes are used across all stress suites to test:
1. Recursive compute-heavy workloads ('fibWasm')
2. Multi-megabyte dynamic memory allocation and linear memory access ('memoryOpsWasm')
3. Host-to-guest and guest-to-host FFI pipelines ('hostImportWasm')
4. Intentional traps, division by zero, memory violations, and infinite loops ('chaosWasm')
-}
module Stress.WasmBytecode
( -- * Pure Compute
fibWasm
, addWasm
-- * Linear Memory Operations
, memoryOpsWasm
-- * Host Function Imports
, hostImportWasm
-- * Chaos and Fault Injection
, chaosWasm
, corruptedMagicWasm
, corruptedSectionWasm
-- * Caller Introspection Guest
, callerGuestWasm
) where
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
-- | Standard WASM header: magic "\0asm" and version 1.
wasmHeader :: [Integer]
wasmHeader = [0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00]
{- | Minimal addition module:
@
(module
(func (export "add") (param i32 i32) (result i32)
local.get 0
local.get 1
i32.add))
@
-}
addWasm :: ByteString
addWasm =
BS.pack $
map fromIntegral $
wasmHeader
++ [ -- Type section: (i32, i32) -> i32
0x01
, 0x07
, 0x01
, 0x60
, 0x02
, 0x7F
, 0x7F
, 0x01
, 0x7F
, -- Function section: func 0 has type 0
0x03
, 0x02
, 0x01
, 0x00
, -- Export section: "add" -> func 0
0x07
, 0x07
, 0x01
, 0x03
, 0x61
, 0x64
, 0x64
, 0x00
, 0x00
, -- Code section
0x0A
, 0x09
, 0x01
, 0x07
, 0x00
, 0x20
, 0x00
, 0x20
, 0x01
, 0x6A
, 0x0B
]
{- | Recursive Fibonacci module:
@
(module
(func $fib (export "fib") (param i32) (result i32)
local.get 0
i32.const 1
i32.le_s
if (result i32)
local.get 0
else
local.get 0
i32.const 1
i32.sub
call 0
local.get 0
i32.const 2
i32.sub
call 0
i32.add
end))
@
-}
fibWasm :: ByteString
fibWasm =
BS.pack $
map fromIntegral $
wasmHeader
++ [ -- Type section: 1 type: (i32) -> i32
0x01
, 0x06
, 0x01
, 0x60
, 0x01
, 0x7F
, 0x01
, 0x7F
, -- Function section: func 0 uses type 0
0x03
, 0x02
, 0x01
, 0x00
, -- Export section: "fib" -> func 0
0x07
, 0x07
, 0x01
, 0x03
, 0x66
, 0x69
, 0x62
, 0x00
, 0x00
, -- Code section:
-- func body length: 28 bytes (0x1C)
-- total code section length: 1 count + 1 size + 28 bytes = 30 bytes (0x1E)
0x0A
, 0x1E
, 0x01
, 0x1C
, 0x00
, 0x20
, 0x00 -- local.get 0
, 0x41
, 0x01 -- i32.const 1
, 0x4C -- i32.le_s
, 0x04
, 0x7F -- if (result i32)
, 0x20
, 0x00 -- local.get 0
, 0x05 -- else
, 0x20
, 0x00 -- local.get 0
, 0x41
, 0x01 -- i32.const 1
, 0x6B -- i32.sub
, 0x10
, 0x00 -- call 0
, 0x20
, 0x00 -- local.get 0
, 0x41
, 0x02 -- i32.const 2
, 0x6B -- i32.sub
, 0x10
, 0x00 -- call 0
, 0x6A -- i32.add
, 0x0B -- end (if)
, 0x0B -- end (func)
]
-- | Linear Memory Operations module:
memoryOpsWasm :: ByteString
memoryOpsWasm =
BS.pack $
map fromIntegral $
wasmHeader
++ [ -- Type section: 4 function types (size 22 = 0x16)
0x01
, 0x16
, 0x04
, -- Type 0: (i32, i32) -> () [write_u32]
0x60
, 0x02
, 0x7F
, 0x7F
, 0x00
, -- Type 1: (i32) -> i32 [read_u32, grow_memory]
0x60
, 0x01
, 0x7F
, 0x01
, 0x7F
, -- Type 2: () -> i32 [memory_size]
0x60
, 0x00
, 0x01
, 0x7F
, -- Type 3: (i32, i32, i32) -> i32 [fill_pattern]
0x60
, 0x03
, 0x7F
, 0x7F
, 0x7F
, 0x01
, 0x7F
, -- Function section: 5 functions (size 6 = 0x06)
0x03
, 0x06
, 0x05
, 0x00
, 0x01
, 0x01
, 0x02
, 0x03
, -- Memory section: 1 memory, min=1, max=1024 (size 5 = 0x05)
0x05
, 0x05
, 0x01
, 0x01
, 0x01
, 0x80
, 0x08
, -- Export section: 6 exports (size 76 = 0x4C)
0x07
, 0x4C
, 0x06
, -- "memory" -> memory 0
0x06
, 0x6D
, 0x65
, 0x6D
, 0x6F
, 0x72
, 0x79
, 0x02
, 0x00
, -- "write_u32" -> func 0
0x09
, 0x77
, 0x72
, 0x69
, 0x74
, 0x65
, 0x5F
, 0x75
, 0x33
, 0x32
, 0x00
, 0x00
, -- "read_u32" -> func 1
0x08
, 0x72
, 0x65
, 0x61
, 0x64
, 0x5F
, 0x75
, 0x33
, 0x32
, 0x00
, 0x01
, -- "grow_memory" -> func 2
0x0B
, 0x67
, 0x72
, 0x6F
, 0x77
, 0x5F
, 0x6D
, 0x65
, 0x6D
, 0x6F
, 0x72
, 0x79
, 0x00
, 0x02
, -- "memory_size" -> func 3
0x0B
, 0x6D
, 0x65
, 0x6D
, 0x6F
, 0x72
, 0x79
, 0x5F
, 0x73
, 0x69
, 0x7A
, 0x65
, 0x00
, 0x03
, -- "fill_pattern" -> func 4
0x0C
, 0x66
, 0x69
, 0x6C
, 0x6C
, 0x5F
, 0x70
, 0x61
, 0x74
, 0x74
, 0x65
, 0x72
, 0x6E
, 0x00
, 0x04
, -- Code section: 5 functions (size 75 = 0x4B)
0x0A
, 0x4B
, 0x05
, -- Func 0 (write_u32): size 9
0x09
, 0x00
, 0x20
, 0x00
, 0x20
, 0x01
, 0x36
, 0x02
, 0x00
, 0x0B
, -- Func 1 (read_u32): size 7
0x07
, 0x00
, 0x20
, 0x00
, 0x28
, 0x02
, 0x00
, 0x0B
, -- Func 2 (grow_memory): size 6
0x06
, 0x00
, 0x20
, 0x00
, 0x40
, 0x00
, 0x0B
, -- Func 3 (memory_size): size 4
0x04
, 0x00
, 0x3F
, 0x00
, 0x0B
, -- Func 4 (fill_pattern): size 43 (0x2B)
0x2B
, 0x01
, 0x02
, 0x7F -- 2 local i32s: $i (local 3), $sum (local 4)
, 0x03
, 0x40 -- loop
, 0x20
, 0x03 -- local.get $i (3)
, 0x20
, 0x01 -- local.get $len (1)
, 0x49 -- i32.lt_u
, 0x04
, 0x40 -- if
, 0x20
, 0x00 -- local.get $off (0)
, 0x20
, 0x03 -- local.get $i (3)
, 0x6A -- i32.add
, 0x20
, 0x02 -- local.get $val (2)
, 0x3A
, 0x00
, 0x00 -- i32.store8 align=0 offset=0
, 0x20
, 0x04 -- local.get $sum (4)
, 0x20
, 0x02 -- local.get $val (2)
, 0x6A -- i32.add
, 0x21
, 0x04 -- local.set $sum (4)
, 0x20
, 0x03 -- local.get $i (3)
, 0x41
, 0x01 -- i32.const 1
, 0x6A -- i32.add
, 0x21
, 0x03 -- local.set $i (3)
, 0x0C
, 0x01 -- br 1 (continue loop)
, 0x0B -- end (if)
, 0x0B -- end (loop)
, 0x20
, 0x04 -- local.get $sum
, 0x0B -- end (func)
]
-- | Host Function Import module:
hostImportWasm :: ByteString
hostImportWasm =
BS.pack $
map fromIntegral $
wasmHeader
++ [ -- Type section: 2 types (size 12 = 0x0C)
0x01
, 0x0C
, 0x02
, -- Type 0: (i32, i32) -> i32 [host_add]
0x60
, 0x02
, 0x7F
, 0x7F
, 0x01
, 0x7F
, -- Type 1: (i32) -> i32 [host_callback, run_host_calls]
0x60
, 0x01
, 0x7F
, 0x01
, 0x7F
, -- Import section: 2 functions imported from "env" (size 36 = 0x24)
0x02
, 0x24
, 0x02
, -- env.host_add -> type 0
0x03
, 0x65
, 0x6E
, 0x76
, 0x08
, 0x68
, 0x6F
, 0x73
, 0x74
, 0x5F
, 0x61
, 0x64
, 0x64
, 0x00
, 0x00
, -- env.host_callback -> type 1
0x03
, 0x65
, 0x6E
, 0x76
, 0x0D
, 0x68
, 0x6F
, 0x73
, 0x74
, 0x5F
, 0x63
, 0x61
, 0x6C
, 0x6C
, 0x62
, 0x61
, 0x63
, 0x6B
, 0x00
, 0x01
, -- Function section: 1 local function with type 1 (size 2 = 0x02)
0x03
, 0x02
, 0x01
, 0x01
, -- Export section: "run_host_calls" -> func 2 (size 18 = 0x12)
0x07
, 0x12
, 0x01
, 0x0E
, 0x72
, 0x75
, 0x6E
, 0x5F
, 0x68
, 0x6F
, 0x73
, 0x74
, 0x5F
, 0x63
, 0x61
, 0x6C
, 0x6C
, 0x73
, 0x00
, 0x02
, -- Code section: 1 function body (size 38 = 0x26)
0x0A
, 0x26
, 0x01
, -- body size: 36 bytes (0x24)
0x24
, 0x01
, 0x02
, 0x7F -- 2 local i32s: $i (local 1), $acc (local 2)
, 0x03
, 0x40 -- loop
, 0x20
, 0x01 -- local.get $i (1)
, 0x20
, 0x00 -- local.get $count (0)
, 0x48 -- i32.lt_s
, 0x04
, 0x40 -- if
, 0x20
, 0x02 -- local.get $acc (2)
, 0x20
, 0x01 -- local.get $i (1)
, 0x10
, 0x01 -- call $host_callback (func 1)
, 0x10
, 0x00 -- call $host_add (func 0)
, 0x21
, 0x02 -- local.set $acc (2)
, 0x20
, 0x01 -- local.get $i (1)
, 0x41
, 0x01 -- i32.const 1
, 0x6A -- i32.add
, 0x21
, 0x01 -- local.set $i (1)
, 0x0C
, 0x01 -- br 1
, 0x0B -- end (if)
, 0x0B -- end (loop)
, 0x20
, 0x02 -- local.get $acc
, 0x0B -- end (func)
]
-- | Chaos & Fault Injection module:
chaosWasm :: ByteString
chaosWasm =
BS.pack $
map fromIntegral $
wasmHeader
++ [ -- Type section: 2 types (size 9 = 0x09)
0x01
, 0x09
, 0x02
, -- Type 0: () -> () [trap_unreachable, infinite_loop]
0x60
, 0x00
, 0x00
, -- Type 1: (i32) -> i32 [div_by_zero, oob_memory_load]
0x60
, 0x01
, 0x7F
, 0x01
, 0x7F
, -- Function section: 4 functions (size 5 = 0x05)
0x03
, 0x05
, 0x04
, 0x00
, 0x01
, 0x01
, 0x00
, -- Memory section: 1 memory (size 4 = 0x04)
0x05
, 0x04
, 0x01
, 0x01
, 0x01
, 0x01
, -- Export section: 5 exports (size 77 = 0x4D)
0x07
, 0x4D
, 0x05
, -- "memory" -> memory 0
0x06
, 0x6D
, 0x65
, 0x6D
, 0x6F
, 0x72
, 0x79
, 0x02
, 0x00
, -- "trap_unreachable" -> func 0
0x10
, 0x74
, 0x72
, 0x61
, 0x70
, 0x5F
, 0x75
, 0x6E
, 0x72
, 0x65
, 0x61
, 0x63
, 0x68
, 0x61
, 0x62
, 0x6C
, 0x65
, 0x00
, 0x00
, -- "div_by_zero" -> func 1
0x0B
, 0x64
, 0x69
, 0x76
, 0x5F
, 0x62
, 0x79
, 0x5F
, 0x7A
, 0x65
, 0x72
, 0x6F
, 0x00
, 0x01
, -- "oob_memory_load" -> func 2
0x0F
, 0x6F
, 0x6F
, 0x62
, 0x5F
, 0x6D
, 0x65
, 0x6D
, 0x6F
, 0x72
, 0x79
, 0x5F
, 0x6C
, 0x6F
, 0x61
, 0x64
, 0x00
, 0x02
, -- "infinite_loop" -> func 3
0x0D
, 0x69
, 0x6E
, 0x66
, 0x69
, 0x6E
, 0x69
, 0x74
, 0x65
, 0x5F
, 0x6C
, 0x6F
, 0x6F
, 0x70
, 0x00
, 0x03
, -- Code section: 4 functions (size 29 = 0x1D)
0x0A
, 0x1D
, 0x04
, -- Func 0 (trap_unreachable): size 3
0x03
, 0x00
, 0x00
, 0x0B
, -- Func 1 (div_by_zero): size 7
0x07
, 0x00
, 0x20
, 0x00
, 0x41
, 0x00
, 0x6D
, 0x0B
, -- Func 2 (oob_memory_load): size 7
0x07
, 0x00
, 0x20
, 0x00
, 0x28
, 0x02
, 0x00
, 0x0B
, -- Func 3 (infinite_loop): size 7
0x07
, 0x00
, 0x03
, 0x40
, 0x0C
, 0x00
, 0x0B
, 0x0B
]
-- | Bytecode with invalid magic header (tests rejection during validation)
corruptedMagicWasm :: ByteString
corruptedMagicWasm = BS.pack [0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x00, 0x00, 0x00]
-- | Bytecode with truncated / invalid section header
corruptedSectionWasm :: ByteString
corruptedSectionWasm =
BS.pack $
map fromIntegral $
wasmHeader ++ [0x01, 0xFF, 0xFF]
{- | Caller introspection test guest:
Imports "caller_env"."inspect_caller" : (i32) -> i32
Exports "memory" (1 page)
Exports "test_caller" (param i32) (result i32) -> calls inspect_caller
-}
callerGuestWasm :: ByteString
callerGuestWasm =
BS.pack $
map fromIntegral $
wasmHeader
++ [ -- 1. Type section: 1 type: (i32) -> i32
0x01
, 0x06
, 0x01
, 0x60
, 0x01
, 0x7F
, 0x01
, 0x7F
, -- 2. Import section: "caller_env"."inspect_caller" -> type 0
0x02
, 0x1D
, 0x01
, 0x0A
, 0x63
, 0x61
, 0x6C
, 0x6C
, 0x65
, 0x72
, 0x5F
, 0x65
, 0x6E
, 0x76
, 0x0E
, 0x69
, 0x6E
, 0x73
, 0x70
, 0x65
, 0x63
, 0x74
, 0x5F
, 0x63
, 0x61
, 0x6C
, 0x6C
, 0x65
, 0x72
, 0x00
, 0x00
, -- 3. Function section: 1 local function using type 0
0x03
, 0x02
, 0x01
, 0x00
, -- 5. Memory section: 1 memory, min=1 page
0x05
, 0x03
, 0x01
, 0x00
, 0x01
, -- 7. Export section: 2 exports ("memory" -> mem 0, "test_caller" -> func 1)
0x07
, 0x18
, 0x02
, 0x06
, 0x6D
, 0x65
, 0x6D
, 0x6F
, 0x72
, 0x79
, 0x02
, 0x00
, 0x0B
, 0x74
, 0x65
, 0x73
, 0x74
, 0x5F
, 0x63
, 0x61
, 0x6C
, 0x6C
, 0x65
, 0x72
, 0x00
, 0x01
, -- 10. Code section: 1 function body (calls imported inspect_caller)
0x0A
, 0x08
, 0x01
, 0x06
, 0x00
, 0x20
, 0x00
, 0x10
, 0x00
, 0x0B
]