Skip to content

Commit 7c7a90c

Browse files
committed
[lldb/Plugins] Fix method dispatch bug when using multiple scripted processes
This patch should address a bug when a user have multiple scripted processes in the same debugging session. In order for the scripted process plugin to be able to call into the scripted object instance methods to fetch the necessary data to reconstruct its state, the scripted process plugin calls into a scripted process interface, that has a reference to the created script object instance. However, prior to this patch, we only had a single instance of the scripted process interface, living the script interpreter. So every time a new scripted process plugin was created, it would overwrite the script object instance that was held by the single scripted process interface in the script interpreter. That would cause all the method calls made to the scripted process interface to be dispatched by the last instanciated script object instance, which is wrong. In order to prevent that, this patch moves the scripted process interface reference to be help by the scripted process plugin itself. rdar://104882562 Differential Revision: https://reviews.llvm.org/D143308 Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent fc34a10 commit 7c7a90c

File tree

10 files changed

+83
-84
lines changed

10 files changed

+83
-84
lines changed

lldb/include/lldb/Interpreter/ScriptInterpreter.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,10 +143,7 @@ class ScriptInterpreter : public PluginInterface {
143143
eScriptReturnTypeOpaqueObject
144144
};
145145

146-
ScriptInterpreter(
147-
Debugger &debugger, lldb::ScriptLanguage script_lang,
148-
lldb::ScriptedProcessInterfaceUP scripted_process_interface_up =
149-
std::make_unique<ScriptedProcessInterface>());
146+
ScriptInterpreter(Debugger &debugger, lldb::ScriptLanguage script_lang);
150147

151148
virtual StructuredData::DictionarySP GetInterpreterInfo();
152149

