fseek(…, …, SEEK_SET) causes reading over the skipped range
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
GLibC |
New
|
Medium
|
|||
glibc (Ubuntu) |
Fix Released
|
Undecided
|
Unassigned | ||
Bionic |
New
|
Low
|
Unassigned | ||
Focal |
Fix Released
|
Undecided
|
Unassigned |
Bug Description
When fseek is called, it calls in turn 1. lseek(), and 2. read(). In glibc 2.29 (maybe earlier) read() is only called for the last block. However in glibc 2.27 Ubuntu 18.04 is using, the read happens over the whole skipped range, which may cause a hang of an app that tries to skip too big range.
There's is a related report: https:/
# Steps to reproduce
In command below, replace `/dev/sda` if necessary with a device that is at least 2 GB in size.
Run `sudo hexdump -C /dev/sda -s 0x80000000 -n 1`. This command uses `hexdump` to print content of a disk at a large offset.
## Expected
The command returns immediately with a print
## Actual
The command hangs with high CPU load. If you use `strace hexdump …`, you'll see there a bunch of reads happens. These reads arise from glibc 2.27 implementation of `fseek()`.
Changed in glibc: | |
importance: | Unknown → Medium |
status: | Unknown → New |
When fseek called, it in turn calls lseek (as expected), and then calls read() over the skipped range (as not expected). In the best case, it's a waste of CPU and IO resources. In the worst case, this causes an application that tried to skip too big range to just hang on fseek().
This is a follow up to discussion at https:/ /sourceware. org/ml/ libc-help/ 2020-01/ threads. html#00046
# Steps to reproduce (in terms of terminal commands)
$ cat test.c
#include <fcntl.h>
#include <stdio.h>
int main() { /tmp/test. c", "r");
perror( ""); 0x7fd2c36c1000, 4096, PROT_READ) = 0 0x7fd2c3628000, 451693) = 0 0x557c9e921000) = 0x557c9e921000 AT_FDCWD, "/tmp/test.c", O_RDONLY) = 3 S_IFREG| 0644, st_size=155, ...}) = 0
FILE* f = fopen("
if (!f)
fseek(f, 30, SEEK_SET);
}
$ gcc test.c -o a
$ strace ./a 2>&1 | tail
mprotect(
munmap(
brk(NULL) = 0x557c9e900000
brk(
openat(
fstat(3, {st_mode=
lseek(3, 0, SEEK_SET) = 0
read(3, "#include <fcntl.h>\n#include <s", 30) = 30
exit_group(0) = ?
+++ exited with
## Expected
There's no read() call after lseek()
## Actual
Both lseek() and read() are called.