我将问题简化为一个非常简单的示例,其中有一个初始化所有内容的结构构造函数,但是valgrind抱怨未初始化的字节。罪魁祸首似乎是该类的布尔成员,这导致将填充字节插入到size_t成员之前。初始化这些填充字节以使valgrind不会抱怨的正确方法是什么?
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define MAX 128
typedef struct foo_struct
{
foo_struct(const std::string& name, bool q = true) : q(q)
{
if (name.size() > MAX)
{
throw std::runtime_error("too big");
}
point_name_size = name.size();
memset(n, 0, sizeof(n));
memcpy(n, name.c_str(), name.size());
}
bool q;
size_t point_name_size;
char n[MAX];
} foo_t;
int main()
{
int fd = open("/tmp/foo", O_WRONLY | O_CREAT, 0666);
if (-1 == fd)
{
throw std::runtime_error("Can't create File Descriptor: " + std::string(strerror(errno)));
}
const foo_t f("hello");
ssize_t written = write(fd, &f, sizeof(f));
std::cout << "wrote " << written << std::endl;
return 0;
}
编译并运行
g++ try.cpp && valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 ./a.out
valgrind错误为
==11790== Syscall param write(buf) points to uninitialised byte(s)
==11790== at 0x54ED154: write (write.c:27)
==11790== by 0x1093DE: main (in /home/gri6507/tmp/a.out)
==11790== Address 0x1fff000251 is on thread 1's stack
==11790== in frame #1, created by main (???:)
答案 0 :(得分:2)
将数据结构序列化为要写入大容量存储的字节块的正确方法是编写将数据编码为所需格式的序列化程序。依靠标准未指定的内容(例如字节序或类型大小)完全是错误的。
有很多可用的序列化库。
答案 1 :(得分:0)
初始化这些填充字节以使valgrind不会抱怨的正确方法是什么?
我不确定执行此操作的“正确方法”,但是有几种可能性。
struct bar
{
size_t point_name_size;
char n[MAX];
bool q;
bool unused[7] ={};
};
此“通常”的大小与64位系统上的结构大小相同。参见here。
struct bar
{
bar()
{
static_assert(std::is_trivially_copyable_v<bar>);
memset(this, 0, sizeof(bar));
}
size_t point_name_size;
char n[MAX];
bool q;
};