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,77 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
32693275 Name name;
32703276 };
32713277
3278+ // Trap if the importable's export's kind doesn't match `kind`.
3279+ void validateImportKindMatches (ExternalKind kind,
3280+ const Importable& importable) {
3281+ auto it = linkedInstances.find (importable.module );
3282+ if (it == linkedInstances.end ()) {
3283+ trap ((std::stringstream ()
3284+ << " Import module " << std::quoted (importable.module .toString ())
3285+ << " doesn't exist." )
3286+ .str ());
3287+ }
3288+ SubType* importedInstance = it->second .get ();
3289+
3290+ Export* export_ = importedInstance->wasm .getExportOrNull (importable.base );
3291+
3292+ if (!export_) {
3293+ trap ((std::stringstream ()
3294+ << " Export " << importable.base << " doesn't exist." )
3295+ .str ());
3296+ }
3297+ if (export_->kind != kind) {
3298+ trap (" Exported kind doesn't match" );
3299+ }
3300+ }
3301+
3302+ // Trap if types don't match between all imports and their corresponding
3303+ // exports. Imported memories and tables must also be a subtype of their
3304+ // export.
3305+ void validateImports () {
3306+ ModuleUtils::iterImportable (
3307+ wasm,
3308+ [this ](ExternalKind kind,
3309+ std::variant<Function*, Memory*, Tag*, Global*, Table*> import ) {
3310+ Importable* importable = std::visit (
3311+ [](const auto & import ) -> Importable* { return import ; }, import );
3312+
3313+ // These two modules are injected implicitly to tests. We won't find any
3314+ // import information for them.
3315+ if ((importable->module == " spectest" &&
3316+ importable->base .startsWith (" print" )) ||
3317+ importable->module == " fuzzing-support" ) {
3318+ return ;
3319+ }
3320+
3321+ validateImportKindMatches (kind, *importable);
3322+
3323+ SubType* importedInstance =
3324+ linkedInstances.at (importable->module ).get ();
3325+ Export* export_ =
3326+ importedInstance->wasm .getExportOrNull (importable->base );
3327+
3328+ if (auto ** memory = std::get_if<Memory*>(&import )) {
3329+ Memory exportedMemory =
3330+ *importedInstance->wasm .getMemory (*export_->getInternalName ());
3331+ exportedMemory.initial =
3332+ importedInstance->getMemorySize (*export_->getInternalName ());
3333+
3334+ if (!exportedMemory.isSubType (**memory)) {
3335+ trap (" Imported memory isn't compatible." );
3336+ }
3337+ }
3338+
3339+ if (auto ** table = std::get_if<Table*>(&import )) {
3340+ Table* exportedTable =
3341+ importedInstance->wasm .getTable (*export_->getInternalName ());
3342+ if (!(*table)->isSubType (*exportedTable)) {
3343+ trap (" Imported table isn't compatible" );
3344+ }
3345+ }
3346+ });
3347+ }
3348+
32723349 TableInstanceInfo getTableInstanceInfo (Name name) {
32733350 auto * table = wasm.getTable (name);
32743351 if (table->imported ()) {
@@ -3326,12 +3403,16 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
33263403 };
33273404
33283405 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 ());
3406+ auto * instance = self ();
3407+ Export* memoryExport = nullptr ;
3408+ for (auto * memory = instance->wasm .getMemory (name); memory->imported ();
3409+ memory = instance->wasm .getMemory (*memoryExport->getInternalName ())) {
3410+ instance = instance->linkedInstances .at (memory->module ).get ();
3411+ memoryExport = instance->wasm .getExport (memory->base );
3412+ }
3413+
3414+ if (memoryExport) {
3415+ return instance->getMemoryInstanceInfo (*memoryExport->getInternalName ());
33353416 }
33363417
33373418 return MemoryInstanceInfo{self (), name};
@@ -3385,6 +3466,11 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
33853466 }
33863467
33873468 Address getMemorySize (Name memory) {
3469+ auto info = getMemoryInstanceInfo (memory);
3470+ if (info.instance != self ()) {
3471+ return info.instance ->getMemorySize (info.name );
3472+ }
3473+
33883474 auto iter = memorySizes.find (memory);
33893475 if (iter == memorySizes.end ()) {
33903476 externalInterface->trap (" getMemorySize called on non-existing memory" );
@@ -3397,7 +3483,7 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
33973483 if (iter == memorySizes.end ()) {
33983484 externalInterface->trap (" setMemorySize called on non-existing memory" );
33993485 }
3400- memorySizes[memory] = size;
3486+ iter-> second = size;
34013487 }
34023488
34033489public:
@@ -4682,12 +4768,14 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
46824768 }
46834769 Flow visitStackSwitch (StackSwitch* curr) { return Flow (NONCONSTANT_FLOW); }
46844770
4685- void trap (const char * why) override {
4771+ void trap (std::string_view why) override {
46864772 // Traps break all current continuations - they will never be resumable.
46874773 self ()->clearContinuationStore ();
46884774 externalInterface->trap (why);
46894775 }
46904776
4777+ void trap (const char * why) override { trap (std::string_view (why)); }
4778+
46914779 void hostLimit (const char * why) override {
46924780 self ()->clearContinuationStore ();
46934781 externalInterface->hostLimit (why);
0 commit comments