it may come as no surprise to regular readers that some of the people in the set of "people who read this Blog" work at Microsoft.
A few of that more restricted set even find one or more of the blogs within this Blog to be useful for their something in their work.
And then a few of that even further restricted set find an interesting problem or issue or bug or design limitation along the way.
In some of those cases, I help them get the bug in and/or help push for a fix in the bug.
This blog is not one of those cases.
In this case, the owners of the component that caused them trouble was deemed a "Won't Fix" bug, since i had a workaround.
This blog you are reading now is going to describe the bug, and the workaround.
First, the simple repro code:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <fcntl.h>
#include <io.h>
void Test1(int argc) {
int Mode;
Mode = _setmode(_fileno(stdout), _O_U16TEXT);
fwprintf(stdout, L"first\nsecond\n");
if (argc > 2) {
fflush(stdout);
}
if (argc > 1) {
_setmode(_fileno(stdout), Mode);
}
}
void __cdecl wmain( int argc, PWSTR *argv) {
SetThreadUILanguage(0);
Test1(argc);
exit(0);
}
So there are three cases here:
- When you execute the above with no additional command line arguments, e.g.
test > out.txt
the result is fine. - When you execute the above with 1 additional argument, e.g.
test 1 > out1.txt
the result contains a spurious 0x0d byte that destroys the integrity of this UTF-16 file. - When you execute the above with 2 additional arguments, e.g.
test 1 2 > out2.txt
the result is fine.
Obviously, proper line breaks are what we expect here, so that case #2 clearly looks like a bug.
Now the most interesting case to me is the first case, and for some developers it is the most common.
It has two features many developers who aren't the sort to be reading this Blog do quite commonly, in that
- no explicit flush of the file is done (it relies on the implicit flush expected to happen during cleanup), and
- the mode that is changed is not restored.
This first case sees no bugs.
Now the second case, which has no explicit flush (it still relies on the implicit flush) but does restore the mode, because even though the app is about to exit, many developers do like to do that sort of cleanup of settings they change.
There are many reasons for this, but the one I find myself doing this for is that people often copy/paste code samples that they put elsewhere. This way, someone will do the cleanup in their app even if they don't pay the same attention to details....
The third case is an interesting one, because in a console app that does not have its output redirected often does not flush.
This simply doesn't occur to the developer in most cases; if the do think about it, they know that stdout will be implicitly flushed anyway.
And here lies the hint as to the problem:
All of the CRT's pending "text mode autoconvert \n to \r\n" that happen during the implicit fflush are done using the current mode of the stream, not the mode at the time that text was fwprintf'ed. And the pending text in the stream is in a state that is halfway to being handled.
Therefore, to avoid the risk here, it is best to always explicitly flush in the current mode, rather than having the implicit flush happen after the mode has changed.
If I don't get any email from a doc writer (there are some doc writers who also read this blog) in a week or so, then I'll probably put in a bug suggesting the need to explicitly fflush prior to a mode change being added to the _setmode documentation. I'm just saying....
Now I had in mind two different potential punchlines to end this blog on:
- one involving the need to not rely on the autoflush mechanisms found in so many airport and Microsoft campus toilets, just in case the flush doesn't happen correctly;
- another equating the mode change to whether one put the seat back in the state it was in (often down if a lady regularly uses the same toilet) and the desirability of msking sure to flush and make sure that the everything is clean prior to lowering the seat.
But I couldn't think of any way to make either of them work out well (toilet humor is undignified, as are flush puns); this blog has been sitting in my "almost finished" pile for over a month now as I tried various ways to redeem it for a world that finds Jackass-style movies to be entertaining before I simply gave up.
MANTECH INTERNATIONAL MANHATTAN ASSOCIATES LSI LINEAR TECHNOLOGY LEXMARK INTERNATIONAL
No comments:
Post a Comment