Author: Emery Conrad
Date: 2026-07-06T16:28:50+03:00
New Revision: a3624cb45f2a3902e59f78eafd005357d2b72688

URL: 
https://github.com/llvm/llvm-project/commit/a3624cb45f2a3902e59f78eafd005357d2b72688
DIFF: 
https://github.com/llvm/llvm-project/commit/a3624cb45f2a3902e59f78eafd005357d2b72688.diff

LOG: [ORC] Track __emutls_t definitions in IRMaterializationUnit (#207161)

When emulated TLS is enabled, `IRMaterializationUnit`'s constructor
emits an `__emutls_t.<var>` symbol for each non-zero-initialized
`thread_local` global and records it in `SymbolFlags`, but never adds it
to `SymbolToDefinition`.

If the same weak (`linkonce_odr`) definition is materialized by more
than one module — e.g. an `inline` function that odr-uses such a
`thread_local`, pulled into two `PartialTranslationUnit`s by clang-repl
— `JITDylib::defineImpl` discards the duplicate via
`IRMaterializationUnit::discard()`. `discard()` looks the symbol up in
`SymbolToDefinition` and, finding nothing, dereferences `end()`: an
assertion failure in `+Asserts` builds and heap corruption otherwise.

Register `__emutls_t.<var>` in `SymbolToDefinition` alongside its flags,
mirroring the `__emutls_v.<var>` handling just above.

### Test

`clang/test/Interpreter/emulated-tls.cpp` reproduces the crash through
clang-repl: two PTUs each odr-use one `inline worker()` that reads a
non-zero `thread_local`, so each re-emits the same weak emulated-TLS
set; defining the second module runs `discard()` over the duplicate. The
test aborts on the unfixed path and prints the expected value with the
fix.

🤖 Done with the help of [Claude Code](https://claude.com/claude-code)
(Claude Opus 4.8, human in the loop)

Co-authored-by: Emery Conrad <[email protected]>

Added: 
    clang/test/Interpreter/emulated-tls.cpp

Modified: 
    llvm/lib/ExecutionEngine/Orc/Layer.cpp

Removed: 
    


################################################################################
diff  --git a/clang/test/Interpreter/emulated-tls.cpp 
b/clang/test/Interpreter/emulated-tls.cpp
new file mode 100644
index 0000000000000..73afe172ef6d9
--- /dev/null
+++ b/clang/test/Interpreter/emulated-tls.cpp
@@ -0,0 +1,25 @@
+// REQUIRES: host-supports-jit
+// UNSUPPORTED: system-windows
+//
+// An inline function that odr-uses a non-zero-initialized thread_local is
+// emitted as a weak (linkonce_odr) definition into every 
PartialTranslationUnit
+// that references it. With emulated TLS that set includes an __emutls_t.<var>
+// symbol. When a later PTU re-defines the same weak set, ORC's
+// IRMaterializationUnit::discard() must find each duplicated symbol in its
+// SymbolToDefinition map. The emulated-TLS path used to register 
__emutls_t.<var>
+// in SymbolFlags but not SymbolToDefinition, so discarding it dereferenced
+// end() -- an assertion failure in +Asserts builds and heap corruption
+// otherwise. Two PTUs each pulling in the same inline worker reproduces it.
+//
+// RUN: cat %s | clang-repl | FileCheck %s
+
+extern "C" int printf(const char *, ...);
+template <int Tag> struct HeavyThing { static thread_local int tls; };
+template <int Tag> thread_local int HeavyThing<Tag>::tls = Tag + 1;
+inline int worker() { return HeavyThing<1>::tls; }
+int callA() { return worker(); }
+int callB() { return worker(); }
+auto r = printf("tls = %d, %d\n", callA(), callB());
+// CHECK: tls = 2, 2
+
+%quit

diff  --git a/llvm/lib/ExecutionEngine/Orc/Layer.cpp 
b/llvm/lib/ExecutionEngine/Orc/Layer.cpp
index eb144275da589..5e95b8c73b482 100644
--- a/llvm/lib/ExecutionEngine/Orc/Layer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Layer.cpp
@@ -70,6 +70,7 @@ IRMaterializationUnit::IRMaterializationUnit(
 
           auto EmuTLST = Mangle(("__emutls_t." + GV.getName()).str());
           SymbolFlags[EmuTLST] = Flags;
+          SymbolToDefinition[EmuTLST] = &GV;
         }
         continue;
       }


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to