Нужно ли беспокоиться о том, что Valgrind сообщает об ошибках, выходящих за рамки моего приложения? - PullRequest
4 голосов
/ 17 ноября 2010

При запуске инструмента Valgrind memcheck я часто получаю много сотен тысяч (или больше, так как Valgrind обрезается на 100K) небольших недопустимых операторов чтения, например ::10000

==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. Это то, что мне нужно беспокоиться?

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;                                                                                                                                                                                                                                                            
}   

РЕДАКТИРОВАТЬ 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

РЕДАКТИРОВАТЬ 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.

Ответы [ 2 ]

5 голосов
/ 17 ноября 2010

В этом случае я бы сказал, что вы делаете. Аргументы функции libc взяты из вашей программы. Я рискнул бы предположить и сказать, что в вашем коде есть ошибка off on, которая заставляет fwrite читать один байт после конца его исходного буфера.

EDIT:

Кстати, такая небольшая ошибка часто может оставаться невидимой (т. Е. Ваш код не падает), потому что и компилятор, и распределитель памяти обычно выделяют блоки памяти в определенных размерах и выравнивают их по краям слова. Это означает, что во многих случаях за запрошенным концом буфера находится небольшая область, к которой вы можете обращаться, не вызывая код защиты памяти. Конечно, ваш код может просто сломаться, если вы измените компилятор, libc, платформу или битность (например, перейдете с 64 на 32 бит).

В Valgrind есть списки подавлений ожидаемых ошибок в libc, которые обычно можно найти в /usr/lib64/valgrind/default.supp или /usr/lib/valgrind/default.supp. Существует довольно много проблем, которые valgrind обнаруживает в libc, многие из них являются преднамеренными для оптимизации кода, но из-за упущений в 99% случаев проблема возникает из-за протестированного кода.

EDIT2:

Имейте в виду, что, как и большинство инструментов отладки, Valgrind будет выводить бесконечно больше полезной информации о проблемах, которые он обнаружит, если вы скомпилируете свой код с символами отладки. Он сможет указать вам конкретные строки кода, которые связаны с проблемой - даже если довольно часто они не находятся там, где лежит реальная проблема. Если вы используете GCC, просто добавьте -g к его параметрам, чтобы компилировать ваш код с отладочными символами. Однако в производственном выпуске не забудьте убрать этот флаг!

1 голос
/ 17 ноября 2010

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

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

...