pread()/pwrite() fail with EBADF in child process if already used before fork()

Christian Franke Christian.Franke@t-online.de
Sun Sep 22 18:09:16 GMT 2024


Found during test of 'stress-ng --pseek ...' from current upstream 
stress-ng git HEAD:

Testcase:

$ uname -r
3.5.4-1.x86_64

$ cat pfail.c
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main()
{
   int fd = open("pwrite.tmp", O_RDWR|O_CREAT|O_BINARY, 0666);
   if (fd < 0) {
     perror("open"); return 1;
   }

   char c = 42;
   if (pwrite(fd, &c, 1, 0) < 0)
     perror("pwrite");

   if (fork() == 0) {
     if (pread(fd, &c, 1, 0) < 0)
       perror("pread");
     _exit(0);
   }

   int status;
   wait(&status);
   return 0;
}

$ make pfail
cc     pfail.c   -o pfail

$ ./pfail
pread: Bad file descriptor

$ strace ./pfail
...
   617   75356 [main] pfail 10826 dofork: 10827 = fork()
    82   11289 [main] pfail 10827 seterrno_from_nt_status: 
/usr/src/debug/cygwin-3.5.4-1/winsup/cygwin/fhandler/disk_file.cc:1883 
status 0xC0000008 -> windows error 6
    80   75436 [main] pfail 10826 wait4: calling proc_subproc, pid -1, 
options 0
    76   11365 [main] pfail 10827 geterrno_from_win_error: windows error 
6 == errno 9
    78   75514 [main] pfail 10826 proc_subproc: args: 5, -7728
    64   11429 [main] pfail 10827 pread: -1 = pread(3, 0x7FFFFCC0B, 1, 
0), errno 9
...


The problem does not occur if there is no pread()/pwrite() before the 
fork(). This suggests that the child process inherits the extra handle 
value used to keep the original seek position, but not the actual handle.

-- 
Regards,
Christian



More information about the Cygwin mailing list