# Why \`std::os::windows::raw::HANDLE\` a pointer while \`windows\_sys::Windows::Win32::Foundation::HANDLE\` a usize?

**URL:** <https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559>\
**Category:** Uncategorized\
**Created:** [September 12, 2023, 8:49am UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559 "2023-09-12T08:49:37Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)\
**Post date:** [September 12, 2023, 8:49am UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/1 "2023-09-12T08:49:37Z")

</div>

This causes some interop trouble.

[Windows Data Types](https://learn.microsoft.com/en-us/windows/win32/winprog/windows-data-types) says that a `HANDLE` is a `*void`, which is consistent with `std`. But by definition, a `HANDLE` is a kernel "object id", similar to a unix file descriptor, not a "memory address". It just happens to be the same size as a pointer. So maybe it shouldn't be represented by a pointer, and from that point of view `windows-sys` is right.

---

<div class="post-metadata">

**Author:** ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)\
**Post date:** [September 12, 2023, 9:09am UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/2 "2023-09-12T09:09:59Z")

</div>

I remember that when [std changed to windows-bindgen generated binding](https://github.com/rust-lang/rust/pull/110152), this problem was mentioned and the reason was "to sidestep opsem concerns about mixing pointer types and integers between languages". Any details or previous discussions?

---

<div class="post-metadata">

**Author:** ![lyphyser](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/lyphyser/32/11336_2.png) [@lyphyser](https://internals.rust-lang.org/u/lyphyser)\
**Post date:** [September 12, 2023, 10:37am UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/3 "2023-09-12T10:37:15Z")

</div>

The only difference is that on CHERI-like systems, pointers have capability/provenance metadata, while usize doesn't.

So whether to use a pointer or usize would depend on how Windows was implementing handles on a given CHERI-like architecture. `usize` would be the default choice, but it would also possible to implement handles as capabilities, in which case using either a pointer or an "offset-less" pointer capability would be appropriate.

So it should probably be usize by default, but be open to depending on cfg directives in case Windows starts supporting a CHERI-like architecture and uses capabilities for handles there.

---

<div class="post-metadata">

**Author:** ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)\
**Post date:** [September 12, 2023, 11:33am UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/4 "2023-09-12T11:33:31Z")

</div>

Talking to my friend who has experience with Windows API and internals, I realized that a `HANDLE` can be literally anything in various contexts and APIs, including but not limited to an NT object ID, a memory address, an offset, or even a thread ID! For example, the [`FindFirstFile` function](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-findfirstfilew) returns a `HANDLE` which is actually a memory address, the [`SYSTEM_PROCESS_INFORMATION` struct](https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation#system_process_information) contains a field named `UniqueProcessId` and has `HANDLE` type. In most Microsoft products, including the dotnet/C# stack, a `HANDLE` is represented as a pointer, as described in the document. So for normal cases, the pointer type is sufficient.

But for stuff that **may or may not** be a pointer, I'm not sure how to represent it in Rust is the most sufficient or correct, especially with possible systems as mentioned above that track metadata about "real" pointers.

---

<div class="post-metadata">

**Author:** ![kornel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kornel/32/2711_2.png) [@kornel](https://internals.rust-lang.org/u/kornel)\
**Post date:** [September 12, 2023, 12:51pm UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/5 "2023-09-12T12:51:56Z")

</div>

I think having it as a pointer to an opaque type is a slightly safer choice, given that identity of `usize` in Rust is a bit confused, and often assumed to be `size_t` rather than the theoretical equivalence to `intptr_t`. But I don't know if Windows will ever support architectures with 128-bit pointers, so the distinction may not matter in practice.

I presume these pointers will never be dereferenced on the Rust side. It's legal in Rust to have dangling raw pointers. The opaque target type needs to have align=1, and then even arbitrary IDs cast to pointers will be fine.

---

<div class="post-metadata">

**Author:** ![chrisd](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chrisd/32/7232_2.png) [@chrisd](https://internals.rust-lang.org/u/chrisd)\
**Post date:** [September 12, 2023, 3:43pm UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/6 "2023-09-12T15:43:24Z")

</div>

The Rust projections for the Win32 SDK come from the [win32metadata project](https://github.com/microsoft/win32metadata). This encodes the APIs as [.NET metadata](https://www.ecma-international.org/wp-content/uploads/ECMA-335_6th_edition_june_2012.pdf). In the metadata, a `HANDLE` is defined as (when represented as C# for clarity):

```rust
[RAIIFree("CloseHandle")]
[InvalidHandleValue(-1L)]
[InvalidHandleValue(0L)]
[NativeTypedef]
public struct HANDLE
{
	public IntPtr Value;
}

```

In the actual metadata that `Value` field is defined as:

```rust
.field public native int Value

```

A `native int` is a "signed integer, native size".

So the answer why windows-rs uses `isize` is "because that's what the metadata tells it". Of course that just moves the question to "why does the metadata say that". Here are some old issues that try to cover that ground:

- [https://github.com/microsoft/win32metadata/issues/21](https://github.com/microsoft/win32metadata/issues/21)
- [Define handle types as void\* so they work with NULL · Issue #395 · microsoft/win32metadata · GitHub](https://github.com/microsoft/win32metadata/issues/395)

---

<div class="post-metadata">

**Author:** ![Noratrieb](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/noratrieb/32/12440_2.png) [@Noratrieb](https://internals.rust-lang.org/u/Noratrieb)\
**Post date:** [September 13, 2023, 3:09pm UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/7 "2023-09-13T15:09:19Z")

</div>

> The only difference is that on CHERI-like systems, pointers have capability/provenance metadata, while usize doesn't.

This is not correct. Pointers and integers are also not the same on any architecture.

> **[Pointers Are Complicated, or: What's in a Byte?](https://www.ralfj.de/blog/2018/07/24/pointers-and-bytes.html)**
>
> This summer, I am again working on Rust full-time, and again I will work (amongst other things) on a “memory model” for Rust/MIR. However, before I can talk about the ideas I have for this ...

But for the purpose of HANDLE, this doesn't really matter, since Rust code never dereferences it.

---

<div class="post-metadata">

**Author:** ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)\
**Post date:** [September 19, 2023, 1:10pm UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/8 "2023-09-19T13:10:00Z")

</div>

> [@lyphyser](#):
>
> The only difference is that on CHERI-like systems, pointers have capability/provenance metadata, while usize doesn't.

May related: [Pre-RFC: `usize` semantics](https://internals.rust-lang.org/t/pre-rfc-usize-semantics/19444)

---

<div class="post-metadata">

**Author:** ![chrisd](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/chrisd/32/7232_2.png) [@chrisd](https://internals.rust-lang.org/u/chrisd)\
**Post date:** [September 19, 2023, 7:57pm UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/9 "2023-09-19T19:57:53Z")

</div>

What follows is my personal opinion alone and should not be taken as the opinion of the project, etc, etc.

I think it would be fine for std to internally use `isize` for kernel `HANDLE`s. The standard library supports a known set of targets where we know the rules and we know what kernel `HANDLE`s are. Also we talk directly to system libraries, we don't go through third parties. If a new target requires special consideration then we can special case it accordingly, though I'm unclear if it would require much effort on our part. If a platform requires stronger distinction between integers and pointers then the Windows headers themselves will also need to decide how to handle that.

However, the public API can't change for backward compatibility reasons. These will always require using pointer types. So `std::os::windows::raw::HANDLE` can never change on currently supported platforms.

---

<div class="post-metadata">

**Author:** ![stackinspector](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/stackinspector/32/9487_2.png) [@stackinspector](https://internals.rust-lang.org/u/stackinspector)\
**Post date:** [September 25, 2023, 4:24am UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/10 "2023-09-25T04:24:04Z")

</div>

One thing I didn't fully realize before is that since `()` is a ZST, a Rust program's access to `*const ()` will be compiled as a no-op, so a `*const ()` is guaranteed never to be dereferenced (except casting to other non-ZST types).

[The Rustonomicon says](https://doc.rust-lang.org/nomicon/exotic-sizes.html#empty-types):

\*const () (or equivalent) works reasonably well for void\*, and can be made into a reference without any safety problems. It still doesn't prevent you from trying to read or write values, but at least it compiles to a no-op instead of Undefined Behavior.

This is exactly the reason why:

> [@kornel](#):
>
> these pointers will never be dereferenced on the Rust side

> [@Noratrieb](#):
>
> Rust code never dereferences it

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [December 24, 2023, 4:24am UTC](https://internals.rust-lang.org/t/why-std-handle-a-pointer-while-windows-sys-handle-a-usize/19559/11 "2023-12-24T04:24:16Z")

</div>

Closed on December 24, 2023, 4:24am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
