Bug with fread() in CentOS 8

Introduction

I discovered a bug the other day in some old C code which appeared when the code started running on CentOS 8. I thought it was worth writing about because the same code had no issue when running on CentOS 7.

Note that this issue really has nothing to do with CentOS. It just so happens that the glibc version changed from 2.17 to 2.28 when moving from CentOS 7 to CentOS 8.

Bug Description

The crux of the issue is that in the CentOS 7 glibc version, a call to fread will return data regardless of whether the “end of file” flag is set on a FILE* variable. In newer glibc versions, a call fread will not return data unless the “end of file” flag is cleared with clearerr.

There’s not anything wrong with the new behavior, but the change can introduce subtle bugs for code which relied on the old behavior.

Example Code

I’ve written an example program which demonstrates this issue.

The test program accepts an input argument which determines whether or not the program will mitigate the bug. If the argument is true, the bug will occur. If the argument is false, the bug will be mitigated by calling clearerr between the two fread calls.

CentOS 7 Output

$ ./test true
Reading - n_read is 6 data is "HELLO " feof is true
Reading - n_read is 5 data is "HELLO WORLD" feof is true
$ ./test false
Reading - n_read is 6 data is "HELLO " feof is true
Reading - n_read is 5 data is "HELLO WORLD" feof is true

CentOS 8 Output

$ ./test true
Reading - n_read is 6 data is "HELLO " feof is true
Reading - n_read is 0 data is "HELLO " feof is true
$ ./test false
Reading - n_read is 6 data is "HELLO " feof is true
Reading - n_read is 5 data is "HELLO WORLD" feof is true