{"id":6493,"date":"2012-09-26T07:00:00","date_gmt":"2012-09-26T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/09\/26\/sabotaging-yourself-closing-a-handle-and-then-using-it\/"},"modified":"2012-09-26T07:00:00","modified_gmt":"2012-09-26T07:00:00","slug":"sabotaging-yourself-closing-a-handle-and-then-using-it","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20120926-00\/?p=6493","title":{"rendered":"Sabotaging yourself: Closing a handle and then using it"},"content":{"rendered":"<p>\nA customer reported a problem with the <code>WaitForSingleObject<\/code>\nfunction:\n<\/p>\n<blockquote CLASS=\"q\">\n<p>\nI have a DLL with an\n<code>Initialize()<\/code> function and an\n<code>Uninitialize()<\/code> function.\nThe code goes like this:\n<\/p>\n<pre>\nHANDLE FooMutex;\nBOOL Initialize()\n{\n ... unrelated initialization stuff ...\n FooMutex = CreateMutex(NULL, FALSE, \"FooMutex\");\n ... error checking removed ...\n return TRUE;\n}\nBOOL Uninitialize()\n{\n \/\/ fail if never initialized\n if (FooMutex == NULL) return FALSE;\n \/\/ fail if already uninitialized\n if (WaitForSingleObject(FooMutex, INFINITE) == WAIT_FAILED)\n  return FALSE;\n ... unrelated cleanup stuff ...\n ReleaseMutex(FooMutex);\n CloseHandle(FooMutex);\n return TRUE;\n}\n<\/pre>\n<p>\nUnder certain conditions, the <code>Initialize()<\/code> function\nis called twice, and the <code>Uninitialize()<\/code> function\nis correspondingly called twice.\nUnder these conditions, if I run the code on a single-processor system\nwith hyperthreading disabled, then everything works fine.\nBut if I enable hypethreading, then the second call to\n<code>Uninitialize()<\/code> hangs in the <code>WaitForSingleObject<\/code>\ncall.\n(As you can see, it&#8217;s waiting for a mutex handle which was closed\nby the previous call to <code>Uninitialize()<\/code>.)\n<\/p>\n<p>\nWhy does this happen only on a hyperthreaded machine?\nShouldn&#8217;t the <code>WaitForSingleObject<\/code> return\n<code>WAIT_FAILED<\/code> because the parameter is invalid?\nIs this a bug in Windows hyperthreading support?\n<\/p>\n<\/blockquote>\n<p>\nRemember,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/02\/10\/10127054.aspx\">\ndon&#8217;t immediately jump to the conspiracy theory<\/a>:&sup1;\nHyperthreading may be the trigger for your problem, but it&#8217;s\nprobably not a bug in hyperthreading.\n<\/p>\n<p>\nWhile it&#8217;s true that <code>WaitForSingleObject<\/code> returns\n<code>WAIT_FAILED<\/code> when given an invalid parameter,\nhandle recycling means that any invalid handle can suddenly\nbecome valid again (but refer to an unrelated object).\n<\/p>\n<p>\nThe problem with hyperthreading will probably recur if you\nrun the scenario on a multiprocessor machine.\nHyperthreading (and multi-core processing) means that two\nthreads can be executing simultaneously, which means that\nthe opportunity for race conditions grows significantly.\n<\/p>\n<p>\nWhat&#8217;s probably happening is that between the two calls to\n<code>Uninitialize()<\/code>,\nanother thread called <code>CreateThread<\/code> or\n<code>CreateEvent<\/code> or some other function which creates\na waitable kernel object.\nThat new kernel object was coincidentally assigned the same\nnumerical handle value that was previously assigned to your\n<code>FooMutex<\/code>.\n(This is perfectly legitimate since you closed the handle,\nthereby making it available for re-use.)\nNow when you call <code>WaitForSingleObject(FooMutex)<\/code>,\nyou are actually waiting on that other object.\nAnd since that other object is not signaled, the wait call waits.\n<\/p>\n<p>\nOkay, so how do we fix the problem?\nThe simple fix is to null out <code>FooMutex<\/code> after closing\nthe handle.\nThis assumes however that your DLL design imposes the restriction\non clients that all calls to <code>Initialize()<\/code> and\n<code>Uninitialize()<\/code> take place on the same thread,\nand that the DLL is uninitialized on the <i>first<\/i> call\nto <code>Uninitialize()<\/code>.\n<\/p>\n<p>\nOh, and you may have noticed another bug:\nWhen <code>Initialize()<\/code> is called the second time,\nthe DLL reinitializes itself.\nIn particular, it re-creates the mutex and overwrites the\nhandle from the previous call to <code>Initialize()<\/code>.\nNow you have a handle leak.\nI suspect that&#8217;s why the call to <code>CreateMutex<\/code>\nexplicitly passes <code>\"FooMutex\"<\/code> as the mutex name.\nThe previous version passed <code>NULL<\/code>, creating an\nanonymous mutex, but then the author discovered that the mutex\n&#8220;stopped working&#8221; because some code was using the old handle\n(using the mutex created by the first call to <code>Initialize()<\/code>)\nand some code was using the new handle\n(using the mutex created by the second call to <code>Initialize()<\/code>).\nUsing a named mutex &#8220;fixes&#8221; the problem by forcing the two calls to\n<code>Initialize()<\/code> to create a handle to the same underlying\nobject.\n<\/p>\n<p>\nTo fix the handle leak, you can just stick a\n<code>if (FooMutex != NULL) return TRUE;<\/code> at the top.\nThe DLL has already been initialized; don&#8217;t need to initialize it again.\n<\/p>\n<p>\nThe design as I inferred it is somewhat unusual, however.\nUsually, when a component exposes <code>Initialize()<\/code> and\n<code>Uninitialize()<\/code> and supports multiple initialization,\nthe convention is that the DLL initialization remains valid\nuntil the <i>last<\/i> call to <code>Uninitialize()<\/code>, not the first one.\nIf that was the design intention of this DLL, then a different fix is\ncalled for,\none which I leave as an exercise,\nsince we&#8217;ve drifted pretty far from the original question.\n<\/p>\n<p>\n&sup1;The authors of\n<i>The Pragmatic Programmer<\/i> call this principle\n<a HREF=\"http:\/\/pragprog.com\/the-pragmatic-programmer\/extracts\/tips\">\n&#8216;select&#8217; isn&#8217;t broken<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A customer reported a problem with the WaitForSingleObject function: I have a DLL with an Initialize() function and an Uninitialize() function. The code goes like this: HANDLE FooMutex; BOOL Initialize() { &#8230; unrelated initialization stuff &#8230; FooMutex = CreateMutex(NULL, FALSE, &#8220;FooMutex&#8221;); &#8230; error checking removed &#8230; return TRUE; } BOOL Uninitialize() { \/\/ fail if [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-6493","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A customer reported a problem with the WaitForSingleObject function: I have a DLL with an Initialize() function and an Uninitialize() function. The code goes like this: HANDLE FooMutex; BOOL Initialize() { &#8230; unrelated initialization stuff &#8230; FooMutex = CreateMutex(NULL, FALSE, &#8220;FooMutex&#8221;); &#8230; error checking removed &#8230; return TRUE; } BOOL Uninitialize() { \/\/ fail if [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6493","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=6493"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6493\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=6493"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=6493"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=6493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}