ZachB
ZachB

Reputation: 15366

Does this violate strict aliasing or pointer alignment rules?

I'm swapping bytes in a char buffer:

char* data; // some char buffer
uint16_t* data16 = reinterpret_cast<uint16_t*>(data);

// For debugging:
int align = reinterpret_cast<uintptr_t>(data) % alignof(uint16_t);
std::cout << "aligned? " << align << "\n";

for (size_t i = 0; i < length_of_data16; i++) {
#if defined(__GNUC__) || defined(__clang__)
  data16[i] = __builtin_bswap16(data16[i]);
#elif defined(_MSC_VER)
  data16[i] = _byteswap_ushort(data16[i]);
#endif
}

I'm casting from char* to uint16_t*, which raises a flag because it's casting to a more strictly aligned type.

However, the code runs correctly (on x86), even when the debugging code prints 1 (as in, not aligned). In the assembly I see MOVDQU, which I take to mean that the compiler recognizes that this might not be aligned.

This looks similar to this question, where the answer was "this is not safe." Does the above code only work on certain architectures and with certain compilers, or is there a subtle difference between these two questions that makes the above code valid?

(Less important: consistent with what I've read online, there's also no noticeable perf difference between aligned and unaligned execution of this code.)

Upvotes: 0

Views: 161

Answers (1)

M.M
M.M

Reputation: 141554

If alignof(unit16_t) != 1 then this line may cause undefined behaviour due to alignment:

uint16_t* data16 = reinterpret_cast<uint16_t*>(data);

Putting an alignment check after this is no good; for a compiler could hardcode the check to say 1 because it knows that correct code couldn't reach that point otherwise.

In Standard C++ , for this check to be meaningful it must occur before the cast, and then the cast must not be performed if the check fails. (UB can time travel).

Of course, individual compilers may choose to define behaviour that is not defined by the Standard, e.g. perhaps g++ targeting x86 or x64 includes a definition that you're allowed to form unaligned pointers and dereference them.

There is no strict aliasing violation, as __builtin_bswap16 is not covered by the standard and we presume g++ implements it in such a way that is consistent with itself. MSVC doesn't do strict aliasing optimizations anyway.

Upvotes: 1

Related Questions