Recently the development team and I managed to get to the bottom of a seemingly bizarre scenario – having removed all references to a particular file from our code (it happened to be a log file which was being created in C:\Temp), ProcMon – that awesome tool which is part of the Sysinternals suite (http://technet.microsoft.com/en-gb/sysinternals/bb842062.aspx) – still showed this file being accessed when we profiled our application.
A bit of background: the team was looking at a bug which caused our application to generate a log file in a fixed location of C:\Temp whenever it started up. Not a huge problem, but sufficiently irritating to cause us to want to fix it – so we did. We removed all references to that fixed location, refactored some troublesome code related to C++ static initialization, and our temporary log file disappeared… or so we thought! To double-check that it had really gone, we installed a new version of our application, ran ProcMon and profiled the activity. Then we did a search in the ProcMon output for our log file, but it was still there! ProcMon clearly showed our process trying to access this file. We checked and double-checked the code, but we’d definitely removed all traces of it. Seriously spooky!
This ghostly residue troubled us enough to investigate further. The access to the file occurred very close to the start of the process’ life – so early, in fact, that it looked to be before our code was even running. This was the first clue. The stack trace corresponding to the access (hats off again to ProcMon!) was a complex-looking chain of Kernel-mode calls via fltmgr.sys – the Windows Filesystem Filter Manager. This was the next clue – it wasn’t our application trying to access the file, it was the operating system itself. How very ghoulish!
OK – I’ll stop with the Halloween references now.
Scrolling up through the ProcMon capture, whizzing past a list of other file accesses (mostly the DLLs that our application uses), the final clue was right at the top of the capture. Just after spawning the process, the very first thing that happened was that Windows was loading its PreFetch cache for our process. Could this be the culprit?
If you’re not familiar with the Windows PreFetcher, and the subsequent SuperFetch and ReadyBoost technologies that are built upon it, it’s a smart bit of Windows tech will which pre-emptively load and cache the files that your process has been seen to be using during previous runs. The idea is that this will help your applications launch faster in subsequent runs because the operating system will have already read these files into memory before the application has even asked for them.
So we did some digging and looked at the prefetch file for our process. These live in the %SYSTEMROOT%\PreFetch folder, and are in binary format. There are some tools available online for viewing the content, or you can open them up in a text editor and, with the right kind of squinting, you can just about make out the entries. Sure enough, Windows had tracked the fact that previous runs of our process had accessed the file in C:\Temp, and, helpfully, it was now trying to pre-fetch the file for us, even though our code had no more references to it.
We deleted the corresponding prefetch file (Windows will recreate these for you the next time your process launches), and mystery solved!
I certainly wouldn’t advocate going around deleting prefetch files – indeed, there’s a lot of bad advice on the internet encouraging you to do so to help you “speed up your computer” when quite the opposite could happen – but sometimes it’s interesting to take a look at how things like this can cause side-effects which leave you scratching your head.