public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* ptrace and pseudoterminals
@ 2015-11-03 23:16 Pavel Labath
  2015-11-04 17:02 ` Peter Hurley
  0 siblings, 1 reply; 7+ messages in thread
From: Pavel Labath @ 2015-11-03 23:16 UTC (permalink / raw)
  To: Oleg Nesterov, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1167 bytes --]

Hello Oleg, everyone,

I have noticed something, which may be considered a race in the
interaction of ptrace and pseudoterminal interfaces. Basically, what
happens is this:
- we have two processes: A and B. B has the slave end of the pty open,
A has the master. A is tracing B.
- B writes some data through the slave end and then stops.
- A waits for B to stop.
- A does a select on the master pty endpoint. select returns there is
no data available
- later, A tries the select again, and this time the data appears.

We are encountering this (very rare) issue in our debugger test suite,
where we check the stdout of the tracee to make sure it is behaving as
expected. I have attached a small program reproducing this behavior
(it fails after about 1000 iterations on a 3.13.0 kernel, I can retry
it on a newer kernel next week if you believe it might work there).
Interestingly, when I replace the pty with a regular pipe, it works as
expected (the data is available as soon as the program stops).

My question is: Is this behavior something that you would consider a
bug? If yes, do you have any pointers, as to where I should look to
fix it?

kind regards,
pavel

[-- Attachment #2: pty.c --]
[-- Type: text/x-csrc, Size: 1628 bytes --]

#include <unistd.h>
#include <assert.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <signal.h>
#include <stdio.h>

void child(int writefd)
{
    ptrace(PTRACE_TRACEME, 0, 0, 0);
    raise(SIGSTOP);
    assert(write(writefd, "x", 1) == 1);
    raise(SIGSTOP);
}

void parent(pid_t child, int readfd)
{
    int status;
    assert(waitpid(child, &status, 0) == child);
    assert(WIFSTOPPED(status));
    assert(WSTOPSIG(status) == SIGSTOP);
    fd_set set;
    struct timeval tv;
    FD_ZERO(&set);
    FD_SET(readfd, &set);
    tv.tv_sec = 0;
    tv.tv_usec = 0;
    assert(select(readfd+1, &set, 0, 0, &tv) == 0);
    FD_ZERO(&set);
    FD_SET(readfd, &set);
    tv.tv_sec = 0;
    tv.tv_usec = 0;

    assert(ptrace(PTRACE_CONT, child, 0, 0) == 0);
    assert(waitpid(child, &status, 0) == child);
    assert(select(readfd+1, &set, 0, 0, &tv) == 1);
    kill(child, SIGKILL);
    assert(close(readfd) == 0);
    assert(waitpid(child, &status, 0) == child);
    assert(WIFSIGNALED(status));
    assert(WTERMSIG(status) == SIGKILL);
}

int main(int argc)
{
    int pipefd[2];
    int i = 0;
    for (;;)
    {
        ++i;
        if (!(i%10))
            printf("%d\n", i);
        assert(openpty(pipefd+0, pipefd+1, 0, 0) == 0);
//        assert(pipe(pipefd) == 0);
        pid_t pid = fork();
        assert(pid != -1);
        if (pid == 0)
        {
            assert(close(pipefd[0]) == 0);
            child(pipefd[1]);
            return 1;
        }
        else
        {
            assert(close(pipefd[1]) == 0);
            parent(pid, pipefd[0]);
        }
    }
    return 0;
}

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2015-11-18 10:11 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-11-03 23:16 ptrace and pseudoterminals Pavel Labath
2015-11-04 17:02 ` Peter Hurley
2015-11-04 19:43   ` Oleg Nesterov
2015-11-05 13:25     ` Peter Hurley
2015-11-05 18:35       ` Pavel Labath
2015-11-05 20:29         ` Peter Hurley
2015-11-18 10:10           ` Pavel Labath

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox