[lldb-dev] SBListener not using a shared_ptr internally? (Update: Segfault after r262863)

Jim Ingham via lldb-dev lldb-dev at lists.llvm.org
Mon Mar 28 11:22:09 PDT 2016


lldb doesn't currently work if you leave the process of cleaning up to the C++ destructor chain.  You need to call Debugger::Destroy on your way out.  

I think there's a bunch more cleanup than just the broadcaster/listener stuff before we'll do this right.

Jim

> On Mar 28, 2016, at 8:55 AM, Paul Peet <paulpeet17 at gmail.com> wrote:
> 
> Hey again,
> 
> I've noticing segfaults after r262863
> (dc5ef2da510f3adba99cd8b2fe18c2e6d417227d).
> Could you try reproducing this bug with this code please?
> 
> int main() {
>  using namespace lldb;
> 
>  SBDebugger::Initialize();
> 
>  SBDebugger debugger = SBDebugger::Create(true);
>  if(!debugger.IsValid()) {
>    return 1;
>  }
> 
>  SBTarget target = debugger.CreateTarget("/home/dev/helloWorld/main");
>  if(!target.IsValid()) {
>    return 1;
>  }
> 
>  const char* args[] = { "/home/dev/helloWorld/main", 0 };
>  const char* env[] = { 0 };
> 
>  SBLaunchInfo launch_info(args);
>  launch_info.SetEnvironmentEntries(env, true);
>  launch_info.SetWorkingDirectory("/home/dev/helloWorld");
>  launch_info.SetLaunchFlags(eLaunchFlagStopAtEntry);
> 
>  SBError error;
>  SBProcess process = target.Launch(launch_info, error);
> 
>  return 0;
> }
> 
> I tried to build lldb with and without the above commit and it turns
> out that the revision is causing the segfault when simply running that
> code (When it's exiting).
> 
> This is the backtrace:
> 
> #0  0x0000555555b03b00 in ?? ()
> #1  0x00007ffff71be1aa in
> lldb_private::Broadcaster::BroadcasterImpl::RestoreBroadcaster() ()
> from /usr/lib/liblldb.so.3.8.0
> #2  0x00007ffff748b674 in
> lldb_private::process_gdb_remote::GDBRemoteCommunicationClient::SendPacketAndWaitForResponse(char
> const*, unsigned long, StringExtractorGDBRemote&, bool) () from
> /usr/lib/liblldb.so.3.8.0
> #3  0x00007ffff748e89d in
> lldb_private::process_gdb_remote::GDBRemoteCommunicationClient::SendGDBStoppointTypePacket(lldb_private::process_gdb_remote::GDBStoppointType,
> bool, unsigned long, unsigned int) () from /usr/lib/liblldb.so.3.8.0
> #4  0x00007ffff746fdab in
> lldb_private::process_gdb_remote::ProcessGDBRemote::DisableBreakpointSite(lldb_private::BreakpointSite*)
> () from /usr/lib/liblldb.so.3.8.0
> #5  0x00007ffff733938b in std::_Function_handler<void
> (lldb_private::BreakpointSite*),
> lldb_private::Process::DisableAllBreakpointSites()::{lambda(lldb_private::BreakpointSite*)#1}>::_M_invoke(std::_Any_data
> const&, lldb_private::BreakpointSite*&&) () from
> /usr/lib/liblldb.so.3.8.0
> #6  0x00007ffff716ae4f in
> lldb_private::BreakpointSiteList::ForEach(std::function<void
> (lldb_private::BreakpointSite*)> const&) () from
> /usr/lib/liblldb.so.3.8.0
> #7  0x00007ffff733ba9f in
> lldb_private::Process::DisableAllBreakpointSites() () from
> /usr/lib/liblldb.so.3.8.0
> #8  0x00007ffff734a58c in lldb_private::Process::Destroy(bool) () from
> /usr/lib/liblldb.so.3.8.0
> #9  0x00007ffff734aa2d in lldb_private::Process::Finalize() () from
> /usr/lib/liblldb.so.3.8.0
> #10 0x00007ffff71d3fe0 in lldb_private::Debugger::Clear() () from
> /usr/lib/liblldb.so.3.8.0
> #11 0x00007ffff71d97cf in lldb_private::Debugger::~Debugger() () from
> /usr/lib/liblldb.so.3.8.0
> #12 0x00007ffff71da0c8 in
> std::_Sp_counted_ptr<lldb_private::Debugger*,
> (__gnu_cxx::_Lock_policy)2>::_M_dispose() () from
> /usr/lib/liblldb.so.3.8.0
> #13 0x00007ffff71cdceb in
> std::vector<std::shared_ptr<lldb_private::Debugger>,
> std::allocator<std::shared_ptr<lldb_private::Debugger> > >::~vector()
> () from /usr/lib/liblldb.so.3.8.0
> #14 0x00007ffff60d9c38 in __run_exit_handlers () from /usr/lib/libc.so.6
> #15 0x00007ffff60d9c85 in exit () from /usr/lib/libc.so.6
> #16 0x00007ffff60c4717 in __libc_start_main () from /usr/lib/libc.so.6
> #17 0x0000555555554f69 in _start ()
> 
> 2016-03-25 22:42 GMT+01:00 Jim Ingham <jingham at apple.com>:
>> What version of the lldb sources are you working with?  I changed the SBListener over to using only the ListenerSP internally
>> in r262863.
>> 
>> Jim
>> 
>>> On Mar 25, 2016, at 1:03 PM, Paul Peet via lldb-dev <lldb-dev at lists.llvm.org> wrote:
>>> 
>>> Hey,
>>> 
>>> I am currently working on lldb bindings for javascript (v8) but it
>>> seems that the API is giving me some troubles.
>>> 
>>> What I am doing is to basically wrap SB* objects into V8 objects, and
>>> since SB objects contain a shared_ptr into an internal class I think I
>>> can simply copy construct them.
>>> 
>>> To return a wrapped SB object by some Javascript function, I am simply
>>> copy constructing the SB object into the wrapper object which is
>>> dynamically allocated and when the Javascript object is garbage
>>> collected it will also destroy the SBObject (And also the shared_ptr,
>>> So it should be save I guess?).
>>> 
>>> Okay, so far so good but I detected some inconsistency when trying to
>>> wrap SBListener. The deal was to make SBListener::WaitForEvent
>>> non-blocking, to do that I am creating a new thread which calls
>>> WaitForEvents, when it returns and the event is valid, the callbacks
>>> given from the Javascript code is called.
>>> 
>>> There is a catch when doing this. I have to track the threads which
>>> belong to a specific SBListener. But there is not actually easy way to
>>> do this because SB objects are just simply shared_ptr. I noticed the
>>> GetSP function which returns the shared_ptr of an SBListener, this
>>> would be a way to solve this issue as I could use a map which maps the
>>> internal SBListener pointer to a Class object which manages the thread
>>> and stuff (SBListenerWorker).
>>> 
>>> // etc. mutex, ...
>>> static std::unordered_map<void*, SBListenerWorker*> ListenerWorkers;
>>> 
>>> GetSP is protected so I had to create a new derived class:
>>> 
>>> class SBListener_Internal : public lldb::SBListener {
>>> public:
>>> SBListener_Internal() = default;
>>> SBListener_Internal(const lldb::SBListener& listener)
>>>     : lldb::SBListener{listener} {
>>> }
>>> ~SBListener_Internal() = default;
>>> 
>>> void* GetInternalPtr() {
>>>   return reinterpret_cast<void*>(GetSP().get());
>>> }
>>> };
>>> 
>>> I had some worried about if the SBListener object could be destroyed
>>> at some point and the internal pointer would still be in the
>>> "ListenerWorkers" map so
>>> to avoid that I copied the the SBListener object into the class which
>>> manages the thread and stuff (SBListenerWorker), that means that the
>>> reference counter should be still > 0 when all other shared_ptrs are
>>> destroyed.
>>> 
>>> Now to the actual problem, it turns out that GetInternalPtr() actually
>>> returns nullptr and instead uses m_opaque_ptr for calling internal
>>> functions.
>>> This means that the SBListener object isn't actually using a
>>> shared_ptr internally, which brings another question up if it is save
>>> to use the SBListener across thread? What happens if the SBListener
>>> gets destroyed.
>>> _______________________________________________
>>> lldb-dev mailing list
>>> lldb-dev at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-dev
>> 



More information about the lldb-dev mailing list