{"id":6343,"date":"2012-10-12T07:00:00","date_gmt":"2012-10-12T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2012\/10\/12\/what-happens-if-you-forget-to-pass-an-overlapped-structure-on-an-asynchronous-handle\/"},"modified":"2023-10-24T15:01:47","modified_gmt":"2023-10-24T22:01:47","slug":"20121012-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20121012-00\/?p=6343","title":{"rendered":"What happens if you forget to pass an OVERLAPPED structure on an asynchronous handle?"},"content":{"rendered":"<p>A customer noticed that they were accidentally issuing some I\/O&#8217;s against an overlapped handle without using an <code>OVERLAPPED<\/code> structure. The calls seemed to work, and the program did not appear to suffer any ill effects, but they were worried that they just being lucky and that eventually the error will come back to bite them. So what really happens if you forget to pass an <code>OVERLAPPED<\/code> structure on an asynchronous handle?<\/p>\n<p>Well, the layer of the kernel that deals with <code>OVERLAPPED<\/code> structures doesn&#8217;t know whether then handle is synchronous or asynchronous. It just assumes that if you don&#8217;t pass an <code>OVERLAPPED<\/code> structure, then the handle is synchronous. And the way it deals with synchronous I\/O without an <code>OVERLAPPED<\/code> is that it creates a temporary <code>OVERLAPPED<\/code> structure on the stack with a null <code>hEvent<\/code>, issues an asynchronous I\/O with that temporary <code>OVERLAPPED<\/code> structure, and then waits for completion with <code>Get\u00adOverlapped\u00adResult(<wbr \/>bWait = TRUE)<\/code>. It then returns the result.<\/p>\n<p>What does this mean for you?<\/p>\n<p>Well, what happens if the <code>hEvent<\/code> is null?<\/p>\n<blockquote class=\"q\"><p><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms683209.aspx\"> If the <b>hEvent<\/b> member of the <b>OVERLAPPED<\/b> structure is NULL<\/a>, the system uses the state of the <b>hFile<\/b> handle to signal when the operation has been completed.<\/p><\/blockquote>\n<p>Okay, let&#8217;s step back and look at what&#8217;s going on here.<\/p>\n<p>First of all, a file handle is a waitable object: It becomes unsignaled when an I\/O operation begins, and it becomes signaled when an I\/O operation ends.<\/p>\n<p>Second of all, this behavior is not useful in general. If you are operating on a synchronous handle, you already know when the I\/O operation ends: It ends when the synchronous I\/O call returns. And if you are operating on an asynchronous handle, all the <code>hFile<\/code> tells you is that <i>some<\/i> I\/O completed, but you don&#8217;t know which one it was. That&#8217;s why the documentation also says<\/p>\n<blockquote class=\"q\"><p>Use of file, named pipe, or communications-device handles for this purpose is discouraged. It is safer to use an event object because of the confusion that can occur when multiple simultaneous overlapped operations are performed on the same file, named pipe, or communications device. In this situation, there is no way to know which operation caused the object&#8217;s state to be signaled.<\/p><\/blockquote>\n<p>What&#8217;s more, if somebody initiates a new I\/O after your asynchronous I\/O completed, the file object becomes unsignaled, and there&#8217;s a possibility that this happened before you got a change to call <code>Wait\u00adFor\u00adSingle\u00adObject<\/code>.<\/p>\n<p>So why have this weird behavior if it&#8217;s not useful in general? Because it&#8217;s what the system itself uses internally to implement synchronous I\/O! It issues the I\/O asynchronously, then waits on the handle. Since the handle is synchronous, the system already knows that there can be only one I\/O in progress at a time, so it can just wait on the <code>hFile<\/code> to know when that I\/O is complete.<\/p>\n<p>Okay, so let&#8217;s look again at the case of the overlapped I\/O issued with no <code>OVERLAPPED<\/code> structure. The layer that deals with <code>OVERLAPPED<\/code> structure assumes it has a synchronous handle and issues an asynchronous I\/O, then waits until the handle is signaled, under the mistaken belief that the handle will be signaled when that I\/O completes (since it &#8220;knows&#8221; that that&#8217;s the only outstanding I\/O request). But if your handle is actually asynchronous, what happens is that the <code>OVERLAPPED<\/code> layer waits on the <code>hFile<\/code>, and the call returns when <i>any<\/i> I\/O on that handle completes. In other words, you&#8217;re in the &#8220;&#8230; is discouraged&#8221; part of the documentation.<\/p>\n<p>Theoretically speaking, then, it is legal to pass <code>NULL<\/code> as the <code>lpOverlapped<\/code> to <code>Read\u00adFile<\/code> when the handle is asynchronous, but the results may not be what you want, since the call may return prematurely if there is other I\/O going on at the same time. And then when the I\/O actually completes, it updates the <code>OVERLAPPED<\/code> structure that was created temporarily on the stack, and we saw that that leads to <a href=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/02\/02\/10123392.aspx\"> memory corruption that goes away when you try to debug it<\/a>.<\/p>\n<p>There are those who argue that the documentation for <code>Read\u00adFile<\/code> is overly cautious when it outright bans the use of a null <code>lpOverlapped<\/code> on asynchronous handles, because if you are <i>really careful<\/i>, you can get it to work, if you can guarantee that no I\/O is outstanding on the handle at the time you issue your I\/O call, and no other I\/O will be issued against the handle while you&#8217;re waiting for your call to complete.<\/p>\n<p>I&#8217;m of the camp that it&#8217;s like telling people that it&#8217;s okay to <a href=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/11\/22\/10094489.aspx\"> change gears on your manual transmission by just slamming the gear stick into position without using the clutch<\/a>. Yes, you can do it if you are really careful and get everything to align just right, but if you mess up, your transmission explodes and spews parts all over the road.<\/p>\n<p>In the customer&#8217;s case they were issuing the I\/O without an <code>OVERLAPPED<\/code> structure after the handle was created and before asynchronous operations began, so it was indeed the case that nobody else was using the handle.\u00b9 The usage was therefore technically safe, but the customer nevertheless chose to switch to using an explicit <code>OVERLAPPED<\/code> structure with an explicit <code>hEvent<\/code>, just in case future code changes resulted in asynchronous operations being performed on the handle at an earlier point. (Wise choice on the customer&#8217;s part. Safety first!)<\/p>\n<p>\u00b9 We&#8217;re assuming that there aren&#8217;t any bugs that result in somebody using a handle after closing it or using an uninitialized handle variable. Even if that assumption isn&#8217;t true, it would also cause problems even in the case where we passed an explicit <code>OVERLAPPED<\/code> structure, so it&#8217;s no buggier than it was before.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>It becomes synchronous, sort of.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-6343","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>It becomes synchronous, sort of.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6343","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=6343"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/6343\/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=6343"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=6343"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=6343"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}