【问题标题】:Do I need to worry about Valgrind reporting errors outside the scope of my application?我是否需要担心 Valgrind 在我的应用程序范围之外报告错误?
【发布时间】:2010-11-16 21:41:24
【问题描述】:

在运行 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[])。如果我通过-1 调整freadfwrite 语句,我似乎没有得到那些Invalid read of size 1 语句,尽管我仍然看到很多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 重新编译,如上所述,它确实将行号与错误相关联。

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

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

这应该将空终止的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

【问题讨论】:

  • 其实可能是你的缓冲区需要变大一点,而不是 fwrite() 需要约束自己...
  • 首先尝试将缓冲区的大小增加 1,看看会发生什么
  • 顺便说一句,您是否使用调试符号编译代码?如果您在编译器选项中使用 -g(假设您使用 gcc),valgrind 将给出更精确和有用的消息。
  • strncpy() 调用的 valgrind 错误是什么?
  • 你的程序确实有第二个参数,对吧?

标签: c linux valgrind libc


【解决方案1】:

在这种情况下,我会说你这样做。 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 表示 off by one 建议。我没想到。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-24
    • 2019-11-18
    • 2020-02-01
    • 2015-01-16
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    相关资源
    最近更新 更多