|
From: Unger, K. <Kri...@t-...> - 2007-03-19 15:43:43
|
We need some explanations, how memcheck works in the 3 following
situations:
Situation A: invalid write for an object located at stack only (in the
sample code: testValgrind1):
--> we observed, that memcheck does not report invalid
write/read (lines of code 49-52)
Situation B: invalid write for an object located at the heap, but with
it's datamembers inside [as part of this object] (in the sample code:
pTestValgrind1)
--> we observed, that memcheck reports invalid write/read
only, if we violate the boundaries of the whole object (lines of code
57-60)
Situation C: invalid write for an object located at the stack, but with
data members located at the heap (in the sample code: testValgrind2)
--> we observed, that memcheck reports invalid write/read of a
data members. (lines of code 66-69)
Thinking about memcheck's idea, this behaviour seems o.k., because
detection of invalid read/write's is connected with "overloaded" new.
But we are not sure, whether we are right, because we did not find some
explicit explanation in valgrind's documentation. (May be, we read it
over.)=20
Could you confirm our explanation? In case, we are wrong, which options
should be used in order to detect invalid write/read for objects in the
situations described above?
Especially, the application, currently valgrinded by us, frequently
covers situation of kind B. Therefore, we misses detection of invalid
write/read not leaving the object's boundary.
Many thanks
Kristel Unger
In order to describe our test in more detail:=20
- We use valgrind-3.1.1 at RH4.
- g++ -c -g3 testValgrind.cpp; g++ -o testValgrind testValgrind.o
- valgrind ./testValgrind &> testValgrind.prot
Content of testValgrind.cpp:
1
////////////////////////////////////////////////////////////////////////
///////
2 /**
3 testValgrind.cpp
4 */
5
6 #include <iostream>
7 #include <sstream>
8 #include <fstream>
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include <assert.h>
12
13 using namespace std;
14 class TestValgrind1
15 {
16 public:
17 char dataA[10];
18 char dataB[10];
19 };
20
21 class TestValgrind2
22 {
23 public:
24 TestValgrind2()
25 {
26 dataA =3D new char[10];
27 dataB =3D new char[10];
28 }
29 ~ TestValgrind2()
30 {
31 delete [] dataA;
32 delete [] dataB;
33 }
34
35 public:
36 char * dataA;
37 char * dataB;
38 };
39
40
////////////////////////////////////////////////////////////////////////
///////
41
42 int main( int argc , char *argv[] )
43 {
44
45 cout << "------------------------------- TestValgrind" <<
endl;
46 TestValgrind1 testValgrind1;
47 cout << sizeof( testValgrind1 ) << endl;
48 strcpy( testValgrind1.dataA , "123456789" ); // correct
49 strcpy( testValgrind1.dataA , "1234567890" ); //
incorrect, but not detected by valgrind
50 strcpy( testValgrind1.dataA , "1234567890123456789" );
// incorrect, but not detected by valgrind
51 strcpy( testValgrind1.dataA , "12345678901234567890" );
// incorrect, but not detected by valgrind
52 strcpy( testValgrind1.dataA ,
"12345678901234567890aaaaaaaaaaa" ); // incorrect, but not detected
by valgrind
53
54 TestValgrind1 * pTestValgrind1 =3D new TestValgrind1;
55 cout << sizeof( *pTestValgrind1 ) << endl;
56 strcpy( pTestValgrind1->dataA , "123456789" ); //
correct
57 strcpy( pTestValgrind1->dataA , "1234567890" ); //
incorrect, but not detected by valgrind
58 strcpy( pTestValgrind1->dataA , "1234567890123456789" );
// incorrect, but not detected by valgrind
59 strcpy( pTestValgrind1->dataA , "12345678901234567890" );
// incorrect and detected by valgrind
60 strcpy( pTestValgrind1->dataA ,
"12345678901234567890aaaaaaaaaaa" ); // incorrect and detected by
valgrind
61
62 delete pTestValgrind1;
63 TestValgrind2 testValgrind2;
64 cout << sizeof( TestValgrind2 ) << endl;
65 strcpy( testValgrind2.dataA , "123456789" ); // correct
66 strcpy( testValgrind2.dataA , "1234567890" ); //
incorrect and detected by valgrind
67 strcpy( testValgrind2.dataA , "1234567890123456789" );
// incorrect and detected by valgrind
68 strcpy( testValgrind2.dataA , "12345678901234567890" );
// incorrect and detected by valgrind
69 strcpy( testValgrind2.dataA ,
"12345678901234567890aaaaaaaaaaa" ); // incorrect and detected by
valgrind
70 cout << "------------------------------- end of
TestValgrind" << endl;
71 }
Content of testValgrind.prot:
1 =3D=3D1254=3D=3D Memcheck, a memory error detector.
2 =3D=3D1254=3D=3D Copyright (C) 2002-2005, and GNU GPL'd, by =
Julian
Seward et al.
3 =3D=3D1254=3D=3D Using LibVEX rev 1575, a library for dynamic =
binary
translation.
4 =3D=3D1254=3D=3D Copyright (C) 2004-2005, and GNU GPL'd, by =
OpenWorks
LLP.
5 =3D=3D1254=3D=3D Using valgrind-3.1.1, a dynamic binary =
instrumentation
framework.
6 =3D=3D1254=3D=3D Copyright (C) 2000-2005, and GNU GPL'd, by =
Julian
Seward et al.
7 =3D=3D1254=3D=3D For more details, rerun with: -v
8 =3D=3D1254=3D=3D
9 ------------------------------- TestValgrind
10 20
11 20
12 =3D=3D1254=3D=3D Invalid write of size 1
13 =3D=3D1254=3D=3D at 0x4005EF8: strcpy =
(mac_replace_strmem.c:269)
14 =3D=3D1254=3D=3D by 0x8048AB1: main (testValgrind.cpp:59)
15 =3D=3D1254=3D=3D Address 0x401E03C is 0 bytes after a block of =
size 20
alloc'd
16 =3D=3D1254=3D=3D at 0x4004790: operator new(unsigned)
(vg_replace_malloc.c:164)
17 =3D=3D1254=3D=3D by 0x8048A3F: main (testValgrind.cpp:54)
18 =3D=3D1254=3D=3D
19 =3D=3D1254=3D=3D Invalid write of size 1
20 =3D=3D1254=3D=3D at 0x4005EEC: strcpy =
(mac_replace_strmem.c:269)
21 =3D=3D1254=3D=3D by 0x8048AC4: main (testValgrind.cpp:60)
22 =3D=3D1254=3D=3D Address 0x401E03C is 0 bytes after a block of =
size 20
alloc'd
23 =3D=3D1254=3D=3D at 0x4004790: operator new(unsigned)
(vg_replace_malloc.c:164)
24 =3D=3D1254=3D=3D by 0x8048A3F: main (testValgrind.cpp:54)
25 =3D=3D1254=3D=3D
26 =3D=3D1254=3D=3D Invalid write of size 1
27 =3D=3D1254=3D=3D at 0x4005EF4: strcpy =
(mac_replace_strmem.c:269)
28 =3D=3D1254=3D=3D by 0x8048AC4: main (testValgrind.cpp:60)
29 =3D=3D1254=3D=3D Address 0x401E03D is 1 bytes after a block of =
size 20
alloc'd
30 =3D=3D1254=3D=3D at 0x4004790: operator new(unsigned)
(vg_replace_malloc.c:164)
31 =3D=3D1254=3D=3D by 0x8048A3F: main (testValgrind.cpp:54)
32 =3D=3D1254=3D=3D
33 =3D=3D1254=3D=3D Invalid write of size 1
34 =3D=3D1254=3D=3D at 0x4005EF8: strcpy =
(mac_replace_strmem.c:269)
35 =3D=3D1254=3D=3D by 0x8048AC4: main (testValgrind.cpp:60)
36 =3D=3D1254=3D=3D Address 0x401E047 is 11 bytes after a block of =
size 20
alloc'd
37 =3D=3D1254=3D=3D at 0x4004790: operator new(unsigned)
(vg_replace_malloc.c:164)
38 =3D=3D1254=3D=3D by 0x8048A3F: main (testValgrind.cpp:54)
39 8
40 =3D=3D1254=3D=3D
41 =3D=3D1254=3D=3D Invalid write of size 1
42 =3D=3D1254=3D=3D at 0x4005EF8: strcpy =
(mac_replace_strmem.c:269)
43 =3D=3D1254=3D=3D by 0x8048B2A: main (testValgrind.cpp:66)
44 =3D=3D1254=3D=3D Address 0x401E07A is 0 bytes after a block of =
size 10
alloc'd
45 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
46 =3D=3D1254=3D=3D by 0x8048C89: TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
47 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
48 =3D=3D1254=3D=3D
49 =3D=3D1254=3D=3D Invalid write of size 1
50 =3D=3D1254=3D=3D at 0x4005EEC: strcpy =
(mac_replace_strmem.c:269)
51 =3D=3D1254=3D=3D by 0x8048B3D: main (testValgrind.cpp:67)
52 =3D=3D1254=3D=3D Address 0x401E07A is 0 bytes after a block of =
size 10
alloc'd
53 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
54 =3D=3D1254=3D=3D by 0x8048C89: TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
55 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
56 =3D=3D1254=3D=3D
57 =3D=3D1254=3D=3D Invalid write of size 1
58 =3D=3D1254=3D=3D at 0x4005EF4: strcpy =
(mac_replace_strmem.c:269)
59 =3D=3D1254=3D=3D by 0x8048B3D: main (testValgrind.cpp:67)
60 =3D=3D1254=3D=3D Address 0x401E07B is 1 bytes after a block =
of size
10 alloc'd
61 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
62 =3D=3D1254=3D=3D by 0x8048C89: =
TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
63 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
64 =3D=3D1254=3D=3D
65 =3D=3D1254=3D=3D Invalid write of size 1
66 =3D=3D1254=3D=3D at 0x4005EF8: strcpy =
(mac_replace_strmem.c:269)
67 =3D=3D1254=3D=3D by 0x8048B3D: main (testValgrind.cpp:67)
68 =3D=3D1254=3D=3D Address 0x401E083 is 9 bytes after a block =
of size
10 alloc'd
69 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
70 =3D=3D1254=3D=3D by 0x8048C89: =
TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
71 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
72 =3D=3D1254=3D=3D
73 =3D=3D1254=3D=3D Invalid write of size 1
74 =3D=3D1254=3D=3D at 0x4005EEC: strcpy =
(mac_replace_strmem.c:269)
75 =3D=3D1254=3D=3D by 0x8048B50: main (testValgrind.cpp:68)
76 =3D=3D1254=3D=3D Address 0x401E07A is 0 bytes after a block =
of size
10 alloc'd
77 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
78 =3D=3D1254=3D=3D by 0x8048C89: =
TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
79 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
80 =3D=3D1254=3D=3D
81 =3D=3D1254=3D=3D Invalid write of size 1
82 =3D=3D1254=3D=3D at 0x4005EF4: strcpy =
(mac_replace_strmem.c:269)
83 =3D=3D1254=3D=3D by 0x8048B50: main (testValgrind.cpp:68)
84 =3D=3D1254=3D=3D Address 0x401E07B is 1 bytes after a block =
of size
10 alloc'd
85 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
86 =3D=3D1254=3D=3D by 0x8048C89: =
TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
87 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
88 =3D=3D1254=3D=3D
89 =3D=3D1254=3D=3D Invalid write of size 1
90 =3D=3D1254=3D=3D at 0x4005EF8: strcpy =
(mac_replace_strmem.c:269)
91 =3D=3D1254=3D=3D by 0x8048B50: main (testValgrind.cpp:68)
92 =3D=3D1254=3D=3D Address 0x401E084 is 10 bytes after a block =
of size
10 alloc'd
93 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
94 =3D=3D1254=3D=3D by 0x8048C89: =
TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
95 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
96 =3D=3D1254=3D=3D
97 =3D=3D1254=3D=3D Invalid write of size 1
98 =3D=3D1254=3D=3D at 0x4005EEC: strcpy =
(mac_replace_strmem.c:269)
99 =3D=3D1254=3D=3D by 0x8048B63: main (testValgrind.cpp:69)
100 =3D=3D1254=3D=3D Address 0x401E07A is 0 bytes after a block =
of size
10 alloc'd
101 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
102 =3D=3D1254=3D=3D by 0x8048C89: =
TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
103 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
104 =3D=3D1254=3D=3D
105 =3D=3D1254=3D=3D Invalid write of size 1
106 =3D=3D1254=3D=3D at 0x4005EF4: strcpy =
(mac_replace_strmem.c:269)
107 =3D=3D1254=3D=3D by 0x8048B63: main (testValgrind.cpp:69)
108 =3D=3D1254=3D=3D Address 0x401E07B is 1 bytes after a block =
of size
10 alloc'd
109 =3D=3D1254=3D=3D at 0x4004BBE: operator new[](unsigned)
(vg_replace_malloc.c:197)
110 =3D=3D1254=3D=3D by 0x8048C89: =
TestValgrind2::TestValgrind2()
(testValgrind.cpp:26)
111 =3D=3D1254=3D=3D by 0x8048AE1: main (testValgrind.cpp:63)
112 =3D=3D1254=3D=3D
113 =3D=3D1254=3D=3D Invalid write of size 1
114 =3D=3D1254=3D=3D at 0x4005EF8: strcpy =
(mac_replace_strmem.c:269)
115 =3D=3D1254=3D=3D by 0x8048B63: main (testValgrind.cpp:69)
116 =3D=3D1254=3D=3D Address 0x401E08F is not stack'd, malloc'd =
or
(recently) free'd
117 ------------------------------- end of TestValgrind
118 =3D=3D1254=3D=3D
119 =3D=3D1254=3D=3D ERROR SUMMARY: 57 errors from 14 contexts =
(suppressed:
16 from 1)
120 =3D=3D1254=3D=3D malloc/free: in use at exit: 0 bytes in 0 =
blocks.
121 =3D=3D1254=3D=3D malloc/free: 3 allocs, 3 frees, 40 bytes =
allocated.
122 =3D=3D1254=3D=3D For counts of detected errors, rerun with: -v
123 =3D=3D1254=3D=3D All heap blocks were freed -- no leaks are =
possible.
|
|
From: Nicholas N. <nj...@cs...> - 2007-03-19 21:02:25
|
On Mon, 19 Mar 2007, Unger, Kristel wrote: > We need some explanations, how memcheck works in the 3 following > situations: > > Situation A: invalid write for an object located at stack only (in the > sample code: testValgrind1): > --> we observed, that memcheck does not report invalid > write/read (lines of code 49-52) > > Situation B: invalid write for an object located at the heap, but with > it's datamembers inside [as part of this object] (in the sample code: > pTestValgrind1) > --> we observed, that memcheck reports invalid write/read > only, if we violate the boundaries of the whole object (lines of code > 57-60) > > Situation C: invalid write for an object located at the stack, but with > data members located at the heap (in the sample code: testValgrind2) > --> we observed, that memcheck reports invalid write/read of a > data members. (lines of code 66-69) > > Thinking about memcheck's idea, this behaviour seems o.k., because > detection of invalid read/write's is connected with "overloaded" new. > But we are not sure, whether we are right, because we did not find some > explicit explanation in valgrind's documentation. (May be, we read it > over.) > > Could you confirm our explanation? In case, we are wrong, which options > should be used in order to detect invalid write/read for objects in the > situations described above? > Especially, the application, currently valgrinded by us, frequently > covers situation of kind B. Therefore, we misses detection of invalid > write/read not leaving the object's boundary. Memcheck can detect accesses to truly unaddressable memory. However, if you have two addressable objects next to each other, and you overrun from one into the other, it won't complain because you're still accessing addressable memory. It can detect the heap block overflow case because it adds unaddressable "red zones" to the start and end of each heap block -- padding areas that should not be used by the program. So it won't detect overruns on the stack, unless they actually go past the top of the stack. And it won't detect overruns on the heap unless they go past the start/end of the heap block. I don't think the overloading of 'new' is relevant here. Nick |