{"id":111002,"date":"2025-03-26T07:00:00","date_gmt":"2025-03-26T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111002"},"modified":"2025-03-26T11:17:57","modified_gmt":"2025-03-26T18:17:57","slug":"20250326-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250326-00\/?p=111002","title":{"rendered":"Why does <ODE>INVALID_<WBR>HANDLE_<WBR>VALUE<\/CODE> cast through a <CODE>LONG_PTR<\/CODE> first?"},"content":{"rendered":"<p>The definition of INVALID_<wbr \/>HANDLE_<wbr \/>VALUE is<\/p>\n<pre>#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)\r\n<\/pre>\n<p>Why is there an extra cast of <code>LONG_PTR<\/code>? Why not just go straight to the final answer?<\/p>\n<pre>#define INVALID_HANDLE_VALUE ((HANDLE)-1)\r\n<\/pre>\n<p>One clue is that 32-bit Windows did use that simpler definition.<\/p>\n<p>That clue tells us that the answer has something to do with 64-bit programming.<\/p>\n<p>The issue is that casting a 32-bit integer to a 64-bit pointer involves two operations: Upgrading the 32-bit value to a 64-bit value, and then treating that 64-bit value as a pointer. The C and C++ languages leave the &#8220;interpreting an integer as a pointer&#8221; as an implementation-defined operation, but at least if the integer is a 64-bit integer and the pointer is a 64-bit pointer, there is only one reasonable implementation, and that is just to take the integer bit pattern and use it as a pointer.<\/p>\n<p>The problem is that if the integer is a 32-bit integer and the pointer is a 64-bit pointer, then multiple implementations might make sense. One might be to zero-extend the 32-bit value to a 64-bit value, which might be preferred on <!-- backref: On how different ABIs choose how to pass 32-bit values in 64-bit registers --> systems that do zero extension naturally. Another would be to sign-extend the 32-bit value to a 64-bit value, which might be preferred on systems that do sign extension naturally. Or it might be to extend based on the signed-ness of the 32-bit value, which might be preferred on systems that can do both types of extensions with equal facility.<\/p>\n<p>Since there are multiple reasonable but conflicting choices that could be made by an implementation, we should avoid casting a 32-bit integer to a 64-bit pointer because we&#8217;re not sure what we&#8217;re going to get.<\/p>\n<p>What we want is a pointer-sized value that has all bits set. So we start with the 32-bit signed integer <tt>-1<\/tt> and cast it to a <code>LONG_PTR<\/code>, which makes it a pointer-sized signed integer. Then we cast that pointer-sized integer to a pointer, which in any reasonable implementation would be a reinterpretation with no change in value.<\/p>\n<p>In other words, the extra cast forces the compiler down the desired path.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor;\"><tt>FFFFFFFF<\/tt><\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"text-align: left;\"><tt>-1<\/tt><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2193<\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"text-align: left;\">sign extension required by language rules<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\"><tt>FFFFFFFF<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\"><tt>FFFFFFFF<\/tt><\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"text-align: left;\"><tt>(LONG_PTR)-1<\/tt><\/td>\n<\/tr>\n<tr>\n<td colspan=\"2\">\u2193<\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"text-align: left;\">only reasonable implementation<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\"><tt>FFFFFFFF<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\"><tt>FFFFFFFF<\/tt><\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"text-align: left;\"><tt>(HANDLE)(LONG_PTR)-1<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If we had omitted the cast to <code>LONG_PTR<\/code>, then we would lose control over the upper 32 bits.<\/p>\n<table class=\"cp3\" style=\"border-collapse: collapse; text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"3\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"border: solid 1px currentcolor;\"><tt>FFFFFFFF<\/tt><\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"text-align: left;\"><tt>-1<\/tt><\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>\u2193<\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"text-align: left;\">no control over how 32-bit value becomes a 64-bit value<\/td>\n<\/tr>\n<tr>\n<td style=\"border: solid 1px currentcolor;\"><tt>????????<\/tt><\/td>\n<td style=\"border: solid 1px currentcolor;\"><tt>FFFFFFFF<\/tt><\/td>\n<td style=\"width: 1em;\">\u00a0<\/td>\n<td style=\"text-align: left;\"><tt>(HANDLE)-1<\/tt><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>As a general rule, therefore, casts between pointers and 32-bit integers are mediated by 64-bit integers so that we can control whether the values are sign-extended or zero-extended. We saw a little while ago that <a title=\"On how different Windows ABIs choose how to pass 32-bit values in 64-bit registers\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20250324-00\/?p=110988\"> different processors have different preferences on how 32-bit values are extended to 64-bit values<\/a>, so we can&#8217;t leave this up to chance.<\/p>\n<p>Once this rule is in place, we can activate compiler warnings that trigger when you perform casts between 32-bit integers and 64-bit pointers. These are usually indications of old 32-bit code that is not 64-bit ready. In the case that the integer is a variable or a function return value, the fix is to upgrade the variable or function to return a 64-bit integer so that the upper 32 bits of pointers are not lost. In the case that the integer is just being smuggled inside a pointer, insert an explicit cast to a 64-bit value to indicate that you don&#8217;t actually have a pointer at all; you just want to create a pointer with a specific bit pattern.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>To ensure that the proper sign extension happens.<\/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":[],"class_list":["post-111002","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing"],"acf":[],"blog_post_summary":"<p>To ensure that the proper sign extension happens.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111002","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=111002"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111002\/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=111002"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111002"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111002"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}