fitzgen assigned fitzgen to issue #13216.
fitzgen opened issue #13216:
Blockers for enabling Wasm GC by default:
- [ ] https://github.com/bytecodealliance/wasmtime/pull/13107
- [ ] https://github.com/bytecodealliance/wasmtime/issues/10327
- [ ] I want to investigate our current code coverage and unit tests for Wasm GC (separately from / in addition to our fuzzing story here)
fitzgen added the wasm-proposal:gc label to Issue #13216.
fitzgen edited issue #13216:
Blockers for enabling Wasm GC by default:
- [ ] https://github.com/bytecodealliance/wasmtime/pull/13107
- [ ] https://github.com/bytecodealliance/wasmtime/issues/10327
- [ ] https://github.com/bytecodealliance/wasmtime/issues/10596
- [ ] I want to investigate our current code coverage and unit tests for Wasm GC (separately from / in addition to our fuzzing story here)
fitzgen edited issue #13216:
Blockers for enabling Wasm GC by default:
- [ ] https://github.com/bytecodealliance/wasmtime/pull/13107
- [ ] https://github.com/bytecodealliance/wasmtime/issues/10327
- [ ] https://github.com/bytecodealliance/wasmtime/issues/10596
- [ ] I want to investigate our current code coverage and unit tests for Wasm GC (separately from / in addition to our fuzzing story here)
- [ ] Enable the copying collector by default
alexcrichton commented on issue #13216:
One other open question I've been thinking: the design of Wasmtime's GC is such that the GC itself is more sandboxed than relying on raw
malloc, for example, but in practice the net effect of the implementation is that this downgrades the severity of a heap corruption bug from a "critical maybe RCE CVE" to a "moderate DoS CVE". That seems like a net win no matter what, but it still means that heap corruption bugs are a CVE just like before.The open question here that I think would be worth considering is: should we go a step further? For example all heap indexing operations right now are panic-y throughout the implementation. Like with component-model-async, should those all use a
bail_bug!lookalike thing? Panic-in-debug-mode but return-error-in-release-mode for example.My thinking here is that if do truly want to plan for heap corruption bugs to be routine enough that we don't want to assign a CVE to all of them we probably need to go the whole distance of closing this off as a CVE vector (as best we can at least).
alexcrichton edited a comment on issue #13216:
One other open question I've been thinking: the design of Wasmtime's GC is such that the GC itself is more sandboxed than relying on raw
malloc, for example, but in practice the net effect of the implementation is that this downgrades the severity of a heap corruption bug from a "critical maybe RCE CVE" to a "moderate DoS CVE". That seems like a net win no matter what, but it still means that heap corruption bugs are a CVE just like before.The open question here that I think would be worth considering is: should we go a step further? For example all heap indexing operations right now are panic-y throughout the implementation. Like with component-model-async, should those all use a
bail_bug!lookalike thing? Panic-in-debug-mode but return-error-in-release-mode for example.My thinking here is that if we do truly want to plan for heap corruption bugs to be routine enough that we don't want to assign a CVE to all of them we probably need to go the whole distance of closing this off as a CVE vector (as best we can at least).
fitzgen commented on issue #13216:
if we do truly want to plan for heap corruption bugs to be routine
Routinely having heap corruption bugs is most definitely not the plan. (Not that bugs are ever the plan, but still.)
My gut reaction is that doing the
bail_bug!thing for the GC would be fairly invasive, likely harm performance, and might not be as effective here as it is for CM async:
We are often accessing the GC heap in code that is logically infallible (e.g. tracing GC edges). Therefore (a) we don't already have a
Resultreturn type that we can smuggle these internal errors into and (b) the only time we would ever return an error would be a programming logic bug, which feels pretty unidiomatic.Adding additional return paths to all collector code will likely harm performance. Those methods that don't return
Resulttoday are also often the very hottest methods (tracing GC edges). We're already struggling to get good performance in the face of the GC heap's sandboxed design, and I would be very reluctant to give ourselves another handicap.It may not be as effective because so much more of the GC implementation is inside JIT code and involves fundamentally unsafe inlined accesses to vmctx fields (inline allocation, barriers, etc). It is not just a bunch of runtime methods that can play nice with
Resultreturns and can use functions to abstract/encapsulate unsafe things while LLVM still inlines everything.The only way to really address these points at the same time, AFAICT, is to self-host the whole collector in Wasm. But we've already talked about how we don't want that on the critical path for shipping Wasm GC.
alexcrichton commented on issue #13216:
On one hand I do agree that we of course aren't planning to have bugs, but on the other hand I feel like history shows that we have consistently had bugs and peer engines also are generally known to have routine bugs/issues related to GC things. Part of the assumption of the sandboxed design is effectively assuming that these bugs will exist, and personally I feel that we should do our best to see that all the way through and strive to completely close off a class of CVEs.
I agree that GC code is largely infallible and additionally that this will harm performance. That was also true of component-model-async, however. There are methods that now return a
Resultpurely for "we got states mixed up" and all the host code is certainly slowed down by returning aResulteverywhere. I feel that the performance critical parts of GC (e.g. collection/sweeping/allocation) all have a solid path to become as-fast-as-possible through self-hosted wasm as well.I also don't quite agree that it'll be less effective than component-model-async. Even with component-model-async there are still paths that panic to become a DoS, for example. In component-model-async there's also quite a lot of trampolines to manage and interactions with
unsafecode. Despite all this, however, I think it was very much the right decision to move tobail_bug!instead of panicking. I agree it's not the most idiomatic, but it's so much easier to review code and not have to try to review all.unwrap()operations for "ok but can this actually panic?". It doesn't mean we're 100% secure from bugs but this is always about defense in depth layers. In other words I don't think the existence of complicated JIT code and GC impl code should dissuade us from making the rest of the system have more defense layers. If anything we should be focusing more on the code we can't add another layer to, and right now that's not the most feasible as it's considered equivalent to everything else.I'm also happy to talk this over in a meeting some more, but personally I feel that we have a pretty compelling case to removing panics here. I feel that the stars are aligned in basically the same manner as component-model-async where I feel it's been quite successful at downgrading would-be-CVEs to "just a bug".
Last updated: May 03 2026 at 22:13 UTC