[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: give_terminal_to() / maybe_give_terminal_to() race
From: |
Earl Chew |
Subject: |
Re: give_terminal_to() / maybe_give_terminal_to() race |
Date: |
Sun, 27 Aug 2023 08:17:21 -0700 |
User-agent: |
Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Thunderbird/102.14.0 |
> It is possible to demonstrate this with some effort using
> a small C program.
For completeness this is an example of a program to reproduce
the issue: DIE("tcgetpgrp"). The failure window is small, so
many iterations and a diverse host workload is required to
demonstrate the issue. Alternatively, deliberately introducing
a short delay at maybe_give_terminal_to() should reduce the
time to detection.
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
#include <sys/wait.h>
#define DIE(...) die(__LINE__, __VA_ARGS__)
void die(unsigned lineno, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
fputc('\n', stderr);
exit(1);
}
int main()
{
const char *ttyname = ctermid(0);
if (!ttyname) DIE("ctermid");
int ttyfd = open(ttyname, O_RDONLY);
if (-1 == ttyfd) DIE(ttyname);
pid_t child = fork();
if (-1 == child) DIE("fork");
if (!child) {
if (setpgid(0, 0)) DIE("setpgid");
kill(getpid(), SIGSTOP);
exit(0);
}
if (setpgid(child, child)) DIE("setpgid");
if (tcsetpgrp(ttyfd, child)) DIE("tcsetpgrp");
int status;
pid_t waited;
waited = waitpid(child, &status, WUNTRACED);
if (waited != child || !WIFSTOPPED(status)) DIE("waitpid");
struct timespec delay = {
.tv_nsec = 10000000
};
nanosleep(&delay, 0);
if (child != tcgetpgrp(ttyfd)) DIE("tcgetpgrp");
return 0;
}
Earl