@@ -558,8 +555,8 @@ class ScriptInterpreter : public PluginInterface {
558555

559556
lldb::ScriptLanguage GetLanguage() { return m_script_lang; }
560557

561-
ScriptedProcessInterface &GetScriptedProcessInterface() {
562-
return *m_scripted_process_interface_up;
558+
virtual lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() {
559+
return std::make_unique<ScriptedProcessInterface>();
563560
}
564561

565562
lldb::DataExtractorSP
@@ -573,7 +570,6 @@ class ScriptInterpreter : public PluginInterface {
573570
protected:
574571
Debugger &m_debugger;
575572
lldb::ScriptLanguage m_script_lang;
576-
lldb::ScriptedProcessInterfaceUP m_scripted_process_interface_up;
577573
};
578574

579575
} // namespace lldb_private

lldb/include/lldb/Interpreter/ScriptedInterface.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class ScriptedInterface {
3030
StructuredData::DictionarySP args_sp,
3131
StructuredData::Generic *script_obj = nullptr) = 0;
3232

33+
StructuredData::GenericSP GetScriptObjectInstance() {
34+
return m_object_instance_sp;
35+
}
36+
3337
template <typename Ret>
3438
static Ret ErrorWithMessage(llvm::StringRef caller_name,
3539
llvm::StringRef error_msg, Status &error,

lldb/source/Interpreter/ScriptInterpreter.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,8 @@ using namespace lldb;
2727
using namespace lldb_private;
2828

2929
ScriptInterpreter::ScriptInterpreter(
30-
Debugger &debugger, lldb::ScriptLanguage script_lang,
31-
lldb::ScriptedProcessInterfaceUP scripted_process_interface_up)
32-
: m_debugger(debugger), m_script_lang(script_lang),
33-
m_scripted_process_interface_up(
34-
std::move(scripted_process_interface_up)) {}
30+
Debugger &debugger, lldb::ScriptLanguage script_lang)
31+
: m_debugger(debugger), m_script_lang(script_lang) {}
3532

3633
void ScriptInterpreter::CollectDataForBreakpointCommandCallback(
3734
std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,

lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp

Lines changed: 23 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,6 @@ bool ScriptedProcess::IsScriptLanguageSupported(lldb::ScriptLanguage language) {
4747
return llvm::is_contained(supported_languages, language);
4848
}
4949

50-
void ScriptedProcess::CheckInterpreterAndScriptObject() const {
51-
lldbassert(m_interpreter && "Invalid Script Interpreter.");
52-
lldbassert(m_script_object_sp && "Invalid Script Object.");
53-
}
54-
5550
lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
5651
lldb::ListenerSP listener_sp,
5752
const FileSpec *file,
@@ -66,8 +61,7 @@ lldb::ProcessSP ScriptedProcess::CreateInstance(lldb::TargetSP target_sp,
6661
auto process_sp = std::shared_ptr<ScriptedProcess>(
6762
new ScriptedProcess(target_sp, listener_sp, scripted_metadata, error));
6863

69-
if (error.Fail() || !process_sp || !process_sp->m_script_object_sp ||
70-
!process_sp->m_script_object_sp->IsValid()) {
64+
if (error.Fail() || !process_sp || !process_sp->m_interface_up) {
7165
LLDB_LOGF(GetLog(LLDBLog::Process), "%s", error.AsCString());
7266
return nullptr;
7367
}
@@ -92,17 +86,28 @@ ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
9286
return;
9387
}
9488

95-
m_interpreter = target_sp->GetDebugger().GetScriptInterpreter();
89+
ScriptInterpreter *interpreter =
90+
target_sp->GetDebugger().GetScriptInterpreter();
9691

97-
if (!m_interpreter) {
92+
if (!interpreter) {
9893
error.SetErrorStringWithFormat("ScriptedProcess::%s () - ERROR: %s",
9994
__FUNCTION__,
10095
"Debugger has no Script Interpreter");
10196
return;
10297
}
10398

99+
// Create process instance interface
100+
m_interface_up = interpreter->CreateScriptedProcessInterface();
101+
if (!m_interface_up) {
102+
error.SetErrorStringWithFormat(
103+
"ScriptedProcess::%s () - ERROR: %s", __FUNCTION__,
104+
"Script interpreter couldn't create Scripted Process Interface");
105+
return;
106+
}
107+
104108
ExecutionContext exe_ctx(target_sp, /*get_process=*/false);
105109

110+
// Create process script object
106111
StructuredData::GenericSP object_sp = GetInterface().CreatePluginObject(
107112
m_scripted_metadata.GetClassName(), exe_ctx,
108113
m_scripted_metadata.GetArgsSP());
@@ -113,8 +118,6 @@ ScriptedProcess::ScriptedProcess(lldb::TargetSP target_sp,
113118
"Failed to create valid script object");
114119
return;
115120
}
116-
117-
m_script_object_sp = object_sp;
118121
}
119122

120123
ScriptedProcess::~ScriptedProcess() {
@@ -147,8 +150,6 @@ Status ScriptedProcess::DoLoadCore() {
147150

148151
Status ScriptedProcess::DoLaunch(Module *exe_module,
149152
ProcessLaunchInfo &launch_info) {
150-
CheckInterpreterAndScriptObject();
151-
152153
/* FIXME: This doesn't reflect how lldb actually launches a process.
153154
In reality, it attaches to debugserver, then resume the process. */
154155
Status error = GetInterface().Launch();
@@ -168,14 +169,11 @@ Status ScriptedProcess::DoLaunch(Module *exe_module,
168169
}
169170

170171
void ScriptedProcess::DidLaunch() {
171-
CheckInterpreterAndScriptObject();
172172
m_pid = GetInterface().GetProcessID();
173173
GetLoadedDynamicLibrariesInfos();
174174
}
175175

176176
Status ScriptedProcess::DoResume() {
177-
CheckInterpreterAndScriptObject();
178-
179177
Log *log = GetLog(LLDBLog::Process);
180178
// FIXME: Fetch data from thread.
181179
const StateType thread_resume_state = eStateRunning;
@@ -198,8 +196,6 @@ Status ScriptedProcess::DoResume() {
198196
}
199197

200198
Status ScriptedProcess::DoStop() {
201-
CheckInterpreterAndScriptObject();
202-
203199
Log *log = GetLog(LLDBLog::Process);
204200

205201
if (GetInterface().ShouldStop()) {
@@ -214,18 +210,10 @@ Status ScriptedProcess::DoStop() {
214210

215211
Status ScriptedProcess::DoDestroy() { return Status(); }
216212

217-
bool ScriptedProcess::IsAlive() {
218-
if (m_interpreter && m_script_object_sp)
219-
return GetInterface().IsAlive();
220-
return false;
221-
}
213+
bool ScriptedProcess::IsAlive() { return GetInterface().IsAlive(); }
222214

223215
size_t ScriptedProcess::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
224216
Status &error) {
225-
if (!m_interpreter)
226-
return ScriptedInterface::ErrorWithMessage<size_t>(
227-
LLVM_PRETTY_FUNCTION, "No interpreter.", error);
228-
229217
lldb::DataExtractorSP data_extractor_sp =
230218
GetInterface().ReadMemoryAtAddress(addr, size, error);
231219

@@ -248,8 +236,6 @@ ArchSpec ScriptedProcess::GetArchitecture() {
248236

249237
Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
250238
MemoryRegionInfo &region) {
251-
CheckInterpreterAndScriptObject();
252-
253239
Status error;
254240
if (auto region_or_err =
255241
GetInterface().GetMemoryRegionContainingAddress(load_addr, error))
@@ -259,8 +245,6 @@ Status ScriptedProcess::DoGetMemoryRegionInfo(lldb::addr_t load_addr,
259245
}
260246

261247
Status ScriptedProcess::GetMemoryRegions(MemoryRegionInfos &region_list) {
262-
CheckInterpreterAndScriptObject();
263-
264248
Status error;
265249
lldb::addr_t address = 0;
266250

@@ -286,22 +270,9 @@ bool ScriptedProcess::DoUpdateThreadList(ThreadList &old_thread_list,
286270
// This is supposed to get the current set of threads, if any of them are in
287271
// old_thread_list then they get copied to new_thread_list, and then any
288272
// actually new threads will get added to new_thread_list.
289-
290-
CheckInterpreterAndScriptObject();
291273
m_thread_plans.ClearThreadCache();
292274

293275
Status error;
294-
ScriptLanguage language = m_interpreter->GetLanguage();
295-
296-
if (language != eScriptLanguagePython)
297-
return ScriptedInterface::ErrorWithMessage<bool>(
298-
LLVM_PRETTY_FUNCTION,
299-
llvm::Twine("ScriptInterpreter language (" +
300-
llvm::Twine(m_interpreter->LanguageToString(language)) +
301-
llvm::Twine(") not supported."))
302-
.str(),
303-
error);
304-
305276
StructuredData::DictionarySP thread_info_sp = GetInterface().GetThreadsInfo();
306277

307278
if (!thread_info_sp)
@@ -400,8 +371,6 @@ bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
400371

401372
lldb_private::StructuredData::ObjectSP
402373
ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
403-
CheckInterpreterAndScriptObject();
404-
405374
Status error;
406375
auto error_with_message = [&error](llvm::StringRef message) {
407376
return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
@@ -486,8 +455,6 @@ ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
486455
}
487456

488457
lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {
489-
CheckInterpreterAndScriptObject();
490-
491458
StructuredData::DictionarySP metadata_sp = GetInterface().GetMetadata();
492459

493460
Status error;
@@ -499,7 +466,7 @@ lldb_private::StructuredData::DictionarySP ScriptedProcess::GetMetadata() {
499466
}
500467

501468
void ScriptedProcess::UpdateQueueListIfNeeded() {
502-
CheckInterpreterAndScriptObject();
469+
CheckScriptedInterface();
503470
for (ThreadSP thread_sp : Threads()) {
504471
if (const char *queue_name = thread_sp->GetQueueName()) {
505472
QueueSP queue_sp = std::make_shared<Queue>(
@@ -510,12 +477,15 @@ void ScriptedProcess::UpdateQueueListIfNeeded() {
510477
}
511478

512479
ScriptedProcessInterface &ScriptedProcess::GetInterface() const {
513-
return m_interpreter->GetScriptedProcessInterface();
480+
CheckScriptedInterface();
481+
return *m_interface_up;
514482
}
515483

516484
void *ScriptedProcess::GetImplementation() {
517-
if (m_script_object_sp &&
518-
m_script_object_sp->GetType() == eStructuredDataTypeGeneric)
519-
return m_script_object_sp->GetAsGeneric()->GetValue();
485+
StructuredData::GenericSP object_instance_sp =
486+
GetInterface().GetScriptObjectInstance();
487+
if (object_instance_sp &&
488+
object_instance_sp->GetType() == eStructuredDataTypeGeneric)
489+
return object_instance_sp->GetAsGeneric()->GetValue();
520490
return nullptr;
521491
}

lldb/source/Plugins/Process/scripted/ScriptedProcess.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,16 @@ class ScriptedProcess : public Process {
9393
private:
9494
friend class ScriptedThread;
9595

96-
void CheckInterpreterAndScriptObject() const;
96+
inline void CheckScriptedInterface() const {
97+
lldbassert(m_interface_up && "Invalid scripted process interface.");
98+
}
99+
97100
ScriptedProcessInterface &GetInterface() const;
98101
static bool IsScriptLanguageSupported(lldb::ScriptLanguage language);
99102

100103
// Member variables.
101104
const ScriptedMetadata m_scripted_metadata;
102-
lldb_private::ScriptInterpreter *m_interpreter = nullptr;
103-
lldb_private::StructuredData::ObjectSP m_script_object_sp = nullptr;
104-
//@}
105+
lldb::ScriptedProcessInterfaceUP m_interface_up;
105106
};
106107

107108
} // namespace lldb_private

lldb/source/Plugins/Process/scripted/ScriptedThread.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ ScriptedThread::Create(ScriptedProcess &process,
3434
return llvm::createStringError(llvm::inconvertibleErrorCode(),
3535
"Invalid scripted process.");
3636

37-
process.CheckInterpreterAndScriptObject();
37+
process.CheckScriptedInterface();
3838

3939
auto scripted_thread_interface =
4040
process.GetInterface().CreateScriptedThreadInterface();

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,6 @@ ScriptInterpreterPythonImpl::ScriptInterpreterPythonImpl(Debugger &debugger)
410410
m_active_io_handler(eIOHandlerNone), m_session_is_active(false),
411411
m_pty_secondary_is_open(false), m_valid_session(true), m_lock_count(0),
412412
m_command_thread_state(nullptr) {
413-
m_scripted_process_interface_up =
414-
std::make_unique<ScriptedProcessPythonInterface>(*this);
415413

416414
m_dictionary_name.append("_dict");
417415
StreamString run_string;
@@ -1480,6 +1478,11 @@ lldb::ValueObjectListSP ScriptInterpreterPythonImpl::GetRecognizedArguments(
14801478
return ValueObjectListSP();
14811479
}
14821480

1481+
ScriptedProcessInterfaceUP
1482+
ScriptInterpreterPythonImpl::CreateScriptedProcessInterface() {
1483+
return std::make_unique<ScriptedProcessPythonInterface>(*this);
1484+
}
1485+
14831486
StructuredData::GenericSP
14841487
ScriptInterpreterPythonImpl::OSPlugin_CreatePluginObject(
14851488
const char *class_name, lldb::ProcessSP process_sp) {

lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPythonImpl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ class ScriptInterpreterPythonImpl : public ScriptInterpreterPython {
124124
GetRecognizedArguments(const StructuredData::ObjectSP &implementor,
125125
lldb::StackFrameSP frame_sp) override;
126126

127+
lldb::ScriptedProcessInterfaceUP CreateScriptedProcessInterface() override;
128+
127129
StructuredData::GenericSP
128130
OSPlugin_CreatePluginObject(const char *class_name,
129131
lldb::ProcessSP process_sp) override;

lldb/test/API/functionalities/scripted_process/TestScriptedProcess.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ def test_scripted_process_and_scripted_thread(self):
103103
id, name stop reason and register context.
104104
"""
105105
self.build()
106-
target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
107-
self.assertTrue(target, VALID_TARGET)
106+
target_0 = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
107+
self.assertTrue(target_0, VALID_TARGET)
108108

109109
os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
110110
def cleanup():
@@ -120,26 +120,50 @@ def cleanup():
120120
launch_info.SetScriptedProcessClassName("dummy_scripted_process.DummyScriptedProcess")
121121

122122
error = lldb.SBError()
123-
process = target.Launch(launch_info, error)
124-
self.assertTrue(process and process.IsValid(), PROCESS_IS_VALID)
125-
self.assertEqual(process.GetProcessID(), 42)
126-
self.assertEqual(process.GetNumThreads(), 1)
123+
process_0 = target_0.Launch(launch_info, error)
124+
self.assertTrue(process_0 and process_0.IsValid(), PROCESS_IS_VALID)
125+
self.assertEqual(process_0.GetProcessID(), 42)
126+
self.assertEqual(process_0.GetNumThreads(), 1)
127127

128-
py_impl = process.GetScriptedImplementation()
128+
py_impl = process_0.GetScriptedImplementation()
129129
self.assertTrue(py_impl)
130130
self.assertTrue(isinstance(py_impl, dummy_scripted_process.DummyScriptedProcess))
131131
self.assertFalse(hasattr(py_impl, 'my_super_secret_member'))
132132
py_impl.my_super_secret_member = 42
133133
self.assertTrue(hasattr(py_impl, 'my_super_secret_member'))
134134
self.assertEqual(py_impl.my_super_secret_method(), 42)
135135

136+
# Try reading from target #0 process ...
137+
addr = 0x500000000
138+
message = "Hello, target 0"
139+
buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
140+
self.assertSuccess(error)
141+
self.assertEqual(buff, message)
142+
143+
target_1 = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
144+
self.assertTrue(target_1, VALID_TARGET)
145+
error = lldb.SBError()
146+
process_1 = target_1.Launch(launch_info, error)
147+
self.assertTrue(process_1 and process_1.IsValid(), PROCESS_IS_VALID)
148+
self.assertEqual(process_1.GetProcessID(), 42)
149+
self.assertEqual(process_1.GetNumThreads(), 1)
150+
151+
# ... then try reading from target #1 process ...
152+
addr = 0x500000000
153+
message = "Hello, target 1"
154+
buff = process_1.ReadCStringFromMemory(addr, len(message) + 1, error)
155+
self.assertSuccess(error)
156+
self.assertEqual(buff, message)
157+
158+
# ... now, reading again from target #0 process to make sure the call
159+
# gets dispatched to the right target.
136160
addr = 0x500000000
137-
message = "Hello, world!"
138-
buff = process.ReadCStringFromMemory(addr, len(message) + 1, error)
161+
message = "Hello, target 0"
162+
buff = process_0.ReadCStringFromMemory(addr, len(message) + 1, error)
139163
self.assertSuccess(error)
140164
self.assertEqual(buff, message)
141165

142-
thread = process.GetSelectedThread()
166+
thread = process_0.GetSelectedThread()
143167
self.assertTrue(thread, "Invalid thread.")
144168
self.assertEqual(thread.GetThreadID(), 0x19)
145169
self.assertEqual(thread.GetName(), "DummyScriptedThread.thread-1")
@@ -163,5 +187,5 @@ def cleanup():
163187
self.assertEqual(idx, int(reg.value, 16))
164188

165189
self.assertTrue(frame.IsArtificial(), "Frame is not artificial")
166-
pc = frame.GetPCAddress().GetLoadAddress(target)
190+
pc = frame.GetPCAddress().GetLoadAddress(target_0)
167191
self.assertEqual(pc, 0x0100001b00)

0 commit comments

Comments
 (0)