From 3a93a15fecae25341534bde69f04cc6479bf02f5 Mon Sep 17 00:00:00 2001 From: Wenju He Date: Fri, 10 Jul 2026 00:33:30 -0700 Subject: [PATCH] [SYCL][TableGen] Emit dynamic table variables as inline DynamicTableEmitter generates a plain (non-inline) global map variable in a header that is #included from multiple translation units. When those TUs end up in different shared libraries loaded into the same process, this violates the One Definition Rule: two strong definitions of DeviceConfigFile::TargetTable get double destructed at exit, causing "double free or corruption" crashes. 0bb722138216 introduced non-inline global. It became a bug on 2026-04-08 with a8dff34478c9 which moved DeviceConfigFile.hpp usage into a second shared library, libLLVMSYCLPostLink.so, creating the second strong definition. It surfaced as a visible crash on 2026-06-12 with b09acde14f87, which added fp8 unittest that links against sycl-jit -> pulling in both libclangDriver.so and libLLVMSYCLPostLink.so in the same process when BUILD_SHARED_LIBS=ON. Co-Authored-By: Claude Sonnet 5 --- llvm/utils/TableGen/DynamicTableEmitter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/utils/TableGen/DynamicTableEmitter.cpp b/llvm/utils/TableGen/DynamicTableEmitter.cpp index d320fa66cdecf..3558b42773c6e 100644 --- a/llvm/utils/TableGen/DynamicTableEmitter.cpp +++ b/llvm/utils/TableGen/DynamicTableEmitter.cpp @@ -121,8 +121,8 @@ void DynamicTableEmitter::emitDynamicTable(const DynamicTable &Table, emitIfdef((Twine("GET_") + Table.PreprocessorGuard + "_IMPL"), OS); // The primary data table contains all the fields defined for this map. - OS << "std::map " << Table.Name - << " = {\n"; + OS << "inline std::map " + << Table.Name << " = {\n"; // Iterate over the key-value pairs the dynamic table will contain. for (unsigned I = 0; I < Table.Entries.size(); ++I) { const Record *Entry = Table.Entries[I];