Date: Mon, 24 Sep 2001 12:06:48 +0200 (IST) From: Eli Zaretskii X-Sender: eliz AT is To: Tim Van Holder cc: djgpp-workers AT delorie DOT com Subject: Re: The Perl/FD issue: update In-Reply-To: <000601c1445e$8d466520$047d76d5@pandora.be> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Reply-To: djgpp-workers AT delorie DOT com Errors-To: nobody AT delorie DOT com X-Mailing-List: djgpp-workers AT delorie DOT com X-Unsubscribes-To: listserv AT delorie DOT com Precedence: bulk On Sun, 23 Sep 2001, Tim Van Holder wrote: > +Auto-closing file: > + _cnt = 0 > + _ptr = 0 > + _base = 0 > + _bufsiz = 0 > + _flag = 514 > + _file = 3 > + _name_to_remove = (null) > + _fillsize = 0 > +* fflush(f) returns 0 > +* fclose(f) returns 0 > >> FD 3, but not our file > +Auto-closing file: > + _cnt = 15075 > + _ptr = 137b2d > + _base = 137610 > + _bufsiz = 16384 > + _flag = 48 > + _file = 3 > + _name_to_remove = (null) > + _fillsize = 0 > +* fflush(f) returns -1 > +* fclose(f) returns -1 > >> Aha - BINGO - this is actually our file. Thanks for debugging this. > So the problem seems to be that FD 3 gets closed using the > WRONG FILE structure (stdaux?) -> the close works, but does > no flushing. Then the fflush and close fail because the FD > is closed. Yes, that is what happens. > So I guess we need skip stdaux and stdprn in fcloseall, if > those FD's were closed at startup? How would you know that stdaux/stdprn were closed at startup? If their handle is reused by some other file, there's no way to know that, I think. Even if there were a way, what you found is an indication of a larger problem, not limited to stdaux/stdprn. It will happen with any FILE stream whose file handle is closed with a call to `close' (as opposed to `fclose'). The problem is that calling `close' leaves the FILE object in a state where the next call to `fopen' cannot reuse it, because it looks as if it were still being used. So `fopen' creates another FILE object, but `open' returns the same handle (3, in this case) which we just closed. So now we have two FILE objects which record the same file handle, but one of them is ``dead'': no output will ever use it. If stdiohk.c walks the FILE objects in a wrong order, it will try to fclose the ``dead'' FILE object first, and the ``alive'' FILE object will never get a chance to be fflushed properly. Fixing this is a bit tricky. Hmm... Okay, one possibility is to change `fwalk' to walk the FILE objects from end to start, on the assumption that the ``dead'' FILEs will be closer to the beginning of the list. That requires a change in the data structure used by `__alloc_file', since it currently lacks a back pointer. It is also somewhat risky to assume that the ``alive'' FILE object will _always_ be after the ``dead'' one. Another possibility is to add to `_close' or to `close' code which will walk FILE objects and if it finds one that uses the handle being closed, it will mark that FILE object as unused, like `fclose' does. The disadvantage of this is that it slows down `_close'/`close', and doesn't catch code which closes the handle via `__dpmi_int' or `int86'. Yet another possibility would be to modify `__alloc_file' to test the handle in each FILE object when it looks for an empty slot: if the handle is invalid, it could consider the FILE object unused, even if its flags say otherwise, and reuse that slot. To see if the handle is invalid, we could lseek(fd, SEEK_CUR, 0L), for example. I like the last alternative more than the others, but the question is: could there be some program out there which closes a handle of a FILE object, but still uses that FILE object later, perhaps with a different handle, and calls `fopen' in between on top of that? And if there is such a program, can we dismiss it by saying it's buggy? Actually, the second alternative above has the same problem as the third. Comments? Thoughts?