[lldb][driver] Fix ELF interposition of HostInfoBase symbols causing segfault (#204710)
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.
Tested-on: FreeBSD 15.1 arm64, Fedora 44 amd64
Closes: #204643
Assisted-by: Claude
Signed-off-by: Minsoo Choo <minsoo@minsoo.io>
This commit is contained in:
1 parent
2018896ecc
commit
106644f6c8
1 file changed
+11
@@ -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.
|
||||
|
||||
Reference in new issue
Block a user