Package: libc6 Version: 2.28-5 Severity: normal Dear Maintainer,
*** Reporter, please consider answering these questions, where appropriate *** * What led up to the situation? * What exactly did you do (or not do) that was effective (or ineffective)? * What was the outcome of this action? * What outcome did you expect instead? *** End of the template - remove these template lines *** it appears that exit() flushes not only output streams but also stdin. In the case of stdin, the flush appears to be an lseek(ftell(stdin) - lseek(0, 0, SEEK_CUR), 0, SEEK_CUR); This seeks the fd 0 to the point last read in stdin by stdio functions. This becomes a problem when the program forks. Indeed after fread(buf, 4095, 1, stdin); each if (!fork()) exit(0); rewinds fd 0 by one byte. I would expect that the previous line had no effect (except some CPU time consumption). The child process does not access stdin (or fd 0) and thus it sounds reasonable that it does not change the file descriptor offset. To illustrate the behaviour, here is a sample C program ---8<------8<------8<------8<------8<------8<------8<------8<--- #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> int main(int argc, char **argv) { char buf[8192]; int type=0; if (argc > 1) type = atoi(argv[1]); fread(buf, 1024, 6, stdin); if (type && !fork()) { sleep(1); if (type >= 2) fclose(stdin); exit(0); } if (type && !fork()) { sleep(2); if (type >= 2) fclose(stdin); exit(0); } if (type && !fork()) { sleep(3); if (type >= 2) fclose(stdin); exit(0); } printf("%ld\n", lseek(0, 0, SEEK_CUR)); wait(NULL); printf("%ld\n", lseek(0, 0, SEEK_CUR)); wait(NULL); printf("%ld\n", lseek(0, 0, SEEK_CUR)); wait(NULL); printf("%ld\n", lseek(0, 0, SEEK_CUR)); exit(0); } ---8<------8<------8<------8<------8<------8<------8<------8<--- Compile it as seektest and do a dd if=/dev/zero bs=1024 count=8 of=inp. The program reads 6kb of data, (conditionally) creates three children and and exits in each one. It prints the offset of fd 0 before the first exit and after each exit. The argument modifies the behaviour of the program. If it is 0 (or absent), then there is no fork(), if 1 or 2, the program forks/exits three times and if it is 2 it fcloses(stdin) in each child before exiting. Usage: No fork: ./seektest 0 < inp 3 forks: ./seektest 1 < inp 3 forks, with fclose(stdin) before exit: ./seektest 2 < inp In the first and last case the result is 8192 8192 8192 8192 which is what I expect. In the second case one gets 8192 6144 4096 2048 which does not look correct. In addition, here is a random number generator ---8<------8<------8<------8<------8<------8<------8<------8<--- #include <stdio.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> int main(void) { pid_t pid = getpid(); char buf[4096]; signal(SIGCHLD, SIG_IGN); fread(buf, 4095, 1, stdin); fork(); fork(); fork(); fork(); fork(); fork(); fork(); fork(); fork(); if (pid == getpid()) { usleep(2000); printf("%ld\n", lseek(0, 0, SEEK_CUR)); } exit(0); } ---8<------8<------8<------8<------8<------8<------8<------8<--- that you can compile as rndseek and use with rndseek < inp (the generator is not very good as random number generator but it illustrates that the behaviour is not what one should get). -- System Information: Debian Release: buster/sid APT prefers oldoldstable-updates APT policy: (500, 'oldoldstable-updates'), (500, 'oldoldstable'), (500, 'unstable') Architecture: amd64 (x86_64) Foreign Architectures: i386 Kernel: Linux 4.12.0-2-amd64 (SMP w/8 CPU cores) Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8), LANGUAGE=fr_FR.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Init: systemd (via /run/systemd/system)