2929#define wasm_wasm_interpreter_h
3030
3131#include < cmath>
32+ #include < iomanip>
3233#include < limits.h>
3334#include < sstream>
3435#include < variant>
@@ -86,7 +87,7 @@ class Flow {
8687 }
8788
8889 Literals values;
89- Name breakTo; // if non-null, a break is going on
90+ Name breakTo; // if non-null, a break is going on
9091 Tag* suspendTag = nullptr ; // if non-null, breakTo must be SUSPEND_FLOW, and
9192 // this is the tag being suspended
9293
@@ -2658,6 +2659,8 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
26582659
26592660 virtual void trap (const char * why) { WASM_UNREACHABLE (" unimp" ); }
26602661
2662+ virtual void trap (std::string_view why) { WASM_UNREACHABLE (" unimp" ); }
2663+
26612664 virtual void hostLimit (const char * why) { WASM_UNREACHABLE (" unimp" ); }
26622665
26632666 virtual void throwException (const WasmException& exn) {
@@ -2937,6 +2940,7 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
29372940 Index oldSize,
29382941 Index newSize) = 0;
29392942 virtual void trap (const char * why) = 0;
2943+ virtual void trap (std::string_view why) { trap (std::string (why).c_str ()); }
29402944 virtual void hostLimit (const char * why) = 0;
29412945 virtual void throwException (const WasmException& exn) = 0;
29422946 // Get the Tag instance for a tag implemented in the host, that is, not
@@ -3178,6 +3182,8 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
31783182 // initialize the rest of the external interface
31793183 externalInterface->init (wasm, *self ());
31803184
3185+ validateImports ();
3186+
31813187 initializeTableContents ();
31823188 initializeMemoryContents ();
31833189
@@ -3269,6 +3275,76 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
32693275 Name name;
32703276 };
32713277
3278+ void validateImportKindMatches (ExternalKind kind,
3279+ const Importable& importable) {
3280+ auto it = linkedInstances.find (importable.module );
3281+ if (it == linkedInstances.end ()) {
3282+ trap ((std::stringstream ()
3283+ << " Import module " << std::quoted (importable.module .toString ())
3284+ << " doesn't exist." )
3285+ .str ());
3286+ }
3287+ SubType* importedInstance = it->second .get ();
3288+
3289+ Export* export_ = importedInstance->wasm .getExportOrNull (importable.base );
3290+
3291+ if (!export_) {
3292+ trap ((std::stringstream ()
3293+ << " Export " << importable.base << " doesn't exist." )
3294+ .str ());
3295+ }
3296+ if (export_->kind != kind) {
3297+ trap (" Exported kind doesn't match" );
3298+ }
3299+ }
3300+
3301+ // Trap if types don't match between all imports and their corresponding
3302+ // exports. Imported memories and tables must also be a subtype of their
3303+ // export.
3304+ void validateImports () {
3305+ ModuleUtils::iterImportable (
3306+ wasm,
3307+ [this ](ExternalKind kind,
3308+ std::variant<Function*, Memory*, Tag*, Global*, Table*> import ) {
3309+ Importable* importable = std::visit (
3310+ [](const auto & import ) -> Importable* { return import ; }, import );
3311+
3312+ // These two modules are injected implicitly to tests. We won't find any
3313+ // import information for them.
3314+ if ((importable->module == " spectest" &&
3315+ importable->base .startsWith (" print" )) ||
3316+ importable->module == " fuzzing-support" ) {
3317+ return ;
3318+ }
3319+
3320+ validateImportKindMatches (kind, *importable);
3321+
3322+ SubType* importedInstance =
3323+ linkedInstances.at (importable->module ).get ();
3324+ Export* export_ =
3325+ importedInstance->wasm .getExportOrNull (importable->base );
3326+
3327+ if (auto ** memory = std::get_if<Memory*>(&import )) {
3328+ Memory exportedMemory =
3329+ *importedInstance->wasm .getMemory (*export_->getInternalName ());
3330+ exportedMemory.initial =
3331+ importedInstance->getMemorySize (*export_->getInternalName ());
3332+
3333+ if (!exportedMemory.isSubType (**memory)) {
3334+ trap (" Imported memory isn't compatible." );
3335+ }
3336+ }
3337+
3338+ if (auto ** table = std::get_if<Table*>(&import )) {
3339+ Table* exportedTable =
3340+ importedInstance->wasm .getTable (*export_->getInternalName ());
3341+ if (!(*table)->isSubType (*exportedTable)) {
3342+ trap (" Imported table isn't compatible" );
3343+ }
3344+ }
3345+ });
3346+ }
3347+
32723348 TableInstanceInfo getTableInstanceInfo (Name name) {
32733349 auto * table = wasm.getTable (name);
32743350 if (table->imported ()) {
@@ -3326,12 +3402,16 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
33263402 };
33273403
33283404 MemoryInstanceInfo getMemoryInstanceInfo (Name name) {
3329- auto * memory = wasm.getMemory (name);
3330- if (memory->imported ()) {
3331- auto & importedInstance = linkedInstances.at (memory->module );
3332- auto * memoryExport = importedInstance->wasm .getExport (memory->base );
3333- return importedInstance->getMemoryInstanceInfo (
3334- *memoryExport->getInternalName ());
3405+ auto * instance = self ();
3406+ Export* memoryExport = nullptr ;
3407+ for (auto * memory = instance->wasm .getMemory (name); memory->imported ();
3408+ memory = instance->wasm .getMemory (*memoryExport->getInternalName ())) {
3409+ instance = instance->linkedInstances .at (memory->module ).get ();
3410+ memoryExport = instance->wasm .getExport (memory->base );
3411+ }
3412+
3413+ if (memoryExport) {
3414+ return instance->getMemoryInstanceInfo (*memoryExport->getInternalName ());
33353415 }
33363416
33373417 return MemoryInstanceInfo{self (), name};
@@ -3385,6 +3465,11 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
33853465 }
33863466
33873467 Address getMemorySize (Name memory) {
3468+ auto info = getMemoryInstanceInfo (memory);
3469+ if (info.instance != self ()) {
3470+ return info.instance ->getMemorySize (info.name );
3471+ }
3472+
33883473 auto iter = memorySizes.find (memory);
33893474 if (iter == memorySizes.end ()) {
33903475 externalInterface->trap (" getMemorySize called on non-existing memory" );
@@ -3397,7 +3482,7 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
33973482 if (iter == memorySizes.end ()) {
33983483 externalInterface->trap (" setMemorySize called on non-existing memory" );
33993484 }
3400- memorySizes[memory] = size;
3485+ iter-> second = size;
34013486 }
34023487
34033488public:
@@ -4682,12 +4767,14 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
46824767 }
46834768 Flow visitStackSwitch (StackSwitch* curr) { return Flow (NONCONSTANT_FLOW); }
46844769
4685- void trap (const char * why) override {
4770+ void trap (std::string_view why) override {
46864771 // Traps break all current continuations - they will never be resumable.
46874772 self ()->clearContinuationStore ();
46884773 externalInterface->trap (why);
46894774 }
46904775
4776+ void trap (const char * why) override { trap (std::string_view (why)); }
4777+
46914778 void hostLimit (const char * why) override {
46924779 self ()->clearContinuationStore ();
46934780 externalInterface->hostLimit (why);
0 commit comments