The following apparently valid code produces a misaligned address runtime error using the UndefinedBehaviorSanitizer sanitiser.
#include <memory>
#include <functional>
struct A{
std::function<void()> data; // seems to occur only if data is a std::function
} ;
struct B{
char data; // occurs only if B contains a member variable
};
struct C:public virtual A,public B{
};
struct D:public virtual C{
};
void test(){
std::make_shared<D>();
}
int main(){
test();
return 0;
}
Compiling and executing on a macbook with
clang++ -fsanitize=undefined --std=c++11 ./test.cpp && ./a.out
produces the output
runtime error: constructor call on misaligned address 0x7fe584500028 for type 'C', which requires 16 byte alignment [...]
.
I would like to understand how and why the error occurs.
Since alignment of std::function<void()>
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.
- A:
char[48] + no padding == 48B
- B:
char[1] + no padding == 1B
- C:
A* + B + A + 7 bytes of padding (align to 16) == 64B
- D:
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).
来源:https://stackoverflow.com/questions/46474238/misaligned-address-using-virtual-inheritance