Under what conditions can SetFocus crash? Another debugging investigation


A customer asked, "Under what conditions can Set­Focus crash?"

We have been going through our error reports and are puzzled by this one. The call stack is as follows:

user32!_except_handler4
ntdll!ExecuteHandler2@20
ntdll!ExecuteHandler@20
ntdll!RtlDispatchException
ntdll!_KiUserExceptionDispatcher@8
0x130862
user32!UserCallWinProcCheckWow
user32!__fnDWORD
ntdll!_KiUserCallbackDispatcher@12
user32!NtUserSetFocus
contoso!DismissPopup

At the point of the crash, the Dismiss­Popup function is calling Set­Focus to restore focus to a window handle that we got from an earlier call to Get­Active­Window. Is this safe? We imagine it might crash if the message handler for the window was unloaded from memory without being properly unregistered; are there any other reasons? More to the point, is there any way to avoid the problem (without fixing the root cause of the crash, which we may not be able to do, e.g. if that window was created by third-party code)?

The full dump file can be found on <location>. The password is <xyzzy>.

Indeed, what the customer suspected is what happened, confirmed by the dump file provided.

The code behind the window procedure got unloaded. User­Call­Win­Proc­Check­Wow is trying to call the window procedure, but instead it took an exception. The address doesn't match any loaded or recently-unloaded module probably because it was a dynamically generated thunk, like the ones ATL generates.

There isn't much you can do to defend against this. Even if you manage to detect the problem and avoid calling Set­Focus in this problematic case, all you're doing is kicking the can further down the road. Your program will crash the next time the window receives a message, which it eventually will. (For example, the next time the user changes a system setting and the WM_SETTING­CHANGE message is broadcast to all top-level windows, or the user plugs in an external monitor and the WM_DISPLAY­CHANGE message is broadcast to all top-level windows.)

Basically, that other component pulled the pin on a grenade and handed it to your thread. That grenade is going to explode sooner or later. The only question is when.

Such is the danger of giving your application an extension model that allows arbitrary third party code to run. The third party code can do good things to make your program more useful, but it can also do bad things to make your program crash.

Comments (10)
  1. Joshua says:

    Well I suppose you could detect the problem by obtaining the window handle, checking if the pointer is mapped (executable memory regions tend to be unmapped when freed, as in this example), and subclass the window. I'd prefer to follow it up w/ an immediate DrstroyWindow.

    Still seems like something you should not be defending against.

    [That will generate both false positives (window procedure thunks) and false negatives (if the unloaded module is somewhere inside the subclass chain, not at the top). -Raymond]
  2. DWalker says:

    "An extension model that allows arbitrary third party code to run"?  Like Windows Explorer used to do?  

    Although that model allowed some helpful add-ins, I realize that it also caused problems and support headaches for Microsoft.  

  3. Myria says:

    Sometimes, that third-party code isn't the result of an extension model.  It can be the result of extension points (a.k.a. AppInit DLLs) or a result of user-mode drivers.

    For example, I once had to debug a crash with no call stack because the user-mode DirectX components of a certain video card's driver crashed in runtime-generated code and that DLL didn't call RtlAddFunctionTable.  That was a fun day.  We got to send a nastygram to that company with a link to the x86-64 calling convention page on MSDN, though.  >.<

  4. The Customer says:

     "There isn't much you can do to defend against this."

    How about: install an exception handler, when the exception hits, follow the frame up to the caller, find the location where 0x130862 was retrieved, and replace it with the address of DefWindowProc?

    [The 0x130862 was obtained from kernel mode, so good luck modifying that. -Raymond]
  5. anonymouscommenter says:

    This is quite off-topic but: I've got a puzzling situation where an application (native, does almost nothing except file/network I/O) I've written is somehow causing Windows to hang when it crashes (e.g, a GPF). I've been able to reproduce this behavior on several machines (all Win7, one a clean install) and the temporary workaround to stop Windows from hanging is to just handle the exception myself (ala SetErrorMode/SetUnfilteredExceptionHandler).

    Any suggestions on how to go about debugging this short of breaking in with a kernel debugger?

  6. T. West says:

    <i>The password is <xyzzy>.</i>

    Arg!  Why did Raymond just post my password in plain-text?  Unguessable passwords are hard to come up with.  Next time please use a filler.

    :-)

  7. anonymouscommenter says:

    You could still subclass the window and blast it out of existence in the exception handler, but that depends on interpreting exception stacks in native mode (always dodgy in production code). OK so doing it in managed mode isn't much more sane.

    [It also means continuing a program that you know is in a bad state, which will just lead to worse states later that you will never be able to debug. -Raymond]
  8. cheong00 says:

    So, the correct way is to ask the parent window to save the focus state of it's active child first, then when the popup is done, ask the parent window to restore it itself?

    [At best, you're just delaying the inevitable. -Raymond]
  9. cheong00 says:

    Why it's just deplaying the problem? Shouldn't the parent window (I mean the previously active control's owner) ought to be able to keep track of states of it's assets?

    If you're talking about "giving your application an extension model that allows arbitrary third party code to run", the parent window could be coded with this extension and asked the third party implementer to call it when needed.

    [Some window called contoso!DisplayPopup. DisplayPopup remembers the active window (which is the parent of the previous focus control), so it can restore it later. While the popup is displayed, the DLL for the previous active window gets unloaded. When the popup is finished, it wants to put focus back on the previous active window, but there is no DLL any more. "Shouldn't the parent window of the previously active control do XYZ?" Answer: "It doesn't matter what the parent window of the previously active control does, because its code got unloaded!" -Raymond]
  10. anonymouscommenter says:

    @cheong00, setting the focus on the previous top-level window should take care of that.

    If the window happens to be a dialog or alike, it should set the focus on whatever child had the focus previously, such a window should have recorded it when it lost focus.

    What the customer reported is a problem of that window if his pop-up is modal.

    If his pop-up is not modal, then the customer shouldn't do anything about focus.

    @Raymond, although I agree we're just delaying the explosion, at least we shouldn't cause it ourselves if we can avoid it.

    Much like carefully walking on a mine field, which is the best we can ever hope to do with software.

Comments are closed.

Skip to main content