Could it be that there's a bug in the Windows Restart Manager callback API?

191 Views Asked by At

As I was investigating a weird crash that I could only reproduce on Windows 8, I found that the EBX register was not restored from calls to either RmShutdown or RmRestart. The first difference I found with running on Windows 8, is that it's using ECX while the win7 version of these functions use (and thus restore) EBX. (I have not investigated other Windows versions closely, just noticed that the bug doesn't repro on Vista.)

When I dug further, I noticed that the call to the RM_WRITE_STATUS_CALLBACK doesn't restore the stack by popping the arguments from it as it seems to be expected by the caller which doesn't do it either. So when RstrtMgr!CRestartManager::ShutdownApplications calls RstrtMgr!_EH_epilog3 the wrong register values are popped from the stack. But at least, ESP is restored properly and the end of RmShutdown properly reset the registers it used, including EBP, which it doesn't use between the call to CRestartManager::ShutdownApplications and the end...

So on Windows 7, all was fine... But the Windows 8 version, since ECX is used instead of EBX, EBX is not restored and if the calling code depends on it... BOOM!!!

To fix this, I simply changed the callback function to use __stdcall (this means I couldn't use the real RM_WRITE_STATUS_CALLBACK type, and needed to typecast it to what the API expect, or use the GetProcAddress technique, which is needed to run the same code on XP anyway).

Am I missing something or is this really an issue with the API? And how about EDI and ESI? They are also NOT restored properly, even on Windows 7. In my case they were not used, so it's fine, but I can't believe none of the callers of these functions would need these registers to be properly restored... Right?

I think I'll file a bug to Microsoft for this... Unless someone can come up with a better explanation...

0

There are 0 best solutions below