valgrind 抱怨 C++ 结构上的未初始化字节
valgrind complains about uninitialized bytes on C++ structure
我已按问题提炼成一个非常简单的示例,其中我有一个正在初始化所有内容的结构构造函数,但 valgrind 抱怨未初始化的字节。罪魁祸首似乎是 class 的布尔成员,它导致在 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 (???:)
What is the right way to initialize those padding bytes so that valgrind doesn't complain?
我不确定 'the right way' 是否可以这样做,但有几种可能性。
- 您为填充创建成员并初始化它们
struct bar
{
size_t point_name_size;
char n[MAX];
bool q;
bool unused[7] ={};
};
此 'typically' 与您在 64 位系统上的结构具有相同的大小。参见 here。
- 如果你是平凡可复制的,你就用 0 填充自己
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;
};
将数据结构序列化为要写入大容量存储的字节块的正确方法是编写序列化程序,将数据编码为所需格式。依赖标准未指定的内容(例如字节顺序或类型大小)是完全错误的。
有大量可用的序列化库。
我已按问题提炼成一个非常简单的示例,其中我有一个正在初始化所有内容的结构构造函数,但 valgrind 抱怨未初始化的字节。罪魁祸首似乎是 class 的布尔成员,它导致在 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 (???:)
What is the right way to initialize those padding bytes so that valgrind doesn't complain?
我不确定 'the right way' 是否可以这样做,但有几种可能性。
- 您为填充创建成员并初始化它们
struct bar
{
size_t point_name_size;
char n[MAX];
bool q;
bool unused[7] ={};
};
此 'typically' 与您在 64 位系统上的结构具有相同的大小。参见 here。
- 如果你是平凡可复制的,你就用 0 填充自己
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;
};
将数据结构序列化为要写入大容量存储的字节块的正确方法是编写序列化程序,将数据编码为所需格式。依赖标准未指定的内容(例如字节顺序或类型大小)是完全错误的。
有大量可用的序列化库。