Valgrind array overrun within objects

961 Views Asked by At

I have a simple program as below.

struct Test
{
    int a[5];
    int b;
};

int main()
{
    Test* t = new Test;
    t->b = 1;
    t->a[5] = 5;          //This is an illegal write
    cout << t->b << endl; //Output is 5
    return 0;
}

Running it with Valgrind Memcheck didn't report the illegal memory write.

I noticed that Valgrind claims the Memcheck tool cannot detect global or stack array overrun, but this array is in heap, right? It's just that the array is in an object.

Is it that Valgrind really cannot detect this kind of error or just I did something wrong? If the former is true, then is there any other tool that can detect this type of error?

==========================================================================

Update:

The compilation command I used was g++ -O0 -g main.cc. The valgrind command was simply valgrind ./a.out, which should invoke the memcheck tool by default.

The compiler version is gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC), and valgrind version is valgrind-3.5.0.

Valgrind output when running this program:

==7759== Memcheck, a memory error detector
==7759== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==7759== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==7759== Command: ./a.out
==7759== 
5
==7759== 
==7759== HEAP SUMMARY:
==7759==     in use at exit: 24 bytes in 1 blocks
==7759==   total heap usage: 1 allocs, 0 frees, 24 bytes allocated
==7759== 
==7759== LEAK SUMMARY:
==7759==    definitely lost: 24 bytes in 1 blocks
==7759==    indirectly lost: 0 bytes in 0 blocks
==7759==      possibly lost: 0 bytes in 0 blocks
==7759==    still reachable: 0 bytes in 0 blocks
==7759==         suppressed: 0 bytes in 0 blocks
==7759== Rerun with --leak-check=full to see details of leaked memory
==7759== 
==7759== For counts of detected and suppressed errors, rerun with: -v
==7759== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4)
2

There are 2 best solutions below

2
On BEST ANSWER

I think the below sentence, which you've already found:

Memcheck cannot detect every memory error your program has. For example, it can't detect out-of-range reads or writes to arrays that are allocated statically or on the stack. But it should detect many errors that could crash your program (eg. cause a segmentation fault).

in case of your class definition should be interpreted this way: although class object is allocated dynamically, the array itself is allocated statically.

I've verified few cases:

Valgrind will report invalid write if array is dynamically allocated:

struct Test
{
    int *a;
    int b;
};

int main()
{
    Test* t = new Test;
    t->a = new int[5];
    t->b = 1;
    t->a[5] = 5;          //This is an illegal write
    cout << t->b << endl; //Output is 5
    delete [] t->a;
    delete t;
    return 0;
}

Also error will be reported if you change the order of the members to:

struct Test
{
  int b;  
  int a[5];
};

This is because when attempting to write to a[5] we will be already behind dynamically allocated object.

With original class definition if you attempt to write to a[6] - because then we are behind b so behind dynamically allocated object.


Update: gcc sanitizer (I suspect clang too) detects this out of bound access at run time by compiling:

g++ -fno-omit-frame-pointer -fsanitize=bounds m.cpp

Output:

m.cpp:15:7: runtime error: index 5 out of bounds for type 'int [5]'
0
On

Valgrind seems has newer tool called SGCheck for detecting stack array overrun

It seems needs version larger than 3.8

check this link

It said

SGCheck is a tool for finding overruns of stack and global arrays. It works by using a heuristic approach derived from an observation about the likely forms of stack and global array accesses.