Issue |
133445
|
Summary |
Theoretical strict aliasing violation in out_ptr_t operator void**?
|
Labels |
new issue
|
Assignees |
|
Reporter |
davidben
|
(I'm filing this as an issue in the implementation, but, unless I'm wrong, I don't see good solutions beyond fixing the standard.)
I was curious how one is meant to implement `std::out_ptr_t::operator void**` and noticed both libc++ and libstdc++ just cast the pointer from `T**` to `void**`:
https://github.com/llvm/llvm-project/blob/main/libcxx/include/__memory/out_ptr.h#L81
Is this cast actually a valid implementation? I mean, this is presumably the intended implementation of `operator void**` because keeping two pointers in the `out_ptr_t` would definitely not be cheap. But ISTM this would cause a strict aliasing violation in the application. AIUI, this is not strictly legal by [strict aliasing](https://en.cppreference.com/w/cpp/language/reinterpret_cast#Type_aliasing):
```
// ptr has dynamic type int*
// https://en.cppreference.com/w/cpp/language/type#Dynamic_type
int *ptr;
// *voidp has type void*
void **voidp = (void**)&ptr;
// ptr is being accessed as a void*, but ptr, of type int*, is not
// type-accessible as a void* because int* and void* are not
// similar.
// https://en.cppreference.com/w/cpp/language/implicit_conversion#Similar_types
*voidp;
```
Now, I played with Clang and GCC in Godbolt and it looks like neither considers types this fine-grained for strict aliasing analysis, so this is probably fine in practice. But if I'm understanding this right and this is just a compiler-specific implementation-detail, it seems we have two consequences:
First, libc++ should probably have a comment to make it clear we're relying on Clang and GCC providing more guarantees than the standard does. (Is that documented anywhere by Clang and GCC?)
Second, `out_ptr_t` is, AIUI, meant to be specialized by user code for custom smart pointers. While an STL implementation can be more easily tied to specific compilers, it's a bit harder for user code to justify doing this, especially if the compilers do not actually document this property. ISTM that means that a more UB-avoiding implementation needs to maintain both `T*` and `void*` storage and track a flag for which was used. That seems poor. Especially when the aim of specialization would be to return a pointer to the smart pointer's underlying storage.
Am I just misunderstanding things? Is this just a mistake in the standard? Is it time to just relax the strict aliasing rule and allow `T*` to be accessed as `void*`, not just convertible to/from?
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs