Skip to content

Commit 8704635

Browse files
authored
Fix the managing of the session dictionary when you have nested wrappers (llvm#132846)
Since the inner wrapper call might have removed one of the entries from the global dict that the outer wrapper ALSO was going to delete, make sure that we check that the key is still in the global dict before trying to act on it.
1 parent 0919ab3 commit 8704635

File tree

5 files changed

+115
-5
lines changed

5 files changed

+115
-5
lines changed

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

+9-5
Original file line numberDiff line numberDiff line change
@@ -1267,6 +1267,8 @@ Status ScriptInterpreterPythonImpl::ExportFunctionDefinitionToInterpreter(
12671267
StringList &function_def) {
12681268
// Convert StringList to one long, newline delimited, const char *.
12691269
std::string function_def_string(function_def.CopyList());
1270+
LLDB_LOG(GetLog(LLDBLog::Script), "Added Function:\n%s\n",
1271+
function_def_string.c_str());
12701272

12711273
Status error = ExecuteMultipleLines(
12721274
function_def_string.c_str(), ExecuteScriptOptions().SetEnableIO(false));
@@ -1336,13 +1338,15 @@ Status ScriptInterpreterPythonImpl::GenerateFunction(const char *signature,
13361338
" for key in new_keys:"); // Iterate over all the keys from session
13371339
// dict
13381340
auto_generated_function.AppendString(
1339-
" internal_dict[key] = global_dict[key]"); // Update session dict
1340-
// values
1341+
" if key in old_keys:"); // If key was originally in
1342+
// global dict
13411343
auto_generated_function.AppendString(
1342-
" if key not in old_keys:"); // If key was not originally in
1343-
// global dict
1344+
" internal_dict[key] = global_dict[key]"); // Update it
13441345
auto_generated_function.AppendString(
1345-
" del global_dict[key]"); // ...then remove key/value from
1346+
" elif key in global_dict:"); // Then if it is still in the
1347+
// global dict
1348+
auto_generated_function.AppendString(
1349+
" del global_dict[key]"); // remove key/value from the
13461350
// global dict
13471351
auto_generated_function.AppendString(
13481352
" return __return_val"); // Return the user callback return value.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
C_SOURCES := main.c
2+
CFLAGS_EXTRAS := -std=c99
3+
4+
include Makefile.rules
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
"""
2+
Test that a Python breakpoint callback defined in another Python
3+
breakpoint callback works properly.
4+
"""
5+
6+
7+
import lldb
8+
import os
9+
import lldbsuite.test.lldbutil as lldbutil
10+
from lldbsuite.test.lldbtest import *
11+
12+
13+
class TestNestedBreakpointCommands(TestBase):
14+
NO_DEBUG_INFO_TESTCASE = True
15+
16+
def test_nested_commands(self):
17+
self.build()
18+
self.main_source_file = lldb.SBFileSpec("main.c")
19+
self.callback_module = "make_bkpt_cmds"
20+
self.do_test()
21+
22+
def do_test(self):
23+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
24+
self, "Set a breakpoint here", self.main_source_file
25+
)
26+
27+
outer_bkpt = target.BreakpointCreateBySourceRegex(
28+
"Set outer breakpoint here", self.main_source_file
29+
)
30+
cmd_file_path = os.path.join(self.getSourceDir(), f"{self.callback_module}.py")
31+
self.runCmd(f"command script import {cmd_file_path}")
32+
outer_bkpt.SetScriptCallbackFunction(f"{self.callback_module}.outer_callback")
33+
34+
process.Continue()
35+
36+
self.assertEqual(
37+
thread.stop_reason, lldb.eStopReasonBreakpoint, "Right stop reason"
38+
)
39+
40+
bkpt_no = thread.stop_reason_data[0]
41+
42+
# We made the callbacks record the new breakpoint ID and the number of
43+
# times a callback ran in some globals in the target. Find them now:
44+
exec_module = target.FindModule(target.executable)
45+
self.assertTrue(exec_module.IsValid(), "Found executable module")
46+
var = exec_module.FindFirstGlobalVariable(target, "g_global")
47+
self.assertSuccess(var.GetError(), "Found globals")
48+
num_hits = var.GetChildAtIndex(1).GetValueAsUnsigned()
49+
inner_id = var.GetChildAtIndex(2).GetValueAsUnsigned()
50+
51+
# Make sure they have the right values:
52+
self.assertEqual(bkpt_no, inner_id, "Hit the right breakpoint")
53+
self.assertEqual(num_hits, 2, "Right counter end value")
54+
self.assertEqual(thread.frames[0].name, "main", "Got to main")
55+
56+
self.assertEqual(outer_bkpt.GetHitCount(), 1, "Hit outer breakpoint once")
57+
58+
inner_bkpt = target.FindBreakpointByID(inner_id)
59+
self.assertEqual(inner_bkpt.GetHitCount(), 1, "Hit inner breakpoint once")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#include <stdio.h>
2+
3+
int g_global[3] = {0, 100000, 100000};
4+
5+
void doSomething() {
6+
g_global[0] = 1; // Set outer breakpoint here
7+
}
8+
9+
int main() {
10+
doSomething(); // Set a breakpoint here
11+
12+
return g_global[0];
13+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import lldb
2+
3+
4+
def set_globals(target, index, value):
5+
exe_module = target.FindModule(target.executable)
6+
var = exe_module.FindFirstGlobalVariable(target, "g_global")
7+
child = var.GetChildAtIndex(index)
8+
child.SetValueFromCString(str(value))
9+
10+
11+
def outer_callback(frame: lldb.SBFrame, bp_loc, internal_dict):
12+
thread = frame.GetThread()
13+
14+
# address of the next frame
15+
next_frame_pc = thread.get_thread_frames()[1].GetPC()
16+
17+
target = thread.process.target
18+
bp = target.BreakpointCreateByAddress(next_frame_pc)
19+
bp.SetScriptCallbackFunction(f"{__name__}.nested_bp_callback")
20+
set_globals(target, 1, 1)
21+
set_globals(target, 2, bp.GetID())
22+
23+
return False
24+
25+
26+
def nested_bp_callback(frame: lldb.SBFrame, bp_loc, extra_args, internal_dict):
27+
target = frame.thread.process.target
28+
set_globals(target, 1, 2)
29+
30+
return True

0 commit comments

Comments
 (0)