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)

Reply via email to