wasmerio/wasmer · error

global #{} is a constant

Error message

global #{} is a constant

What it means

During Wasm-to-Cranelift translation, code_translator handles Operator::GlobalSet. If state.get_global resolves the global index to GlobalVariable::Const, the global is a constant and cannot be assigned, so translation panics. Well-formed Wasm modules mark such globals immutable in their type section, so this usually indicates an invalid or corrupted module.

Source

Thrown at lib/compiler-cranelift/src/translator/code_translator.rs:231

                GlobalVariable::Const(val) => val,
                GlobalVariable::Memory { gv, offset, ty } => {
                    let addr =
                        materialize_global_value(&mut builder.cursor(), environ.pointer_type(), gv);
                    let mut flags = ir::MemFlagsData::trusted();
                    // Put globals in the "table" abstract heap category as well.
                    set_memflags_alias_region(builder.func, &mut flags, MemoryAliasRegion::Table);
                    builder.ins().load(ty, flags, addr, offset)
                }
                GlobalVariable::Custom => environ.translate_custom_global_get(
                    builder.cursor(),
                    GlobalIndex::from_u32(*global_index),
                )?,
            };
            state.push1(val);
        }
        Operator::GlobalSet { global_index } => {
            match state.get_global(builder.func, *global_index, environ)? {
                GlobalVariable::Const(_) => panic!("global #{} is a constant", *global_index),
                GlobalVariable::Memory { gv, offset, ty } => {
                    let addr =
                        materialize_global_value(&mut builder.cursor(), environ.pointer_type(), gv);
                    let mut flags = ir::MemFlagsData::trusted();
                    // Put globals in the "table" abstract heap category as well.
                    set_memflags_alias_region(builder.func, &mut flags, MemoryAliasRegion::Table);
                    let mut val = state.pop1();
                    // Ensure SIMD values are cast to their default Cranelift type, I8x16.
                    if ty.is_vector() {
                        val = optionally_bitcast_vector(val, I8X16, builder);
                    }
                    debug_assert_eq!(ty, builder.func.dfg.value_type(val));
                    builder.ins().store(flags, val, addr, offset);
                }
                GlobalVariable::Custom => {
                    let val = state.pop1();
                    environ.translate_custom_global_set(
                        builder.cursor(),

View on GitHub (pinned to 8c4b9ee9d3)

Solutions

  1. Validate the module before compilation (wasm-validate app.wasm or Wasmer's validation pass) — a valid module can never do this.
  2. Fix the producer toolchain so global.set only targets mutable (0x01 mutability) globals.
  3. Change the global's declared mutability byte in the module if it is genuinely meant to be written.
  4. If you believe the module is valid, report a Wasmer bug with the failing module attached.

Example fix

// before (globals section, byte view)
0x03 0x7F 0x00 0x41 0x00 0x0B  // global #3, i32, MUTABLE=0x00
// after
0x03 0x7F 0x01 0x41 0x00 0x0B  // global #3, i32, MUTABLE=0x01 (writable)
Defensive patterns

Strategy: validation

Validate before calling

// Validate modules before compiling; a valid module can never hit this:
$ wasm-validate app.wasm   # or via the wasm-tools/wasmparser validator in-pipeline

Try / catch

// Wrap compilation of untrusted modules
let result = std::panic::catch_unwind(|| compiler.compile(module, environ));
match result {
    Ok(r) => r,
    Err(_) => return Err(CompileError::InvalidModule("global.set on const global")),
}

Prevention

When it happens

Trigger: Translating a function body (via parse_function_body → translate_operator) containing global.set whose index refers to a global recorded as Const — i.e. writing to an immutable global, typically from a module that bypassed validation or from a get_global/state tracking bug.

Common situations: Feeding hand-crafted or fuzzed Wasm binaries that skip the validator; toolchain bugs emitting global.set to immutable globals; old/hand-patched modules where the global's mutability flag disagrees with actual writes.

Related errors


AI-assisted analysis of wasmerio/wasmer@8c4b9ee9d3 (2026-09-01). Data as JSON: /api/errors/0b2131b2d90a4062. Report an issue: GitHub.