kcrash, fork, and stdout/stderr

Thiago Macieira thiago at kde.org
Mon Dec 4 04:43:14 UTC 2017


On Sunday, 3 December 2017 12:12:53 PST David Faure wrote:
> > This should already work, unless the O_CLOEXEC flag has been set on the
> > file descriptor for stderr.  The kernel should duplicate open
> > descriptors on fork(2), and exec(2) should maintain its association to
> > any already-open descriptors.
> 
> Hmm then I don't understand the SIGPIPE.

SIGPIPE is sent to the writing process whenever the write would end in EPIPE. 
That's a legacy of Unix that makes sense for command-line applications that 
should exit if the downstream pipeline closed, but in non-graphical 
applications it makes no sense. It makes zero sense to do that for sockets...

I have a pending Linux kernel patch to disable that per file descriptor, 
following OpenBSD's API.

Anyway, moving on...

> > But, which process was the one writing to the terminal?  Do we know that
> > the destination of stderr was a PTY instead of being filtered through
> > some kind of kdeinit magic?
> 
> Yes, no kdeinit involved. Here's the setup:
> 
> $ bin/kcrashtest testAutoRestartDirectly
>       starts test_crasher (with QProcess, using waitForFinished())
>           which crashes :)
>           KCrash catches that, and since the Autorestart flag is set,
>              sets the env var KCRASH_AUTO_RESTARTED,
>              and starts test_crasher again (it checks that env var, so no
> infinite loop)
> 
> The first test_crasher then exits (after waitpid(), but that's just waiting
> for the child to start, right?).

Sorry, more details here. Can you provide the strace for clone, pipe, pipe2, 
dup, dup2, dup3, execve, waitpid, waitid, wait4?

QProcess starts a process. 

Does that process start something else? Or is QProcess's direct child that 
crashes?

The crash handler is in-process, correct? Then you execve in place?

Or do you fork a child at that point? fork from inside a signal handler is an 
incredibly bad idea, don't do it.

Or does the signal handler write to another process which in turn restarts the 
process?

> Is this because QProcess set up something for catching stderr, which no
> longer exists when the process exits?

Possibly. QProcess creates a pipe for stderr and it exists only so long as the 
direct child exists. Once the child exits, QProcess closes the reading end of 
the pipe and any process that tries to write to it will get SIGPIPE.

> Oh.....
> proc.setProcessChannelMode(QProcess::ForwardedChannels);
> fixes it!

That makes QProcess not create a pipe and instead pass its own stderr to the 
child. Then it's SEP.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel Open Source Technology Center



More information about the Kde-frameworks-devel mailing list