| Issue |
63906
|
| Summary |
clang generates aligned instructions dereferencing a pointer to a type alias declared with __aligned__(1)
|
| Labels |
|
| Assignees |
|
| Reporter |
ben-cohen-xs
|
*The following bug report assumes that defining a pointer type with the attribute `__aligned__(1)` tells the compiler that it must not assume that the value is aligned and it must generate unaligned instructions. (For example, it must generate `movups` instead of `movaps`. The gcc [manual](https://gcc.gnu.org/onlinedocs/gcc-13.1.0/gcc/Common-Type-Attributes.html) is a bit vague about this assumption but this StackOverflow [answer](https://stackoverflow.com/questions/47510783/why-does-u) by Peter Cordes is clear that it is correct.)*
The following test case, for x86_64, defines `uint128_u` as a [type alias](https://en.cppreference.com/w/cpp/language/type_alias) of `__uint128_t` with alignment 1. The `main()` function passes two `void*` pointers that are _not_ aligned to 16 bytes to the `compare()` function, which casts them to `uint128_u*` and dereferences them.
The code generated by `clang` uses aligned instructions which cause the program to fail with a segmentation fault. This happens whether or not you use optimization, but it doesn't happen if you use a `typedef` instead of `using`. It also doesn't happen if you use `gcc`.
**Test case**
* To reproduce, compile the files below on x86_64:
```
clang++ -c -o compare.o compare.cpp -Wall
clang++ -c -o test.o test.cpp -Wall
clang++ -o test test.o compare.o -Wall
```
* To run:
```
./test
```
* Expected behaviour: execution succeeds
* Observed behaviour: segmentation fault with a misaligned memory access in compare() at `movaps` for -O0 or `movdqa` for -O3
**compare.h**
```
#ifndef COMPARE_H
#define COMPARE_H
extern bool compare(const void* v1, const void* v2);
#endif
```
**compare.cpp**
```
#include "compare.h"
#define USE_USING 1
#if USE_USING
using uint128_u = __attribute__((__aligned__(1), may_alias)) __uint128_t;
#else
typedef __attribute__((__aligned__(1), may_alias)) __uint128_t uint128_u;
#endif
bool compare(const void* v1, const void* v2)
{
return *static_cast<const uint128_u*>(v1)
== *static_cast<const uint128_u*>(v2);
}
```
**test.cpp**
```
// test.cpp: Test to demonstrate that clang does not generate unaligned
// instructions for a type alias declared with `using` and
// __aligned__(1).
//
// Compile on x86_64 with
// clang++ -c -o compare.o compare.cpp -Wall
// clang++ -c -o test.o test.cpp -Wall
// clang++ -o test test.o compare.o -Wall
// Run with
// ./test
//
// Expected behaviour: execution succeeds
// Observed behaviour: segmentation fault with a misaligned memory access
// in compare() at `movaps` for -O0 or `movdqa` for -O3
//
// The problem does not happen if you use g++ or change USE_USING to 0 in
// compare.cpp.
#include <cstdlib>
#include <cstdint>
#include <iostream>
#include "compare.h"
int main()
{
__attribute__((__aligned__(16))) char some_bytes[40] = {};
if (((uintptr_t)(&some_bytes) % 16) != 0)
{
abort();
}
// v1 and v2 intentionally have alignment at non-16-byte addresses
void *v1 = &(some_bytes[8]);
void *v2 = &(some_bytes[24]);
bool result = compare(v1, v2);
std::cout << "Result: " << result << std::endl;
}
```
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs