{"id":108684,"date":"2023-08-31T07:00:00","date_gmt":"2023-08-31T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108684"},"modified":"2023-08-31T06:46:05","modified_gmt":"2023-08-31T13:46:05","slug":"20230831-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230831-00\/?p=108684","title":{"rendered":"Diagnosing a crash when trying to call <CODE>ReadFile<\/CODE> via language interop"},"content":{"rendered":"<p>A customer was having trouble calling the <code>Read\u00adFile<\/code> function with the interop feature of their language. It crashed with<\/p>\n<pre>(df4.1ef4): Access violation - code c0000005 (first chance)\r\n\r\nrax=0000000001260000 rbx=00000093834eb020 rcx=0000000000000264\r\nrdx=00000093834eb028 rsi=0000000000000264 rdi=0000000000000000\r\nrip=00007ff9eaddaf5f rsp=00000093834eaf50 rbp=00000093834eb029\r\n r8=000000000000003c  r9=00000093834eb020 r10=00000093834eb028\r\nr11=0000000000000246 r12=ffffffff89010f67 r13=0000000000000001\r\nr14=000000d900000000 r15=0000000000000000\r\niopl=0         nv up ei pl nz na po nc\r\ncs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206\r\nKERNELBASE!ReadFile+0xaf:\r\n00007ff9`eaddaf5f mov     [r14],103h ds:000000d9`00000000=????????????????\r\n<\/pre>\n<p>Their interop declaration looked something like this.<\/p>\n<pre>function ReadFile(\r\n    handle: integer,\r\n    buffer: array of byte,\r\n    length: integer,\r\n    actual: ref integer,\r\n    overlapped: integer): integer;\r\n\r\n\/\/ called as follows\r\n\r\nvar handle: integer; \/* assume we get a handle somehow *\/\r\nvar buffer: array(256) of byte;\r\nvar actual: integer;\r\nvar result: integer;\r\n\r\nresult = ReadFile(handle, buffer, 256, actual, 0);\r\n<\/pre>\n<p>From the crash, we see that we are moving the value <code>0x0103<\/code> into an invalid pointer.<\/p>\n<p>Can you solve the mystery?<\/p>\n<p>Hint: The disassembly shows that this code is running in 64-bit mode.<\/p>\n<p>Another hint: The value <code>0x103<\/code> is <code>STATUS_<wbr \/>PENDING<\/code>.<\/p>\n<p>Yet another hint: The invalid address happens to be an exact multiple of 4GB.<\/p>\n<p>Okay, let&#8217;s put the hints together.<\/p>\n<p>The last hint steers you to the answer: In the <code>Read\u00adFile<\/code> function, the <code>handle<\/code> and <code>overlapped<\/code> parameters are pointer-sized, whereas the <code>length<\/code> and <code>actual<\/code> parameters are 32-bit integers, but the interop declaration calls them all the same thing: <code>integer<\/code>. I&#8217;m guessing that in this language, <code>integer<\/code> is a 32-bit integer.<\/p>\n<p>Due to the size mismatch, the caller puts a 32-bit zero on the stack, but the function expects a pointer and reads a 64-bit value. As a result, only the lower-order 32 bits end up zero, and the upper 32 bits contain uninitialized stack data.<\/p>\n<p>The other clue that the problem is with the <code>overlapped<\/code> parameter is that the first use of the invalid pointer is to write <code>STATUS_<wbr \/>PENDING<\/code> to it, which makes sense because that&#8217;s what gets written to an <code>OVERLAPPED<\/code> structure to indicate that the I\/O is in progress.<\/p>\n<p>I mentioned that the first parameter <code>handle<\/code> is also pointer-sized, yet nothing appears to go wrong with the handle. Why do we get away with an incorrect declaration for <code>handle<\/code>, but not for <code>overlapped<\/code>?<\/p>\n<p>The Windows x86-64 calling convention puts the first four parameters in registers, so the <code>handle<\/code> parameter goes into the <code>rcx<\/code> register. The x86-64 architecture has the policy that if you load a 32-bit value into a 64-bit register, the upper 32 bits are set to zero by default.\u00b9 The value being loaded into the <code>rcx<\/code> register almost certainly came from memory or another register, and the load of a 32-bit value into that register will implicitly zero-extend the value to 64 bits.<\/p>\n<p>\u00b9 There is a separate instruction for loading with sign extension.<\/p>\n<p><b>Related reading<\/b>: <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230828-00\/?p=108657\"> Which processors prefer sign-extended loads, and which prefer zero-extended loads<\/a>?<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Checking the signatures and inferring what could have gone wrong.<\/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-108684","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Checking the signatures and inferring what could have gone wrong.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108684","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=108684"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108684\/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=108684"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108684"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108684"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}