There is indeed something wrong here.
I have rewritten your code to the essentials, to be able to check (a)
whether the length of the file matters, (b) ensure none of the fseek,
ftell, fgetc and ungetc functions reports an error before fclose
crashes. The code is attached.
The command I used to compile and execute the code is
gcc $CFLAGS -o foo foo.c && ./foo; echo "return: $?"
CFLAGS is a sequence of flags used to conditionally include parts of the
code.
To see that the length of the file is insignificant, include -DNEW
-DLENGTH=n in CFLAGS, with variable n. (Note, if the file is shorter
than 2 characters AND you do not include both UNGETC and SEEKSET in
CFLAGS, there will be a checked runtime failure with return code 12 (the
second fgetc fails). That's insubstantial here.)
When I compile the code with CFLAGS="" (no flags), the execution
succeeds (return value is 0).
Likewise when CFLAGS="-DUNGETC" (unget the first character).
Likewise CFLAGS="-DSEEKEND" (seek to the end after open).
Likewise CFLAGS="-DSEEKSET" (seek to the start before second fgetc).
Likewise in all combinations of two of the three flags.
In all these cases, the output from printf is as expected.
However, with CFLAGS="-DSEEKEND -DSEEKSET -DUNGETC" (ungetc and both
seeks), the program apparently crashes. The return value is 134, and an
invalid pointer error from free() is reported, similar to the one Stefan
got, see below.
The output from printf reveals that after ungetc and seek to start, the
position is negative (the actual value depends on the length N of the
file, and is precisely 1 - N). This happens for N > 2. (So for N = 3,
the third position reported is -2, etc.)
When N = 2, the execution fails with return code 11 (position after seek
to start is EOF).
For N < 2, the execution fails as for N > 2 (dump, return 134), BUT this
time it does not happen on fclose, but on the second fgetc (modify the
code to convince yourself).
What is more fancy, is that if you add an innocent statement such as
printf("\n") anywhere BEFORE the seek to end, the execution crashes but
instead of the long dump a segfault is reported on fclose, and the
return value is 139, not 134.
If this is not a bug, then it would be good to have this interesting
behavior documented.
Regards,
vQ
On 01/18/2011 03:08 PM, Stefan Sablatnög wrote:
Hi everybody,
I encounter a bug with ungetc on many different glibc system, though all are
ubuntu, at least debain I thought this place would be right.
My problem is a segmentation fault on fclose, that happens when I run the
following short test program. Assume a file named abc exists and it contains at
least 10 characters. ( I use Hello)
Here is the program:
#include
int main(int argc, char *argv[])
{
FILE *file = fopen("abc", "rb");
if (0 != file)
{
int pos = 0;
int len = 0;
int value1;
pos = ftell(file);
if(-1 == pos)
{
return -1;
}
if(0 != fseek(file, 0, SEEK_END))
{
return -1;
}
len = ftell(file);
if(0 != fseek(file, pos, SEEK_SET))
{
return -1;
}
value1 = fgetc(file);
printf("%c\n",value1);
ungetc(value1, file);
value1 = fgetc(file);
printf("%c\n",value1);
ungetc('#', file);
value1 = fgetc(file);
printf("%c\n",value1);
ungetc('?', file);
fseek(file, 0, SEEK_SET);
value1 = fgetc(file);
printf("%c\n",value1);
fclose(file);
printf("OK\n");
}
}
So there is nothing very fancy, just some harmless file operations. What I
receive is:
stefan@pilch2:/tmp$ echo "Hello">abc
stefan@pilch2:/tmp$ ./test_ungetc
H
H
#
e
*** glibc detected *** ./test_ungetc: free(): invalid pointer: 0xb787f000 ***
=== Backtrace: =
/lib/tls/i686/cmov/libc.so.6(+0x6b591)[0xb776f591]
/lib/tls/i686/cmov/libc.so.6(+0x6cde8)[0xb7770de8]
/lib/tls/i686/cmov/libc.so.6(cfree+0x6d)[0xb7773ecd]
/lib/tls/i686/cmov/libc.so.6(_IO_free_backup_area+0x34)[0xb776da34]
/lib/tls/i686/cmov/libc.so.6(_IO_unsave_markers+0x32)[0xb776d752]
/lib/tls/i686/cmov/libc.so.6(_IO_file_close_it+0x42)[0xb776c542]
/lib/tls/i686/cmov/libc.so.6(fclose+0x188)[0xb775fae8]
./test_ungetc[0x804872f]
/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb771abd6]
./test_ungetc[0x80484e1]
=== Memory map:
08048000-08049000 r-xp 08:04 16975036 /tmp/test_ungetc
08049000-0804a000 r--p 08:04 16975036 /tmp/test_ungetc
0804a000-0804b000 rw-p 1000 08:04 16975036 /tmp/test_ungetc
09f8e000-09faf000 rw-p 00:00 0 [heap]
b75bf000-b75dc000 r-xp 08:04 1387787/lib/libgcc_s.so.1
b75dc000-b75dd000 r--p 0001c000 08:04 1387787/lib/libgcc_s.so.1
b75dd000-b75de000 rw-p 0001d000 08:04 1387787/lib/libgcc_s.so.1
b760-b7621000 rw-p 00:00 0
b7621000-