-
Notifications
You must be signed in to change notification settings - Fork 816
[Exceptions] Fix cross-module Tag handling in interpreter #7955
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
Conversation
src/wasm-interpreter.h
Outdated
virtual void throwException(const WasmException& exn) = 0; | ||
// Get the Tag instance for a tag implemented in the host, that is, not | ||
// among the linked ModuleRunner instances. | ||
virtual Tag* getHostTag(Name name) { WASM_UNREACHABLE("missing host tag"); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this be a general getImportedTag
? Host tags shouldn't be special for any reason and it would be best to be consistent in how we handle imports. Specifically, we should follow the same patterns for getImportedFunction
and whatever we do for tags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(And btw we should also follow the same shared pattern for tables and memories as well.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have these special host tags in the fuzzer, which we don't for functions - so this pattern is very convenient here, but maybe not for functions.
Perhaps this could be refactored to make these host tags come from a special internal module, I considered that but it was a lot more work, and I wasn't sure it would lead to benefits.
I do agree it makes sense to unify this, but I'm not sure which way, so I'd like to leave that for later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have lots of host functions in the fuzzer as well, but we treat them as normal imports by wrapping the custom functionality in the FuncData's std::function. Tags wouldn't need that last part, since only their identity matters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, we handle tags differently by having an instance of them (which we can take the address of), unlike those functions. It's possible to handle it otherwise but it would be a lot more work I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think concretely the changes I would want to see here is to rename this function to getImportedTag
and to add a ModuleRunnerBase::getExportedTag
function that calls externalInterface->getImportedTag(tag)
on imported tags. That would replace the while
loop in getCanonicalTag
to track down the definition of imported tags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I tried to do that in the last two commits, PTAL
- I thought you meant to generate an internal module etc. - that would be a lot more work, obviously.
- But I don't quite think I follow you, as the loop in
getCanonicalTag
is still necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If getCanonicalTag
calls out to the ExternalInterface to retrieve imported tags, then in multi-instance scenarios that ExternalInterface will look up the instance providing the import and call getExportedTag
on it (which might in turn call externalInterface->getImportedTag
again if it is a re-exported tag). So the loop is replaced with a recursion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh right, the loop isn't needed. Done.
src/tools/execution-results.h
Outdated
if (tag->module == "fuzzing-support") { | ||
if (tag->base == "wasmtag") { | ||
wasmTag = tag->name; | ||
wasmTag.name = tag->name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this renaming of tags still necessary? It seems like it is probably a vestige of using names to identify tags, and isn't something I would expect to be necessary. In general an external interface should not be modifying the module it is providing an environment to.
Edit: Ah, this shouldn't be necessary after the other comment is addressed.
src/wasm-interpreter.h
Outdated
} | ||
auto* tag = wasm.getTag(*export_->getInternalName()); | ||
if (tag->imported()) { | ||
tag = externalInterface->getImportedTag(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should pass the tag
rather than the name
so that the external interface can inspect the module
and base
import names to resolve the import. The external interface should never need to look at an internal name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh nice, yes, that is cleaner. Done.
jsTag = tag->name; | ||
} | ||
// Set up tags. (Setting these values is useful for debugging - making the | ||
// Tag objects valid - and also appears in fuzz-exec logging.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should also need to set the type of the tags to make them valid. Hopefully the fuzzer can find that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added, can't hurt for debugging. I'm not sure if we notice these atm enough for the fuzzer to.
src/wasm-interpreter.h
Outdated
throwException(WasmException{ | ||
self()->makeExnData(self()->getModule()->getTag(curr->tag), arguments)}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably return a NONCONSTANT_FLOW when the tag is imported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, done.
src/wasm-interpreter.h
Outdated
virtual Tag* getImportedTag(Tag* tag) { | ||
WASM_UNREACHABLE("missing imported tag"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason not to make this pure virtual like getImportedFunction
? Should getImportedFunction
also have an unreachable default implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's just that there are a bunch of cases that want the default impl for tags, and for functions we implement it anyhow. But I guess consistency matters more, I made it pure virtual.
Make ExnData store a
Tag*
, allowing proper identification.Like FuncData etc., move that logic into the interpreter.