On Sun, Dec 11, 2022 at 04:10:41PM -0800, Jeremy Mates wrote:
>      ...
>      42136 ex       RET   read -1 errno 35 Resource temporarily unavailable
>      42136 ex       CALL  read(0,0x3d94b585400,0xff)
>      42136 ex       RET   read -1 errno 35 Resource temporarily unavailable
>      42136 ex       CALL  read(0,0x3d94b585400,0xff)
>      ...
>  
> this condition can be reproduced with:
> 
>       #include <sys/wait.h>
>       #include <err.h>
>       #include <fcntl.h>
>       #include <stdlib.h>
>       #include <unistd.h>
>       #define TARGET_FD STDIN_FILENO
>       int main(int argc, char *argv[]) {
>               int flags, status;
>               pid_t pid;
>               pid = fork();
>               if (pid < 0) err(1, "fork failed");
>               if (pid == 0) {
>                       flags = fcntl(TARGET_FD, F_GETFL, 0);
>                       if (flags == -1) err(1, "fcntl getfl failed");
>                       flags |= O_NONBLOCK;
>                       flags = fcntl(TARGET_FD, F_SETFL, flags);
>                       if (flags == -1) err(1, "fcntl setfl failed");
>                       argv++;
>                       execvp(*argv, argv);
>                       err(1, "execvp failed");
>               }
>               wait(&status);
>               exit(0);
>       }
> 
> and then running whatever-the-above-was-compiled-to as
> 
>     ./whatever /usr/bin/ex
> 
> or also under modern code that for some reason sets O_NONBLOCK and
> forgets to turn it off when calling out to an editor, hypothetically
> 
> https://github.com/osa1/tiny
> 
> and likely other, similar programs. Probably, O_NONBLOCK should be
> disabled on STDIN_FILENO before calling out to unknown programs.
> Probably, vi should be patched to not eat CPU when the previous case is
> not handled.
> 
> Thoughts?

I think this is the wrong way around. The callers need to be fixed to pass
a blocking stdin to programs since that is what every unix utility
expects. What you propose it to fix every unix utility to have such a check
at the start of main. Sorry but no.
 
> diff --git usr.bin/vi/cl/cl_main.c usr.bin/vi/cl/cl_main.c
> index 33614c99594..f87a04cad8b 100644
> --- usr.bin/vi/cl/cl_main.c
> +++ usr.bin/vi/cl/cl_main.c
> @@ -54,7 +54,7 @@ main(int argc, char *argv[])
>       CL_PRIVATE *clp;
>       GS *gp;
>       size_t rows, cols;
> -     int rval;
> +     int flags, oflags, rval;
>       char *ttype;
>  
>       /* Create and initialize the global structure. */
> @@ -89,6 +89,14 @@ main(int argc, char *argv[])
>       /* Ex wants stdout to be buffered. */
>       (void)setvbuf(stdout, NULL, _IOFBF, 0);
>  
> +     /* Ensure blocking I/O to avoid 100% CPU on EAGAIN */
> +     if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) == -1)
> +             exit (1);
> +     oflags = flags;
> +     flags &= ~O_NONBLOCK;
> +     if (fcntl(STDIN_FILENO, F_SETFL, flags) == -1)
> +             exit (1);
> +
>       /* Start catching signals. */
>       if (sig_init(gp, NULL))
>               exit (1);
> @@ -102,6 +110,9 @@ main(int argc, char *argv[])
>       /* Clean up the terminal. */
>       (void)cl_quit(gp);
>  
> +     /* Restore flags */
> +     fcntl(STDIN_FILENO, F_SETFL, oflags);
> +
>       /*
>        * XXX
>        * Reset the O_MESG option.
> 

-- 
:wq Claudio

Reply via email to