Bug 2358265 - Regression in glibc ≥ 2.41.9000-1.fc43: fclose() fails after performing fread() on a character device
Summary: Regression in glibc ≥ 2.41.9000-1.fc43: fclose() fails after performing fread...
Keywords:
Status: CLOSED RAWHIDE
Alias: None
Product: Fedora
Classification: Fedora
Component: glibc
Version: rawhide
Hardware: Unspecified
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Carlos O'Donell
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2025-04-08 13:10 UTC by Petr Pisar
Modified: 2025-04-18 13:03 UTC (History)
14 users (show)

Fixed In Version: glibc-2.41.9000-10.fc43
Clone Of:
Environment:
Last Closed: 2025-04-18 13:03:34 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)

Description Petr Pisar 2025-04-08 13:10:23 UTC
After upgrading glibc from 2.40.9000-37.fc43 to glibc-2.41.9000-1.fc43.x86_64, I experience a failure in fclose() after fread()ing from a character device:

$ cat test.c 
#include <stdio.h>
#define handle_error(msg) { perror(msg); return (1); }

int main(void) 
{
    char buf[1];
    FILE *file;

    if (!(file = fopen("/dev/zero", "rb")))
        handle_error("fopen");
    if (fread(buf, sizeof(buf[0]), 1, file) < 1)
        handle_error("fread");
    if (fclose(file))
        handle_error("fclose");
    return(0);
}

$ gcc -Wall -pedantic -O0 -g test.c 
$ ./a.out 
fclose: Invalid argument

If I replace /dev/zero with /dev/urandom, it also fails. If I replace the file name with an existing regular file, e.g. /etc/hosts, it passes. If I comment out the fread() call, it also passes.

Either I miss something obvious, or there is some bug in glibc.

It happens also with the latest glibc-2.41.9000-8.fc43.x86_64.

First I suspected kernel, but syscalls looks all right:

