Monday, April 30, 2012

Mwahahaha... It lives! (The MSVC Muffler)

Many of you will probably have heard my ramblings (or more accurately, rants) about the verbosity of MSVC, in particular its annoying habit of echoing the name of the file (or if provided with a temp file containing a long list of files, the entire contents of said temp file) as the first thing it does. Making matters worse is that there is absolutely no compiler flag that can turn this annoying braindead crap off (though they fortunately had the decency to allow you to turn off the versioning+copyright notice).

In the name of "science" (actually, just an excuse in this case to finally rid my compiles of this plague), I finally set out to investigate how I could vanquish this thing forever...

... well, that is after having my initial experiment exploded, and brought down my system with it, requiring a manual reboot. But, that's what the "mad scientists" of old were always seen to be doing, right? ;)

Firstly, what was I trying to do?
In earlier investigations of this issue, I figured out that MSVC (or more specifically, cl.exe) was echoing the filename(s) on the first line (and first line only) of its stdout output. Most of the time, this is all it would spit out first, unless there was some other kind of error that occurred. But, then again, in those other cases, that first error usually wasn't of any use either, so in effect, the first line of MSVC output can be considered always useless and able to be safely discarded.

In previous attempts at solving this problem, I'd mainly concentrated on trying to find a way to hack scons (that being my main build-system for anything C/C++) so that it could process the output emitted by MSVC. I assumed that since everything was in Python, it'd end up being a breeze to ignore that first line once I figured out where to intercept the output. However, as it turns out, I've come to find that this is actually quite a long, tortuous road through quite a twisting mass of code, that probably wouldn't actually even work...or maybe I did try it, and but it didn't work.

This time, I tried instead to find a way to dump in a wrapper which could seamlessly wrap the MSVC commands (i.e. by having the same name as the compiler - "cl"), but which would feed the output through some filter before spitting it out. After a bit of Googling, I finally found that the answer was to use the Unix "tail" command.

A train-wreck waiting to happen...
Now, for good measure, I decided to put the wrapper beside the compile scripts for one of the projects I was working on to try it out (just in case I needed to do further editing, in which case it'd have been a very annoying editing dance with UAC - curse that thing! It's one of two reasons that I advocate that everyone installs things to "C:\apps\" not "C:\Program Files\" these days; the other reason being the space in "Program Files" which complicates path handling for nearly everything).

Everything was in place.

I started the compile.

Suddenly, everything started running really slowly. Then, it became impossible to change windows (including trying to get to the offending window to either close it, or kill it). Trying to bring up the task manager (ctrl-shift-esc) to kill the offending processes was futile (it didn't show up until some 5 minutes later, only to crash a few seconds later).

It'd been quite a while since I'd used it, but I tried to issue the old "Ctrl-Alt-Del". I hadn't used it ever since I learnt about the more direct Ctrl-Shift-Esc, which didn't need to go through the Windows secure login system (which would apparently need to lock everything, show its screen, and then unlock things or something like that, as I once read on the blog of a Microsoft employee). The thing with Ctrl-Alt-Del was that it was really slow, which really isn't too confidence inspiring when you've got an out of control process you need to bring under control immediately (or else it's going to nuke something or send the system into swap soon), and that pressing Ctrl-Alt-Del a second time would trigger the system to shut down suddenly (which really isn't something you really want, if the system suddenly clears up again having pressed this combo twice but before it had responded to the initial request, and now proceeds to shut itself down without any recourse to change your mind and abort the shutdown).

Anyways, back to today's story.

Ctrl-Alt-Del turned the screen black, but it did seem to force a change somewhere. Some instances of "tail" started crashing, withtheir dialogs kept popping up sporadically. In fact, that was the first thing that managed to emerge from the cloak of darkness. The Aero theming died, and left just that awful "basic" look with those ugly big-gap-toothy min/max/close button cluster and sickly-pale-blue window borders. Somewhere amongst all this chaos, Firefox was killed but managed to pop up its crash reporter. The task manager briefly flickered before committing suicide. Another host of tail instances crashing flashed by. Aero briefly flicked back into life, and it was possible to bring up the offending window, which by now was filled with a long list of errors about waiting not living long enough to wait out the "completion signal".

I tried once again to fire up the Task Manager. "Denied! Not enough system resources to continue". In the offending window, I issued a series of Ctrl-C's. No response. Nothing. I clicked on the Close button for that window a few dozen times too. Nothing. "Not enough system resources!", blurted a lame-duck dialog, while the hard disk clattered away madly (presumably swapping like crazy. Swapping is evil).

For a few minutes, hell froze over again. Even the mouse over effects barely worked. And then, all of a sudden, a flurry of ^C's started appearing in a row on the offending window, like a chain of ants on a death march to a nest being destroyed, pausing every once in a while to observe the char-grilled scent in the air.

Another set of last ditch Close-button clicks were issued.

But it was no use. A hard reboot was in order...

The culprit
As it turned out, it was a case of infinite recursion gone wrong. Although it was unintentional, it nevertheless was infinite recursion. And as I learned today, when that infinite recursion occurs on the operating system level, then there's absolutely nothing you can do to save the situation.

What was the cause of this infinite recursion? Well, the original wrapper script (cl.bat) looked a bit like this:

@echo off
cl %* | tail +2

Owing to the way that search-paths work, this means that the current directory is searched first, hence resulting in infinite recursion, whereby each cl.bat invocation would call another cl.bat ad nauseum. Woops!

The corrected script (which seems to work safely now):
Save the following as cl.bat, and dump it somewhere on path (but before the "real" cl)...

@echo off
cl.exe %* | tail +2

No comments:

Post a Comment