What happens if I call KillTimer with a NULL hwnd?


A customer discovered a bug in their code and wanted some information on how serious it was, so they could assess how urgently they need to issue a fix.

We have code that calls Set­Timer with a valid window handle, but then we destroy the window before we get around to calling Kill­Timer. When we finally do call Kill­Timer, we do so with a NULL window handle. The Kill­Timer calls are probably harmless, but are we leaking the timers?

The customer's real concern was actually in the part of the problem they thought was a point of little concern. The window manager cleans up orphaned timers when the associated window is destroyed, so there is no timer leak in this case. Of course, it's still good practice to clean up those timers. (Note however that a similar situation does lead to leaked timers.)

The real danger is in the Kill­Timer call. By passing a null window handle, you are killing a thread timer. Maybe you're lucky and there is no thread timer whose ID is the value you passed as the second parameter, but someday your luck will run out and you will accidentally kill somebody else's timer.

The customer was pleased with this explanation.

That's exactly the information we were looking for. Thanks.

Comments (16)
  1. Joshua says:

    I'd say that thread timers not accepting the passed-in ID for thread timers in CreateTimer was a mistake, but that's set in concrete now.

    [It does accept the passed-in ID. You use it to reset an existing thread timer. This is called out in the SetTimer documentation. -Raymond]
  2. Guillaume says:

    "Someone else's timer" ? Even thread timers that are in another process (owned by the same user) ? That could be an interesting fault injection scenario !

  3. waleri says:

    [It does accept the passed-in ID. You use it to reset an existing thread timer. This is called out in the SetTimer documentation. -Raymond]

    Yes, but it would be much better if error/null is returned in case of HWND_NULL/InvalidTimerID are passed. It is a little counterintuitive to provide an ID and get a new one in return. I guess timers were global back then.

    PS.

    Can't post using IE8

  4. Klimax says:

    @Matteo Italia 31 May 2012 8:22 AM:

    Or when you are running inside somebody else code. (when being library)

  5. @waleri says:

    So what's your proposal? while ( SetTimer( id ) != ERROR_SUCCESS ) ++id;? The point is, when you install a thread timer your code no longer controls which ID's are in use and which ones aren't.

  6. Anybody else noticed that Internet Explorer leaks systimers (those that make the carets blink) like crazy? And the carets don't blink anymore.

  7. Klimax says:

    @alegr1

    No. (IE9) Might be caused by third party program/plugin.

  8. MItaly says:

    @Guillaume: if you pass NULL to SetTimer/KillTimer you create/destroy a thread timer *of the current thread*, so there's no way you could destroy inadvertently a timer of another process; the scenario Raymond is talking about is when you are sharing your thread with code you don't wrote (e.g. a third party library/component/… that your code uses) that happens to use a thread timer.

  9. Dave says:

    That's exactly the information we were looking for. Thanks.

    This sounds worryingly like "So someone else's app crashes rather than ours. Thanks, we can safely ignore the problem".

  10. Gabe says:

    Dave: It sounds to me like it will only crash their own app — assuming that their app uses thread timers, which I'm guessing they actually don't.

  11. Anonymous Coward says:

    Well, technically all the information they needed was in the MSDN pages for SetTimer and KillTimer. Must say though that I couldn't have thought up a more oblique way of stating it all.

    Also, the way SetTimer reacts to the id parameter is bad design. Either you want a new id, or you want to modify an existing id. In the first case if the id isn't zero, then the caller thinks we're in the second case, so the function should throw an exception because a bug has just been discovered.

    Gabe, if the past is any predictor for the future, one day they will call some library that creates some thread timers behind the curtains.

  12. waleri says:

    >>> So what's your proposal? while ( SetTimer( id ) != ERROR_SUCCESS ) ++id;? The point is, when you install a thread timer your code no longer controls which ID's are in use and which ones aren't.

    Exactly, if I *install* a timer then I don't know the ID so passing an ID should fail. In other words, to *create* a timer one should call SetTimer(0, 0) and calling SetTimer(0, InvalidID) should fail. You can still hit another timer accidentally but at least it won't leak.

  13. 640k says:

    "somebody else's timer" -> A timer in *your* process. Not somebody else's timer.

  14. Anonymous Coward says:

    640k, that assumes that all timers in your process are yours. In practice they may not be since other code that you interface with may under the covers create timers of which you're unaware.

  15. Manuel says:

    Actually, every process has an OWNER. Which usually isn't the developer who wrote the code.

  16. @Manuel says:

    So what? A soon as you host a common control in your dialog (for example, the progress bar or sysanimate32) or if you use the predefined dialogs for Open/Save/Printer Selection, you can have "unwanted" timers in your process. Many of them. Hopefully, they are all bound to some private window belonging to the control, and not to the thread.

Comments are closed.