<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>