Skip to content

Commit bb1370a

Browse files
committed
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. (cherry picked from commit 8704635)
1 parent 2da05a0 commit bb1370a

File tree

5 files changed

+115
-5
lines changed

5 files changed

+115
-5
lines changed

Diff for: lldb/source/Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.cpp

+9-5
Original file line numberDiff line numberDiff line change
@@ -1284,6 +1284,8 @@ Status ScriptInterpreterPythonImpl::ExportFunctionDefinitionToInterpreter(
12841284
StringList &function_def) {
12851285
// Convert StringList to one long, newline delimited, const char *.
12861286
std::string function_def_string(function_def.CopyList());
1287+
LLDB_LOG(GetLog(LLDBLog::Script), "Added Function:\n%s\n",
1288+
function_def_string.c_str());
12871289

12881290
Status error = ExecuteMultipleLines(
12891291
function_def_string.c_str(),
@@ -1354,13 +1356,15 @@ Status ScriptInterpreterPythonImpl::GenerateFunction(const char *signature,
13541356
" for key in new_keys:"); // Iterate over all the keys from session
13551357
// dict
13561358
auto_generated_function.AppendString(
1357-
" internal_dict[key] = global_dict[key]"); // Update session dict
1358-
// values
1359+
" if key in old_keys:"); // If key was originally in
1360+
// global dict
13591361
auto_generated_function.AppendString(
1360-
" if key not in old_keys:"); // If key was not originally in
1361-
// global dict
1362+
" internal_dict[key] = global_dict[key]"); // Update it
13621363
auto_generated_function.AppendString(
1363-
" del global_dict[key]"); // ...then remove key/value from
1364+
" elif key in global_dict:"); // Then if it is still in the
1365+
// global dict
1366+
auto_generated_function.AppendString(
1367+
" del global_dict[key]"); // remove key/value from the
13641368
// global dict
13651369
auto_generated_function.AppendString(
13661370
" 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)