Valgrind ClientCheck 未初始化的字符串
我是 Valgrind 的新手,在查找其中一些警告的来源时遇到了一些麻烦。我一直在使用 memcheck.h
中的 VALGRIND_CHECK_VALUE_IS_DEFINED 宏来尝试找到错误的确切来源,这让我怀疑我是否正确使用了该工具。
这是我使用 Valgrind 运行的示例程序:
#include <valgrind/memcheck.h>
int main() {
std::string str("test");
VALGRIND_CHECK_VALUE_IS_DEFINED(str);
return 0;
}
导致出现以下警告:
==9612== Uninitialised byte(s) found during client check request
==9612== at 0x11EB45: main (main.cpp:5)
==9612== Address 0x1ffefffd35 is on thread 1's stack
==9612== in frame #0, created by main (main.cpp:3)
==9612== Uninitialised value was created by a stack allocation
==9612== at 0x11EA8E: main (main.cpp:3)
非常相似的程序:
#include <valgrind/memcheck.h>
int main() {
int x = 0;
VALGRIND_CHECK_VALUE_IS_DEFINED(x);
return 0;
}
没有这样的问题。我使用标志 --track-origins=yes 进行线路跟踪,并在 Ubuntu 20.04 LTS 上使用 g++ 9.4.0 编译为 c++17(尽管我收到了与 clang++ 14.0.0 相同的警告)。
这是我的错误,还是 Valgrind 的问题?
I'm new to Valgrind, and I've had some trouble finding the source of some of it's warnings. I've been using the VALGRIND_CHECK_VALUE_IS_DEFINED macro from memcheck.h
to try and locate the exact source of the error, which has led me to wonder if I am using the tool correctly.
Here is a sample program that I run with Valgrind:
#include <valgrind/memcheck.h>
int main() {
std::string str("test");
VALGRIND_CHECK_VALUE_IS_DEFINED(str);
return 0;
}
Which results in the following warnings:
==9612== Uninitialised byte(s) found during client check request
==9612== at 0x11EB45: main (main.cpp:5)
==9612== Address 0x1ffefffd35 is on thread 1's stack
==9612== in frame #0, created by main (main.cpp:3)
==9612== Uninitialised value was created by a stack allocation
==9612== at 0x11EA8E: main (main.cpp:3)
A very similar program:
#include <valgrind/memcheck.h>
int main() {
int x = 0;
VALGRIND_CHECK_VALUE_IS_DEFINED(x);
return 0;
}
has no such issue. I am using the flag --track-origins=yes for line tracing, and compiling as c++17 using g++ 9.4.0 (although I received the same warning with clang++ 14.0.0) on Ubuntu 20.04 LTS.
Is this a mistake on my end, or is it an issue with Valgrind?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
原因很简单。 std::string 大致由指针、长度和 allocate_capacity 成员组成。在 64 位类 Unix 平台上它们都是 8 字节。如果字符串足够短,“SSO”[小字符串优化]将通过联合回收(并扩展)分配的容量成员来存储字符串。
请注意,clang libc++ 的做法有点不同(我认为那里的联合回收了指针和允许更大“小”字符串的容量)。
这意味着
sizeof(std::string)
是 32。那么有两种可能性。local_buf
中的任何备用容量(libstdc++ 为 16 字节)都将未初始化。考虑以下代码。我使用了 VALGRIND_GET_VBITS ,它将获取一个字节,其中已定义内存的位设置为零,未定义内存的位设置为 1。
对于
str
(使用 4 个字节加 1 个字节作为 nul,因此 SSO 缓冲区为 5 个字节)。 “未初始化字节”消息后的输出是字节 0 位 0
[同1至13]
字节 14 位 0
字节 15 位 ff
[同样16到30]
byte 31 位 ff
所以你可以看到字节 15 到 31 是未定义的。那是 11 个字节,这正是我所期望的。 16 个字节用于 SSO local_buf,其中前 5 个字节由“test\0”初始化。
对于 str2,没有“未初始化字节”消息,并且 VBITS 均已定义。
最后,对于 str3,对于 SSO 来说太长,再次出现“未初始化字节”消息,这次输出是
字节 0 位 0
[相同 1 至 22]
字节 23 位 0
字节 24 位 ff
[同样25到30]
byte 31 位 ff
这又符合预期。现在,字符串的最后 8 个字节就像未使用的填充并且未初始化。
The reason for this is fairly straightforward. An std::string roughly consists of a pointer, length and allocated_capacity members. On 64bit Unix-like platforms they are all 8 bytes. The "SSO" [Small String Optimization] will recycle (and extend) the allocated capacity member via a union to store the string if it is short enough.
Note that clang libc++ does things a bit differently (I think that the union there recycles the pointer and the capacity to allow larger "small" strings).
This means that
sizeof(std::string)
is 32. There are then two possibilities.local_buf
(16 bytes for libstdc++) will be uninitialized.Consider the following code. I've used VALGRIND_GET_VBITS which will get a byte with bits set to zero for defined memory and set to 1 for undefined memory.
For
str
(used 4 bytes plus one for nul, so 5 bytes of the SSO buffer). The output after the "Uninitialized bytes" message isbyte 0 bits 0
[same 1 to 13]
byte 14 bits 0
byte 15 bits ff
[same 16 to 30]
byte 31 bits ff
So you can see bytes 15 to 31 are undefined. That's 11 bytes, which is what I expected. 16 bytes for the SSO local_buf, the first 5 bytes of which are initialized by "test\0".
For str2 there is no "Uninitialized bytes" message, and the VBITS are all defined.
Lastly for str3, too long for SSO, again there is an "Uninitialized bytes" message and this time the output is
byte 0 bits 0
[same 1 to 22]
byte 23 bits 0
byte 24 bits ff
[same 25 to 30]
byte 31 bits ff
Again this is as expected. Now the last 8 bytes of the string are acting like unused padding and are uninitialized.