[Lldb-commits] [lldb] [lldb] Guard stale SBProcess target access (PR #192842)
via lldb-commits
lldb-commits at lists.llvm.org
Sun Apr 19 04:21:04 PDT 2026
https://github.com/sfu2 updated https://github.com/llvm/llvm-project/pull/192842
>From 14bf8a77cccf112a6ace39022b387eb5d06e7fae Mon Sep 17 00:00:00 2001
From: sfu <shuhaofu.g at gmail.com>
Date: Sun, 19 Apr 2026 19:20:17 +0800
Subject: [PATCH] lldb: guard stale SBProcess target access
SBSaveCoreOptions can retain a ProcessSP after DeleteTarget destroys
the Target, leaving Process with a weak_ptr<Target> whose pointee has
already been destroyed. Stale SBProcess handles then reach through
Process::GetTarget() and crash while dereferencing that expired target
relationship.
Add a nullable Process::GetTargetSP() helper for SB API callers, use it
to make SBProcess::GetTarget() return an invalid target and make
SBProcess::SaveCore() fail with an error when the target has already been
deleted. Add an API regression test that keeps a core-backed process
alive through SBSaveCoreOptions, deletes the target, and verifies both
paths fail safely instead of crashing.
---
lldb/include/lldb/Target/Process.h | 5 +
lldb/source/API/SBProcess.cpp | 23 ++--
lldb/unittests/API/CMakeLists.txt | 1 +
.../API/SBProcessDeleteTargetTest.cpp | 101 ++++++++++++++++++
4 files changed, 123 insertions(+), 7 deletions(-)
create mode 100644 lldb/unittests/API/SBProcessDeleteTargetTest.cpp
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 19b5ae3041826..ca53f4633f4d5 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1244,6 +1244,11 @@ class Process : public std::enable_shared_from_this<Process>,
/// Get the target object pointer for this module.
///
+ /// \return
+ /// A Target object pointer to the target that owns this
+ /// module.
+ lldb::TargetSP GetTargetSP() const { return m_target_wp.lock(); }
+
/// \return
/// A Target object pointer to the target that owns this
/// module.
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index 14ce236b4f1b5..ca8d2100f4075 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -241,12 +241,15 @@ SBTarget SBProcess::GetTarget() const {
LLDB_INSTRUMENT_VA(this);
SBTarget sb_target;
- TargetSP target_sp;
ProcessSP process_sp(GetSP());
- if (process_sp) {
- target_sp = process_sp->GetTarget().shared_from_this();
- sb_target.SetSP(target_sp);
- }
+ if (!process_sp)
+ return sb_target;
+
+ TargetSP target_sp = process_sp->GetTargetSP();
+ if (!target_sp)
+ return sb_target;
+
+ sb_target.SetSP(target_sp);
return sb_target;
}
@@ -1274,8 +1277,14 @@ lldb::SBError SBProcess::SaveCore(SBSaveCoreOptions &options) {
return error;
}
- std::lock_guard<std::recursive_mutex> guard(
- process_sp->GetTarget().GetAPIMutex());
+ TargetSP target_sp = process_sp->GetTargetSP();
+ if (!target_sp) {
+ error = Status::FromErrorString(
+ "SBProcess is invalid because its target has been deleted");
+ return error;
+ }
+
+ std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
if (process_sp->GetState() != eStateStopped) {
error = Status::FromErrorString("the process is not stopped");
diff --git a/lldb/unittests/API/CMakeLists.txt b/lldb/unittests/API/CMakeLists.txt
index b86054fb353f7..19a6302021d8e 100644
--- a/lldb/unittests/API/CMakeLists.txt
+++ b/lldb/unittests/API/CMakeLists.txt
@@ -3,6 +3,7 @@ add_lldb_unittest(APITests
SBLineEntryTest.cpp
SBMutexTest.cpp
SBBreakpointClearConditionTest.cpp
+ SBProcessDeleteTargetTest.cpp
SBAPITEST
diff --git a/lldb/unittests/API/SBProcessDeleteTargetTest.cpp b/lldb/unittests/API/SBProcessDeleteTargetTest.cpp
new file mode 100644
index 0000000000000..0decbd6d0b371
--- /dev/null
+++ b/lldb/unittests/API/SBProcessDeleteTargetTest.cpp
@@ -0,0 +1,101 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Use the umbrella header for -Wdocumentation.
+#include "lldb/API/LLDB.h"
+
+#include "TestingSupport/SubsystemRAII.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "gtest/gtest.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+class SBProcessDeleteTargetTest : public testing::Test {
+protected:
+ void SetUp() override {
+ debugger = SBDebugger::Create(/*source_init_files=*/false);
+ }
+
+ void TearDown() override { SBDebugger::Destroy(debugger); }
+
+ static bool DebuggerSupportsLLVMTarget(llvm::StringRef target) {
+ SBStructuredData data = SBDebugger::GetBuildConfiguration()
+ .GetValueForKey("targets")
+ .GetValueForKey("value");
+ for (size_t i = 0; i < data.GetSize(); ++i) {
+ char buf[100] = {0};
+ size_t size = data.GetItemAtIndex(i).GetStringValue(buf, sizeof(buf));
+ if (llvm::StringRef(buf, size) == target)
+ return true;
+ }
+ return false;
+ }
+
+ static std::string GetCoreFixturePath(llvm::StringRef name) {
+ llvm::SmallString<256> path(__FILE__);
+ llvm::sys::path::remove_filename(path);
+ llvm::sys::path::append(path, "..", "..", "test", "API");
+ llvm::sys::path::append(path, "tools", "lldb-dap", "coreFile", name);
+ return std::string(path.str());
+ }
+
+ void LoadCore(SBTarget &target, SBProcess &process) {
+ std::string binary_path = GetCoreFixturePath("linux-x86_64.out");
+ std::string core_path = GetCoreFixturePath("linux-x86_64.core");
+ ASSERT_TRUE(llvm::sys::fs::exists(binary_path));
+ ASSERT_TRUE(llvm::sys::fs::exists(core_path));
+
+ SBError error;
+ target = debugger.CreateTarget(binary_path.c_str(), /*target_triple=*/"",
+ /*platform_name=*/"",
+ /*add_dependent_modules=*/false, error);
+ EXPECT_TRUE(target);
+ EXPECT_TRUE(error.Success()) << error.GetCString();
+ debugger.SetSelectedTarget(target);
+
+ process = target.LoadCore(core_path.c_str());
+ EXPECT_TRUE(process);
+ }
+
+ SubsystemRAII<lldb::SBDebugger> subsystems;
+ SBDebugger debugger;
+};
+
+} // namespace
+
+TEST_F(SBProcessDeleteTargetTest, GetTargetAndSaveCoreFailSafelyAfterDelete) {
+ if (!DebuggerSupportsLLVMTarget("X86"))
+ GTEST_SKIP() << "X86 target is not enabled";
+
+ SBTarget target;
+ SBProcess process;
+ LoadCore(target, process);
+ ASSERT_TRUE(target.IsValid());
+ ASSERT_TRUE(process.IsValid());
+ ASSERT_EQ(process.GetState(), eStateStopped);
+
+ SBSaveCoreOptions options;
+ options.SetProcess(process);
+
+ ASSERT_TRUE(debugger.DeleteTarget(target));
+ ASSERT_FALSE(target.IsValid());
+ EXPECT_FALSE(process.IsValid());
+
+ EXPECT_FALSE(process.GetTarget().IsValid());
+
+ SBError error = process.SaveCore(options);
+ EXPECT_TRUE(error.Fail());
+ EXPECT_STREQ("SBProcess is invalid because its target has been deleted",
+ error.GetCString());
+}
More information about the lldb-commits
mailing list