Skip to content

Conversation

@stevenfontanella
Copy link
Member

@stevenfontanella stevenfontanella commented Dec 3, 2025

  • At instantiation time, check the types of exports against their corresponding imports, and trap if they don't match.
    • Exported memories and tables must be a subtype of the corresponding import.
    • Function types aren't checked yet because we don't have a way to check the exact type of function re-exports; i.e. exact-func-imports.wast would fail to instantiate on line 85.
  • Copy exact-func-import.wast from the testsuite repo, which now passes.
  • Fix ref_func.wast and tags.wast which also otherwise fail with the new validations.
  • Fix getMemoryInstanceInfo to follow import chains rather than just one import.
  • Also fix getMemorySize to read the runtime page size from imports when applicable. This is necessary to keep track of page sizes correctly when we import a memory that's later grown e.g. in test/spec/imports.wast.
  • Fixes imports0, imports2, linking0, linking3 and partially fixes imports, imports3 and memory64.

As followups, we should improve the handling of the "spectest" module by implementing the implicit definition described by the spec, and we should add tracking for exact types of function re-exports so that we can enable import-time type checking for function types.

@stevenfontanella stevenfontanella changed the base branch from main to multithread December 4, 2025 00:39
@stevenfontanella stevenfontanella force-pushed the import-validation branch 2 times, most recently from 3920f0c to 766d753 Compare December 5, 2025 00:16
Base automatically changed from multithread to main December 5, 2025 21:10
@stevenfontanella stevenfontanella force-pushed the import-validation branch 6 times, most recently from 1f212af to 1368f6a Compare December 10, 2025 02:52
@stevenfontanella stevenfontanella marked this pull request as ready for review December 12, 2025 23:35
@stevenfontanella
Copy link
Member Author

Will run this through the fuzzer as well before merging

trap((std::stringstream()
<< "importGlobals: unknown import: " << import->module.str << "."
<< import->name.str)
.str());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not know about this nice pattern for stringstream 😄


virtual void trap(const char* why) { WASM_UNREACHABLE("unimp"); }

virtual void trap(std::string_view why) { WASM_UNREACHABLE("unimp"); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need two trap forms? This does not need to be fast. How about making them both std::string?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we remove the const char* overload then we'd need to change it in a few other places that override it e.g. in ConstantExpressionRunner link, so for this PR I was just going to introduce the "better" overload without removing the old one right away. I mostly just want to avoid C-strings and I think string_view is the best parameter as long as we're changing it. I'll move this to a new PR instead.

src/wasm.h Outdated
return true;
}

bool isSubType(const Table& other) { return Table::isSubType(*this, other); }
Copy link
Member

@kripken kripken Dec 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to put logic like this in ir/, so that we can keep wasm.h shorter. This might fit in memory-utils.h, table-utils.h etc?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we split out the Memory class to its own file in that case? I'm thinking it's good to avoid too many free functions especially since we have to differentiate them by name e.g. MemoryIsSubType, TableIsSubType, etc. The memory class seems like the right place to keep this function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see where you're coming from, but it would be a large change in our style.

Our current approach is that the core IR is in very simple classes, all in wasm.h. We do have methods on those classes, but just very basic things that are useful universally. And we make an effort to split out things that are useful in more narrow contexts, to ir/*-utils.h and other helpers.

So concretely, we already have e.g. MemoryUtils::flatten(), and I think we can add MemoryUtils::isSubType() alongside that?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, and to explain the current style, the main motivation is to keep wasm.h small, and other headers that are used universally. That makes it easier to read wasm.h etc. and get a general idea of the shape of things, and also helps compile times.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks for the explanation! Moved them to the utils headers.

Base automatically changed from ctor-import to main December 14, 2025 02:48
stevenfontanella added a commit that referenced this pull request Dec 14, 2025
ctor-eval doesn't have access to imports and previously didn't have any
special handling for this. Globals would fail to
import (https://github.com/WebAssembly/binaryen/blob/main/src/tools/wasm-ctor-eval.cpp#L247),
which would prevent further
evaluation (https://github.com/WebAssembly/binaryen/blob/main/src/tools/wasm-ctor-eval.cpp#L1451).
This is why global-get-init.wast didn't optimize away even though it
does nothing.

We already stubbed out imports to "env". Change the code to create a
stub module for all modules named in imports, so that instantiation is
valid and evaluation can continue. This also unblocks #8086 which checks
imports and requires them to exist during instantiation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants