4

在运行 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[])。如果我通过 调整freadfwrite语句-1,我似乎没有得到这些Invalid read of size 1语句,尽管我仍然看到很多特定于的Invalid read of size 4和:8zlib

==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如前所述,我正在重新编译它,它确实将行号与错误相关联。

但我只是在做一个简单strncpyargv[]变量,例如:

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

这应该将 null 终止的argv[2]字符串复制到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]),这应该导致一个空终止的uniqTag

4

2 回答 2

5

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

编辑:

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

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

编辑2:

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

于 2010-11-16T21:47:13.923 回答
1

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

不过,这可能实际上不是错误,也可能不是您的错误。但它可能是。

于 2010-11-16T21:47:57.647 回答