After adding some logging I figured out that the race condition is caused by process.Continue() did not guarantee process has been really resumed yet in async mode, so the second wait_for_process_stop() is skipped immediately to kill listener thread and destroying debugger. I know I have a race condition bug here because of polling for process state, but why is lldb crashing when listener thread has exited and SBDebugger.Destroy() is called? What is the situation that SBDebugger.Destroy() can be called safely?
==================do_test================== Launch result: success <Listener> Listening Thread ID: 4660334592 WaitForEvent... Target event: ModulesLoaded WaitForEvent... Process event: StateChanged, Stopped Stop reason: 5 WaitForEvent... Breakpoint event: [Added] SBBreakpoint: id = 1, name = 'main', locations = 1 WaitForEvent... [main] killing listener thread Process event: StateChanged, Running Stop reason: 0 <Listener> Exiting listener thread [main] destroy debugger Segmentation fault: 11 On Thu, Feb 4, 2016 at 8:22 PM, Jeffrey Tan <jeffrey.fu...@gmail.com> wrote: > Sorry, I have actually tried to exit the event listening thread before > debugger destroy, but still go the crash randomly(1 out of 5 runs). Here is > the code: > > > ==========Main Thread========== > def wait_for_process_stop(process): > while not process.is_stopped: > time.sleep(0.1) > > def launch_debugging(debugger, stop_at_entry): > error = lldb.SBError() > listener = lldb.SBListener('Chrome Dev Tools Listener') > target = debugger.GetSelectedTarget() > process = target.Launch (listener, > None, # argv > None, # envp > None, # stdin_path > None, # stdout_path > None, # stderr_path > None, # working directory > 0, # launch flags > stop_at_entry, # Stop at entry > error) # error > print 'Launch result: %s' % str(error) > listener_thread = LLDBListenerThread(debugger) > listener_thread.start() > return listener_thread > > def do_test(): > debugger = lldb.SBDebugger.Create() > debugger.SetAsync(True) > executable_path = > '~/Personal/compiler/CompilerConstruction/code/compiler' > target = debugger.CreateTargetWithFileAndArch(executable_path, > lldb.LLDB_ARCH_DEFAULT) > > listener_thread = launch_debugging(debugger, stop_at_entry=True) > process = debugger.GetSelectedTarget().process > > wait_for_process_stop(process) # wait for entry breakpoint. > target.BreakpointCreateByName('main') > process.Continue() > wait_for_process_stop(process) # wait for main breakpoint. > > listener_thread.should_quit = True > listener_thread.join() > > lldb.SBDebugger.Destroy(debugger) > > def main(): > do_test() > do_test() > > ==========Listening Thread========== > class LLDBListenerThread(Thread): > should_quit = False > > def __init__(self, debugger): > Thread.__init__(self) > process = debugger.GetSelectedTarget().process > self.listener = debugger.GetListener() > self._add_listener_to_process(process) > self._add_listener_to_target(process.target) > > def _add_listener_to_target(self, target): > # Listen for breakpoint/watchpoint events > (Added/Removed/Disabled/etc). > broadcaster = target.GetBroadcaster() > mask = lldb.SBTarget.eBroadcastBitBreakpointChanged | > lldb.SBTarget.eBroadcastBitWatchpointChanged | > lldb.SBTarget.eBroadcastBitModulesLoaded > broadcaster.AddListener(self.listener, mask) > > def _add_listener_to_process(self, process): > # Listen for process events (Start/Stop/Interrupt/etc). > broadcaster = process.GetBroadcaster() > mask = lldb.SBProcess.eBroadcastBitStateChanged | > lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR | > lldb.SBProcess.eBroadcastBitInterrupt > broadcaster.AddListener(self.listener, mask) > > def run(self): > while not self.should_quit: > event = lldb.SBEvent() > print 'WaitForEvent...' > if self.listener.WaitForEvent(1, event): > if lldb.SBTarget.EventIsTargetEvent(event): > self._handle_target_event(event) > elif lldb.SBProcess.EventIsProcessEvent(event): > self._handle_process_event(event) > elif lldb.SBBreakpoint.EventIsBreakpointEvent(event): > self._handle_breakpoint_event(event) > elif lldb.SBThread.EventIsThreadEvent(event): > self._handle_thread_event(event) > else: > self._handle_unknown_event(event) > > _hand_XXX_event() methods just dump some logging information of the debug > events. > > > Crashed Thread: 0 Dispatch queue: com.apple.main-thread > > Exception Type: EXC_BAD_ACCESS (SIGSEGV) > Exception Codes: EXC_I386_GPFLT > > Thread 0 Crashed:: Dispatch queue: com.apple.main-thread > 0 _lldb.so 0x0000000111528179 > EventMatcher::operator()(std::__1::shared_ptr<lldb_private::Event> const&) > const + 21 > 1 _lldb.so 0x00000001115275d2 > lldb_private::Listener::FindNextEventInternal(lldb_private::Broadcaster*, > lldb_private::ConstString const*, unsigned int, unsigned int, > std::__1::shared_ptr<lldb_private::Event>&, bool) + 176 > 2 _lldb.so 0x0000000111527952 > lldb_private::Listener::WaitForEventsInternal(lldb_private::TimeValue > const*, lldb_private::Broadcaster*, lldb_private::ConstString const*, > unsigned int, unsigned int, std::__1::shared_ptr<lldb_private::Event>&) + > 134 > 3 _lldb.so 0x0000000111527ae9 > lldb_private::Listener::WaitForEventForBroadcasterWithType(lldb_private::TimeValue > const*, lldb_private::Broadcaster*, unsigned int, > std::__1::shared_ptr<lldb_private::Event>&) + 27 > 4 _lldb.so 0x000000011171de6c > lldb_private::Process::WaitForStateChangedEvents(lldb_private::TimeValue > const*, std::__1::shared_ptr<lldb_private::Event>&, > lldb_private::Listener*) + 112 > 5 _lldb.so 0x000000011171dc95 > lldb_private::Process::WaitForProcessToStop(lldb_private::TimeValue const*, > std::__1::shared_ptr<lldb_private::Event>*, bool, lldb_private::Listener*, > lldb_private::Stream*) + 377 > 6 _lldb.so 0x000000011172616a > lldb_private::Process::HaltForDestroyOrDetach(std::__1::shared_ptr<lldb_private::Event>&) > + 216 > 7 _lldb.so 0x000000011171d8b0 > lldb_private::Process::Destroy(bool) + 146 > 8 _lldb.so 0x000000011171d56d > lldb_private::Process::Finalize() + 91 > 9 _lldb.so 0x00000001115173c4 > lldb_private::Debugger::Clear() + 148 > 10 _lldb.so 0x00000001115171fd > lldb_private::Debugger::Destroy(std::__1::shared_ptr<lldb_private::Debugger>&) > + 37 > 11 _lldb.so 0x000000010f83c144 > lldb::SBDebugger::Destroy(lldb::SBDebugger&) + 116 > 12 _lldb.so 0x000000010f884daf > _wrap_SBDebugger_Destroy(_object*, _object*) + 120 > 13 org.python.python 0x000000010e53e75f PyEval_EvalFrameEx + > 12761 > > > On Thu, Feb 4, 2016 at 5:37 PM, Jim Ingham <jing...@apple.com> wrote: > >> I don't know what: >> >> event_thread = LLDBListenerThread(debugger) >> >> does, but from your little sketch it looks like you are starting up a >> thread listening on this debugger, and so far as I can see you destroy the >> debugger out from under it without ever closing down that thread. That >> doesn't seem like a good idea. >> >> Jim >> >> >> >> >> > On Feb 4, 2016, at 5:27 PM, Jeffrey Tan via lldb-dev < >> lldb-dev@lists.llvm.org> wrote: >> > >> > Hi, >> > >> > I am revising our lldb automation tests into async mode. However, I >> found it randomly crashes depends on timing. And the crash happens mostly >> while launching lldb twice in a row. I have narrowed down the code into a >> simple repro below. Any assumption I made wrong with the LLDB API here? >> > >> > The crash stack seems to be not consistently. In the small repro below, >> the crash stack is: >> > Crashed Thread: 0 Dispatch queue: com.apple.main-thread >> > >> > Exception Type: EXC_BAD_ACCESS (SIGSEGV) >> > Exception Codes: EXC_I386_GPFLT >> > >> > Thread 0 Crashed:: Dispatch queue: com.apple.main-thread >> > 0 _lldb.so 0x00000001088c7179 >> EventMatcher::operator()(std::__1::shared_ptr<lldb_private::Event> const&) >> const + 21 >> > 1 _lldb.so 0x00000001088c65d2 >> lldb_private::Listener::FindNextEventInternal(lldb_private::Broadcaster*, >> lldb_private::ConstString const*, unsigned int, unsigned int, >> std::__1::shared_ptr<lldb_private::Event>&, bool) + 176 >> > 2 _lldb.so 0x00000001088c6952 >> lldb_private::Listener::WaitForEventsInternal(lldb_private::TimeValue >> const*, lldb_private::Broadcaster*, lldb_private::ConstString const*, >> unsigned int, unsigned int, std::__1::shared_ptr<lldb_private::Event>&) + >> 134 >> > 3 _lldb.so 0x00000001088c6ae9 >> lldb_private::Listener::WaitForEventForBroadcasterWithType(lldb_private::TimeValue >> const*, lldb_private::Broadcaster*, unsigned int, >> std::__1::shared_ptr<lldb_private::Event>&) + 27 >> > 4 _lldb.so 0x0000000108abce6c >> lldb_private::Process::WaitForStateChangedEvents(lldb_private::TimeValue >> const*, std::__1::shared_ptr<lldb_private::Event>&, >> lldb_private::Listener*) + 112 >> > 5 _lldb.so 0x0000000108abcc95 >> lldb_private::Process::WaitForProcessToStop(lldb_private::TimeValue const*, >> std::__1::shared_ptr<lldb_private::Event>*, bool, lldb_private::Listener*, >> lldb_private::Stream*) + 377 >> > 6 _lldb.so 0x0000000108ac516a >> lldb_private::Process::HaltForDestroyOrDetach(std::__1::shared_ptr<lldb_private::Event>&) >> + 216 >> > 7 _lldb.so 0x0000000108abc8b0 >> lldb_private::Process::Destroy(bool) + 146 >> > 8 _lldb.so 0x0000000108abc56d >> lldb_private::Process::Finalize() + 91 >> > 9 _lldb.so 0x00000001088b63c4 >> lldb_private::Debugger::Clear() + 148 >> > 10 _lldb.so 0x00000001088b61fd >> lldb_private::Debugger::Destroy(std::__1::shared_ptr<lldb_private::Debugger>&) >> + 37 >> > 11 _lldb.so 0x0000000106bdb144 >> lldb::SBDebugger::Destroy(lldb::SBDebugger&) + 116 >> > 12 _lldb.so 0x0000000106c23daf >> _wrap_SBDebugger_Destroy(_object*, _object*) + 120 >> > 13 org.python.python 0x00000001058dd75f >> PyEval_EvalFrameEx + 12761 >> > >> > while in the real unit test it is crashing at: >> > Thread 12 Crashed: >> > 0 libsystem_kernel.dylib 0x00007fff8635a286 __pthread_kill >> + 10 >> > 1 libsystem_c.dylib 0x00007fff919409b3 abort + 129 >> > 2 libc++abi.dylib 0x00007fff8a94ea21 abort_message >> + 257 >> > 3 libc++abi.dylib 0x00007fff8a9769d1 >> default_terminate_handler() + 267 >> > 4 libobjc.A.dylib 0x00007fff935e77eb >> _objc_terminate() + 124 >> > 5 libc++abi.dylib 0x00007fff8a9740a1 >> std::__terminate(void (*)()) + 8 >> > 6 libc++abi.dylib 0x00007fff8a973b30 __cxa_throw + >> 121 >> > 7 com.apple.LLDB.framework 0x000000010b994c6b >> std::__1::shared_ptr<lldb_private::Process>::shared_ptr<lldb_private::Process>(std::__1::weak_ptr<lldb_private::Process> >> const&, std::__1::enable_if<is_convertible<lldb_private::Process*, >> lldb_private::Process*>::value, >> std::__1::shared_ptr<lldb_private::Process>::__nat>::type) + 99 >> > 8 com.apple.LLDB.framework 0x000000010b8ac762 >> lldb_private::Process::AppendSTDOUT(char const*, unsigned long) + 86 >> > 9 com.apple.LLDB.framework 0x000000010b6951d7 >> lldb_private::Communication::ReadThread(void*) + 287 >> > 10 libsystem_pthread.dylib 0x00007fff8d92c05a _pthread_body >> + 131 >> > 11 libsystem_pthread.dylib 0x00007fff8d92bfd7 _pthread_start >> + 176 >> > >> > >> > ================Repro Code==================== >> > >> > def wait_for_process_stop(process): >> > while not process.is_stopped: >> > time.sleep(0.1) >> > >> > def launch_debugging(debugger, stop_at_entry): >> > error = lldb.SBError() >> > listener = lldb.SBListener('Chrome Dev Tools Listener') >> > target = debugger.GetSelectedTarget() >> > process = target.Launch (listener, >> > None, # argv >> > None, # envp >> > None, # stdin_path >> > None, # stdout_path >> > None, # stderr_path >> > None, # working directory >> > 0, # launch flags >> > stop_at_entry, # Stop at entry >> > error) # error >> > print 'Launch result: %s' % str(error) >> > event_thread = LLDBListenerThread(debugger) >> > event_thread.start() >> > return process >> > >> > def do_test(): >> > debugger = lldb.SBDebugger.Create() >> > debugger.SetAsync(True) >> > target = debugger.CreateTargetWithFileAndArch(executable_path, >> lldb.LLDB_ARCH_DEFAULT) >> > >> > process = launch_debugging(debugger, stop_at_entry=True) >> > >> > wait_for_process_stop(process) # wait for entry breakpoint. >> > target.BreakpointCreateByName('main') >> > process.Continue() >> > wait_for_process_stop(process) # wait for main breakpoint. >> > lldb.SBDebugger.Destroy(debugger) >> > >> > def main(): >> > do_test() >> > do_test() >> > _______________________________________________ >> > lldb-dev mailing list >> > lldb-dev@lists.llvm.org >> > http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev >> >> >
_______________________________________________ lldb-dev mailing list lldb-dev@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev