Search code examples
c++c++11memcheck

Invalid read of size 8, Invalid write of size 8 (Valgrind)


I've been playing around with the following code for several hours this evening and I am just scratching my head with it.

I keep getting "Invalid write of size 8" and "Invalid read of size 8" when using a function to populate an array from stdin.

Any help would be appreciated... I know there are a lot of these errors on Stack Overflow, but most of them are unique to the situation.

void RawScore(unsigned int rawScoreCount, unsigned int numStudents, student studentInfo[],
              unsigned int projectCount, double rawScores[], double scores[], double weights[])
{
    int id;

    for (int i = 0; i < rawScoreCount; i++)
    {
        std::cin >> id;

        for (int j = 0; j < numStudents; j++)
        {
            if (id == studentInfo[j].id)
            {
                for (int k = 0; k < projectCount; k++)
                {
                    std::cin >> rawScores[k];
                    studentInfo[j].score += rawScores[k]/scores[k] * weights[k];
                }
            }
        }
            std::cin.ignore(10000, '\n');
    }
}

The error from Memcheck is below:

==5793== Memcheck, a memory error detector
==5793== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==5793== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==5793== Command: a.out.app
==5793== 
==5793== Invalid write of size 8
==5793==    at 0x40E54DB: std::__1::istreambuf_iterator<char, std::__1::char_traits<char> > std::__1::num_get<char, std::__1::istreambuf_iterator<char, std::__1::char_traits<char> > >::__do_get_floating_point<double>(std::__1::istreambuf_iterator<char, std::__1::char_traits<char> >, std::__1::istreambuf_iterator<char, std::__1::char_traits<char> >, std::__1::ios_base&, unsigned int&, double&) const (in /usr/lib/i386-linux-gnu/libc++.so.1.0)
==5793==    by 0x40E517E: std::__1::num_get<char, std::__1::istreambuf_iterator<char, std::__1::char_traits<char> > >::do_get(std::__1::istreambuf_iterator<char, std::__1::char_traits<char> >, std::__1::istreambuf_iterator<char, std::__1::char_traits<char> >, std::__1::ios_base&, unsigned int&, double&) const (in /usr/lib/i386-linux-gnu/libc++.so.1.0)
==5793==    by 0x804D0FA: std::__1::basic_istream<char, std::__1::char_traits<char> >::operator>>(double&) (locale:771)
==5793==    by 0x804CECC: RawScore(unsigned int, unsigned int, student*, unsigned int, double*, double*, double*) (input.cpp:44)
==5793==    by 0x804EE6A: main (main.cpp:35)
==5793==  Address 0x445c388 is 0 bytes after a block of size 40 alloc'd
==5793==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5793==    by 0x40BA709: operator new(unsigned int) (in /usr/lib/i386-linux-gnu/libc++.so.1.0)
==5793==    by 0x804EE26: main (main.cpp:32)
==5793== 
==5793== Invalid read of size 8
==5793==    at 0x804CED3: RawScore(unsigned int, unsigned int, student*, unsigned int, double*, double*, double*) (input.cpp:49)
==5793==    by 0x804EE6A: main (main.cpp:35)
==5793==  Address 0x445c388 is 0 bytes after a block of size 40 alloc'd
==5793==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==5793==    by 0x40BA709: operator new(unsigned int) (in /usr/lib/i386-linux-gnu/libc++.so.1.0)
==5793==    by 0x804EE26: main (main.cpp:32)
==5793== 
....... output of program here ......
==5793== 
==5793== HEAP SUMMARY:
==5793==     in use at exit: 0 bytes in 0 blocks
==5793==   total heap usage: 9 allocs, 9 frees, 476 bytes allocated
==5793== 
==5793== All heap blocks were freed -- no leaks are possible
==5793== 
==5793== For counts of detected and suppressed errors, rerun with: -v
==5793== ERROR SUMMARY: 20 errors from 2 contexts (suppressed: 0 from 0)

I've narrowed down the problem to the following two lines, 10 errors on write and 10 on read:

std::cin >> rawScores[k];
studentInfo[j].score += rawScores[k]/scores[k] * weights[k];

Any insight would be appreciated!


Solution

  • std::cin >> rawScores[k];
    studentInfo[j].score += rawScores[k]/scores[k] * weights[k];
    

    From your above program j and k depends on the user input and hence their values can go beyond the actual array's studentInfo rawScores index.

    Your program should have logic so that it your program does not access array bounds.

    You may monitor your program

    $ valgrind --tool=memcheck --db-attach=yes ./a.out
    

    For detailed information about this concept and how to use it, you may refer following post:

    https://stackoverflow.com/a/22658693/2724703