Search code examples
c++language-lawyerc++20strict-aliasing

Aliasing accesses through a std::bit_cast()ed pointer


Violating strict-aliasing rules yields undefined behavior, e.g. when sending a struct over the network into a char buffer, and then that char pointer is C-style/reinterpret_cast casted to a struct pointer.

The C++ std::bit_cast() function looks like it could be used to cast such pointers in an (implementation?) defined way, i.e. without violating strict-aliasing rules.

Example:

#include <sys/types.h>
#include <netinet/in.h>

#include <bit>

int get_sock_addr(const struct sockaddr *a)
{
    struct sockaddr_in *x = std::bit_cast<struct sockaddr_in*>(a);
    return x->sin_addr.s_addr;
}

So the caller of get_sock_addr() somehow obtained a sockaddr pointer and has determined that it actually points to a sockaddr_in struct.

So, is such pointer casting via std::bit_cast() a valid use-case?

Or does it somehow yield undefined behavior, as well?

If it's defined behavior, does the standard classify such pointer-casting as implementation-defined behavior?


The std::bit_cast() proposal mentions:

If no value representation corresponds to To's object representation then the returned value is unspecified.

So is a standard-conforming compiler possible where different pointer representations are incompatible such that they can't correspond to each other?


Solution

  • Converting the pointer value is irrelevant. What matters is the object. You have a pointer to an object of type X, but the pointer's type is Y. Trying to access the object of type X through a pointer/reference to unrelated type Y is where the UB comes from.

    How you obtained those pointers is mostly irrelevant. So bit_cast is no better than reinterpret_cast in this regard.

    If there is no sockaddr_in there, then you can't pretend that there is one. However, it's possible that implicit object creation in C++20 already solves this matter, depending on your code. If it does, then it still doesn't matter how you get the pointer.