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
