Author: Emery Conrad Date: 2026-07-28T18:12:35+03:00 New Revision: 62f429ec6e85224a0f7fa6d4e51595b27e5ac9c1
URL: https://github.com/llvm/llvm-project/commit/62f429ec6e85224a0f7fa6d4e51595b27e5ac9c1 DIFF: https://github.com/llvm/llvm-project/commit/62f429ec6e85224a0f7fa6d4e51595b27e5ac9c1.diff LOG: [clang][CodeGen] Skip deleted globals in emitUsed (#210959) A global on the `llvm.used`/`llvm.compiler.used` list can be deleted before the module is released: CodeGen erases an unreferenced `GlobalValue` without RAUW when the same mangled name is redefined with a different type (`GetOrCreateLLVMGlobal`), which nulls the `WeakTrackingVH` on the used list — value handles are not uses, so the `use_empty()` guard does not protect them. In whole-TU compilation this is unobservable because the accompanying `err_duplicate_mangled_name` suppresses `Release()`. The incremental interpreter, however, clears the diagnostic state after the failed parse and keeps building the same module, so the next successful parse runs `Release()` and crashes in `emitUsed` dereferencing the dead handle: ``` clang-repl> __attribute__((used)) int a asm("sym") = 1; float b asm("sym") = 2.0f; clang-repl> int ok = 0; clang-repl: .../ValueHandle.h:95: llvm::Value& llvm::ValueHandleBase::operator*() const: Assertion `V && "Dereferencing deleted ValueHandle"' failed. ``` Out-of-tree incremental clients hit the same crash through other routes that delete an emitted used global before module release (e.g. CppInterOp's force-emission of reflection queries, see compiler-research/CppInterOp#1068). Fix: skip null handles when building the used array. The repro above is included as a lit test; `clang/test/Interpreter`, `clang/test/CodeGen`, and `clang/test/CodeGenCXX` pass locally. 🤖 Done with the help of [Claude Code](https://claude.com/claude-code) (Fable 5, human in the loop) Co-authored-by: Emery Conrad <[email protected]> Added: clang/test/Interpreter/used-global-after-error.cpp Modified: clang/lib/CodeGen/CodeGenModule.cpp Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 817b2b5e6a69d..e7c1d182fd20d 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3703,13 +3703,16 @@ static void emitUsed(CodeGenModule &CGM, StringRef Name, if (List.empty()) return; - // Convert List to what ConstantArray needs. - SmallVector<llvm::Constant*, 8> UsedArray; - UsedArray.resize(List.size()); - for (unsigned i = 0, e = List.size(); i != e; ++i) { - UsedArray[i] = - llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( - cast<llvm::Constant>(&*List[i]), CGM.Int8PtrTy); + // Convert List to what ConstantArray needs. A used global may have been + // deleted after it was added to the list (e.g. when its home module keeps + // accumulating declarations after an erroneous incremental parse), leaving + // a null value handle behind; skip those entries. + SmallVector<llvm::Constant *, 8> UsedArray; + UsedArray.reserve(List.size()); + for (const llvm::WeakTrackingVH &VH : List) { + if (llvm::Value *V = VH) + UsedArray.push_back(llvm::ConstantExpr::getPointerBitCastOrAddrSpaceCast( + cast<llvm::Constant>(V), CGM.Int8PtrTy)); } if (UsedArray.empty()) diff --git a/clang/test/Interpreter/used-global-after-error.cpp b/clang/test/Interpreter/used-global-after-error.cpp new file mode 100644 index 0000000000000..fc1043042d5cc --- /dev/null +++ b/clang/test/Interpreter/used-global-after-error.cpp @@ -0,0 +1,15 @@ +// REQUIRES: host-supports-jit +// UNSUPPORTED: system-aix +// RUN: cat %s | clang-repl | FileCheck %s + +// A cast<> of a null WeakTrackingVH used to crash emitUsed when a global on +// the llvm.used list was deleted before the module was released: the +// duplicate definition below is diagnosed by CodeGen, which then replaces the +// used global's unreferenced GV with a diff erently-typed one; the failed +// parse keeps the module alive, and the next successful parse finalizes it. +extern "C" int printf(const char *, ...); +__attribute__((used)) int a asm("sym") = 1; float b asm("sym") = 2.0f; +auto r1 = printf("ok = %d\n", 42); +// CHECK: ok = 42 + +%quit _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
