Re: Closing the FILE object.

From: Jesse Pollard (pollard@tomcat.admin.navo.hpc.mil)
Date: Fri Jul 14 2000 - 16:23:06 EDT

  • Next message: Evan Langlois: "UDMA on WD Drives"

    --------- Received message begins Here ---------

    >
    >
    > 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;
    > }
    >
    >
    > Script started on Fri Jul 14 12:50:27 2000
    > $$$ man fclose
    > FCLOSE(3) Linux Programmer's Manual FCLOSE(3)
    [snip]
    > ERRORS
    > line 1 EBADF The argument stream is not an open stream.
    > line 4
    > The fclose function may also fail and set errno for any of
    > the errors specified for the routines close(2) or
    > fflush(3).
    >
    > SEE ALSO
    > close(2), fflush(3), fopen(3), setbuf(3)
    >
    > STANDARDS
    > The fclose function conforms to ANSI C3.159-1989 (``ANSI
    > C'').
    >
    > BSD MANPAGE 29 November 1993 1
    >
    > line 19/66 (END)# exit
    > exit
    >
    > Script done on Fri Jul 14 12:50:47 2000
    >
    >
    > I reported a similar problem several years ago when I way trying to
    > substitute during runtime, a FILE pointer obtained from a fopen() and
    > the default FILE pointer(s) of stdin, stdout, stderr. In other words,
    > if the program didn't have a terminal, stdout and stderr would go to
    > a file.
    >
    > Because the FILE *object didn't work as a real pointer, I could not
    > do:
    > FILE *fp;
    >
    > fp = fopen("filename", "w");
    > fflush(stdout);
    > fflush(stderr);
    > stdout = fp;
    > stderr = fp;
    >
    > The next write to stdout would segfault. This behavior was never seen
    > on any other Unix system, including Ultrix and Sun(s). In fact, the
    > interplay of the FILE object was a feature of Unix 'C' programming.
    >
    > In the example above, I could have saved the original FILE *, and
    > restored it later in the program. With Linux, you can't even compile
    > such a program because the assignments will result in 'invalid lvalue'
    > errors. This is because Linux libc's stdout is not a FILE * at all!
    >
    > This breaks compatability rules because, for instance fprintf() takes,
    > as it's first parameter, a pointer of type FILE.
    >
    > So we have the case of fprintf(stderr, ...) compiling and working because
    > stderr is a FILE pointer, but I can't make a legal assignment to it like
    > any other FILE pointers.
    >
    > Go figure.

    Yes, No and I understand.

    AT&T System V had stdin/stdout/stderr defined as if the following were used:

    const FILE *stdin = &STDIN;

    static FILE STDIN = {....};

    This ment that the default stdin/stdout.... were constants and could not
    be modified.

    HOWEVER, the release 2 manpage suggested that for portability all
    I/O should go through a file pointer defined as:

    FILE *input = stdin;

    Then you COULD replace the default input by

       altinput = fopen(...);
       input = altinput;

    The other note is that the manpage goes back to BSD in 1993. I don't think
    the library functions implimenting fopen/fclose ... have remained the same.

    At the time the man page was written the standard I/O library created the
    file pointer from something like:

    static FILE io[MAXFILECOUNT];
    static int nextfile = 0;

    ....
    FILE * fopen(char *path, char * mode)
    {
            ...
            initialization for io[nextfile]
            io[nextfile] = open(path, intflags);
            ...
            if (io[nextfile] >= 0)
                return(&io[nextfile++]);
            return(NULL);
    }

    This allows the manpage to be correct, since the structure pointed to by
    the FILE * variable is never deallocated. It is also NOT thread safe.

    ALSO NOTE - this does not conflict with the "const FILE *stdin.." shown
    earlier. stdin/stdout/stderr were not part of this array.

    I don't think stdio library works that way anymore.

    MAXFILECOUNT was 16 to 32 at the time, and multi-threaded I/O did not exist.

    I think the manpage needs to be rewritten.

    -------------------------------------------------------------------------
    Jesse I Pollard, II
    Email: pollard@navo.hpc.mil

    Any opinions expressed are solely my own.

    -
    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 : Fri Jul 14 2000 - 16:27:41 EDT