The following apparently valid code produces a misaligned address runtime error using the UndefinedBehaviorSanitizer sanitiser.
#include
#incl
Since alignment of std::function
is 16 and size is 48 lets simplify. This code has the same behavior but is easier to understand:
struct alignas(16) A
{ char data[48]; };
struct B
{ char data; };
struct C : public virtual A, public B
{};
struct D : public virtual C
{};
int main()
{
D();
}
We have the following alignments and sizes:
|__A__|__B__|__C__|__D__|
alignment (bytes): | 16 | 1 | 16 | 16 |
size (bytes): | 48 | 1 | 64 | 80 |
Now lets see how this looks like in memory. More explanation on that can be found in this great answer.
char[48] + no padding == 48B
char[1] + no padding == 1B
A* + B + A + 7 bytes of padding (align to 16) == 64B
C* + C + 8 bytes of padding (align to 16) == 80B
Now it is easy to see that the offset of C
inside D
is 8 bytes, but C
is aligned to 16. Thus error, which is helpfully accompanied by this pseudo-graphic
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
^
Here each zero is 1 byte.
UPDATE:
Where and how to place padding is up to a C++ compiler. Standard does not specify it. It looks like with the size of padding it has, clang is unable to align everything in D
. One way to mitigate the misalignment is to design your classes carefully so that they have the same alignment (e.g., 8 bytes).