From c829f298a3911073517d56d07f1d97d9dcf139b6 Mon Sep 17 00:00:00 2001 From: jiajia Qian Date: Fri, 19 Jun 2026 08:49:50 +0800 Subject: [PATCH] linker: detect duplicate exported definitions without imports The duplicate-export check in GetImportExportPairs() only triggers when iterating over imports. If no module imports a symbol, the linker never looks up the export table for that name, so multiple modules can each export the same function and spvtools::Link() silently accepts them instead of reporting a One Definition Rule violation. Add a standalone pass over the exports map before the import-matching loop to reject links where the same symbol name is exported by more than one module. This correctly handles LinkOnceODR symbols because they are already deduplicated into a single export entry by the preceding linkonce processing. Fixes the piglit clLinkProgram test where two modules each define get_number() with Export linkage but neither imports it. Signed-off-by: jiajia Qian --- source/link/linker.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/link/linker.cpp b/source/link/linker.cpp index 002cc41f18..cbd205c1b5 100644 --- a/source/link/linker.cpp +++ b/source/link/linker.cpp @@ -504,6 +504,18 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer, << possible_export.second.name << "\"."; } + // Detect duplicate exported definitions (One Definition Rule violation). + // The existing check inside the import-matching loop below only catches + // duplicates when there is a corresponding import. This standalone check + // catches the case where multiple modules export the same symbol but no + // module imports it. + for (const auto& exp : exports) { + if (exp.second.size() > 1u) + return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY) + << "Too many external references, " << exp.second.size() + << ", were found for \"" << exp.first << "\"."; + } + // Find the import/export pairs for (const auto& import : imports) { std::vector possible_exports;