From 660ac76db1b2491777e3596042d328f0bb91363c Mon Sep 17 00:00:00 2001 From: Gaurav Chaudhary Date: Sat, 8 Aug 2026 17:28:22 +0530 Subject: [PATCH 1/4] wasm2c: reject contradictory imports instead of aborting Preflight ComputeUniqueImports() before codegen and return Result::Error when the same module/field name is imported with different external kinds, instead of hitting UNIMPLEMENTED/abort on valid-but-unlinkable modules. Fixes #2751 Signed-off-by: Gaurav Chaudhary --- src/c-writer.cc | 18 +++++++++++++----- test/wasm2c/contradictory-imports.txt | 9 +++++++++ 2 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 test/wasm2c/contradictory-imports.txt diff --git a/src/c-writer.cc b/src/c-writer.cc index 4ab14ddb0..7a875b6e8 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -378,7 +378,7 @@ class CWriter { void Write(const FuncTypeExpr&); void WriteTagDecls(); void WriteTags(); - void ComputeUniqueImports(); + Result ComputeUniqueImports(); void BeginInstance(); void WriteImports(); void WriteTailCallWeakImports(); @@ -1810,7 +1810,7 @@ void CWriter::WriteTags() { } } -void CWriter::ComputeUniqueImports() { +Result CWriter::ComputeUniqueImports() { using modname_name_pair = std::pair; std::map import_map; for (const Import* import : module_->imports) { @@ -1821,7 +1821,13 @@ void CWriter::ComputeUniqueImports() { modname_name_pair(import->module_name, import->field_name), import); if (!iterator_and_insertion_bool.second) { if (iterator_and_insertion_bool.first->second->kind() != import->kind()) { - UNIMPLEMENTED("contradictory import declaration"); + fprintf(stderr, + "error: contradictory import declaration: \"%s\".\"%s\" is " + "imported as both a %s and a %s\n", + import->module_name.c_str(), import->field_name.c_str(), + GetKindName(iterator_and_insertion_bool.first->second->kind()), + GetKindName(import->kind())); + return Result::Error; } else { fprintf(stderr, "warning: duplicate import declaration \"%s\" \"%s\"\n", import->module_name.c_str(), import->field_name.c_str()); @@ -1838,6 +1844,7 @@ void CWriter::ComputeUniqueImports() { for (const auto& node : import_map) { unique_imports_.push_back(node.second); } + return Result::Ok; } void CWriter::BeginInstance() { @@ -1846,8 +1853,6 @@ void CWriter::BeginInstance() { return; } - ComputeUniqueImports(); - // define names of per-instance imports for (const Import* import : module_->imports) { DefineImportName(import, import->module_name, import->field_name); @@ -6193,6 +6198,9 @@ void CWriter::WriteCSource() { Result CWriter::WriteModule(const Module& module) { WABT_USE(options_); module_ = &module; + + CHECK_RESULT(ComputeUniqueImports()); + WriteCHeader(); WriteCSource(); return result_; diff --git a/test/wasm2c/contradictory-imports.txt b/test/wasm2c/contradictory-imports.txt new file mode 100644 index 000000000..3fd520fa0 --- /dev/null +++ b/test/wasm2c/contradictory-imports.txt @@ -0,0 +1,9 @@ +;;; RUN: %(wat2wasm)s %(in_file)s -o %(temp_file)s.wasm +;;; RUN: %(wasm2c)s %(temp_file)s.wasm -o %(temp_file)s.c +;;; ERROR: 1 +(module + (import "e" "x" (func)) + (import "e" "x" (global i32))) +(;; STDERR ;;; +error: contradictory import declaration: "e"."x" is imported as both a func and a global +;;; STDERR ;;) From fdcbc5b78691be8f65f6c115a8ae66e50ab71430 Mon Sep 17 00:00:00 2001 From: Gaurav Chaudhary Date: Sun, 16 Aug 2026 09:23:46 +0530 Subject: [PATCH 2/4] wasm2c: restore ComputeUniqueImports in BeginInstance Clear import accumulators at the start of ComputeUniqueImports() so it can run from both WriteModule() preflight and BeginInstance(). Keeps early rejection of contradictory imports while making the unique_imports_ dependency explicit at the point of use. Fixes #2751 Signed-off-by: Gaurav Chaudhary --- src/c-writer.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/c-writer.cc b/src/c-writer.cc index 7a875b6e8..f095d2311 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1811,6 +1811,11 @@ void CWriter::WriteTags() { } Result CWriter::ComputeUniqueImports() { + unique_imports_.clear(); + import_module_set_.clear(); + import_func_module_set_.clear(); + import_func_module_map_.clear(); + using modname_name_pair = std::pair; std::map import_map; for (const Import* import : module_->imports) { @@ -1853,6 +1858,10 @@ void CWriter::BeginInstance() { return; } + if (Failed(ComputeUniqueImports())) { + return; + } + // define names of per-instance imports for (const Import* import : module_->imports) { DefineImportName(import, import->module_name, import->field_name); From b9daac60087845e2d933bd5288cfe705474ab13f Mon Sep 17 00:00:00 2001 From: Gaurav Chaudhary Date: Mon, 17 Aug 2026 13:17:27 +0530 Subject: [PATCH 3/4] wasm2c: use single ComputeUniqueImports call with result_ propagation Remove duplicate ComputeUniqueImports() from WriteModule(). Keep one call in BeginInstance(), set result_ on failure, and stop emission in WriteModuleInstance, WriteCHeader, and WriteModule when result_ is Error. Fixes #2751 Signed-off-by: Gaurav Chaudhary --- src/c-writer.cc | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/c-writer.cc b/src/c-writer.cc index f095d2311..dd33e6d89 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1859,6 +1859,7 @@ void CWriter::BeginInstance() { } if (Failed(ComputeUniqueImports())) { + result_ = Result::Error; return; } @@ -2133,6 +2134,9 @@ void CWriter::WriteV128Decl() { void CWriter::WriteModuleInstance() { BeginInstance(); + if (Failed(result_)) { + return; + } WriteGlobals(); WriteMemories(); WriteTables(); @@ -6145,6 +6149,9 @@ void CWriter::WriteCHeader() { Write(s_header_top); Write(Newline()); WriteModuleInstance(); + if (Failed(result_)) { + return; + } WriteInitDecl(); WriteFreeDecl(); WriteGetFuncTypeDecl(); @@ -6208,9 +6215,10 @@ Result CWriter::WriteModule(const Module& module) { WABT_USE(options_); module_ = &module; - CHECK_RESULT(ComputeUniqueImports()); - WriteCHeader(); + if (Failed(result_)) { + return result_; + } WriteCSource(); return result_; } From 1a0967d087b3778c4222617c1b9eadaa8034671d Mon Sep 17 00:00:00 2001 From: Gaurav Chaudhary Date: Tue, 18 Aug 2026 07:50:41 +0530 Subject: [PATCH 4/4] wasm2c: drop unnecessary ComputeUniqueImports clears Single call site in BeginInstance() no longer needs accumulator clears added for the earlier dual-call approach. Fixes #2751 Signed-off-by: Gaurav Chaudhary --- src/c-writer.cc | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/c-writer.cc b/src/c-writer.cc index dd33e6d89..93c469e3e 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1811,11 +1811,6 @@ void CWriter::WriteTags() { } Result CWriter::ComputeUniqueImports() { - unique_imports_.clear(); - import_module_set_.clear(); - import_func_module_set_.clear(); - import_func_module_map_.clear(); - using modname_name_pair = std::pair; std::map import_map; for (const Import* import : module_->imports) {