Stream: git-wasmtime

Topic: wasmtime / issue #13865 Debugger breakpoints leak into co...


view this post on Zulip Wasmtime GitHub notifications bot (Jul 11 2026 at 13:51):

Aristide021 opened issue #13865:

Test Case

Attached: demo.wasm plus its source:

wasmtime-cache-bug-repro.zip

// demo.rs
fn add(a: i32, b: i32) -> i32 {
    let c = a + b;
    c
}

fn main() {
    println!("{}", add(3, 4));
}

Steps to Reproduce

Step 1: rm -rf ~/Library/Caches/BytecodeAlliance.wasmtime (Linux: ~/.cache/wasmtime) so the cache is cold

Step 2: Debug the module under lldb with one breakpoint, the initial run compiles the module and populates the cache.

lldb --batch \
 -o "settings set plugin.jit-loader.gdb.enable on" \
 -o "breakpoint set --file demo.rs --line 2" \
 -o run \
 -o continue \
 -- wasmtime run -D debug-info -O opt-level=0 demo.wasm

then echo $?

Step 3: Run the module again without debugger

wasmtime run -D debug-info -O opt-level=0 demo.wasm

then echo $?

Expected Results

Both runs print 7 and exit 0.

Actual Results

The debugged run itself behaves normally, the breakpoint hits and the program works. But the next run of the module, with no debugger attached, is killed by SIGTRAP with no output (macOS: exit 133; Linux: Trace/breakpoint trap). Every run after that fails the same way until the cache is cleared, after which the same command prints 7 again.

Debugging against a warm cache does not corrupt it; the corruption only happens when the debugged process is the one that compiles the module and writes the cache entry.

Versions and Environment

Wasmtime version or commit: 46.0.1 (also reproduced on 45.0.0)

Operating system: MacOS 26.5.2 and Linux (Debian trixie); LLDB 17 (Xcode) and LLDB 19 (Debian)

Architecture: aarch64 (both)

Extra Info

What I checked while root-causing this:

The mechanism appears to be in CodeBuilder::compile_cached (crates/wasmtime/src/compile/runtime.rs): the compute closure publishes the mmap (which triggers GDB-JIT registration, at which point the debugger writes its breakpoints into the mapping) and the serialize closure then reads code.mmap().to_vec() from that same mapping. I'd propose serializing from a copy captured before publish_mmap, unless you'd prefer a different approach.

Workaround until then: -C cache=n while debugging, plus clearing the cache once if already affected.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 11 2026 at 13:51):

Aristide021 added the bug label to Issue #13865.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 13 2026 at 14:06):

alexcrichton added the wasmtime:debugging label to Issue #13865.

view this post on Zulip Wasmtime GitHub notifications bot (Jul 13 2026 at 14:08):

alexcrichton commented on issue #13865:

Not something I would have expected, but thanks for filing an issue here! I agree that this seems like we're seeing the debugger's modifications of program code and accidentally serializing that out, and I'd also agree that the best fix here is to publish after we create the cache entry rather than beforehand like happens now. In theory "just" some refactoring around here, although it'll likely end up being a bit more complicated, too.


Last updated: Jul 29 2026 at 05:03 UTC