2010-11-16 4 views
4

При запуске memcheck инструмент VALGRIND, я часто получаю много сотен тысяч (или больше, так как Valgrind отсекает на 100К) малого недействителен чтения заявления, например:Нужно ли беспокоиться о ошибках сообщения 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. Это что-то, о чем я должен беспокоиться?

EDIT

Если я изменить 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[]). Если я регулирую оба оператора fread и fwrite по -1, не похоже, чтобы получить эти Invalid read of size 1 заявления, хотя я до сих пор вижу много 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 

EDIT 3

Я перекомпиляю с -g, который, как уже упоминалось, связывает номера строк с ошибками.

Но я просто делаю несложные strncpy из argv[] переменных, например .:

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

+0

Попробуйте увеличить размер буферов на 1 и посмотреть, что произойдет – thkala

+1

BTW, вы компиляция кода с помощью отладочных символов? Если вы используете -g в параметрах компилятора (при условии, что вы используете gcc), valgrind выдаст более точные и полезные сообщения. – thkala

ответ

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

+1 для предложения _off_ _by_ _one_. Я об этом не думал. – nategoose

1

Вы должны следить за стеком вызовов до тех пор, пока не получите код, который принадлежит вам, и найдите источник ошибки. В этом случае STARCH_gzip_deflate, по-видимому, вызывает fwrite с чем-то плохим (возможно, плохим FILE * или буфером, который вы пытаетесь записать), что приводит к тому, что valgrind лает на вас.

Возможно, это на самом деле не ошибка или что это не ваша ошибка. Но это, вероятно, так.