{"record":{"id":"05b7b62d15cca39f","repo":"wasmerio/wasmer","slug":"cannot-write-non-scalar-value-as-bytes","errorCode":null,"errorMessage":"Cannot write non-scalar value as bytes","messagePattern":"Cannot write non-scalar value as bytes","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/wasix/src/syscalls/wasix/call_dynamic.rs","lineNumber":33,"sourceCode":"        }\n    }};\n}\n\nfn write_value(\n    memory: &MemoryView,\n    offset: &mut u64,\n    max: u64,\n    strict: bool,\n    value: &Value,\n) -> Result<bool, MemoryAccessError> {\n    match value {\n        Value::I32(value) => write_value!(memory, *offset, max, strict, value),\n        Value::I64(value) => write_value!(memory, *offset, max, strict, value),\n        Value::F32(value) => write_value!(memory, *offset, max, strict, value),\n        Value::F64(value) => write_value!(memory, *offset, max, strict, value),\n        Value::V128(value) => write_value!(memory, *offset, max, strict, value),\n        // ExternRef, FuncRef, and ExceptionRef cannot be represented as byte slices\n        _ => panic!(\"Cannot write non-scalar value as bytes\"),\n    }\n}\n\nmacro_rules! read_value {\n    ($memory:expr, $offset:expr, $max:expr, $strict:expr, $ty:ident, $val:ident, $len:expr) => {{\n        if $offset + $len > $max {\n            Ok(if $strict {\n                None\n            } else {\n                Some(Value::$val($ty::default()))\n            })\n        } else {\n            let mut buffer = [0u8; $len];\n            $memory.read($offset, &mut buffer)?;\n            $offset += $len;\n            Ok(Some(Value::$val($ty::from_le_bytes(buffer))))\n        }\n    }};","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/wasmerio/wasmer/blob/8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5/lib/wasix/src/syscalls/wasix/call_dynamic.rs#L15-L51","documentation":"`write_value` in the `__main__`-style dynamic closure call syscall (`call_dynamic`) serializes `Value`s into linear memory as raw bytes. Only scalar types (i32/i64/f32/f64/v128) have byte representations; ExternRef, FuncRef, and ExceptionRef values cannot be written as byte slices, so the code panics instead of writing garbage.","triggerScenarios":"Calling a function via `call_dynamic` (indirect `__indirect_function_table` invocation) whose parameters include a reference type (externref/funcref/exceptionref), with argument values supplied from memory or host code.","commonSituations":"Dynamically calling WASIX closure functions from modules that use the reference-types proposal; host code building argument buffers for dynamic calls with non-scalar signatures; ABI mismatches where a table slot's function type contains refs but the caller assumes scalars.","solutions":["Restrict dynamically called functions to scalar-only signatures (i32/i64/f32/f64/v128) — wrap ref-taking functions with a scalar adapter","Pass references through a side table (index as i32) instead of embedding them in the dynamic call's memory arguments","Validate the target function's type against scalar-only types before invoking `call_dynamic`","If refs are required, use direct (non-dynamic) Wasm invocation through the linker where references are supported"],"exampleFix":"// before: dynamic call with a funcref arg\nargs.push(Value::FuncRef(Some(funcref)));\nwrite_value(memory, &mut off, max, strict, &Value::FuncRef(...)); // panics\n// after: pass an index into a side table\nargs.push(Value::I32(funcrev_index as i32));\nwrite_value(memory, &mut off, max, strict, &Value::I32(funcrev_index as i32));","handlingStrategy":"validation","validationCode":"// Reject non-scalar argument values before the dynamic call\nif !args.iter().all(|v| matches!(v,\n    Value::I32(_) | Value::I64(_) | Value::F32(_) | Value::F64(_) | Value::V128(_)))\n{\n    return Err(Errno::Notsup);\n}","typeGuard":"fn is_scalar_value(v: &Value) -> bool {\n    matches!(v, Value::I32(_) | Value::I64(_) | Value::F32(_) | Value::F64(_) | Value::V128(_))\n}","tryCatchPattern":"let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| write_value(memory, &mut off, max, strict, &value)));\nif result.is_err() { /* handle non-scalar arg: use side-table handle instead */ }","preventionTips":["Only dynamic-call functions with scalar-only signatures","Pass references as i32 side-table handles","Validate the callee's type against scalars before call_dynamic","Keep closure descriptors generated from sanitized function types"],"tags":["wasix","syscalls","reference-types","memory","unsupported-feature"],"backgroundTag":"non-scalar-value-unsupported","analyzedSha":"8c4b9ee9d33fb2068863fbb3d328683e7e6ff7f5","analyzedAt":"2026-09-01T23:06:31.009Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}