Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions source/link/linker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,17 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer,
<< possible_export.second.name << "\".";
}

// Detect multiple strong definitions of the same symbol.
// The import-matching loop below only visits symbols that are imported, so it
// would silently accept multiple exports when nothing imports them. Check
// all exports here so that duplicates are always rejected.
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<LinkageSymbolInfo> possible_exports;
Expand All @@ -512,10 +523,6 @@ spv_result_t GetImportExportPairs(const MessageConsumer& consumer,
if (possible_exports.empty() && !allow_partial_linkage)
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
<< "Unresolved external reference to \"" << import.name << "\".";
else if (possible_exports.size() > 1u)
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
<< "Too many external references, " << possible_exports.size()
<< ", were found for \"" << import.name << "\".";

if (!possible_exports.empty())
linkings_to_do->emplace_back(import, possible_exports.front());
Expand Down
33 changes: 33 additions & 0 deletions test/link/matching_imports_to_exports_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,39 @@ OpDecorate %1 LinkageAttributes "foo" Export
}
}

TEST_F(MatchingImportsToExports, MultipleDefinitionsNoImport) {
// Two modules export the same symbol but nothing imports it.
// The linker must still reject this as a duplicate strong definition.
const std::string body1 = R"(
OpCapability Linkage
OpCapability Addresses
OpCapability Kernel
OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 42
%1 = OpVariable %2 Uniform %3
)";
const std::string body2 = R"(
OpCapability Linkage
OpCapability Addresses
OpCapability Kernel
OpMemoryModel Physical64 OpenCL
OpDecorate %1 LinkageAttributes "foo" Export
%2 = OpTypeFloat 32
%3 = OpConstant %2 -1
%1 = OpVariable %2 Uniform %3
)";

spvtest::Binary linked_binary;
EXPECT_EQ(SPV_ERROR_INVALID_BINARY,
AssembleAndLink({body1, body2}, &linked_binary))
<< GetErrorMessage();
EXPECT_THAT(GetErrorMessage(),
HasSubstr("Too many external references, 2, were found "
"for \"foo\"."));
}

TEST_F(MatchingImportsToExports, SameNameDifferentTypes) {
const std::string body1 = R"(
OpCapability Linkage
Expand Down