我需要担心Valgrind在申请范围之外报告错误吗?

运行Valgrind的memcheck工具时,我经常会得到几十万(或更多,因为Valgrind在100K切断)小的无效读取语句,例如:

 ==32027== Invalid read of size 1 ==32027== at 0x3AB426E26A: _IO_default_xsputn (in /lib64/libc-2.5.so) ==32027== by 0x3AB426CF70: _IO_file_xsputn@@GLIBC_2.2.5 (in /lib64/libc-2.5.so) ==32027== by 0x3AB42621FA: fwrite (in /lib64/libc-2.5.so) ==32027== by 0x4018CA: STARCH_gzip_deflate (in /home/areynolds/trunk/utility/applications/bed/starch/bin/starch) ==32027== by 0x401F48: compressFileWithGzip (in /home/areynolds/trunk/utility/applications/bed/starch/bin/starch) ==32027== by 0x4028B5: transformInput (in /home/areynolds/trunk/utility/applications/bed/starch/bin/starch) ==32027== by 0x402F12: main (in /home/areynolds/trunk/utility/applications/bed/starch/bin/starch) ==32027== Address 0x7febb9b3c is on thread 1's stack 

这些语句是指调用我的应用程序之外的函数(“ starch ”),它似乎是libc一部分。 这是我需要关心的吗?

编辑

如果我修改fwrite调用删除一个字节,那么我的gzipstream被损坏。 这是原来的代码:

 int STARCH_gzip_deflate(FILE *source, FILE *dest, int level) { int ret, flush; unsigned have; z_stream strm; unsigned char in[STARCH_Z_CHUNK]; unsigned char out[STARCH_Z_CHUNK]; /* initialize deflate state */ strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; /* deflateInit2 allows creation of archive with gzip header, ie a gzip file */ /* cf. http://www.zlib.net/manual.html */ ret = deflateInit2(&strm, level, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY); if (ret != Z_OK) return ret; /* compress until end of file */ do { strm.avail_in = fread(in, 1, STARCH_Z_CHUNK, source); if (ferror(source)) { (void)deflateEnd(&strm); return Z_ERRNO; } flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; strm.next_in = in; do { strm.avail_out = STARCH_Z_CHUNK; strm.next_out = out; ret = deflate(&strm, flush); assert(ret != Z_STREAM_ERROR); have = STARCH_Z_CHUNK - strm.avail_out; /* invalid read happens here */ if (fwrite(out, 1, have, dest) != have || ferror(dest)) { (void)deflateEnd(&strm); return Z_ERRNO; } } while (strm.avail_out == 0); assert(strm.avail_in == 0); } while (flush != Z_FINISH); assert(ret == Z_STREAM_END); /* clean up and return */ (void)deflateEnd(&strm); return Z_OK; } 

编辑2

我想我看到了这个问题。 我in[STARCH_Z_CHUNK]而不是in[STARCH_Z_CHUNK + 1] (同样out[] )。 如果我调整freadfwrite语句的-1 ,我似乎并没有得到那些Invalid read of size 1语句的Invalid read of size 1 ,尽pipe我仍然看到很多Invalid read of size 48特定于zlib

 ==32624== Invalid read of size 4 ==32624== at 0x3AB5206455: deflateInit2_ (in /usr/lib64/libz.so.1.2.3) ==32624== by 0x40180E: STARCH_gzip_deflate (in /home/areynolds/trunk/utility/applications/bed/starch/bin/starch) ==32624== by 0x401F48: compressFileWithGzip (in /home/areynolds/trunk/utility/applications/bed/starch/bin/starch) ==32624== by 0x402C03: transformInput (in /home/areynolds/trunk/utility/applications/bed/starch/bin/starch) ==32624== by 0x402F12: main (in /home/areynolds/trunk/utility/applications/bed/starch/bin/starch) ==32624== Address 0x7feafde38 is on thread 1's stack 

编辑3

我正在用-g重新编译,如前所述,它将行号与错误联系起来。

但是我只是做一个简单的argv[]variables,例如:

 strncpy(uniqTag, argv[2], strlen(argv[2]) + 1); 

这应该复制以null结尾的argv[2]string到uniqTag ,但是valgrind仍然将其标记为错误。

编辑4

这里是错误信息:

 ==3682== Invalid read of size 1 ==3682== at 0x4A081C1: strncpy (mc_replace_strmem.c:329) ==3682== by 0x4022F1: parseCommandLineInputs (starch.c:589) ==3682== by 0x402F20: main (starch.c:46) ==3682== Address 0x7fedffe11 is on thread 1's stac 

这是两条相关的路线。 valgrind在说第二行是无效的读取:

 uniqTag = (char *)malloc(strlen(argv[2]) + 1); strncpy(uniqTag, argv[2], strlen(argv[2]) + 1); 

因为strlen(argv[2]) + 1 > strlen(argv[2]) ,这应该导致以null结尾的uniqTag

在这种情况下,我会说,你这样做。 libc函数参数来自你的程序。 我会冒险猜测,并说你的代码中有一个错误导致fwrite读取源缓冲区末尾的一个字节。

编辑:

顺便说一下,这样一个小错误往往可以保持不可见(即你的代码不会崩溃),因为编译器和内存分配器通常分配特定大小的内存块,并在字边对齐它们。 这意味着很多时候有一个小区域超出了请求的缓冲区,您可以访问而不触发内存保护代码。 当然,如果你改变编译器,libc,平台或位(例如从64位到32位),你的代码可能会中断。

Valgrind在libc中有预期的错误列表,通常可以在/usr/lib64/valgrind/default.supp或/usr/lib/valgrind/default.supp找到。 valgrind在libc中检测到的问题有很多,其中许多是为了优化代码而有意识的,但是由于99%的情况下是被测试的代码导致了这个问题。

EDIT2:

请记住,与大多数调试工具一样,如果您使用调试符号编译您的代码,Valgrind将针对其检测到的问题输出无限多的有用信息。 它将能够指出与特定问题相关的特定代码行 – 即使通常它们并不是实际问题所在。 如果您使用GCC,只需在其选项中添加-g以使用调试符号编译您的代码。 但是在发行版中,请记住删除该标志!

你应该关掉调用堆栈,直到找到你的代码并查找错误的来源。 在这种情况下, STARCH_gzip_deflate似乎是用一些不好的东西(可能是错误的FILE *或你正试图写出的缓冲区)来调用fwrite ,这会导致valgrind向你咆哮。

虽然这可能不是一个错误,也不是你的错误。 但可能是。