[Bug stdio/34335] New: fseek() deferred and ftell() wrong after fread() on character device whose .read does not advance *ppos
twied at gmx dot net via Glibc-bugs <[email protected]> Tue, 30 Jun 2026 14:56:14 +0000
| Newsgroups | gmane.comp.lib.glibc.bugs |
|---|---|
| Message-ID | <[email protected]/bugzilla/> |
https://sourceware.org/bugzilla/show_bug.cgi?id=34335
Bug ID: 34335
Summary: fseek() deferred and ftell() wrong after fread() on
character device whose .read does not advance *ppos
Product: glibc
Version: unspecified
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: stdio
Assignee: unassigned at sourceware dot org
Reporter: twied at gmx dot net
Target Milestone: ---
After fseek() + fread() on /dev/cpu/*/msr, both ftell() and lseek(fileno(f), 0,
SEEK_CUR) return wrong values. The two also disagree with each other.
The MSR driver's .read handler does not advance the kernel file position
(*ppos). This is unusual (/dev/cpu/*/cpuid, /dev/port, and /dev/nvram do
advance the file file position), but intentional.
Using raw file descriptor operations, I get the correct result:
```
int fd = open("/dev/cpu/0/msr", O_RDONLY);
lseek(fd, 0x10, SEEK_SET);
read(fd, &val, 8);
lseek(fd, 0, SEEK_CUR); // returns 0x10
```
Using stdio:
```
FILE *f = fopen("/dev/cpu/0/msr", "r");
fseek(f, 0x10, SEEK_SET);
fread(&val, 8, 1, f);
ftell(f); // returns 0x18
lseek(fileno(f), 0, SEEK_CUR); // returns 0x0
```
I am aware that calling ftell() or lseek() on a character device is unusual,
and that file position may be meaningless for some devices (serial ports,
/dev/null, etc.). The MSR driver, however, uses the file position as a register
index and supports lseek, by design.
Related LKML discussion on the MSR driver's *ppos behavior:
https://lore.kernel.org/lkml/[email protected]/
Full reproducer (needs x86 and root):
```
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
int main(void)
{
uint64_t val;
/* Raw fd: driver behaves correctly */
int fd = open("/dev/cpu/0/msr", O_RDONLY);
if (fd < 0) {
perror("/dev/cpu/0/msr");
return 1;
}
off_t pos_seek = lseek(fd, 0x10, SEEK_SET);
ssize_t n = read(fd, &val, sizeof(val));
if (n != sizeof(val)) {
perror("read");
return 1;
}
off_t pos_after = lseek(fd, 0, SEEK_CUR);
printf("Raw fd:\n");
printf(" after lseek(0x10): 0x%lx\n", (long)pos_seek);
printf(" after read(): 0x%lx\n", (long)pos_after);
close(fd);
/* stdio: both ftell and lseek return wrong values */
FILE *f = fopen("/dev/cpu/0/msr", "r");
if (!f) {
perror("/dev/cpu/0/msr");
return 1;
}
if (fseek(f, 0x10, SEEK_SET) != 0) {
perror("fseek");
return 1;
}
if (fread(&val, sizeof(val), 1, f) != 1) {
perror("fread");
return 1;
}
long pos_ftell = ftell(f);
off_t pos_lseek = lseek(fileno(f), 0, SEEK_CUR);
printf("stdio:\n");
printf(" ftell(): 0x%lx\n", pos_ftell);
printf(" lseek(SEEK_CUR): 0x%lx\n", (long)pos_lseek);
printf(" expected: 0x10\n");
fclose(f);
return 0;
}
```
Tested on glibc 2.39, kernel 6.17.10 Fedora 43 and glibc 2.42, kernel 6.19.8
Debian 14.
--
You are receiving this mail because:
You are on the CC list for the bug.