Public bug reported:

1) lsb_release -rd
Description:    Ubuntu 16.04.3 LTS
Release:        16.04

2) apt-cache policy libc6
libc6:
  Installed: 2.23-0ubuntu10
  Candidate: 2.23-0ubuntu10
  Version table:
 *** 2.23-0ubuntu10 500
        500 http://archive.ubuntu.com/ubuntu xenial-updates/main amd64 Packages
        500 http://security.ubuntu.com/ubuntu xenial-security/main amd64 
Packages
        100 /var/lib/dpkg/status
     2.23-0ubuntu3 500

3) The following program fails to terminate, although it should when
compiled with no optimizations. This can be compiled with both clang and
gcc and the same behavior described happens. This doesn't seem to happen
with older versions of the library [citation needed].

Contents of 123.txt
```
AA\n
BB\n
CC
```

Code:

```
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

void h(FILE* fd) {
        (void)fd;
        pid_t p = fork();
        if(!p) {    
                exit(1);   
        } else {
                int s;
                waitpid( p, &s,0);
        } 
}  

int main() {
        FILE* fd = fopen("123.txt", "r");
        size_t cap = 20;
        ssize_t br = 0;
        char* buf = malloc(cap);
        int linecount = 0;
        while(1)  {
                br = getline( &buf , &cap, fd);
                if(br == -1) break;
                puts(buf);
                h(fd);
        }   
        free(buf);
        fclose(fd);
        return 0; 
} 
```

Expected:

```
AA  
    
BB  
    
CC  
    
```

Actual:
```
AA  
    
BB  
    
CC  
    
AA  
    
BB  
    
CC  
    
<doesn't terminate>
```


* I believe it is with how the FILE* object is being buffered and how getline 
is interacting with the buffer with a combination of fork. 
* If we change main to a syscall only version, it works as expected with the 
fork

```
int main() {
        int fd = open("123.txt", O_RDONLY);
        size_t cap = 20;
        ssize_t br = 0;
        char* buf = malloc(cap);
        int linecount = 0;
        while(1)  {
                br = read( fd , buf, cap);
                if (br == -1) break;
                buf[br] = 0;
                puts(buf);
                if (br < cap) break;
                h(fd);
        }   
        free(buf);
        close(fd);
        return 0; 
} 
```
* The `fread` version of the program terminates as expected.
* If the fork call is not there -- the program executes as normal. 
* If there is any call to `fseek(fd, 0, SEEK_CUR)` after the getline but before 
the fork, the issues goes away. Not with `ftell(fd)` though.
* If there is the same check after the fork, the file is outputted twice and 
then the program terminates.
* The issues also goes away if we set the file object to be unbuffered 
(`setvbuf(fd, NULL, _IONBF, 0);`) right after the file's opening
* Stepping through gdb, I came to an infinite cycle in 
glibc/libio/genops.c#underflow and glibc/libio/iogetdelim.c#_IO_getdelim . When 
the last line of the file is reached, an underflow calculation is done in 
iogetdelim and an execution path sets the flags of the file to _IO_EOF_SEEN, 
which getline (seems) to ignore and thinking that the file cache is invalidated 
starts over. I don't know how much this will help.

Found by: Yuxuan Ren <yre...@illinois.edu>
Confirmation Testing/Validation: Lawrence Angrave <angr...@illinois.edu>

** Affects: glibc (Ubuntu)
     Importance: Undecided
         Status: New


** Tags: getline

-- 
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/1750173

Title:
  getline doesn't terminate after fork

To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1750173/+subscriptions

-- 
ubuntu-bugs mailing list
ubuntu-bugs@lists.ubuntu.com
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs

Reply via email to