Skip to content

Commit 91be248

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 bc97405 commit 91be248

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
@@ -1286,6 +1286,8 @@ Status ScriptInterpreterPythonImpl::ExportFunctionDefinitionToInterpreter(
12861286
StringList &function_def) {
12871287
// Convert StringList to one long, newline delimited, const char *.
12881288
std::string function_def_string(function_def.CopyList());
1289+
LLDB_LOG(GetLog(LLDBLog::Script), "Added Function:\n%s\n",
1290+
function_def_string.c_str());
12891291

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