以下明显有效的代码使用 UndefinedBehaviorSanitizer 清理程序产生未对齐的地址运行时错误。
#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;
}
在 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();
}
我们有以下对齐方式和尺寸:
|__A__|__B__|__C__|__D__|
alignment (bytes): | 16 | 1 | 16 | 16 |
size (bytes): | 48 | 1 | 64 | 80 |
现在让我们看看这在内存中是什么样子的。对此的更多解释可以在这个很好的答案.
-
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
现在很容易看出偏移量C
inside 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
^
这里每个零是 1 个字节。
UPDATE:
在何处以及如何放置填充取决于 C++ 编译器。标准没有明确规定。它看起来像填充的大小,clang 无法对齐所有内容D
。减轻错位的一种方法是仔细设计类,使它们具有相同的对齐方式(例如 8 字节)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)