Hi!
Why is the NonZeroUsize::new_unchecked method marked as unsafe? If I understand correctly, the unsafe
keyword is reserved for methods/functions that can lead directly or indirectly to undefined behavior (UB).
But I fail to see how the unsafe
status of NonZeroUsize::new_unchecked
is relevant since all its methods are safe, and, as such, are not guaranteed to actually return a non-zero value. In other words, unsafe code cannot trust the NonZeroUsize::get
method (and should perform a non-zero test) because it is not itself unsafe (as explained in the nomicon).
1 Like
The purpose of NonZeroUsize is to give a promise to the compiler that the value inside of it is never 0. That means that e.g. Option<NonZeroUsize>
is the same size as usize
with None
being represented as 0
. If that constructor were safe, you could violate that guarantee.
2 Likes
Unsafe code can trust this method to return non-zero, precisely because there is no safe way to construct a NonZeroUsize
without a non-zero value.
This is unlike the examples in the nomicon, like "can BTreeMap trust Ord implementations to be correct?" In that case, an incorrect Ord implementation can be written in safe Rust, so we can't allow such code to violate memory safety.
2 Likes
Thanks! Looks like a good reason for this to be unsafe.
The fact there is no safe way to construct NonZeroUsize
without a non-zero value does not mean ::get
will actually return a non-zero value. If unsafe code cannot trust that safe code is correct, then it cannot trust the fact a bogus implementation of :get
won't return 0. An example of bogus implementation would be:
fn get(self) -> usize {
0
}
There's an important nuance that that's missing. Unsafe code cannot trust that arbitrary safe code is correct. It can absolutely trust that safe code in its own module is correct. (Otherwise wrapping unsafe things in safe abstractions could never work, since doing so inherently involves some safe code.)
3 Likes
Unsafe code can also assume that the standard library APIs are not actively malicious.
For example, unsafe code can and does rely on the fact that [T]::as_ptr
actually returns a pointer to the start of slice's allocation.
2 Likes
Thanks @sfackler, @scottmcm, that clarifies things a lot!