Pointer to usize transmute lead to unexpected errors

Hi, I'm trying to do pointer arithmetic, and apparently because raw pointers are not Send, I am transmuting them to usize and back to send them into multiple threads.

However, for some reason I have stumbled onto a bug. Sadly, I can not reproduce it in a minimal example (this seems to be edge case of some sort), but when I'm transmuting *const *const T into usize, and then reverse the operation inside of a (parallel) iterator, it gives nonsensical error message (attempt to access vector of length 729, but index is 0).

I have replaced the transmutes with pointer casts (as usize and as *const *const T) and it seems to work now, but I wonder

  1. What could cause such bug? I've read a bit about pointer provenance, but didn't understand it well enough to judge if it could be the reason.

  2. What is the "correct" way of doing multi-threaded pointer arithmetic, considering that const * and mut * are not Send?

You can wrap the pointer in a newtype that does implement Send, like:

4 Likes

Yeah, that seems a bit more convenient than usize conversions. Thanks.

Yeah, you should never transmute pointers. Transmute means "re-interpret bit-by-bit". That operation is basically completely nonsensical outside of a very limited set of "pure value" types (such as primitives and direct, owning aggregates thereof).

When you start bringing indirection into the picture, all hell breaks loose. In particular, people often confuse the following two scenarios:

  • transmuting a value of type T to a value of type U. This can, for example, be realized by obtaining a pointer of type *const T, then casting (not transmuting!) the pointer to *const U, finally reading it to obtain a value of type U. This is usually what people want. It is performed by casting the pointer, because that is an operation that preserves provenance, and it's sometimes the only correct option. E.g. transmuting a fat pointer to a thin pointer is simply not possible because they have different sizes; you need the compiler to understand the conversion operation in order to throw away the correct half of the pointer-metadata pair.
  • directly transmuting (not casting!) a pointer of type *const T itself into a pointer of type *const U. This is basically almost never correct and almost never what people want.
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.