{"id":4753,"date":"2013-04-04T07:00:00","date_gmt":"2013-04-04T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2013\/04\/04\/dont-forget-the-fourth-parameter-to-readfile-and-writefile-is-sometimes-mandatory\/"},"modified":"2013-04-04T07:00:00","modified_gmt":"2013-04-04T07:00:00","slug":"dont-forget-the-fourth-parameter-to-readfile-and-writefile-is-sometimes-mandatory","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20130404-00\/?p=4753","title":{"rendered":"Don&#8217;t forget, the fourth parameter to ReadFile and WriteFile is sometimes mandatory"},"content":{"rendered":"<p><P>\nThe <CODE>Read&shy;File<\/CODE>\nand\n<CODE>Write&shy;File<\/CODE>\nfunctions have a parameter called\n<CODE>lp&shy;Number&shy;Of&shy;Byte&shy;Read<\/CODE>,\nwhich is documented as\n<\/P>\n<PRE>\n  __out_opt LPDWORD lpNumberOfBytesRead,\n\/\/ or\n  __out_opt LPDWORD lpNumberOfBytesWritten,\n<\/PRE>\n<P>\n&#8220;Cool,&#8221; you think.\n&#8220;That parameter is optional, and I can safely pass <CODE>NULL<\/CODE>.&#8221;\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\n<P>\nMy program runs fine if standard output is a console,\nbut if I redirect standard output, then it crashes\non the <CODE>Write&shy;File<\/CODE> call.\nI verified that the handle is valid.\n<\/P>\n<PRE>\nint __cdecl main(int, char **)\n{\n  \/\/ error checking removed for expository purposes\n  HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);\n  WriteFile(hStdOut, &#8220;hello&#8221;, 5, NULL, NULL);\n  return 0;\n}\n<\/PRE>\n<P>\nThe crash occurs inside the <CODE>Write&shy;File<\/CODE> function\ntrying to write to a null pointer.\n<\/P>\n<\/BLOCKQUOTE>\n<P>\nBut you need to read further in the documentation for\n<CODE>Write&shy;File<\/CODE>:\n<\/P>\n<BLOCKQUOTE CLASS=\"q\">\n<DL>\n<DT><I>lp&shy;Number&shy;Of&shy;Bytes&shy;Written<\/I> [out, optional] \n<DD>\n<P>\n    A pointer to the variable that receives the number of bytes written\n    when using a synchronous <I>hFile<\/I> parameter.\n    <B>Write&shy;File<\/B> sets this value to zero\n    before doing any work or error checking.\n    Use <B>NULL<\/B> for this parameter if this is an asynchronous operation\n    to avoid potentially erroneous results.\n<\/P>\n<P>\n    This parameter can be <B>NULL<\/B>\n    only when the <I>lp&shy;Over&shy;lapped<\/I> parameter is not <B>NULL<\/B>.\n<\/P>\n<\/DL>\n<\/BLOCKQUOTE>\n<P>\nThat second paragraph is the catch:\nThe parameter is sometimes optional and sometimes mandatory.\nThe annotation language used in the function head is not\nexpressive enough to say,\n&#8220;Sometimes optional, sometimes mandatory,&#8221;\nso it chooses the weakest annotation (&#8220;optional&#8221;)\nso as not to generate false positives when run through\n<A HREF=\"http:\/\/msdn.microsoft.com\/en-us\/library\/bb385907.aspx\">\nstatic code analysis tools<\/A>.\n<\/P>\n<P>\nWith the benefit of hindsight, the functions probably should have\nbeen split into pairs, one for use with an <CODE>OVERLAPPED<\/CODE>\nstructure and one without.\nThat way, one version of the function would have a mandatory\n<CODE>lp&shy;Number&shy;Of&shy;Bytes&shy;Written<\/CODE>\nparameter and no\n<CODE>lp&shy;Over&shy;lapped<\/CODE> parameter at all;\nthe other would have a mandatory\n<CODE>lp&shy;Over&shy;lapped<\/CODE> parameter and no\n<CODE>lp&shy;Number&shy;Of&shy;Bytes&shy;Written<\/CODE>\nparameter at all.\n<\/P>\n<P>\nThe crash trying to write to a null pointer is consistent with the\nremark in the documentation that\nthe\n<CODE>lp&shy;Number&shy;Of&shy;Bytes&shy;Written<\/CODE>\nis set to zero before any work is performed.\nAs for why the code runs okay if output is not redirected:\n<A HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/09\/29\/10217910.aspx\">\nAppearing to succeed is a valid form of undefined behavior<\/A>.\nIt appears that when the output handle is a console,\nthe rule about\n<CODE>lp&shy;Number&shy;Of&shy;Bytes&shy;Written<\/CODE>\nis not consistently enforced.\n<\/P>\n<P>\nAt least for now.\n<\/P><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Read&shy;File and Write&shy;File functions have a parameter called lp&shy;Number&shy;Of&shy;Byte&shy;Read, which is documented as __out_opt LPDWORD lpNumberOfBytesRead, \/\/ or __out_opt LPDWORD lpNumberOfBytesWritten, &#8220;Cool,&#8221; you think. &#8220;That parameter is optional, and I can safely pass NULL.&#8221; My program runs fine if standard output is a console, but if I redirect standard output, then it crashes on [&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-4753","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The Read&shy;File and Write&shy;File functions have a parameter called lp&shy;Number&shy;Of&shy;Byte&shy;Read, which is documented as __out_opt LPDWORD lpNumberOfBytesRead, \/\/ or __out_opt LPDWORD lpNumberOfBytesWritten, &#8220;Cool,&#8221; you think. &#8220;That parameter is optional, and I can safely pass NULL.&#8221; My program runs fine if standard output is a console, but if I redirect standard output, then it crashes on [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4753","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=4753"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/4753\/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=4753"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=4753"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=4753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}