[Lldb-commits] [lldb] [lldb] Allow forks to occur in expression evaluation (PR #184815)

via lldb-commits lldb-commits at lists.llvm.org
Tue Apr 14 18:55:48 PDT 2026


jimingham wrote:

> The use case for us is to fork() the current process in an expression and then exec into a python debugger with the forked child.
> 
> So the expression does a fork and optionally an exec. In this case we probably always want to stay with the parent process as we are running an expression. Not sure we should listen to the follow fork mode for fork/vfork in expressions.
> 
> On linux, when you fork, the lldb-server will get a notification about the child process. If we following the parent, then the lldb-server needs a packet that tells it to detach from the forked child process and it will also clear any breakpoints in the child process so the forked child doesn't crash if it hits breakpoints that were set in the parent. If we are following the child, lldb-server needs to do the opposite: detach from the parent process and clear the breakpoints in that process and then switch over the becoming the GDB server for the child process.
> 
> So the ProcessGDBRemote::DidFork()/DidVFork() will send the packets down the lldb-server to do this work.
> 
> So if we run an expression that contains a fork() or vfork() we need it to be able to keep the process running and send these packets.
> 
> We both don't have much of an idea where this can and should be handled and we would like your input on where this should happen.

Note, I didn't do any of the implementation of follows-fork and since Darwin doesn't have fork notifications I've never had cause to look at that code.  

`fork` generally makes a new process and starts it off with a copy of the current thread.  That current thread has our expression frames still jammed on the end of its stack.  If you exec right away as you are supposed to, or at least never return from the code you called in the expression, then that won't matter.  But if that code actually returns, then you'll jump to _start - and after that things will probably go poorly.  That's why I was suggesting that even if you don't intend to follow the fork into the child, you manage the child running the expression to completion.  OTOH if you are ok with the restriction that the child never returns from whatever function you called that ended up forking, then you don't need to worry about that.  For realz the only thing that's actually supported if fork, mess with file handles and exec, that seems a reasonable restriction.

It strikes me as wrong that you are checking in the stop info of some thread that got a vfork event whether the process is running an expression.  For instance, I could be running the expression `sleep(100000)` and that causes us to allow all threads to run while handling the expression and then one of the other threads could call fork for an entirely unrelated reason.  In that case it would surely be wrong to override the follows fork mode in this case, and there might be other ways the fork caused by an expression needs to be handled differently from "fork that happens to happen while the expression is running."

I'm assuming the thread that forks on the parent side is the one that gets the vfork event.  So if you detect the fork in the ThreadPlanCallFunction::ShouldStop you would know whether the fork is from an expression or not?  Then you would know "fork came from expression" as opposed to "fork happened while expression was running".  Again I'm not 100% sure that difference matters but it seems like it should.

https://github.com/llvm/llvm-project/pull/184815


More information about the lldb-commits mailing list