jimingham c21cd52fab
Fix a crash when a stop hook deletes itself in its callback. (#160416)
We're iterating over the stop hooks so if one of them changes the stop
hook list by deleting itself or another stop hook, that invalidates our
iterator.

I chose to fix this by making a copy of the stop hook list and iterating
over that. That's a cheap operation since this is just an array of
shared pointers. But more importantly doing it this way means that if on
a stop where one stop hook deletes another, the deleted hook will always
get a chance to run. If you iterated over the list itself, then whether
that to be deleted hook gets to run would be dependent on whether it was
before or after the deleting stop hook, which would be confusing.
2025-11-07 11:38:57 -08:00

76 lines
2.3 KiB
Python

import lldb
class stop_handler:
def __init__(self, target, extra_args, dict):
self.extra_args = extra_args
self.target = target
self.counter = 0
ret_val = self.extra_args.GetValueForKey("return_false")
if ret_val:
self.ret_val = False
else:
self.ret_val = True
def handle_stop(self, exe_ctx, stream):
self.counter += 1
stream.Print("I have stopped %d times.\n" % (self.counter))
increment = 1
value = self.extra_args.GetValueForKey("increment")
if value:
increment = value.GetUnsignedIntegerValue()
else:
stream.Print("Could not find increment in extra_args\n")
frame = exe_ctx.GetFrame()
expression = "g_var += %d" % (increment)
expr_result = frame.EvaluateExpression(expression)
if not expr_result.GetError().Success():
stream.Print(
"Error running expression: %s" % (expr_result.GetError().GetCString())
)
value = exe_ctx.target.FindFirstGlobalVariable("g_var")
if not value.IsValid():
stream.Print("Didn't get a valid value for g_var.")
else:
int_val = value.GetValueAsUnsigned()
stream.Print("Returning value: %d from handle_stop.\n" % (self.ret_val))
return self.ret_val
class bad_handle_stop:
def __init__(self, target, extra_args, dict):
print("I am okay")
def handle_stop(self):
print("I am bad")
class no_handle_stop:
def __init__(self, target, extra_args, dict):
print("I am okay")
class self_deleting_stop:
def __init__(self, target, extra_args, dict):
self.target = target
def handle_stop(self, exe_ctx, stream):
interp = exe_ctx.target.debugger.GetCommandInterpreter()
result = lldb.SBCommandReturnObject()
interp.HandleCommand("handle_id", result)
id_str = result.GetOutput().rstrip()
command = f"target stop-hook delete {id_str}"
interp.HandleCommand(command, result)
stop_hook_id = 0
def handle_stop_hook_id(debugger, command, exe_ctx, result, extra_args):
global stop_hook_id
if command == "":
result.AppendMessage(str(stop_hook_id))
else:
stop_hook_id = int(command)