运行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[]
)。 如果我调整fread
和fwrite
语句的-1
,我似乎并没有得到那些Invalid read of size 1
语句的Invalid read of size 1
,尽pipe我仍然看到很多Invalid read of size 4
和8
特定于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向你咆哮。
虽然这可能不是一个错误,也不是你的错误。 但可能是。