Date: Fri, 10 Aug 2001 23:29:40 +0400 From: "Andrey A. Chernov" <ache@nagual.pp.ru> To: arch@freebsd.org Cc: bugs@freebsd.org Subject: CFR: fseek<0 + feof error (with fix) Message-ID: <20010810232939.A14964@nagual.pp.ru>
next in thread | raw e-mail | index | archive | help
According to POSIX fseek{o}() description, it must return
[EINVAL]
The whence argument is invalid. The resulting file-position
indicator would be set to a negative value.
which expicetly disallows seek beyond beginning of a file. Currently we
not implement this. But this situation is worse due to additional feof()
bug in that case. Try following program with zero-sized "test" file:
#include <stdio.h>
main() {
FILE *f;
int i, c;
f = fopen("test", "r");
c = fgetc(f);
printf("c %d\n", c);
printf("feof %d\n", feof(f));
i = fseek(f, -30, 0);
printf("fseek %d\n", i);
printf("feof %d\n", feof(f));
c = fgetc(f);
printf("c %d\n", c);
printf("feof %d\n", feof(f));
}
Currently it produce following output:
c -1
feof 1
fseek 0 (must be -1, per POSIX)
feof 0 (if prev. one is 0, can be 0, but must be 1 otherwise)
c -1
feof 0 (true bug, must be 1 !!!)
I.e. if someone use
while (!feof(f)) {
c = fgetc(f);
...
}
loop after occasional negative seek, it loops forever since feof(f) will
be always 0 despite the fact that returned c == EOF. I.e. broken
fseek() broke feof() too forever (this is real life example from ARC
archiver).
Here is a patch which fix this situation and makes fseek() POSIXed in some
obvious cases like regular files (other types of files require much more
work, but partial problem fix for 99% cases is much better than no fix at
all). I plan to commit it. Please comment.
--- fseek.c.old Fri Aug 10 23:11:10 2001
+++ fseek.c Fri Aug 10 23:07:28 2001
@@ -133,11 +133,19 @@
curoff += fp->_p - fp->_bf._base;
offset += curoff;
+ if (offset < 0) {
+ errno = EINVAL;
+ return (EOF);
+ }
whence = SEEK_SET;
havepos = 1;
break;
case SEEK_SET:
+ if (offset < 0) {
+ errno = EINVAL;
+ return (EOF);
+ }
case SEEK_END:
curoff = 0; /* XXX just to keep gcc quiet */
havepos = 0;
@@ -181,6 +189,10 @@
if (_fstat(fp->_file, &st))
goto dumb;
target = st.st_size + offset;
+ if (target < 0) {
+ errno = EINVAL;
+ return (EOF);
+ }
}
if (!havepos) {
--
Andrey A. Chernov
http://ache.pp.ru/
To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010810232939.A14964>
