llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Minsoo Choo (mchoo7)

<details>
<summary>Changes</summary>

Commit 67e571d (#<!-- -->179306) added lldbHost and lldbUtility to 
`LLDB_DRIVER_LINK_LIBS` A side-effect is that HostInfoBase.cpp, which contains 
the file-static `g_fields` pointer, is now compiled into both the lldb binary 
and liblldb.so, giving each its own independent `g_fields`.

On ELF platforms this creates an interposition hazard. When 
`LLDB_ENABLE_DYNAMIC_SCRIPTINTERPRETERS` is set, AddLLDB.cmake switches all 
LLDB libraries to `CXX_VISIBILITY_PRESET=default` so that the version script 
can re-export private symbols needed by dynamically loaded plugins. The Python 
plugin calls `HostInfo::GetShlibDir()` directly, so 
extract-dynamic-script-interpreter-exports.py adds `HostInfoBase::GetShlibDir` 
to liblldb.so's exports (global: in the version script). 
`HostInfoBase::Initialize()` is not called by the plugin and stays local:.

At runtime the dynamic linker resolves liblldb.so's PLT entry for 
`GetShlibDir()` to lldb's copy (ELF interposition: executable symbols win), 
which holds a never-initialized `g_fields == nullptr`. `Initialize()` was 
already called, but it ran on liblldb.so's own copy via the 
version-script-local binding. Dereferencing `nullptr + 0x108` (offset of 
`m_lldb_so_dir_once`) crashes in `pthread_once`.

To fix this, pass `--exclude-libs,ALL` to the lldb executable on ELF platforms. 
This keeps every archive-contributed symbol (lldbHost, lldbUtility, LLVM libs) 
out of lldb's `.dynsym`, eliminating the interposition. liblldb.so's PLT for 
`GetShlibDir()` then finds only liblldb.so's own exported definition, so 
`Initialize()` and `GetShlibDir()` consistently operate on the same `g_fields`.

The issue does not affect Darwin because Mach-O uses a two-level namespace: 
symbol references in liblldb.dylib are bound to a specific library at link 
time, so lldb's copy is never a candidate for resolution regardless of 
visibility.

Closes: #<!-- -->204643
Assisted-by: Claude

---
Full diff: https://github.com/llvm/llvm-project/pull/204710.diff


1 Files Affected:

- (modified) lldb/tools/driver/CMakeLists.txt (+11) 


``````````diff
diff --git a/lldb/tools/driver/CMakeLists.txt b/lldb/tools/driver/CMakeLists.txt
index 0534ddc9a58c3..38670a14a78b0 100644
--- a/lldb/tools/driver/CMakeLists.txt
+++ b/lldb/tools/driver/CMakeLists.txt
@@ -52,6 +52,17 @@ add_dependencies(lldb
   ${tablegen_deps}
 )
 
+# lldbHost and lldbUtility are also statically linked into liblldb.so, so any
+# state they carry exists in two independent copies. On ELF platforms this
+# creates an interposition hazard: when liblldb.so exports a symbol from those
+# archives (e.g. for dynamic plugin loading), the dynamic linker can resolve
+# it to lldb's copy instead of liblldb.so's, breaking shared-state assumptions.
+# --exclude-libs,ALL keeps archive symbols out of lldb's .dynsym, eliminating
+# the hazard without affecting the executable's own use of those symbols.
+if(UNIX AND NOT APPLE)
+  target_link_options(lldb PRIVATE "LINKER:--exclude-libs,ALL")
+endif()
+
 if(LLDB_BUILD_FRAMEWORK)
   # In the build-tree, we know the exact path to the framework directory.
   # The installed framework can be in different locations.

``````````

</details>


https://github.com/llvm/llvm-project/pull/204710
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to