$ strace -v -- ./a.out 
execve("./a.out", ["./a.out"], ["SHELL=/bin/bash", "HISTCONTROL=ignoredups", "HISTSIZE=1000", "HOSTNAME=fedora-43", "GPG_TTY=/dev/pts/3", "PWD=/tmp", "LOGNAME=test", "COBBLER_SERVER=lab.rhts.englab.b"..., "HOME=/home/test", "LANG=en_US.UTF-8", "LS_COLORS=rs=0:di=01;34:ln=01;36"..., "TERM=screen.xterm-256color", "LESSOPEN=||/usr/bin/lesspipe.sh "..., "USER=test", "SHLVL=1", "PS1=\\u@\\h:\\w $ ", "DEBUGINFOD_URLS=https://debuginf"..., "DEBUGINFOD_IMA_CERT_PATH=/etc/ke"..., "PATH=/usr/local/bin:/usr/bin:/ho"..., "MAIL=/var/spool/mail/test", "OLDPWD=/home/test/fedora/csnappy"..., "_=/usr/bin/strace"]) = 0
brk(NULL)                               = 0xc757000
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f16f8947000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_dev=makedev(0xfc, 0), st_ino=133313, st_mode=S_IFREG|0644, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=96, st_size=46785, st_atime=1744117592 /* 2025-04-08T15:06:32.339597967+0200 */, st_atime_nsec=339597967, st_mtime=1744117591 /* 2025-04-08T15:06:31.203000000+0200 */, st_mtime_nsec=203000000, st_ctime=1744117591 /* 2025-04-08T15:06:31.228000000+0200 */, st_ctime_nsec=228000000}) = 0
mmap(NULL, 46785, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f16f893b000
close(3)                                = 0
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p7\0\0\0\0\0\0"..., 832) = 832
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
fstat(3, {st_dev=makedev(0xfc, 0), st_ino=171910, st_mode=S_IFREG|0755, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=4792, st_size=2444256, st_atime=1744117589 /* 2025-04-08T15:06:29.536000000+0200 */, st_atime_nsec=536000000, st_mtime=1743638400 /* 2025-04-03T02:00:00+0200 */, st_mtime_nsec=0, st_ctime=1744117589 /* 2025-04-08T15:06:29.496000000+0200 */, st_ctime_nsec=496000000}) = 0
pread64(3, "\6\0\0\0\4\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0@\0\0\0\0\0\0\0"..., 784, 64) = 784
mmap(NULL, 2034704, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f16f874a000
mmap(0x7f16f88b8000, 479232, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16e000) = 0x7f16f88b8000
mmap(0x7f16f892d000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e2000) = 0x7f16f892d000
mmap(0x7f16f8933000, 31760, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f16f8933000
close(3)                                = 0
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f16f8747000
arch_prctl(ARCH_SET_FS, 0x7f16f8747740) = 0
set_tid_address(0x7f16f8747a10)         = 40636
set_robust_list(0x7f16f8747a20, 24)     = 0
rseq(0x7f16f8747680, 0x20, 0, 0x53053053) = 0
mprotect(0x7f16f892d000, 16384, PROT_READ) = 0
mprotect(0x402000, 4096, PROT_READ)     = 0
mprotect(0x7f16f8986000, 8192, PROT_READ) = 0
prlimit64(0, RLIMIT_STACK, NULL, {rlim_cur=8192*1024, rlim_max=RLIM64_INFINITY}) = 0
munmap(0x7f16f893b000, 46785)           = 0
getrandom("\xaf\x44\xe9\x36\x66\x9d\x8b\xa7", 8, GRND_NONBLOCK) = 8
brk(NULL)                               = 0xc757000
brk(0xc778000)                          = 0xc778000
openat(AT_FDCWD, "/dev/zero", O_RDONLY) = 3
fstat(3, {st_dev=makedev(0, 0x6), st_ino=6, st_mode=S_IFCHR|0666, st_nlink=1, st_uid=0, st_gid=0, st_blksize=4096, st_blocks=0, st_rdev=makedev(0x1, 0x5), st_atime=1744094012 /* 2025-04-08T08:33:32.143370891+0200 */, st_atime_nsec=143370891, st_mtime=1744094012 /* 2025-04-08T08:33:32.143370891+0200 */, st_mtime_nsec=143370891, st_ctime=1744094012 /* 2025-04-08T08:33:32.143370891+0200 */, st_ctime_nsec=143370891}) = 0
ioctl(3, TCGETS, 0x7fffc0149950)        = -1 ENOTTY (Inappropriate ioctl for device)
read(3, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 4096) = 4096
lseek(3, 0, SEEK_CUR)                   = 0
close(3)                                = 0
dup(2)                                  = 3
fcntl(3, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
fstat(3, {st_dev=makedev(0, 0x18), st_ino=6, st_mode=S_IFCHR|0620, st_nlink=1, st_uid=0, st_gid=5, st_blksize=1024, st_blocks=0, st_rdev=makedev(0x88, 0x3), st_atime=1744117656 /* 2025-04-08T15:07:36+0200 */, st_atime_nsec=0, st_mtime=1744117656 /* 2025-04-08T15:07:36+0200 */, st_mtime_nsec=0, st_ctime=1744110065 /* 2025-04-08T13:01:05.542000000+0200 */, st_ctime_nsec=542000000}) = 0
write(3, "fclose: Invalid argument\n", 25fclose: Invalid argument
) = 25
close(3)                                = 0
exit_group(1)                           = ?
+++ exited with 1 +++

Comment 1 Florian Weimer 2025-04-08 14:58:26 UTC
I'm bisecting this.

Comment 2 Florian Weimer 2025-04-08 15:19:17 UTC
Caused by:

commit be6818be31e756398e45f70e2819d78be0961223
Author: Joseph Myers <josmyers>            
Date:   Tue Jan 28 20:22:56 2025 +0000
                    
    Make fclose seek input file to right offset (bug 12724)

I can see what is wrong and will post an upstream patch. Thanks for the report.

Comment 3 Florian Weimer 2025-04-08 17:11:00 UTC
Upstream patch posted:

[PATCH] libio: Synthesize ESPIPE error if lseek returns 0 after reading bytes
<https://inbox.sourceware.org/libc-alpha/87cydmpq0h.fsf@oldenburg.str.redhat.com/>

Comment 4 Frédéric Bérat 2025-04-18 13:03:34 UTC
The fix should have landed in Rawhide through https://bodhi.fedoraproject.org/updates/FEDORA-2025-778b706f66

Specifically:
- libio: Synthesize ESPIPE error if lseek returns 0 after reading bytes


Note You need to log in before you can comment on or make changes to this bug.