summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJérôme Vouillon <jerome.vouillon@gmail.com>2024-03-27 17:26:57 -0400
committerGitHub <noreply@github.com>2024-03-27 14:26:57 -0700
commiteae2638a53e778e24e1ed042f2e16aa0b3b127a5 (patch)
treee5e3bf1c41c86050cba7953f6097799bf6100ec1 /src
parent61877e9bbc6df38d3bb342a695ead0bc290fbb40 (diff)
downloadbinaryen-eae2638a53e778e24e1ed042f2e16aa0b3b127a5.tar.gz
binaryen-eae2638a53e778e24e1ed042f2e16aa0b3b127a5.tar.bz2
binaryen-eae2638a53e778e24e1ed042f2e16aa0b3b127a5.zip
wasm-merge: Check that the types of imports and exports match (#6437)
Diffstat (limited to 'src')
-rw-r--r--src/tools/wasm-merge.cpp108
1 files changed, 108 insertions, 0 deletions
diff --git a/src/tools/wasm-merge.cpp b/src/tools/wasm-merge.cpp
index ec67d56fc..8e8e2d80d 100644
--- a/src/tools/wasm-merge.cpp
+++ b/src/tools/wasm-merge.cpp
@@ -381,6 +381,38 @@ void copyModuleContents(Module& input, Name inputName) {
// TODO: type names, features, debug info, custom sections, dylink info, etc.
}
+void reportTypeMismatch(bool& valid, const char* kind, Importable* import) {
+ valid = false;
+ std::cerr << "Type mismatch when importing " << kind << " " << import->base
+ << " from module " << import->module << " ($" << import->name
+ << "): ";
+}
+
+// Check that the export and import limits match.
+template<typename T>
+void checkLimit(bool& valid, const char* kind, T* export_, T* import) {
+ if (export_->initial < import->initial) {
+ reportTypeMismatch(valid, kind, import);
+ std::cerr << "minimal size " << export_->initial
+ << " is smaller than expected minimal size " << import->initial
+ << ".\n";
+ }
+ if (import->hasMax()) {
+ if (!export_->hasMax()) {
+ reportTypeMismatch(valid, kind, import);
+ std::cerr << "expecting a bounded " << kind
+ << " but the "
+ "imported "
+ << kind << " is unbounded.\n";
+ } else if (export_->max > import->max) {
+ reportTypeMismatch(valid, kind, import);
+ std::cerr << "maximal size " << export_->max
+ << " is larger than expected maximal size " << import->max
+ << ".\n";
+ }
+ }
+}
+
// Find pairs of matching imports and exports, and make uses of the import refer
// to the exported item (which has been merged into the module).
void fuseImportsAndExports() {
@@ -428,6 +460,82 @@ void fuseImportsAndExports() {
}
});
+ // Make sure that the export types match the import types.
+ bool valid = true;
+ ModuleUtils::iterImportedFunctions(merged, [&](Function* import) {
+ auto internalName = kindModuleExportMaps[ExternalKind::Function]
+ [import->module][import->base];
+ if (internalName.is()) {
+ auto* export_ = merged.getFunction(internalName);
+ if (!HeapType::isSubType(export_->type, import->type)) {
+ reportTypeMismatch(valid, "function", import);
+ std::cerr << "type " << export_->type << " is not a subtype of "
+ << import->type << ".\n";
+ }
+ }
+ });
+ ModuleUtils::iterImportedTables(merged, [&](Table* import) {
+ auto internalName =
+ kindModuleExportMaps[ExternalKind::Table][import->module][import->base];
+ if (internalName.is()) {
+ auto* export_ = merged.getTable(internalName);
+ checkLimit(valid, "table", export_, import);
+ if (export_->type != import->type) {
+ reportTypeMismatch(valid, "table", import);
+ std::cerr << "export type " << export_->type
+ << " is different from import type " << import->type << ".\n";
+ }
+ }
+ });
+ ModuleUtils::iterImportedMemories(merged, [&](Memory* import) {
+ auto internalName =
+ kindModuleExportMaps[ExternalKind::Memory][import->module][import->base];
+ if (internalName.is()) {
+ auto* export_ = merged.getMemory(internalName);
+ if (export_->is64() != import->is64()) {
+ reportTypeMismatch(valid, "memory", import);
+ std::cerr << "index type should match.\n";
+ }
+ checkLimit(valid, "memory", export_, import);
+ }
+ });
+ ModuleUtils::iterImportedGlobals(merged, [&](Global* import) {
+ auto internalName =
+ kindModuleExportMaps[ExternalKind::Global][import->module][import->base];
+ if (internalName.is()) {
+ auto* export_ = merged.getGlobal(internalName);
+ if (export_->mutable_ != import->mutable_) {
+ reportTypeMismatch(valid, "global", import);
+ std::cerr << "mutability should match.\n";
+ }
+ if (export_->mutable_ && export_->type != import->type) {
+ reportTypeMismatch(valid, "global", import);
+ std::cerr << "export type " << export_->type
+ << " is different from import type " << import->type << ".\n";
+ }
+ if (!export_->mutable_ && !Type::isSubType(export_->type, import->type)) {
+ reportTypeMismatch(valid, "global", import);
+ std::cerr << "type " << export_->type << " is not a subtype of "
+ << import->type << ".\n";
+ }
+ }
+ });
+ ModuleUtils::iterImportedTags(merged, [&](Tag* import) {
+ auto internalName =
+ kindModuleExportMaps[ExternalKind::Tag][import->module][import->base];
+ if (internalName.is()) {
+ auto* export_ = merged.getTag(internalName);
+ if (HeapType(export_->sig) != HeapType(import->sig)) {
+ reportTypeMismatch(valid, "tag", import);
+ std::cerr << "export type " << export_->sig
+ << " is different from import type " << import->sig << ".\n";
+ }
+ }
+ });
+ if (!valid) {
+ Fatal() << "import/export mismatches";
+ }
+
// Update the things we found.
updateNames(merged, kindNameUpdates);
}