当运行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
调用以删除一个字节,那么我的gzip流会被破坏。这是原始代码:
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, i.e. 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
语句,尽管我仍然看到很多{{1} }}和Invalid read of size 4
特定于8
:
zlib
编辑3
我正在使用==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
进行重新编译,如上所述,它会将行号与错误相关联。
但我只是做了-g
个strncpy
变量,例如:
argv[]
这应该将以空值终止的strncpy(uniqTag, argv[2], strlen(argv[2]) + 1);
字符串复制到argv[2]
,但uniqTag
仍将此标记为错误。
编辑4
以下是错误消息:
valgrind
这是两条相关的路线; valgrind说第二行是无效的读物:
==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
由于uniqTag = (char *)malloc(strlen(argv[2]) + 1);
strncpy(uniqTag, argv[2], strlen(argv[2]) + 1);
,这应该会导致以空值终止的strlen(argv[2]) + 1 > strlen(argv[2])
。
答案 0 :(得分:5)
在这种情况下,我会说你这样做。 libc函数参数来自您的程序。我猜错了,并说你的代码中有一个错误导致fwrite读取超过其源缓冲区末尾的一个字节。
编辑:
顺便说一下,这样一个小错误通常是看不见的(即你的代码不会崩溃)因为编译器和内存分配器通常都会分配特定大小的内存块并将它们对齐在字边缘。这意味着很多时候,在请求的缓冲区末端有一个小区域,您可以访问它而不会触发内存保护代码。当然,如果更改编译器,libc,平台或位数(例如,从64位到32位),您的代码可能会中断。
Valgrind有针对libc中预期错误的抑制列表,您通常可以在/usr/lib64/valgrind/default.supp或/usr/lib/valgrind/default.supp中找到它。 valgrind在libc中检测到了很多问题,其中许多都是为了优化代码而故意的,但是由于99%的情况下的抑制是测试代码导致问题。
EDIT2:
请记住,与大多数调试工具一样,如果使用调试符号编译代码,Valgrind将输出有关它检测到的问题的无限更多有用信息。它将能够指出与问题相关的特定代码行 - 即使它们经常不是实际问题所在。如果您使用GCC,只需在其选项中添加-g,即可使用调试符号编译代码。但是在生产版本中,请记住删除该标志!
答案 1 :(得分:1)
您应该按照调用堆栈的方式进行操作,直到找到属于您的代码并查找错误的来源。在这种情况下,STARCH_gzip_deflate
似乎正在调用fwrite
,其中包含错误的内容(可能是错误的FILE *
或您尝试写出的缓冲区),这会导致valgrind咆哮你。
但这可能实际上不是错误,也不是你的错误。但它可能是。