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

Reply via email to