mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-10-02 04:50:21 +00:00
lldb: backport export trie fixes to LLDB 22 and older
Older versions of LLDB crash on macOS 27 when starting a debugging
session on macOS 27 due to a stack overflow in `ParseExportTries`.
The fixes from LLVM 23 can’t be cherry-picked due to other changes. They
have been manually backported and squashed into a single patch.
(cherry picked from commit 53b813b166)
This commit is contained in:
committed by
Ihar Hrachyshka
parent
9c847cd37c
commit
51db35b37c
@@ -0,0 +1,124 @@
|
||||
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
|
||||
index 2c7005449f..e0c426afa0 100644
|
||||
--- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
|
||||
+++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
|
||||
@@ -137,6 +137,14 @@
|
||||
using namespace lldb_private;
|
||||
using namespace llvm::MachO;
|
||||
|
||||
+/// Upper bound on the length of a symbol name assembled from export-trie edge
|
||||
+/// labels. A corrupt trie can encode an edge label whose terminator is far
|
||||
+/// away in the trie data, so a single label is many megabytes long; appending
|
||||
+/// it to the running name would otherwise request an unbounded allocation. No
|
||||
+/// legitimate symbol name comes close to this size. Also 1 MiB is the
|
||||
+/// symbol length limit in ld.
|
||||
+static constexpr size_t kMaxTrieSymbolNameLength = 1 << 20; // 1 MiB
|
||||
+
|
||||
LLDB_PLUGIN_DEFINE(ObjectFileMachO)
|
||||
|
||||
static void PrintRegisterValue(RegisterContext *reg_ctx, const char *name,
|
||||
@@ -2050,15 +2058,21 @@
|
||||
}
|
||||
};
|
||||
|
||||
-static bool ParseTrieEntries(DataExtractor &data, lldb::offset_t offset,
|
||||
- const bool is_arm, addr_t text_seg_base_addr,
|
||||
- std::vector<llvm::StringRef> &nameSlices,
|
||||
- std::set<lldb::addr_t> &resolver_addresses,
|
||||
- std::vector<TrieEntryWithOffset> &reexports,
|
||||
- std::vector<TrieEntryWithOffset> &ext_symbols) {
|
||||
+static bool ParseTrieEntriesImpl(DataExtractor &data, lldb::offset_t offset,
|
||||
+ const bool is_arm, addr_t text_seg_base_addr,
|
||||
+ std::string &prefix,
|
||||
+ std::set<lldb::addr_t> &resolver_addresses,
|
||||
+ std::vector<TrieEntryWithOffset> &reexports,
|
||||
+ std::vector<TrieEntryWithOffset> &ext_symbols,
|
||||
+ std::set<lldb::offset_t> &visited_nodes) {
|
||||
if (!data.ValidOffset(offset))
|
||||
return true;
|
||||
|
||||
+ // Every node in a well-formed trie is reached by exactly one path, so a node
|
||||
+ // offset seen twice means the trie is corrupt.
|
||||
+ if (!visited_nodes.insert(offset).second)
|
||||
+ return false;
|
||||
+
|
||||
// Terminal node -- end of a branch, possibly add this to
|
||||
// the symbol table or resolver table.
|
||||
const uint64_t terminalSize = data.GetULEB128(&offset);
|
||||
@@ -2098,14 +2112,9 @@
|
||||
add_this_entry = true;
|
||||
}
|
||||
if (add_this_entry) {
|
||||
- std::string name;
|
||||
- if (!nameSlices.empty()) {
|
||||
- for (auto name_slice : nameSlices)
|
||||
- name.append(name_slice.data(), name_slice.size());
|
||||
- }
|
||||
- if (name.size() > 1) {
|
||||
+ if (prefix.size() > 1) {
|
||||
// Skip the leading '_'
|
||||
- e.entry.name.SetCStringWithLength(name.c_str() + 1, name.size() - 1);
|
||||
+ e.entry.name.SetString(llvm::StringRef(prefix).drop_front());
|
||||
}
|
||||
if (import_name) {
|
||||
// Skip the leading '_'
|
||||
@@ -2126,23 +2135,36 @@
|
||||
const uint8_t childrenCount = data.GetU8(&children_offset);
|
||||
for (uint8_t i = 0; i < childrenCount; ++i) {
|
||||
const char *cstr = data.GetCStr(&children_offset);
|
||||
- if (cstr)
|
||||
- nameSlices.push_back(llvm::StringRef(cstr));
|
||||
- else
|
||||
+ if (!cstr)
|
||||
return false; // Corrupt data
|
||||
+ if (prefix.size() + llvm::StringRef(cstr).size() > kMaxTrieSymbolNameLength)
|
||||
+ return false; // Corrupt data: implausibly long symbol name.
|
||||
+ const size_t prevSize = prefix.size();
|
||||
+ prefix.append(cstr);
|
||||
lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset);
|
||||
- if (childNodeOffset) {
|
||||
- if (!ParseTrieEntries(data, childNodeOffset, is_arm, text_seg_base_addr,
|
||||
- nameSlices, resolver_addresses, reexports,
|
||||
- ext_symbols)) {
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
- nameSlices.pop_back();
|
||||
+ // A child offset of 0 points back at the root; like any other repeated
|
||||
+ // offset it is a cycle, which ParseTrieEntriesImpl rejects as corrupt.
|
||||
+ if (!ParseTrieEntriesImpl(data, childNodeOffset, is_arm, text_seg_base_addr,
|
||||
+ prefix, resolver_addresses, reexports,
|
||||
+ ext_symbols, visited_nodes))
|
||||
+ return false;
|
||||
+ prefix.resize(prevSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+static bool ParseTrieEntries(
|
||||
+ DataExtractor &data, const bool is_arm, lldb::addr_t text_seg_base_addr,
|
||||
+ std::set<lldb::addr_t> &resolver_addresses,
|
||||
+ std::vector<TrieEntryWithOffset> &reexports,
|
||||
+ std::vector<TrieEntryWithOffset> &ext_symbols) {
|
||||
+ lldb::offset_t offset = 0;
|
||||
+ std::set<lldb::offset_t> visited_nodes;
|
||||
+ std::string prefix;
|
||||
+ return ParseTrieEntriesImpl(data, offset, is_arm, text_seg_base_addr, prefix,
|
||||
+ resolver_addresses, reexports, ext_symbols,
|
||||
+ visited_nodes);
|
||||
+}
|
||||
static SymbolType GetSymbolType(const char *&symbol_name,
|
||||
bool &demangled_is_synthesized,
|
||||
const SectionSP &text_section_sp,
|
||||
@@ -2666,9 +2688,8 @@
|
||||
lldb::addr_t text_segment_file_addr = LLDB_INVALID_ADDRESS;
|
||||
if (text_segment_sp)
|
||||
text_segment_file_addr = text_segment_sp->GetFileAddress();
|
||||
- std::vector<llvm::StringRef> nameSlices;
|
||||
- ParseTrieEntries(dyld_trie_data, 0, is_arm, text_segment_file_addr,
|
||||
- nameSlices, resolver_addresses, reexport_trie_entries,
|
||||
+ ParseTrieEntries(dyld_trie_data, is_arm, text_segment_file_addr,
|
||||
+ resolver_addresses, reexport_trie_entries,
|
||||
external_sym_trie_entries);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
diff --git a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
|
||||
index 0be7b4c6f8..f9d9a05920 100644
|
||||
--- a/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
|
||||
+++ b/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
|
||||
@@ -137,6 +137,14 @@
|
||||
static constexpr llvm::StringLiteral g_loader_path = "@loader_path";
|
||||
static constexpr llvm::StringLiteral g_executable_path = "@executable_path";
|
||||
|
||||
+/// Upper bound on the length of a symbol name assembled from export-trie edge
|
||||
+/// labels. A corrupt trie can encode an edge label whose terminator is far
|
||||
+/// away in the trie data, so a single label is many megabytes long; appending
|
||||
+/// it to the running name would otherwise request an unbounded allocation. No
|
||||
+/// legitimate symbol name comes close to this size. Also 1 MiB is the
|
||||
+/// symbol length limit in ld.
|
||||
+static constexpr size_t kMaxTrieSymbolNameLength = 1 << 20; // 1 MiB
|
||||
+
|
||||
LLDB_PLUGIN_DEFINE(ObjectFileMachO)
|
||||
|
||||
static void PrintRegisterValue(RegisterContext *reg_ctx, const char *name,
|
||||
@@ -1994,15 +2002,21 @@
|
||||
}
|
||||
};
|
||||
|
||||
-static bool ParseTrieEntries(DataExtractor &data, lldb::offset_t offset,
|
||||
- const bool is_arm, addr_t text_seg_base_addr,
|
||||
- std::vector<llvm::StringRef> &nameSlices,
|
||||
- std::set<lldb::addr_t> &resolver_addresses,
|
||||
- std::vector<TrieEntryWithOffset> &reexports,
|
||||
- std::vector<TrieEntryWithOffset> &ext_symbols) {
|
||||
+static bool ParseTrieEntriesImpl(DataExtractor &data, lldb::offset_t offset,
|
||||
+ const bool is_arm, addr_t text_seg_base_addr,
|
||||
+ std::string &prefix,
|
||||
+ std::set<lldb::addr_t> &resolver_addresses,
|
||||
+ std::vector<TrieEntryWithOffset> &reexports,
|
||||
+ std::vector<TrieEntryWithOffset> &ext_symbols,
|
||||
+ std::set<lldb::offset_t> &visited_nodes) {
|
||||
if (!data.ValidOffset(offset))
|
||||
return true;
|
||||
|
||||
+ // Every node in a well-formed trie is reached by exactly one path, so a node
|
||||
+ // offset seen twice means the trie is corrupt.
|
||||
+ if (!visited_nodes.insert(offset).second)
|
||||
+ return false;
|
||||
+
|
||||
// Terminal node -- end of a branch, possibly add this to
|
||||
// the symbol table or resolver table.
|
||||
const uint64_t terminalSize = data.GetULEB128(&offset);
|
||||
@@ -2042,14 +2056,9 @@
|
||||
add_this_entry = true;
|
||||
}
|
||||
if (add_this_entry) {
|
||||
- std::string name;
|
||||
- if (!nameSlices.empty()) {
|
||||
- for (auto name_slice : nameSlices)
|
||||
- name.append(name_slice.data(), name_slice.size());
|
||||
- }
|
||||
- if (name.size() > 1) {
|
||||
+ if (prefix.size() > 1) {
|
||||
// Skip the leading '_'
|
||||
- e.entry.name.SetCStringWithLength(name.c_str() + 1, name.size() - 1);
|
||||
+ e.entry.name.SetString(llvm::StringRef(prefix).drop_front());
|
||||
}
|
||||
if (import_name) {
|
||||
// Skip the leading '_'
|
||||
@@ -2070,23 +2079,37 @@
|
||||
const uint8_t childrenCount = data.GetU8(&children_offset);
|
||||
for (uint8_t i = 0; i < childrenCount; ++i) {
|
||||
const char *cstr = data.GetCStr(&children_offset);
|
||||
- if (cstr)
|
||||
- nameSlices.push_back(llvm::StringRef(cstr));
|
||||
- else
|
||||
+ if (!cstr)
|
||||
return false; // Corrupt data
|
||||
+ if (prefix.size() + llvm::StringRef(cstr).size() > kMaxTrieSymbolNameLength)
|
||||
+ return false; // Corrupt data: implausibly long symbol name.
|
||||
+ const size_t prevSize = prefix.size();
|
||||
+ prefix.append(cstr);
|
||||
lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset);
|
||||
- if (childNodeOffset) {
|
||||
- if (!ParseTrieEntries(data, childNodeOffset, is_arm, text_seg_base_addr,
|
||||
- nameSlices, resolver_addresses, reexports,
|
||||
- ext_symbols)) {
|
||||
- return false;
|
||||
- }
|
||||
- }
|
||||
- nameSlices.pop_back();
|
||||
+ // A child offset of 0 points back at the root; like any other repeated
|
||||
+ // offset it is a cycle, which ParseTrieEntriesImpl rejects as corrupt.
|
||||
+ if (!ParseTrieEntriesImpl(data, childNodeOffset, is_arm, text_seg_base_addr,
|
||||
+ prefix, resolver_addresses, reexports,
|
||||
+ ext_symbols, visited_nodes))
|
||||
+ return false;
|
||||
+ prefix.resize(prevSize);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+static bool ParseTrieEntries(
|
||||
+ DataExtractor &data, const bool is_arm, lldb::addr_t text_seg_base_addr,
|
||||
+ std::set<lldb::addr_t> &resolver_addresses,
|
||||
+ std::vector<TrieEntryWithOffset> &reexports,
|
||||
+ std::vector<TrieEntryWithOffset> &ext_symbols) {
|
||||
+ lldb::offset_t offset = 0;
|
||||
+ std::set<lldb::offset_t> visited_nodes;
|
||||
+ std::string prefix;
|
||||
+ return ParseTrieEntriesImpl(data, offset, is_arm, text_seg_base_addr, prefix,
|
||||
+ resolver_addresses, reexports, ext_symbols,
|
||||
+ visited_nodes);
|
||||
+}
|
||||
+
|
||||
static bool
|
||||
TryParseV2ObjCMetadataSymbol(const char *&symbol_name,
|
||||
const char *&symbol_name_non_abi_mangled,
|
||||
@@ -2659,9 +2682,8 @@
|
||||
lldb::addr_t text_segment_file_addr = LLDB_INVALID_ADDRESS;
|
||||
if (text_segment_sp)
|
||||
text_segment_file_addr = text_segment_sp->GetFileAddress();
|
||||
- std::vector<llvm::StringRef> nameSlices;
|
||||
- ParseTrieEntries(dyld_trie_data, 0, is_arm, text_segment_file_addr,
|
||||
- nameSlices, resolver_addresses, reexport_trie_entries,
|
||||
+ ParseTrieEntries(dyld_trie_data, is_arm, text_segment_file_addr,
|
||||
+ resolver_addresses, reexport_trie_entries,
|
||||
external_sym_trie_entries);
|
||||
}
|
||||
|
||||
@@ -77,6 +77,10 @@ stdenv.mkDerivation (
|
||||
# Fix build with gcc15
|
||||
# https://github.com/llvm/llvm-project/commit/bb59f04e7e75dcbe39f1bf952304a157f0035314
|
||||
./lldb-add-include-cstdint.patch
|
||||
]
|
||||
++ lib.optionals (lib.versionOlder (lib.versions.major release_version) "23") [
|
||||
# Backports several fixes to export trie parsing. Otherwise, LLDB crashes when starting a debugging session on macOS 27.
|
||||
(getVersionFile "lldb/backport-ParseTrieEntries-fixes.patch")
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
|
||||
@@ -20,6 +20,17 @@
|
||||
path = ../18;
|
||||
}
|
||||
];
|
||||
"lldb/backport-ParseTrieEntries-fixes.patch" = [
|
||||
{
|
||||
before = "22";
|
||||
path = ../18;
|
||||
}
|
||||
{
|
||||
after = "22";
|
||||
before = "23";
|
||||
path = ../22;
|
||||
}
|
||||
];
|
||||
"llvm/backport-darwin-triple-parsing.patch" = [
|
||||
{
|
||||
after = "18";
|
||||
|
||||
Reference in New Issue
Block a user