Visual C++ Precompiled Header Errors on Windows 7
Several customers have encountered the following error while using the Visual C++ compiler on Windows 7:
fatal error C1859: ‘stdafx.pch’ unexpected precompiled header error, simply rerunning the compiler might fix this problem
This error manifests under the following conditions:
· The Visual C++ compiler is invoked on Windows 7.
· Precompiled header (PCH) files are enabled.
· /analyze is enabled (this is not a necessary condition, but it increases the probability of encountering this behavior).
Despite the error message’s suggestion, “simply rerunning the compiler” probably won’t help the situation. Indeed, the underlying cause of this error is far from “simple” as it stems from an interaction between our venerable precompiled header architecture and the new security enhancements in Windows 7.
Visual C++ Precompiled Headers and ASLR
Precompiled header files store the “state” of a compilation up to a certain point, and that state information can be reused in subsequent compiler invocations to significantly increase build throughput. For the past 15 years, our compiler has persisted precompiled headers to disk and reloaded them directly into virtual memory with 99.999% reliability and considerable performance gains. The tradeoff, however, was a degree of fragility in our architecture.
Since the PCH file itself contains internal pointers, it must be loaded at the exact same address in virtual memory where it was created. The pointers will be inaccurate if the PCH is loaded at a different address in subsequent compilations. To complicate matters, the PCH also contains polymorphic objects, and each polymorphic object contains its own virtual function table pointer (VFTP). These VFTPs point to virtual function tables stored in modules. Therefore, if a polymorphic object in the PCH depends on a virtual function table in a particular module, that module must be loaded at the exact same virtual address as when the PCH was created. If the module is loaded at a different address in subsequent compilations, the VFTP’s in the PCH will be inaccurate.
That’s a long-winded way of saying “both the PCH file and the modules it depends upon must not move between compilations!” The Visual C++ compiler will verify that both of these conditions are met before building, otherwise it will fail immediately with the above error. The latter condition bit us on Windows 7, which introduced more aggressive algorithms for Address Space Layout Randomization (ASLR). ASLR mitigates certain malware exploits by randomly relocating modules within a process. To circumvent ASLR randomization in Vista, the compiler modules were previously built with /dynamicbase:no back in Visual Studio 2008. This was insufficient in Win7 as randomization became more aggressive.
Our first attempt to fix the problem involved setting the preferred base address of each compiler module to a location that we considered “safe” (i.e. would decrease the odds of modules colliding sufficiently). Unfortunately, cascading rebases continuously thwarted our efforts as one module would move into the preferred address space of another, and the domino effect would continue until a module that the PCH used was rebased. Failures like this were difficult to diagnose and often involved subtle factors, such as process creation order (i.e. devenv.exe loads a module that cl.exe uses, etc) and the Native DLL Loader. We were essentially locked in a losing battle with the Butterfly effect.
The majority of alternative solutions required either a substantial amount of work or an unacceptable performance hit. We finally decided to implement our own dispatch mechanism within the PCH data structures that eliminated the virtual function tables altogether. By “devirtualizing” the PCH data structures, we successfully eliminated the second criterion: compiler modules can now move about the process without breaking the precompiled header file.
This fix will be available in the final release of Visual Studio 2010, and a hotfix for Visual Studio 2008 will be released shortly. If you are encountering this problem in the interim, please try the following workarounds:
· Disable /analyze (if enabled).
· Invoke a clean build.
· Reboot your machine.
· Disable PCH files.
Visual C++ Compiler Team
The public patch for Visual Studio 2008 SP1 has been released. You may download it here.