bin/104295: freopen(NULL, ...) does bad things to file offset.
Ruslan Ermilov
ru at FreeBSD.org
Wed Oct 11 10:35:48 PDT 2006
The following reply was made to PR bin/104295; it has been noted by GNATS.
From: Ruslan Ermilov <ru at FreeBSD.org>
To: trasz <trasz at pin.if.uz.zgora.p>
Cc: bug-followup at FreeBSD.org, Andrey Chernov <ache at nagual.pp.ru>
Subject: Re: bin/104295: freopen(NULL, ...) does bad things to file offset.
Date: Wed, 11 Oct 2006 21:14:44 +0400
On Wed, Oct 11, 2006 at 01:02:28PM +0000, trasz wrote:
> Freopen(3) does bad things to the file offset when supplied with NULL
> as a file path (freopen(NULL, mode, fd);). The test program below returns:
>
> file offset before freopen is 100.
> file offset after freopen is 2399.
>
It's actually the minimum of a pagesize and file size. Now we know
the size of your /etc/passwd. :-)
> #include <stdio.h>
>
> int main(void)
> {
> int ret;
> FILE *f;
>
> f=fopen("/etc/passwd", "r");
> if (f==NULL) {
> perror("fopen");
> exit(-1);
> }
>
> ret=fseek(f, 100, SEEK_CUR);
> if (ret<0) {
> perror("fseek");
> exit(-1);
> }
>
> ret=ftell(f);
> fprintf(stderr, "file offset before freopen is %d.\n", ret);
>
> f=freopen(NULL, "r", f);
> if (f==NULL) {
> perror("freopen");
> exit(-1);
> }
>
> ret=ftell(f);
> fprintf(stderr, "file offset after freopen is %d.\n", ret);
>
> return 0;
> }
>
It's only a problem when a file was initially opened read-only;
if you open it "r+" the problem doesn't show up.
I don't know the stdio code very well, but I tracked it down to
optimizations in _fseeko(); basically, freopen() calls
_fseeko(fp, 0, SEEK_SET, 0) and that's getting optimized by not
doing a real seek and simply adjusting the pointers. Later in
freopen(), these pointers get reset but the underlying file in
question stays at its old position. I've worked around this
by temporarily disabling the fseek() optimization:
%%%
Index: freopen.c
===================================================================
RCS file: /home/ncvs/src/lib/libc/stdio/freopen.c,v
retrieving revision 1.13
diff -u -p -r1.13 freopen.c
--- freopen.c 22 May 2004 15:19:41 -0000 1.13
+++ freopen.c 11 Oct 2006 17:01:00 -0000
@@ -115,6 +115,7 @@ freopen(file, mode, fp)
}
if (oflags & O_TRUNC)
ftruncate(fp->_file, 0);
+ fp->_flags |= __SNPT;
if (_fseeko(fp, 0, oflags & O_APPEND ? SEEK_END : SEEK_SET,
0) < 0 && errno != ESPIPE) {
sverrno = errno;
%%%
Someone with more stdio-fu should pick it up. Andrey?
Cheers,
--
Ruslan Ermilov
ru at FreeBSD.org
FreeBSD committer
More information about the freebsd-bugs
mailing list