I’ve been having a go at working with raw pointers in Rust, and I came across the offset function, which is unsafe. However you can implement a very simple version of offset by just casting the pointer to a usize, adding or subtracting an offset in bytes and then casting back to a pointer - all of which is safe in the language. So what makes the offset function unsafe? Obviously subsequently accessing the data pointed to would be unsafe, but that’s not what would make the offset function itself unsafe.
Because it uses the offset intrinsic which has the following requirement:
Both the starting and resulting pointer must be either in bounds or one byte past the end of an allocated object. If either pointer is out of bounds or arithmetic overflow occurs then any further use of the returned value will result in undefined behavior.
I believe this is because it preserves aliasing information but I’m not quite sure.
Yes, it does make sense what you are saying.
Dereferencing the pointer is unsafe, not getting the offset itself.
Since offsetting is risky, the intent was probably to make it very clear that it is unsafe to do so.
Although, reading the API, it says
or arithmetic overflow occurs then any further use of the returned value will result in undefined behavior. At the same time, Rust does not consider “unsafe” in that sense to have an arithmetic overflow, so the overflow itself should not explain why it is marked unsafe.
May be it’s because of the intrinsic? It does not convert, so, may be what it is doing is actually “unsafe”.
rustc uses llvm as the backend, and it has this answer item that explains the difference between using .offset() and casting to an integer, adding, and casting back. How is GEP different from ptrtoint, arithmetic, and inttoptr?. (.offset() uses GEP).
Rust doesn’t consider arithmetic overflow that occurs when using various built-in operators on the integer types to be unsafe, but that says nothing about the behaviour of other functions or other types.