Strange behaviour of `as_ptr()`

Hi,

I'm using const_utf16 to have the UTF-16 equivalent of Windows constant like this:

// crate::consts::algo
pub const BCRYPT_SHA256_ALGORITHM_WSTR: &[u16] =
    const_utf16::encode!(windows::Win32::Security::Cryptography::BCRYPT_SHA256_ALGORITHM);

In the same file, if I do:

fn f() {
    dbg!(BCRYPT_SHA256_ALGORITHM_WSTR.as_ptr());
}

I get an address (BCRYPT_SHA256_ALGORITHM_WSTR.as_ptr() = 0x00007ff6db829f38).

In another file, I do the same dbg! call:

// crate::other

fn g() {
    dbg!(crate::consts::algo::BCRYPT_SHA256_ALGORITHM_WSTR.as_ptr());
}

The address is slightly different and I don't understand why:

crate::consts::algo::BCRYPT_SHA256_ALGORITHM_WSTR.as_ptr() = 0x00007ff6db82b058

What am I missing?

Whenever you use a const variable, imagine the compiler copy/pastes its value directly into your code (you can read the more technical definition in the Rust Reference).

That means your code is roughly equivalent to this:

// consts/algo.rs
pub const BCRYPT_SHA256_ALGORITHM_WSTR: &[u16] = &[0, 1, 2, 3];

fn f() {
    let temp_1 = &[0, 1, 2, 3];
    dbg!(temp_1.as_ptr());
}

// other.rs

fn g() {
    let temp_2 = &[0, 1, 2, 3];
    dbg!(temp_2.as_ptr());
}

When phrased like this, it's obvious that temp_1 and temp_2 are completely different variables that live in different locations in memory. Hence the different addresses.

If you were to compile in release mode, you'll probably see the optimiser move the BCRYPT_SHA256_ALGORITHM_WSTR into some readonly data section in your program that f() and g() both refer to instead of having multiple copies floating around. This behaviour isn't guaranteed, but optimising compilers will do it pretty often because it helps reduce your overall binary size (you can think of string literals as const variables, and imagine if your binary had 50 redundant copies of " ").

If you want a guarantee that BCRYPT_SHA256_ALGORITHM_WSTR will have the same address every time, change it to a static variable.

The rule of thumb is that you use a const when you want this sort of copy/paste semantics with immutable variables, and only make something static when you want the semantics of a stereotypical global variable (only one instance, using & gives you the same address every time, etc.).

3 Likes

Thank you very much!

1 Like