Question

When running Valgrind's memcheck tool, I often get many hundreds of thousands (or more, since Valgrind cuts off at 100K) of small invalid read statements, e.g.:

==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

These statements refer to calls to functions outside of my application ("starch") and which appear to be part of libc. Is this something I need to be concerned with?

EDIT

If I modify the fwrite call to remove one byte, then my gzip stream gets corrupted. Here's the original code:

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

I think I see the problem. I have in[STARCH_Z_CHUNK] and not in[STARCH_Z_CHUNK + 1] (and likewise for out[]). If I adjust both of the fread and fwrite statements by -1, I don't seem to get those Invalid read of size 1 statements, although I still see a lot of Invalid read of size 4 and 8 which are specific to 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

I am recompiling with -g which, as mentioned, does associate line numbers with errors.

But I'm just doing a straightforward strncpy of argv[] variables, e.g.:

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

This should copy over the null-terminated argv[2] string to uniqTag, but valgrind still marks this as an error.

EDIT 4

Here's the error message:

==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

Here are the two relevant lines; valgrind is saying the second line is an invalid read:

uniqTag = (char *)malloc(strlen(argv[2]) + 1); 
strncpy(uniqTag, argv[2], strlen(argv[2]) + 1);

Because strlen(argv[2]) + 1 > strlen(argv[2]), this should result in a null-terminated uniqTag.

Was it helpful?

Solution

In this case I'd say that you do. The libc function arguments come from your program. I'd hazard a guess and say that you have an off by one error in your code that leads fwrite to read one byte past the end of its source buffer.

EDIT:

By the way, such a small error can often remain unseen (i.e. your code does not crash) because both the compiler and the memory allocator usually allocate memory blocks in specific sizes and align them at word edges. This means that many times there is a small region past the requested buffer end that you can access without triggering the memory protection code. Of course your code might just break if you change compiler, libc, platform or bitness (e.g. go from 64 to 32 bit).

Valgrind has suppression lists for expected errors in libc, which you can usually find at /usr/lib64/valgrind/default.supp or /usr/lib/valgrind/default.supp. There are quite a few issues that valgrind detects in libc, many of them intentional in an effort to optimise the code, but due to the suppresions in 99% of the cases it's the tested code that causes the problem.

EDIT2:

Keep in mind that, like most debugging tools, Valgrind will output infinitely more useful information on the issues it detects if you compile your code with debugging symbols. It will be able to point you to specific lines of code that are related to the issue - even if quite often they are not where the actual issue lies. If you use GCC just add -g to its options to compile your code with debugging symbols. In a production release, though, please remember to remove that flag!

OTHER TIPS

You should follow down the call stack until you get to some code that is yours and look for the error's origin. In this case, STARCH_gzip_deflate appears to be calling fwrite with something that is bad (probably a bad FILE * or the buffer you are attempting to write out) which is causing the valgrind to bark at you.

It is possible that this is not actually an error or that it is not your error, though. But it probably is.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top