i need you to realize you linked me at the exact same part of rust docs that i, myself, linked. i was not asking why one is safe and the other is not, i was asking what optimization differences there are
Conversation
llvm.org/docs/GetElemen is informative in a subtle way: because an inbounds gep cannot overflow, the compiler can make assumptions about ordering of pointers, among other things
1
Replying to
Main guarantees is that it's in-bound. ptr::wrapping_add method is poorly named. The main difference is that it permits the result to not be within the bounds of the object. Disallowing wrapping as part of inbounds is a bonus thing.
1
So, among many other things, it's guaranteed to not be a null pointer and null checks can be eliminated. A negative offset will go backwards within the object, a positive offset will go forwards within the object (up to one byte past the end) and a zero offset will stay the same.
2
Replying to
"a `negative offset` will go backwards within the object" is not necessarily true, and the entire reason i'm looking closely at these functions
2
if you have a 2^31+1 byte alloc in a 2^32-byte address space, 0x80000001 may be a valid offset that does not go backwards
2
1
A valid offset by C rules, but to the non-allocated byte one past the end, and UB to actually dereference. You need at least a 2^31+2 byte allocation for 0x80000001 to be a valid offset of an allocated byte.
1
1
Neither GCC or LLVM supports ptrdiff+1 size allocations. Both of them delegate responsibility to the malloc and mmap implementations in libc to report an error for overflow large allocations. Some malloc implementations handle this and others (glibc) are broken with GCC/LLVM.
2
2
4
Rust explicitly defines isize::MAX as the maximum size object that's permitted. Unsafe code needs to uphold this by making sure not to do it.
Some malloc implementations like musl & jemalloc have this check internally but Rust has to check itself with an unknown/generic malloc.
1
1
3
See gcc.gnu.org/bugzilla/show_ for a thread about this. ptrdiff_t+1 or larger objects are just not permitted with LLVM and GCC. It's not a C standard violation but rather they require that all standard ways of allocating objects (C, POSIX) have checks preventing larger objects.
1
I helped fix multiple malloc and libc implementations but there are still common ones like glibc that are broken with GCC/LLVM. It's a bad idea to use objects larger than PTRDIFF_MAX even with a compiler supporting it since x-y will be undefined if it overflows.
I made the initial implementation of Rust's iterators, Vec<T> and other parts of the standard library. These issues had to be resolved in a safe way, and defining isize::MAX as the maximum object size with enforcement in the allocation paths was the only realistic way to do it.
1
1
Even with the C standard semantics, it's unrealistic to avoid x-y when it would overflow. GCC and LLVM don't give you the opportunity to try to use it correctly. It just isn't supported. It's one of many rules they don't really bother to document. It's how they intend it to work.
2
2
Just to be crystal clear... by "compiler supporting PTRDIFF_MAX + 1", you mean "the compiler assumes an object of PTRDIFF_MAX + 1 can possibly exist" (and gcc/llvm doesn't)?
1
Yes, that's what I mean. GCC and LLVM don't support objects larger than PTRDIFF_MAX. It's not seen as a bug but it could be seen as a missing feature. It doesn't appear there's any interest in implementing it though.
So, you need a compiler supporting that *and* it's still hard.
1
Show replies



