Mar*_* B. 5 c string valgrind strlen
让我们考虑一下这个简单的测试程序:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buf[256];
int i;
strcpy(buf,"Hello world!");
i = strlen(buf);
printf("Length of string is %d.\n",i);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
在使用英特尔c ++编译器进行编译并打开优化(O3)时,我从valgrind得到以下错误:
==8727== Conditional jump or move depends on uninitialised value(s)
==8727== at 0x4009EF: main (strtest.cpp:11)
==8727== Use of uninitialised value of size 8
==8727== at 0x4FC61ED: _itoa_word (in /lib64/libc-2.4.so)
==8727== by 0x4FC9317: vfprintf (in /lib64/libc-2.4.so)
==8727== by 0x4FD02A9: printf (in /lib64/libc-2.4.so)
==8727== by 0x400A09: main (strtest.cpp:13)
==8727== Conditional jump or move depends on uninitialised value(s)
==8727== at 0x4FC61F7: _itoa_word (in /lib64/libc-2.4.so)
==8727== by 0x4FC9317: vfprintf (in /lib64/libc-2.4.so)
==8727== by 0x4FD02A9: printf (in /lib64/libc-2.4.so)
==8727== by 0x400A09: main (strtest.cpp:13)
==8727== Conditional jump or move depends on uninitialised value(s)
==8727== at 0x4FC9386: vfprintf (in /lib64/libc-2.4.so)
==8727== by 0x4FD02A9: printf (in /lib64/libc-2.4.so)
==8727== by 0x400A09: main (strtest.cpp:13)
==8727== Conditional jump or move depends on uninitialised value(s)
==8727== at 0x4FC990F: vfprintf (in /lib64/libc-2.4.so)
==8727== by 0x4FD02A9: printf (in /lib64/libc-2.4.so)
==8727== by 0x400A09: main (strtest.cpp:13)
==8727== Conditional jump or move depends on uninitialised value(s)
==8727== at 0x4FC82F2: vfprintf (in /lib64/libc-2.4.so)
==8727== by 0x4FD02A9: printf (in /lib64/libc-2.4.so)
==8727== by 0x400A09: main (strtest.cpp:13)
Run Code Online (Sandbox Code Playgroud)
我使用的是最新版本的valgrind(3.6.1).关闭优化(-O0)时不会发生这种情况,而g ++不会发生这种情况.但是,它出现在我迄今为止尝试过的所有英特尔编译器中(11.0,11.1,12).
看起来这些错误与字符串函数的SIMD加速有关,就像C字符串,strlen和Valgrind中讨论的那样.
据说这是valgrind中的一个错误,现在已修复.但是,尽管使用最新的valgrind版本,我仍然有这些错误.有人对此有所帮助吗?
Valgrind试图确定一个值是否取决于初始化的内存,这一般不是一个易处理的问题.Valgrind通过跟踪设置的位进行"尽力而为",并允许它们级联.有很多方法可以欺骗它.例如,我刚刚编写了这段代码:
#include <stdlib.h>
int main(int argc, char *argv[])
{
unsigned *p = malloc(sizeof(unsigned));
unsigned x = *p;
free(p);
unsigned f = x == 0;
unsigned g = x == 1;
return f & g;
}
Run Code Online (Sandbox Code Playgroud)
旁注:严格来说,上述程序在任何没有陷阱表示的平台上都是正确的
unsigned int,这在我们的平台上是正确的(Valgrind仅限x86).未在这些平台上调用未定义的行为,并且mainC标准保证在此类平台上返回0.引用: n1256:7.20.3.3:
malloc返回值为"不确定"的对象.n1256 3.17.2:不确定值是"陷阱表示"或"未指定的值".请注意,在x86上没有无符号整数的陷阱表示.
根据Valgrind的说法,既f没有g正确初始化,f & g也无法初始化.但是,结果总是为零,因为任何有一盎司逻辑的人都会告诉你.Valgrind不理解逻辑,根据一些简单的规则,它只是跟随位.
这里可能发生的是英特尔的C编译器为您提供了一个strlen使用SSE或某种技巧的优化版本,这导致Valgrind中的"未初始化"位被置于结果中.当然,如果优化的代码读取超过初始化部分,buf然后执行如上所述的一系列操作,这自然会发生.当然,它可以做类似的事情,因为以这种方式执行它会更快(并且只要不跨越页面边界,读取x86上的数组末尾总是安全的).你有一些选择.
使用Valgrind和Intel的编译器时关闭优化.
将代码添加到Valgrind以捕获此特定类型的错误.(Valgrind已经有特殊情况了.)
有条件地修改您的代码以使Valgrind得到正确的结果.例如,将它放在顶部:
// This only fixes the error if sizeof(buf) is at least as large
// as the largest multiple of 16 larger than strlen(buf)
#if VALGRIND
memset(buf, '\0', sizeof(buf));
#endif
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
3994 次 |
| 最近记录: |