Re: Closing the FILE object.

From: Richard B. Johnson (root@chaos.analogic.com)
Date: Fri Jul 14 2000 - 13:25:52 EST


On 14 Jul 2000, Michael Poole wrote:

> "Richard B. Johnson" <root@chaos.analogic.com> writes:
>
> > This is in reference to the reported seg-faults when attempting to
> > fclose() an invalid file pointer.
> >
> > The following shows that my current 'C' runtime library does not
> > adhere to any known standard when referencing the FILE object during
> > fclose(). This is gcc 2.7.2.3 (libc 5.3.12)
> >
> > According to existing Linux documentation, this should return
> > EBADF. It should NOT seg-fault.
> >
> > #include <stdio.h>
> > #include <malloc.h>
> >
> > int main ()
> > {
> > FILE *fp;
> > fp = (FILE *)malloc(sizeof(FILE));/* Make sure the pointer is valid */
> > fprintf(stderr, "%p\n", fp); /* Display valid address */
> > fclose(fp);
> > puts("It worked??"); /* Will not occur */
> > return 0;
> > }
>
> Don't you remember what happened the last time you tried to treat
> FILE* as something besides an opaque pointer? I thought Uli Drepper
> was clear in his explanation that you're not allowed to do that and
> expect consistent results. A FILE* may have arbitrary state inside of
> it, and if you didn't get the FILE* from an fopen() type call (or as
> stdin, stdout, stderr), then you can't expect fclose() to work.
>

Yes I remember. And the answer was that FILE wasn't FILE. In
the failed explaination, the response boiled down to the idea
of using FILE as FILE was dumb and that I was dumb to even think
that I could use a FILE pointer as a FILE pointer.
 
> In fact, if you even THOUGHT about it, you'd see that your example is
> pretty stupid. A FILE* stream is supposed to have a buffer. If the
> thing pointed to by FILE* contains a pointer to that buffer, then you
> just gave fclose() something with illegal state. There are a number
> of other reasons that you should not expect an arbitrary FILE* to be
> acceptable to fclose().
>

I gave fclose() a bad file descriptor. It should return EBADF just
like the documentation states.

> Further, I don't think the standard even mandates that FILE by itself
> be meaningful. If FILE is typedef'ed as char, no interface would
> break (although warnings would be harder to diagnose), but your code
> above would (rightly) break the stdio.h implementation.
>

FILE can't be typedef'ed to something for one function call and
be something else for another. Whatever FILE is, it is forever, until
#undef(ed).

FILE it typedefed to struct _IO_FILE in the current headers.
struct _IO_FILE is defined in libio.h.

A pointer to type FILE is, therefore, a pointer to the structure defined
in libio.h.

A FILE * is therefore a 'struct _IO_FILE *'.

stdin, stdout, and stderr are defined in stdio.h. They are:
extern FILE *stdin, *stdout, *stderr.

Then there is a redefinition:

#define stdin _IO_stdin;
#define stdout _IO_stdout;
#define stderr _IO_stderr;

So, let's see what they are:
In libio.h, they reference _IO_FILE *, initialized with the address
of the specific structure. They are, therefore, in fact, valid
pointers of type FILE.

So FILE *stdin is like any other FILE *. It should work by the same
rules.

The BUG, and it is a BUG, is that a seldom used function like fclose()
has been 'optimized'.

struct _IO_FILE contains some pointers. If these pointers are dereferenced
during the fclose(), and they are NULL, or point to memory you don't own,
your program will seg-fault.

fclose() should check these structure members and return EBADF,
as specified, instead of just crashing.

Now, if the specification of fclose() allowed a seg-fault that's quite
another thing. According to Linux's own documentation, it should
return with -1 and set errno to EBADF if I give it trash.

> I don't know what standard you think mandates that library functions
> protect the user against severe user boneheadedness, but if you want
> to write sane code, you shouldn't do boneheaded things.
>
> Michael
>

Cheers,
Dick Johnson

Penguin : Linux version 2.2.15 on an i686 machine (797.90 BogoMips).

"Memory is like gasoline. You use it up when you are running. Of
course you get it all back when you reboot..."; Actual explanation
obtained from the Micro$oft help desk.

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jul 15 2000 - 21:00:20 EST