最小示例:
#include <fstream>
struct TFoo
{
bool Field1_ = false;
uint64_t Field2_ = 0;
};
int main() {
TFoo Foo_{};
const char* filename = "text.txt";
std::ofstream f(filename);
f.write((char*)(&Foo_), sizeof(Foo_));
}从msan中的第5版开始,clang报告类似以下内容:
Uninitialized bytes in __interceptor_fwrite at offset 0 inside [0x720000000000, 15)
==71928==WARNING: MemorySanitizer: use-of-uninitialized-value
#0 0x2823aa (/home/<hidden>/test-ofstream+0x2823aa)
#1 0x27830f (/home/<hidden>/test-ofstream+0x27830f)
#2 0x272757 (/home/<hidden>/test-ofstream+0x272757)
#3 0x271388 (/home/<hidden>/test-ofstream+0x271388)
#4 0x270c96 (/home/<hidden>/test-ofstream+0x270c96)
#5 0x2709e2 (/home/<hidden>/test-ofstream+0x2709e2)
#6 0x26ff9e (/home/<hidden>/test-ofstream+0x26ff9e)
#7 0x7fbc7238382f (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)这是因为Field1_和Field2_之间的填充字节未初始化。
没关系,MSAN是对的。
但是,如果代码包含非常大的代码示例(将结构保存为二进制文件),有没有什么漂亮的方法可以让代码变得更好?
(打包的结构不是我们的解决方案。)
发布于 2018-01-26 17:08:03
如果您可以更改struct TFoo的定义,则可以像这样添加一个构造函数:
struct TFoo {
bool Field1_;
uint64_t Fields_;
TFoo() { memset(this, 0, sizeof(*this)); }
TFoo(const TFoo &rhs) : TFoo() { Field1_ = rhs.Field1_; Field2_ = rhs.Field2_; }
};根据标准,我认为您不能以这种方式使用memset,但它可能适用于您的编译器。请参阅How can I zero just the padding bytes of a class?,其中讨论了此解决方案。
原始答案
这让我想到了将Field1_和Field2_之间的填充字节清零的想法。但老实说,我不确定它是否符合标准。当然,TFoo对象的某种序列化会更好,但如果我理解正确的话,这不适合您,不是吗?
struct TFoo
{
bool Field1_ = false;
uint64_t Field2_ = 0;
};
struct TFooWrapper {
union {
TFoo tfoo;
char dummy[sizeof(TFoo)] = { 0 };
} u;
};更新
从http://en.cppreference.com/w/cpp/language/union:最多一个变体成员可以有一个默认的成员初始值设定项。因此,上面的代码可能不正确。但是您可以,例如,为TFooWrapper定义默认构造函数,将所有字节置零。
https://stackoverflow.com/questions/48458115
复制相似问题