Skip to content

Commit e846fb4

Browse files
authored
[lldb] Prevent passing a nullptr to std::string in ObjectFileMachO (#100421)
Prevent passing a nullptr to std::string::insert in ObjectFileMachO::GetDependentModules. Calling GetCString on an empty ConstString will return a nullptr, which is undefined behavior. Instead, use the GetString helper which will return an empty string in that case. rdar://132388027
1 parent 8b094c9 commit e846fb4

File tree

1 file changed

+104
-103
lines changed

1 file changed

+104
-103
lines changed

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Lines changed: 104 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,9 @@ using namespace lldb;
137137
using namespace lldb_private;
138138
using namespace llvm::MachO;
139139

140+
static constexpr llvm::StringLiteral g_loader_path = "@loader_path";
141+
static constexpr llvm::StringLiteral g_executable_path = "@executable_path";
142+
140143
LLDB_PLUGIN_DEFINE(ObjectFileMachO)
141144

142145
static void PrintRegisterValue(RegisterContext *reg_ctx, const char *name,
@@ -5116,123 +5119,121 @@ UUID ObjectFileMachO::GetUUID() {
51165119
}
51175120

51185121
uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
5122+
ModuleSP module_sp = GetModule();
5123+
if (!module_sp)
5124+
return 0;
5125+
51195126
uint32_t count = 0;
5120-
ModuleSP module_sp(GetModule());
5121-
if (module_sp) {
5122-
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
5123-
llvm::MachO::load_command load_cmd;
5124-
lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
5125-
std::vector<std::string> rpath_paths;
5126-
std::vector<std::string> rpath_relative_paths;
5127-
std::vector<std::string> at_exec_relative_paths;
5128-
uint32_t i;
5129-
for (i = 0; i < m_header.ncmds; ++i) {
5130-
const uint32_t cmd_offset = offset;
5131-
if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
5132-
break;
5127+
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
5128+
llvm::MachO::load_command load_cmd;
5129+
lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
5130+
std::vector<std::string> rpath_paths;
5131+
std::vector<std::string> rpath_relative_paths;
5132+
std::vector<std::string> at_exec_relative_paths;
5133+
uint32_t i;
5134+
for (i = 0; i < m_header.ncmds; ++i) {
5135+
const uint32_t cmd_offset = offset;
5136+
if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr)
5137+
break;
51335138

5134-
switch (load_cmd.cmd) {
5135-
case LC_RPATH:
5136-
case LC_LOAD_DYLIB:
5137-
case LC_LOAD_WEAK_DYLIB:
5138-
case LC_REEXPORT_DYLIB:
5139-
case LC_LOAD_DYLINKER:
5140-
case LC_LOADFVMLIB:
5141-
case LC_LOAD_UPWARD_DYLIB: {
5142-
uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
5143-
// For LC_LOAD_DYLIB there is an alternate encoding
5144-
// which adds a uint32_t `flags` field for `DYLD_USE_*`
5145-
// flags. This can be detected by a timestamp field with
5146-
// the `DYLIB_USE_MARKER` constant value.
5147-
bool is_delayed_init = false;
5148-
uint32_t use_command_marker = m_data.GetU32(&offset);
5149-
if (use_command_marker == 0x1a741800 /* DYLIB_USE_MARKER */) {
5150-
offset += 4; /* uint32_t current_version */
5151-
offset += 4; /* uint32_t compat_version */
5152-
uint32_t flags = m_data.GetU32(&offset);
5153-
// If this LC_LOAD_DYLIB is marked delay-init,
5154-
// don't report it as a dependent library -- it
5155-
// may be loaded in the process at some point,
5156-
// but will most likely not be load at launch.
5157-
if (flags & 0x08 /* DYLIB_USE_DELAYED_INIT */)
5158-
is_delayed_init = true;
5159-
}
5160-
const char *path = m_data.PeekCStr(name_offset);
5161-
if (path && !is_delayed_init) {
5162-
if (load_cmd.cmd == LC_RPATH)
5163-
rpath_paths.push_back(path);
5164-
else {
5165-
if (path[0] == '@') {
5166-
if (strncmp(path, "@rpath", strlen("@rpath")) == 0)
5167-
rpath_relative_paths.push_back(path + strlen("@rpath"));
5168-
else if (strncmp(path, "@executable_path",
5169-
strlen("@executable_path")) == 0)
5170-
at_exec_relative_paths.push_back(path +
5171-
strlen("@executable_path"));
5172-
} else {
5173-
FileSpec file_spec(path);
5174-
if (files.AppendIfUnique(file_spec))
5175-
count++;
5176-
}
5139+
switch (load_cmd.cmd) {
5140+
case LC_RPATH:
5141+
case LC_LOAD_DYLIB:
5142+
case LC_LOAD_WEAK_DYLIB:
5143+
case LC_REEXPORT_DYLIB:
5144+
case LC_LOAD_DYLINKER:
5145+
case LC_LOADFVMLIB:
5146+
case LC_LOAD_UPWARD_DYLIB: {
5147+
uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
5148+
// For LC_LOAD_DYLIB there is an alternate encoding
5149+
// which adds a uint32_t `flags` field for `DYLD_USE_*`
5150+
// flags. This can be detected by a timestamp field with
5151+
// the `DYLIB_USE_MARKER` constant value.
5152+
bool is_delayed_init = false;
5153+
uint32_t use_command_marker = m_data.GetU32(&offset);
5154+
if (use_command_marker == 0x1a741800 /* DYLIB_USE_MARKER */) {
5155+
offset += 4; /* uint32_t current_version */
5156+
offset += 4; /* uint32_t compat_version */
5157+
uint32_t flags = m_data.GetU32(&offset);
5158+
// If this LC_LOAD_DYLIB is marked delay-init,
5159+
// don't report it as a dependent library -- it
5160+
// may be loaded in the process at some point,
5161+
// but will most likely not be load at launch.
5162+
if (flags & 0x08 /* DYLIB_USE_DELAYED_INIT */)
5163+
is_delayed_init = true;
5164+
}
5165+
const char *path = m_data.PeekCStr(name_offset);
5166+
if (path && !is_delayed_init) {
5167+
if (load_cmd.cmd == LC_RPATH)
5168+
rpath_paths.push_back(path);
5169+
else {
5170+
if (path[0] == '@') {
5171+
if (strncmp(path, "@rpath", strlen("@rpath")) == 0)
5172+
rpath_relative_paths.push_back(path + strlen("@rpath"));
5173+
else if (strncmp(path, "@executable_path",
5174+
strlen("@executable_path")) == 0)
5175+
at_exec_relative_paths.push_back(path +
5176+
strlen("@executable_path"));
5177+
} else {
5178+
FileSpec file_spec(path);
5179+
if (files.AppendIfUnique(file_spec))
5180+
count++;
51775181
}
51785182
}
5179-
} break;
5180-
5181-
default:
5182-
break;
51835183
}
5184-
offset = cmd_offset + load_cmd.cmdsize;
5185-
}
5184+
} break;
51865185

5187-
FileSpec this_file_spec(m_file);
5188-
FileSystem::Instance().Resolve(this_file_spec);
5189-
5190-
if (!rpath_paths.empty()) {
5191-
// Fixup all LC_RPATH values to be absolute paths
5192-
std::string loader_path("@loader_path");
5193-
std::string executable_path("@executable_path");
5194-
for (auto &rpath : rpath_paths) {
5195-
if (llvm::StringRef(rpath).starts_with(loader_path)) {
5196-
rpath.erase(0, loader_path.size());
5197-
rpath.insert(0, this_file_spec.GetDirectory().GetCString());
5198-
} else if (llvm::StringRef(rpath).starts_with(executable_path)) {
5199-
rpath.erase(0, executable_path.size());
5200-
rpath.insert(0, this_file_spec.GetDirectory().GetCString());
5201-
}
5202-
}
5186+
default:
5187+
break;
5188+
}
5189+
offset = cmd_offset + load_cmd.cmdsize;
5190+
}
52035191

5204-
for (const auto &rpath_relative_path : rpath_relative_paths) {
5205-
for (const auto &rpath : rpath_paths) {
5206-
std::string path = rpath;
5207-
path += rpath_relative_path;
5208-
// It is OK to resolve this path because we must find a file on disk
5209-
// for us to accept it anyway if it is rpath relative.
5210-
FileSpec file_spec(path);
5211-
FileSystem::Instance().Resolve(file_spec);
5212-
if (FileSystem::Instance().Exists(file_spec) &&
5213-
files.AppendIfUnique(file_spec)) {
5214-
count++;
5215-
break;
5216-
}
5217-
}
5218-
}
5192+
FileSpec this_file_spec(m_file);
5193+
FileSystem::Instance().Resolve(this_file_spec);
5194+
5195+
if (!rpath_paths.empty()) {
5196+
// Fixup all LC_RPATH values to be absolute paths.
5197+
const std::string this_directory =
5198+
this_file_spec.GetDirectory().GetString();
5199+
for (auto &rpath : rpath_paths) {
5200+
if (llvm::StringRef(rpath).starts_with(g_loader_path))
5201+
rpath = this_directory + rpath.substr(g_loader_path.size());
5202+
else if (llvm::StringRef(rpath).starts_with(g_executable_path))
5203+
rpath = this_directory + rpath.substr(g_executable_path.size());
52195204
}
52205205

5221-
// We may have @executable_paths but no RPATHS. Figure those out here.
5222-
// Only do this if this object file is the executable. We have no way to
5223-
// get back to the actual executable otherwise, so we won't get the right
5224-
// path.
5225-
if (!at_exec_relative_paths.empty() && CalculateType() == eTypeExecutable) {
5226-
FileSpec exec_dir = this_file_spec.CopyByRemovingLastPathComponent();
5227-
for (const auto &at_exec_relative_path : at_exec_relative_paths) {
5228-
FileSpec file_spec =
5229-
exec_dir.CopyByAppendingPathComponent(at_exec_relative_path);
5206+
for (const auto &rpath_relative_path : rpath_relative_paths) {
5207+
for (const auto &rpath : rpath_paths) {
5208+
std::string path = rpath;
5209+
path += rpath_relative_path;
5210+
// It is OK to resolve this path because we must find a file on disk
5211+
// for us to accept it anyway if it is rpath relative.
5212+
FileSpec file_spec(path);
5213+
FileSystem::Instance().Resolve(file_spec);
52305214
if (FileSystem::Instance().Exists(file_spec) &&
5231-
files.AppendIfUnique(file_spec))
5215+
files.AppendIfUnique(file_spec)) {
52325216
count++;
5217+
break;
5218+
}
52335219
}
52345220
}
52355221
}
5222+
5223+
// We may have @executable_paths but no RPATHS. Figure those out here.
5224+
// Only do this if this object file is the executable. We have no way to
5225+
// get back to the actual executable otherwise, so we won't get the right
5226+
// path.
5227+
if (!at_exec_relative_paths.empty() && CalculateType() == eTypeExecutable) {
5228+
FileSpec exec_dir = this_file_spec.CopyByRemovingLastPathComponent();
5229+
for (const auto &at_exec_relative_path : at_exec_relative_paths) {
5230+
FileSpec file_spec =
5231+
exec_dir.CopyByAppendingPathComponent(at_exec_relative_path);
5232+
if (FileSystem::Instance().Exists(file_spec) &&
5233+
files.AppendIfUnique(file_spec))
5234+
count++;
5235+
}
5236+
}
52365237
return count;
52375238
}
52385239

0 commit comments

Comments
 (0)