Date: Wed, 11 Oct 2006 17:30:22 GMT From: Ruslan Ermilov <ru@FreeBSD.org> To: freebsd-bugs@FreeBSD.org Subject: Re: bin/104295: freopen(NULL, ...) does bad things to file offset. Message-ID: <200610111730.k9BHUMH4085536@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/104295; it has been noted by GNATS.
From: Ruslan Ermilov <ru@FreeBSD.org>
To: trasz <trasz@pin.if.uz.zgora.p>
Cc: bug-followup@FreeBSD.org, Andrey Chernov <ache@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@FreeBSD.org
FreeBSD committer
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200610111730.k9BHUMH4085536>
