0

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!

Sterling
  • 3
  • 1
  • 2

4 Answers4

1
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

Community
  • 1
  • 1
Mantosh Kumar
  • 5,659
  • 3
  • 24
  • 48
  • The output is not showing anything going out of bounds. I also ran this on VS debugger and could not see it going out of bounds. – Sterling Nov 08 '14 at 05:37
  • Out of bound access have undefined behaviour hence sometime it does not appear immediately in program. But valgrind report certanily indicates that your program has out of bond access. You may refer the steps suggested above and debug your program live at the point of error. you may verify all variables and your source input status at that point. – Mantosh Kumar Nov 08 '14 at 05:42
  • Thank you! You are right -- I played around with the definition/declaration and did this: double* rawScores = new double[rawScoreCount+2]; C++ is fairly new to me -- if something was hitting the bounds I have always been accustomed to a nice crash! – Sterling Nov 08 '14 at 06:01
1

Do you allocate rawScores properly?

You also need to make sure that projectCount is lower than rawScores size

Eric
  • 19,525
  • 19
  • 84
  • 147
0
  1. Check if you have assigned enough memory to the arrays [rawScores, scores, weights, studentInfo] before you pass to this function.
  2. check the user input, should be in the range of arrays.

it Would surly solve your problem

Rupesh Yadav.
  • 894
  • 2
  • 10
  • 24
0

Array bounds overruns are insidious. In c++, if you don't damage something you care about, you may never find out that you overran something... Except some of your values may not be quite correct. (This is the "error" at the core of a lot of virus attacks - taking advantage of poorly written programs that make assumptions about buffer/array sizes.

Let's say you have something like:

   char buffer[50];
   char author[] = "My Name";

   cout << author;
   cin >> buffer;

If I type a 20 character input string, no harm, no foul.

If I type a 55 character input string, "My Name" will be partially overwritten, which no one will notice, unless I try to reprint author. Which may not happen until many (many) statements later. When you see author, maybe it looks like "1234ame", and you'll be asking "where'd that come from?

Worse yet, If I type a 70 character input string, I'll trash author, and whatever comes after it, perhaps a memory management control block, i/o buffer, etc. and perhaps that will be "noticeable" (or not).

Now, I hope you see why an array management error may not show until long after it's committed, if at all. "No failures" may not mean "correct", so your comment about "output not showing anything out of bounds" may not be as comforting as you hoped.

As Rupesh said earlier - pay careful attention to your arrays, both allocation and filling.

If that's not the answer you need, then you need to show definition of arrays and how they are created.