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...