source: mainline/uspace/app/tester/mm/common.c@ 1b3e854

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1b3e854 was 1b3e854, checked in by Martin Decky <martin@…>, 14 years ago

add library function for explicit heap structure consistency check
use extensive heap consistency checks in the heap allocator tests

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * Copyright (c) 2009 Martin Decky
3 * Copyright (c) 2009 Tomas Bures
4 * Copyright (c) 2009 Lubomir Bulej
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <malloc.h>
32#include <as.h>
33#include <adt/list.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <errno.h>
37#include "../tester.h"
38#include "common.h"
39
40/*
41 * Global error flag. The flag is set if an error
42 * is encountered (overlapping blocks, inconsistent
43 * block data, etc.)
44 */
45bool error_flag = false;
46
47/*
48 * Memory accounting: the amount of allocated memory and the
49 * number and list of allocated blocks.
50 */
51size_t mem_allocated;
52size_t mem_blocks_count;
53
54static LIST_INITIALIZE(mem_blocks);
55static LIST_INITIALIZE(mem_areas);
56
57/** Initializes the memory accounting structures.
58 *
59 */
60void init_mem(void)
61{
62 mem_allocated = 0;
63 mem_blocks_count = 0;
64}
65
66/** Cleanup all allocated memory blocks and mapped areas.
67 *
68 * Set the global error_flag if an error occurs.
69 *
70 */
71void done_mem(void)
72{
73 link_t *link;
74
75 while ((link = list_head(&mem_blocks)) != NULL) {
76 mem_block_t *block = list_get_instance(link, mem_block_t, link);
77 free_block(block);
78 }
79
80 while ((link = list_head(&mem_areas)) != NULL) {
81 mem_area_t *area = list_get_instance(link, mem_area_t, link);
82 unmap_area(area);
83 }
84}
85
86static bool overlap_match(link_t *link, void *addr, size_t size)
87{
88 mem_block_t *block = list_get_instance(link, mem_block_t, link);
89
90 /* Entry block control structure <mbeg, mend) */
91 uint8_t *mbeg = (uint8_t *) block;
92 uint8_t *mend = (uint8_t *) block + sizeof(mem_block_t);
93
94 /* Entry block memory <bbeg, bend) */
95 uint8_t *bbeg = (uint8_t *) block->addr;
96 uint8_t *bend = (uint8_t *) block->addr + block->size;
97
98 /* Data block <dbeg, dend) */
99 uint8_t *dbeg = (uint8_t *) addr;
100 uint8_t *dend = (uint8_t *) addr + size;
101
102 /* Check for overlaps */
103 if (((mbeg >= dbeg) && (mbeg < dend)) ||
104 ((mend > dbeg) && (mend <= dend)) ||
105 ((bbeg >= dbeg) && (bbeg < dend)) ||
106 ((bend > dbeg) && (bend <= dend)))
107 return true;
108
109 return false;
110}
111
112/** Test overlap
113 *
114 * Test whether a block starting at @addr overlaps with another,
115 * previously allocated memory block or its control structure.
116 *
117 * @param addr Initial address of the block
118 * @param size Size of the block
119 *
120 * @return False if the block does not overlap.
121 *
122 */
123static int test_overlap(void *addr, size_t size)
124{
125 bool fnd = false;
126
127 list_foreach(mem_blocks, link) {
128 if (overlap_match(link, addr, size)) {
129 fnd = true;
130 break;
131 }
132 }
133
134 return fnd;
135}
136
137static void check_consistency(const char *loc)
138{
139 /* Check heap consistency */
140 void *prob = heap_check();
141 if (prob != NULL) {
142 TPRINTF("\nError: Heap inconsistency at %p in %s.\n",
143 prob, loc);
144 TSTACKTRACE();
145 error_flag = true;
146 }
147}
148
149/** Checked malloc
150 *
151 * Allocate @size bytes of memory and check whether the chunk comes
152 * from the non-mapped memory region and whether the chunk overlaps
153 * with other, previously allocated, chunks.
154 *
155 * @param size Amount of memory to allocate
156 *
157 * @return NULL if the allocation failed. Sets the global error_flag to
158 * true if the allocation succeeded but is illegal.
159 *
160 */
161static void *checked_malloc(size_t size)
162{
163 void *data;
164
165 /* Allocate the chunk of memory */
166 data = malloc(size);
167 check_consistency("checked_malloc");
168 if (data == NULL)
169 return NULL;
170
171 /* Check for overlaps with other chunks */
172 if (test_overlap(data, size)) {
173 TPRINTF("\nError: Allocated block overlaps with another "
174 "previously allocated block.\n");
175 TSTACKTRACE();
176 error_flag = true;
177 }
178
179 return data;
180}
181
182
183/* Allocate block
184 *
185 * Allocate a block of memory of @size bytes and add record about it into
186 * the mem_blocks list. Return a pointer to the block holder structure or
187 * NULL if the allocation failed.
188 *
189 * If the allocation is illegal (e.g. the memory does not come from the
190 * right region or some of the allocated blocks overlap with others),
191 * set the global error_flag.
192 *
193 * @param size Size of the memory block
194 *
195 */
196mem_block_t *alloc_block(size_t size)
197{
198 /* Check for allocation limit */
199 if (mem_allocated >= MAX_ALLOC)
200 return NULL;
201
202 /* Allocate the block holder */
203 mem_block_t *block =
204 (mem_block_t *) checked_malloc(sizeof(mem_block_t));
205 if (block == NULL)
206 return NULL;
207
208 link_initialize(&block->link);
209
210 /* Allocate the block memory */
211 block->addr = checked_malloc(size);
212 if (block->addr == NULL) {
213 free(block);
214 check_consistency("alloc_block");
215 return NULL;
216 }
217
218 block->size = size;
219
220 /* Register the allocated block */
221 list_append(&block->link, &mem_blocks);
222 mem_allocated += size + sizeof(mem_block_t);
223 mem_blocks_count++;
224
225 return block;
226}
227
228/** Free block
229 *
230 * Free the block of memory and the block control structure allocated by
231 * alloc_block. Set the global error_flag if an error occurs.
232 *
233 * @param block Block control structure
234 *
235 */
236void free_block(mem_block_t *block)
237{
238 /* Unregister the block */
239 list_remove(&block->link);
240 mem_allocated -= block->size + sizeof(mem_block_t);
241 mem_blocks_count--;
242
243 /* Free the memory */
244 free(block->addr);
245 check_consistency("free_block (a)");
246 free(block);
247 check_consistency("free_block (b)");
248}
249
250/** Calculate expected value
251 *
252 * Compute the expected value of a byte located at @pos in memory
253 * block described by @block.
254 *
255 * @param block Memory block control structure
256 * @param pos Position in the memory block data area
257 *
258 */
259static inline uint8_t block_expected_value(mem_block_t *block, uint8_t *pos)
260{
261 return ((uintptr_t) block ^ (uintptr_t) pos) & 0xff;
262}
263
264/** Fill block
265 *
266 * Fill the memory block controlled by @block with data.
267 *
268 * @param block Memory block control structure
269 *
270 */
271void fill_block(mem_block_t *block)
272{
273 for (uint8_t *pos = block->addr, *end = pos + block->size;
274 pos < end; pos++)
275 *pos = block_expected_value(block, pos);
276
277 check_consistency("fill_block");
278}
279
280/** Check block
281 *
282 * Check whether the block @block contains the data it was filled with.
283 * Set global error_flag if an error occurs.
284 *
285 * @param block Memory block control structure
286 *
287 */
288void check_block(mem_block_t *block)
289{
290 for (uint8_t *pos = block->addr, *end = pos + block->size;
291 pos < end; pos++) {
292 if (*pos != block_expected_value(block, pos)) {
293 TPRINTF("\nError: Corrupted content of a data block.\n");
294 TSTACKTRACE();
295 error_flag = true;
296 return;
297 }
298 }
299}
300
301/** Get random block
302 *
303 * Select a random memory block from the list of allocated blocks.
304 *
305 * @return Block control structure or NULL if the list is empty.
306 *
307 */
308mem_block_t *get_random_block(void)
309{
310 if (mem_blocks_count == 0)
311 return NULL;
312
313 unsigned int idx = rand() % mem_blocks_count;
314 link_t *entry = list_nth(&mem_blocks, idx);
315
316 if (entry == NULL) {
317 TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
318 TSTACKTRACE();
319 error_flag = true;
320 }
321
322 return list_get_instance(entry, mem_block_t, link);
323}
324
325/* Map memory area
326 *
327 * Map a memory area of @size bytes and add record about it into
328 * the mem_areas list. Return a pointer to the area holder structure or
329 * NULL if the mapping failed.
330 *
331 * @param size Size of the memory area
332 *
333 */
334mem_area_t *map_area(size_t size)
335{
336 /* Allocate the area holder */
337 mem_area_t *area =
338 (mem_area_t *) checked_malloc(sizeof(mem_area_t));
339 if (area == NULL)
340 return NULL;
341
342 link_initialize(&area->link);
343
344 /* Map the memory area */
345 void *addr = as_get_mappable_page(size);
346 if (addr == NULL) {
347 free(area);
348 check_consistency("map_area (a)");
349 return NULL;
350 }
351
352 area->addr = as_area_create(addr, size, AS_AREA_WRITE | AS_AREA_READ);
353 if (area->addr == (void *) -1) {
354 free(area);
355 check_consistency("map_area (b)");
356 return NULL;
357 }
358
359 area->size = size;
360
361 /* Register the allocated area */
362 list_append(&area->link, &mem_areas);
363
364 return area;
365}
366
367/** Unmap area
368 *
369 * Unmap the memory area and free the block control structure.
370 * Set the global error_flag if an error occurs.
371 *
372 * @param area Memory area control structure
373 *
374 */
375void unmap_area(mem_area_t *area)
376{
377 /* Unregister the area */
378 list_remove(&area->link);
379
380 /* Free the memory */
381 int ret = as_area_destroy(area->addr);
382 if (ret != EOK)
383 error_flag = true;
384
385 free(area);
386 check_consistency("unmap_area");
387}
388
389/** Calculate expected value
390 *
391 * Compute the expected value of a byte located at @pos in memory
392 * area described by @area.
393 *
394 * @param area Memory area control structure
395 * @param pos Position in the memory area data area
396 *
397 */
398static inline uint8_t area_expected_value(mem_area_t *area, uint8_t *pos)
399{
400 return ((uintptr_t) area ^ (uintptr_t) pos) & 0xaa;
401}
402
403/** Fill area
404 *
405 * Fill the memory area controlled by @area with data.
406 *
407 * @param area Memory area control structure
408 *
409 */
410void fill_area(mem_area_t *area)
411{
412 for (uint8_t *pos = area->addr, *end = pos + area->size;
413 pos < end; pos++)
414 *pos = area_expected_value(area, pos);
415
416 check_consistency("fill_area");
417}
Note: See TracBrowser for help on using the repository browser.