2010-11-16 36 views
4

当运行Valgrind的的memcheck工具,我经常收到几十万(或更多,因为Valgrind的在100K切断)的小无效读语句,如:我是否需要担心Valgrind在我的应用程序范围之外报告错误?

==32027== Invalid read of size 1 
==32027== at 0x3AB426E26A: _IO_default_xsputn (in /lib64/libc-2.5.so) 
==32027== by 0x3AB426CF70: [email protected]@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;                                                                
} 

EDIT 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重新编译,如前所述,它将行号与错误关联起来。

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

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

这应在空值终止字符串argv[2]复制到uniqTag,但仍valgrind标志着这是一个错误。

EDIT 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

+0

其实它可能是你的缓冲区,需要得到大一点,而不是fwrite(),需要克制自己... – thkala 2010-11-16 22:09:27

+0

尝试增加缓冲区的大小1,看看会发生什么 – thkala 2010-11-16 22:19:18

+1

顺便说一句,你是用调试符号编译你的代码?如果在编译器选项中使用-g(假设你使用gcc),valgrind会发出更精确和有用的消息。 – thkala 2010-11-16 22:21:01

回答

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以使用调试符号编译您的代码。但是,在产品发布中,请记住删除该标志!

+0

对于_off_ __ __一个建议+1。我没有想到这一点。 – nategoose 2010-11-16 21:49:35

1

你应该追踪调用堆栈,直到找到你的代码并寻找错误的起源。在这种情况下,STARCH_gzip_deflate看起来叫fwrite有一些坏的东西(可能是坏的FILE *或你试图写出来的缓冲区),这会导致valgrind向你咆哮。

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

相关问题