<div dir="ltr">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 <span style="color:rgb(80,0,80);font-size:12.8px">SBDebugger.Destroy</span>() is called? What is the situation that <span style="color:rgb(80,0,80);font-size:12.8px">SBDebugger.Destroy() can be called safely?</span><div><br></div><div><div>==================do_test==================</div><div>Launch result: success</div><div><Listener> Listening Thread ID: 4660334592</div><div>WaitForEvent...</div><div>Target event: ModulesLoaded</div><div>WaitForEvent...</div><div>Process event: StateChanged, Stopped</div><div>Stop reason: 5</div><div>WaitForEvent...</div><div>Breakpoint event: [Added] SBBreakpoint: id = 1, name = 'main', locations = 1</div><div>WaitForEvent...</div><div>[main] killing listener thread</div><div> Process event: StateChanged, Running</div><div>Stop reason: 0</div><div><Listener> Exiting listener thread</div><div>[main] destroy debugger</div><div>Segmentation fault: 11</div></div><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Feb 4, 2016 at 8:22 PM, Jeffrey Tan <span dir="ltr"><<a href="mailto:jeffrey.fudan@gmail.com" target="_blank">jeffrey.fudan@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">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:<div><br></div><div><br></div><div>==========Main Thread==========</div><div><span class=""><div>def wait_for_process_stop(process):</div><div> while not process.is_stopped:</div><div> time.sleep(0.1)</div><div><br></div><div>def launch_debugging(debugger, stop_at_entry):</div><div> error = lldb.SBError()</div><div> listener = lldb.SBListener('Chrome Dev Tools Listener')</div><div> target = debugger.GetSelectedTarget()</div><div> process = target.Launch (listener,</div><div> None, # argv</div><div> None, # envp</div><div> None, # stdin_path</div><div> None, # stdout_path</div><div> None, # stderr_path</div><div> None, # working directory</div><div> 0, # launch flags</div><div> stop_at_entry, # Stop at entry</div><div> error) # error</div><div> print 'Launch result: %s' % str(error)</div></span><div> listener_thread = LLDBListenerThread(debugger)</div><div> listener_thread.start()</div><div> return listener_thread</div><span class=""><div><br></div><div>def do_test():</div><div> debugger = lldb.SBDebugger.Create()</div><div> debugger.SetAsync(True)</div></span><div> executable_path = '~/Personal/compiler/CompilerConstruction/code/compiler'</div><div> target = debugger.CreateTargetWithFileAndArch(executable_path, lldb.LLDB_ARCH_DEFAULT)</div><div><br></div><div> listener_thread = launch_debugging(debugger, stop_at_entry=True)</div><div> process = debugger.GetSelectedTarget().process</div><span class=""><div><br></div><div> wait_for_process_stop(process) # wait for entry breakpoint.</div><div> target.BreakpointCreateByName('main')</div><div> process.Continue()</div><div> wait_for_process_stop(process) # wait for main breakpoint.</div><div><br></div></span><div> listener_thread.should_quit = True</div><div> listener_thread.join()</div><span class=""><div><br></div><div> lldb.SBDebugger.Destroy(debugger)</div><div><br></div><div>def main():</div><div> do_test()</div><div> do_test()</div></span></div><div><br></div><div>==========Listening Thread==========<br></div><div><div>class LLDBListenerThread(Thread):</div><div> should_quit = False</div></div><div><br></div><div> def __init__(self, debugger):</div><div> Thread.__init__(self)</div><div> process = debugger.GetSelectedTarget().process</div><div> self.listener = debugger.GetListener()</div><div> self._add_listener_to_process(process)</div><div> self._add_listener_to_target(process.target)</div><div><br></div><div><div> def _add_listener_to_target(self, target):</div><div> # Listen for breakpoint/watchpoint events (Added/Removed/Disabled/etc).</div><div> broadcaster = target.GetBroadcaster()</div><div> mask = lldb.SBTarget.eBroadcastBitBreakpointChanged | lldb.SBTarget.eBroadcastBitWatchpointChanged | lldb.SBTarget.eBroadcastBitModulesLoaded</div><div> broadcaster.AddListener(self.listener, mask)</div><div><br></div><div> def _add_listener_to_process(self, process):</div><div> # Listen for process events (Start/Stop/Interrupt/etc).</div><div> broadcaster = process.GetBroadcaster()</div><div> mask = lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitSTDOUT | lldb.SBProcess.eBroadcastBitSTDERR | lldb.SBProcess.eBroadcastBitInterrupt</div><div> broadcaster.AddListener(self.listener, mask)</div><div><br></div><div> def run(self):</div><div> while not self.should_quit:</div><div> event = lldb.SBEvent()</div><div> print 'WaitForEvent...'</div><div> if self.listener.WaitForEvent(1, event):</div><div> if lldb.SBTarget.EventIsTargetEvent(event):</div><div> self._handle_target_event(event)</div><div> elif lldb.SBProcess.EventIsProcessEvent(event):</div><div> self._handle_process_event(event)</div><div> elif lldb.SBBreakpoint.EventIsBreakpointEvent(event):</div><div> self._handle_breakpoint_event(event)</div><div> elif lldb.SBThread.EventIsThreadEvent(event):</div><div> self._handle_thread_event(event)</div><div> else:</div><div> self._handle_unknown_event(event)</div></div><div><br></div><div>_hand_XXX_event() methods just dump some logging information of the debug events. </div><div><br></div><div><br></div><div><span class=""><div>Crashed Thread: 0 Dispatch queue: com.apple.main-thread</div><div><br></div><div>Exception Type: EXC_BAD_ACCESS (SIGSEGV)</div><div>Exception Codes: EXC_I386_GPFLT</div><div><br></div><div>Thread 0 Crashed:: Dispatch queue: com.apple.main-thread</div></span><div>0 _lldb.so <span style="white-space:pre-wrap"> </span>0x0000000111528179 EventMatcher::operator()(std::__1::shared_ptr<lldb_private::Event> const&) const + 21</div><div>1 _lldb.so <span style="white-space:pre-wrap"> </span>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</div><div>2 _lldb.so <span style="white-space:pre-wrap"> </span>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</div><div>3 _lldb.so <span style="white-space:pre-wrap"> </span>0x0000000111527ae9 lldb_private::Listener::WaitForEventForBroadcasterWithType(lldb_private::TimeValue const*, lldb_private::Broadcaster*, unsigned int, std::__1::shared_ptr<lldb_private::Event>&) + 27</div><div>4 _lldb.so <span style="white-space:pre-wrap"> </span>0x000000011171de6c lldb_private::Process::WaitForStateChangedEvents(lldb_private::TimeValue const*, std::__1::shared_ptr<lldb_private::Event>&, lldb_private::Listener*) + 112</div><div>5 _lldb.so <span style="white-space:pre-wrap"> </span>0x000000011171dc95 lldb_private::Process::WaitForProcessToStop(lldb_private::TimeValue const*, std::__1::shared_ptr<lldb_private::Event>*, bool, lldb_private::Listener*, lldb_private::Stream*) + 377</div><div>6 _lldb.so <span style="white-space:pre-wrap"> </span>0x000000011172616a lldb_private::Process::HaltForDestroyOrDetach(std::__1::shared_ptr<lldb_private::Event>&) + 216</div><div>7 _lldb.so <span style="white-space:pre-wrap"> </span>0x000000011171d8b0 lldb_private::Process::Destroy(bool) + 146</div><div>8 _lldb.so <span style="white-space:pre-wrap"> </span>0x000000011171d56d lldb_private::Process::Finalize() + 91</div><div>9 _lldb.so <span style="white-space:pre-wrap"> </span>0x00000001115173c4 lldb_private::Debugger::Clear() + 148</div><div>10 _lldb.so <span style="white-space:pre-wrap"> </span>0x00000001115171fd lldb_private::Debugger::Destroy(std::__1::shared_ptr<lldb_private::Debugger>&) + 37</div><div>11 _lldb.so <span style="white-space:pre-wrap"> </span>0x000000010f83c144 lldb::SBDebugger::Destroy(lldb::SBDebugger&) + 116</div><div>12 _lldb.so <span style="white-space:pre-wrap"> </span>0x000000010f884daf _wrap_SBDebugger_Destroy(_object*, _object*) + 120</div><div>13 org.python.python <span style="white-space:pre-wrap"> </span>0x000000010e53e75f PyEval_EvalFrameEx + 12761</div></div><div><br></div></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Feb 4, 2016 at 5:37 PM, Jim Ingham <span dir="ltr"><<a href="mailto:jingham@apple.com" target="_blank">jingham@apple.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">I don't know what:<br>
<br>
event_thread = LLDBListenerThread(debugger)<br>
<br>
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.<br>
<br>
Jim<br>
<div><div><br>
<br>
<br>
<br>
> On Feb 4, 2016, at 5:27 PM, Jeffrey Tan via lldb-dev <<a href="mailto:lldb-dev@lists.llvm.org" target="_blank">lldb-dev@lists.llvm.org</a>> wrote:<br>
><br>
> Hi,<br>
><br>
> 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?<br>
><br>
> The crash stack seems to be not consistently. In the small repro below, the crash stack is:<br>
> Crashed Thread: 0 Dispatch queue: com.apple.main-thread<br>
><br>
> Exception Type: EXC_BAD_ACCESS (SIGSEGV)<br>
> Exception Codes: EXC_I386_GPFLT<br>
><br>
> Thread 0 Crashed:: Dispatch queue: com.apple.main-thread<br>
> 0 _lldb.so 0x00000001088c7179 EventMatcher::operator()(std::__1::shared_ptr<lldb_private::Event> const&) const + 21<br>
> 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<br>
> 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<br>
> 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<br>
> 4 _lldb.so 0x0000000108abce6c lldb_private::Process::WaitForStateChangedEvents(lldb_private::TimeValue const*, std::__1::shared_ptr<lldb_private::Event>&, lldb_private::Listener*) + 112<br>
> 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<br>
> 6 _lldb.so 0x0000000108ac516a lldb_private::Process::HaltForDestroyOrDetach(std::__1::shared_ptr<lldb_private::Event>&) + 216<br>
> 7 _lldb.so 0x0000000108abc8b0 lldb_private::Process::Destroy(bool) + 146<br>
> 8 _lldb.so 0x0000000108abc56d lldb_private::Process::Finalize() + 91<br>
> 9 _lldb.so 0x00000001088b63c4 lldb_private::Debugger::Clear() + 148<br>
> 10 _lldb.so 0x00000001088b61fd lldb_private::Debugger::Destroy(std::__1::shared_ptr<lldb_private::Debugger>&) + 37<br>
> 11 _lldb.so 0x0000000106bdb144 lldb::SBDebugger::Destroy(lldb::SBDebugger&) + 116<br>
> 12 _lldb.so 0x0000000106c23daf _wrap_SBDebugger_Destroy(_object*, _object*) + 120<br>
> 13 org.python.python 0x00000001058dd75f PyEval_EvalFrameEx + 12761<br>
><br>
> while in the real unit test it is crashing at:<br>
> Thread 12 Crashed:<br>
> 0 libsystem_kernel.dylib 0x00007fff8635a286 __pthread_kill + 10<br>
> 1 libsystem_c.dylib 0x00007fff919409b3 abort + 129<br>
> 2 libc++abi.dylib 0x00007fff8a94ea21 abort_message + 257<br>
> 3 libc++abi.dylib 0x00007fff8a9769d1 default_terminate_handler() + 267<br>
> 4 libobjc.A.dylib 0x00007fff935e77eb _objc_terminate() + 124<br>
> 5 libc++abi.dylib 0x00007fff8a9740a1 std::__terminate(void (*)()) + 8<br>
> 6 libc++abi.dylib 0x00007fff8a973b30 __cxa_throw + 121<br>
> 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<br>
> 8 com.apple.LLDB.framework 0x000000010b8ac762 lldb_private::Process::AppendSTDOUT(char const*, unsigned long) + 86<br>
> 9 com.apple.LLDB.framework 0x000000010b6951d7 lldb_private::Communication::ReadThread(void*) + 287<br>
> 10 libsystem_pthread.dylib 0x00007fff8d92c05a _pthread_body + 131<br>
> 11 libsystem_pthread.dylib 0x00007fff8d92bfd7 _pthread_start + 176<br>
><br>
><br>
> ================Repro Code====================<br>
><br>
> def wait_for_process_stop(process):<br>
> while not process.is_stopped:<br>
> time.sleep(0.1)<br>
><br>
> def launch_debugging(debugger, stop_at_entry):<br>
> error = lldb.SBError()<br>
> listener = lldb.SBListener('Chrome Dev Tools Listener')<br>
> target = debugger.GetSelectedTarget()<br>
> process = target.Launch (listener,<br>
> None, # argv<br>
> None, # envp<br>
> None, # stdin_path<br>
> None, # stdout_path<br>
> None, # stderr_path<br>
> None, # working directory<br>
> 0, # launch flags<br>
> stop_at_entry, # Stop at entry<br>
> error) # error<br>
> print 'Launch result: %s' % str(error)<br>
> event_thread = LLDBListenerThread(debugger)<br>
> event_thread.start()<br>
> return process<br>
><br>
> def do_test():<br>
> debugger = lldb.SBDebugger.Create()<br>
> debugger.SetAsync(True)<br>
> target = debugger.CreateTargetWithFileAndArch(executable_path, lldb.LLDB_ARCH_DEFAULT)<br>
><br>
> process = launch_debugging(debugger, stop_at_entry=True)<br>
><br>
> wait_for_process_stop(process) # wait for entry breakpoint.<br>
> target.BreakpointCreateByName('main')<br>
> process.Continue()<br>
> wait_for_process_stop(process) # wait for main breakpoint.<br>
> lldb.SBDebugger.Destroy(debugger)<br>
><br>
> def main():<br>
> do_test()<br>
> do_test()<br>
</div></div>> _______________________________________________<br>
> lldb-dev mailing list<br>
> <a href="mailto:lldb-dev@lists.llvm.org" target="_blank">lldb-dev@lists.llvm.org</a><br>
> <a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev</a><br>
<br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div></div>