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)
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]'