-
Notifications
You must be signed in to change notification settings - Fork 747
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Wasm GC] Ignore unreachable sets for purposes of non-nullable locals #5665
Conversation
It turns out this is tricky. If we land this PR, then any pass that does a refinalize will need to fix up non-nullable locals, beceause refinalization can propagate unreachability - and with this PR, unreachability affects non-nullable local validation. In practice , that means adding non-nullable fixups to 24 more passes (!) (all those that don't do it now, but do perform a refinalize). That's so many passes that probably we would want to just constantly run non-nullable fixups after every pass and not bother with |
Another workaround would be to treat these local.sets specially in the binary writer and emit them even though we otherwise wouldn't. Another fix would be in the spec/v8, where we could consider all locals to be initialized in unreachable code. |
Filed WebAssembly/function-references#98 to discuss a spec change. |
Unfortunately, I found this wouldn't be simple, as atm we stop at the first block etc. child that is unreachable. So to do this, we'd need to continue onward to check for sets, which would add complexity and overhead. |
What about the solution of continuing to skip emitting things even beyond the end of blocks, as long as those blocks are unnamed? |
That doesn't seem simple. It would affect multiple functions, as e.g. Lines 237 to 241 in 5679e3b
It might be worth trying though, I'm just saying it's not obvious to me that it will work or work easily. (OTOH, just running non-nullable local fixups, or just running dce before binary emitting, would definitely work and be very simple - but slow us down.) |
This would all be much easier if we could separate iteration from other logic using generators built on C++20 coroutines :'( |
I had the idea to notice in ReFinalize when we turn a set unreachable. That is rare, so doing more work in that case would be fine. And it's a change in one place (ReFinalize) and not in multiple passes. That works ok (with some fallout in (module
(func $2
(local $3 (ref array))
(drop
(block (result nullref)
(unreachable)
(local.set $3
(ref.as_non_null
(ref.null none)
)
)
(ref.null none)
)
)
(drop
(local.get $3)
)
)
) That won't validate in v8 but it does work in Binaryen. Noticing that in ReFinalize is not simple and would, I think, add overhead (we'd need to track when we turn any child of anything unreachable, and see if there's a set after it). |
DCE at the end avoids issues with non-nullable local operations in unreachable code, which is still being discussed. This PR avoids fuzzer errors for now, but we should revert it when we have a proper fix. See * #5599 * #5665 * WebAssembly/function-references#98
As of #5677 we have a fuzzer workaround here, and nothing else seems urgent. Closing, and we'll see how the spec and other discussions go around this topic. |
See #5665 #5599, this is an existing issue and we have a workaround for it using --dce, but it does not always work. I seem to be seeing this in higher frequency since landing recent fuzzer improvements, so ignore it. There is some risk of us missing real bugs here (that we validate and V8 does not), but this is a validation error which is not as serious as a difference in behavior. And this is a long-standing issue that hasn't bitten us yet.
DCE at the end avoids issues with non-nullable local operations in unreachable code, which is still being discussed. This PR avoids fuzzer errors for now, but we should revert it when we have a proper fix. See * WebAssembly#5599 * WebAssembly#5665 * WebAssembly/function-references#98
…Assembly#6337) See WebAssembly#5665 WebAssembly#5599, this is an existing issue and we have a workaround for it using --dce, but it does not always work. I seem to be seeing this in higher frequency since landing recent fuzzer improvements, so ignore it. There is some risk of us missing real bugs here (that we validate and V8 does not), but this is a validation error which is not as serious as a difference in behavior. And this is a long-standing issue that hasn't bitten us yet.
As pointed out by @tlively in #5599, we don't emit unreachable code in the binary
format, which means such sets can't help gets validate.
Fixes #5599