Tizen 2.1 base
[external/device-mapper.git] / unit-tests / mm / pool_valgrind_t.c
1 #include "libdevmapper.h"
2
3 #include <assert.h>
4
5 /*
6  * Checks that valgrind is picking up unallocated pool memory as
7  * uninitialised, even if the chunk has been recycled.
8  *
9  *     $ valgrind --track-origins=yes ./pool_valgrind_t
10  *
11  *     ==7023== Memcheck, a memory error detector
12  *     ==7023== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
13  *     ==7023== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
14  *     ==7023== Command: ./pool_valgrind_t
15  *     ==7023==
16  *     first branch worked (as expected)
17  *     ==7023== Conditional jump or move depends on uninitialised value(s)
18  *     ==7023==    at 0x4009AC: main (in /home/ejt/work/lvm2/unit-tests/mm/pool_valgrind_t)
19  *     ==7023==  Uninitialised value was created by a client request
20  *     ==7023==    at 0x4E40CB8: dm_pool_free (in /home/ejt/work/lvm2/libdm/ioctl/libdevmapper.so.1.02)
21  *     ==7023==    by 0x4009A8: main (in /home/ejt/work/lvm2/unit-tests/mm/pool_valgrind_t)
22  *     ==7023==
23  *     second branch worked (valgrind should have flagged this as an error)
24  *     ==7023==
25  *     ==7023== HEAP SUMMARY:
26  *     ==7023==     in use at exit: 0 bytes in 0 blocks
27  *     ==7023==   total heap usage: 2 allocs, 2 frees, 2,104 bytes allocated
28  *     ==7023==
29  *     ==7023== All heap blocks were freed -- no leaks are possible
30  *     ==7023==
31  *     ==7023== For counts of detected and suppressed errors, rerun with: -v
32  *     ==7023== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
33  */
34
35 #define COUNT 10
36
37 static void check_free()
38 {
39         int i;
40         char *blocks[COUNT];
41         struct dm_pool *p = dm_pool_create("blah", 1024);
42
43         for (i = 0; i < COUNT; i++)
44                 blocks[i] = dm_pool_alloc(p, 37);
45
46         /* check we can access the last block */
47         blocks[COUNT - 1][0] = 'E';
48         if (blocks[COUNT - 1][0] == 'E')
49                 printf("first branch worked (as expected)\n");
50
51         dm_pool_free(p, blocks[5]);
52
53         if (blocks[COUNT - 1][0] == 'E')
54                 printf("second branch worked (valgrind should have flagged this as an error)\n");
55
56         dm_pool_destroy(p);
57 }
58
59 /* Checks that freed chunks are marked NOACCESS */
60 static void check_free2()
61 {
62         struct dm_pool *p = dm_pool_create("", 900); /* 900 will get
63                                                       * rounded up to 1024,
64                                                       * 1024 would have got
65                                                       * rounded up to
66                                                       * 2048 */
67         char *data1, *data2;
68
69         assert(p);
70         data1 = dm_pool_alloc(p, 123);
71         assert(data1);
72
73         data1 = dm_pool_alloc(p, 1024);
74         assert(data1);
75
76         data2 = dm_pool_alloc(p, 123);
77         assert(data2);
78
79         data2[0] = 'A';         /* should work fine */
80
81         dm_pool_free(p, data1);
82
83         /*
84          * so now the first chunk is active, the second chunk has become
85          * the free one.
86          */
87         data2[0] = 'B';         /* should prompt an invalid write error */
88
89         dm_pool_destroy(p);
90 }
91
92 static void check_alignment()
93 {
94         /*
95          * Pool always tries to allocate blocks with particular alignment.
96          * So there are potentially small gaps between allocations.  This
97          * test checks that valgrind is spotting illegal accesses to these
98          * gaps.
99          */
100
101         int i, sum;
102         struct dm_pool *p = dm_pool_create("blah", 1024);
103         char *data1, *data2;
104         char buffer[16];
105
106
107         data1 = dm_pool_alloc_aligned(p, 1, 4);
108         assert(data1);
109         data2 = dm_pool_alloc_aligned(p, 1, 4);
110         assert(data1);
111
112         snprintf(buffer, sizeof(buffer), "%c", *(data1 + 1)); /* invalid read size 1 */
113         dm_pool_destroy(p);
114 }
115
116 /*
117  * Looking at the code I'm not sure allocations that are near the chunk
118  * size are working.  So this test is trying to exhibit a specific problem.
119  */
120 static void check_allocation_near_chunk_size()
121 {
122         int i;
123         char *data;
124         struct dm_pool *p = dm_pool_create("", 900);
125
126         /*
127          * allocate a lot and then free everything so we know there
128          * is a spare chunk.
129          */
130         for (i = 0; i < 1000; i++) {
131                 data = dm_pool_alloc(p, 37);
132                 memset(data, 0, 37);
133                 assert(data);
134         }
135
136         dm_pool_empty(p);
137
138         /* now we allocate something close to the chunk size ... */
139         data = dm_pool_alloc(p, 1020);
140         assert(data);
141         memset(data, 0, 1020);
142
143         dm_pool_destroy(p);
144 }
145
146 /* FIXME: test the dbg_malloc at exit (this test should be in dbg_malloc) */
147 static void check_leak_detection()
148 {
149         int i;
150         struct dm_pool *p = dm_pool_create("", 1024);
151
152         for (i = 0; i < 10; i++)
153                 dm_pool_alloc(p, (i + 1) * 37);
154 }
155
156 /* we shouldn't get any errors from this one */
157 static void check_object_growth()
158 {
159         int i;
160         struct dm_pool *p = dm_pool_create("", 32);
161         char data[100];
162         void *obj;
163
164         memset(data, 0, sizeof(data));
165
166         dm_pool_begin_object(p, 43);
167         for (i = 1; i < 100; i++)
168                 dm_pool_grow_object(p, data, i);
169         obj = dm_pool_end_object(p);
170
171         dm_pool_destroy(p);
172 }
173
174 int main(int argc, char **argv)
175 {
176         check_free();
177         check_free2();
178         check_alignment();
179         check_allocation_near_chunk_size();
180         check_leak_detection();
181         check_object_growth();
182         return 0;
183 }