Lar*_*ars 6 c++ memory-alignment virtual-inheritance sanitizer clang++
以下显然有效的代码使用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;
}
Run Code Online (Sandbox Code Playgroud)
在macbook上编译和执行
clang++ -fsanitize=undefined --std=c++11 ./test.cpp && ./a.out
产生输出
runtime error: constructor call on misaligned address 0x7fe584500028 for type 'C', which requires 16 byte alignment [...].
我想了解错误发生的方式和原因.
由于对齐方式std::function<void()>为16,尺寸为48,因此简化了。此代码具有相同的行为,但更易于理解:
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();
}
Run Code Online (Sandbox Code Playgroud)
我们有以下对齐方式和大小:
|__A__|__B__|__C__|__D__|
alignment (bytes): | 16 | 1 | 16 | 16 |
size (bytes): | 48 | 1 | 64 | 80 |
Run Code Online (Sandbox Code Playgroud)
现在让我们看看它在内存中的样子。关于这个的更多解释可以在这个很好的答案中找到。
char[48] + no padding == 48Bchar[1] + no padding == 1BA* + B + A + 7 bytes of padding (align to 16) == 64BC* + C + 8 bytes of padding (align to 16) == 80B现在可以很容易地看到,C内部的偏移量D是8个字节,但C与16对齐。
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
^
Run Code Online (Sandbox Code Playgroud)
这里每个零是1个字节。
更新:在哪里以及如何放置填充取决于C ++编译器。Standard未指定。看起来像具有的填充大小一样,clang无法将中的所有内容对齐D。减轻不对齐的一种方法是仔细设计类,以使它们具有相同的对齐方式(例如8个字节)。