OK guys here’s a strange one. I’m running WinXP Pro and VisualC 6 with
SP3. Today I noticed that with my filter installed, every fifth or sixth
time I tried to save a source file from within VisualC, I’d get the
error ‘Cannot save file. The file may be in use by another application.’
After clicking OK, I noticed that the original source file has been
DELETED from my hard drive. If I attempt to save again, it will usually
work and the file will be re-created, but nonetheless I assumed that
this was a bug with my filter.
Well, it turns out this has nothing to do with my filter per se. It is a
bug with ANY filesystem filter in combination with VisualC. It took me
just a few minutes of searching on Google to determine that dozens of
other people have experienced this in combinition with VisualC and
various other filter drivers (mostly Antivirus).
The problem is NOT that the filter is locking the file (as at least one
Microsoft employee claims on Usenet). The problem SEEMS TO BE a race
condition between two threads in VisualC. Any filter that delays the
operation of the IRP_MJ_CREATE request will expose this bug immediately.
You can see this easily by modifying a copy of Filemon to display the
thread ID for each request (in addition to the process ID). Then load up
a filesystem filter driver that performs some non-trivial amount of work
in IRP_MJ_CREATE. Then save a source file ‘foo.cpp’. What you will see
in the success case is something like this:
Thread 1: Dump contents of open source file foo.cpp to temp.tmp
…
Thread 2: Open foo.cpp
Thread 2: Cleanup foo.cpp
Thread 2: Close foo.cpp
Thread 1: Rename temp.tmp to foo.cpp
…
In the failure case you will instead see:
Thread 1: Dump contents of open source file to temp.tmp
…
Thread 2: Open foo.cpp
Thread 1: Rename temp.tmp to foo.cpp - ACCESS DENIED
Thread 2: Cleanup foo.cpp
Thread 2: Close foo.cpp
…
As you see, there is a nasty race condition here. In the failure case,
note that since Thread 2’s open of foo.cpp is delayed by the filter, it
doesn’t get a chance to close foo.cpp before Thread 1 attempts to rename
over it with the temp file. I don’t know what Thread 2’s purpose is, but
it’s definitely the party-pooper here.
This bug has apparently been around for years, according to the
newsgroups. I know that various Microsoft employees read this list quite
frequently, so please put in a word with the VisualC team about getting
it fixed (if it’s not fixed in Visual Studio .NET).
I am actually going to put in special-case code in my filter to retry
the rename if the current process is MSDEV.EXE to work around this.
- Nicholas Ryan