source: mainline/uspace/app/tester/mm/common.c@ 209cd41

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 209cd41 was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 9.9 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 <stdlib.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_first(&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_first(&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(mem_block_t *block, void *addr, size_t size)
87{
88 /* Entry block control structure <mbeg, mend) */
89 uint8_t *mbeg = (uint8_t *) block;
90 uint8_t *mend = (uint8_t *) block + sizeof(mem_block_t);
91
92 /* Entry block memory <bbeg, bend) */
93 uint8_t *bbeg = (uint8_t *) block->addr;
94 uint8_t *bend = (uint8_t *) block->addr + block->size;
95
96 /* Data block <dbeg, dend) */
97 uint8_t *dbeg = (uint8_t *) addr;
98 uint8_t *dend = (uint8_t *) addr + size;
99
100 /* Check for overlaps */
101 if (((mbeg >= dbeg) && (mbeg < dend)) ||
102 ((mend > dbeg) && (mend <= dend)) ||
103 ((bbeg >= dbeg) && (bbeg < dend)) ||
104 ((bend > dbeg) && (bend <= dend)))
105 return true;
106
107 return false;
108}
109
110/** Test overlap
111 *
112 * Test whether a block starting at @addr overlaps with another,
113 * previously allocated memory block or its control structure.
114 *
115 * @param addr Initial address of the block
116 * @param size Size of the block
117 *
118 * @return False if the block does not overlap.
119 *
120 */
121static int test_overlap(void *addr, size_t size)
122{
123 bool fnd = false;
124
125 list_foreach(mem_blocks, link, mem_block_t, block) {
126 if (overlap_match(block, addr, size)) {
127 fnd = true;
128 break;
129 }
130 }
131
132 return fnd;
133}
134
135static void check_consistency(const char *loc)
136{
137 /* Check heap consistency */
138 void *prob = heap_check();
139 if (prob != NULL) {
140 TPRINTF("\nError: Heap inconsistency at %p in %s.\n",
141 prob, loc);
142 TSTACKTRACE();
143 error_flag = true;
144 }
145}
146
147/** Checked malloc
148 *
149 * Allocate @size bytes of memory and check whether the chunk comes
150 * from the non-mapped memory region and whether the chunk overlaps
151 * with other, previously allocated, chunks.
152 *
153 * @param size Amount of memory to allocate
154 *
155 * @return NULL if the allocation failed. Sets the global error_flag to
156 * true if the allocation succeeded but is illegal.
157 *
158 */
159static void *checked_malloc(size_t size)
160{
161 void *data;
162
163 /* Allocate the chunk of memory */
164 data = malloc(size);
165 check_consistency("checked_malloc");
166 if (data == NULL)
167 return NULL;
168
169 /* Check for overlaps with other chunks */
170 if (test_overlap(data, size)) {
171 TPRINTF("\nError: Allocated block overlaps with another "
172 "previously allocated block.\n");
173 TSTACKTRACE();
174 error_flag = true;
175 }
176
177 return data;
178}
179
180/** Allocate block
181 *
182 * Allocate a block of memory of @size bytes and add record about it into
183 * the mem_blocks list. Return a pointer to the block holder structure or
184 * NULL if the allocation failed.
185 *
186 * If the allocation is illegal (e.g. the memory does not come from the
187 * right region or some of the allocated blocks overlap with others),
188 * set the global error_flag.
189 *
190 * @param size Size of the memory block
191 *
192 */
193mem_block_t *alloc_block(size_t size)
194{
195 /* Check for allocation limit */
196 if (mem_allocated >= MAX_ALLOC)
197 return NULL;
198
199 /* Allocate the block holder */
200 mem_block_t *block =
201 (mem_block_t *) checked_malloc(sizeof(mem_block_t));
202 if (block == NULL)
203 return NULL;
204
205 link_initialize(&block->link);
206
207 /* Allocate the block memory */
208 block->addr = checked_malloc(size);
209 if (block->addr == NULL) {
210 free(block);
211 check_consistency("alloc_block");
212 return NULL;
213 }
214
215 block->size = size;
216
217 /* Register the allocated block */
218 list_append(&block->link, &mem_blocks);
219 mem_allocated += size + sizeof(mem_block_t);
220 mem_blocks_count++;
221
222 return block;
223}
224
225/** Free block
226 *
227 * Free the block of memory and the block control structure allocated by
228 * alloc_block. Set the global error_flag if an error occurs.
229 *
230 * @param block Block control structure
231 *
232 */
233void free_block(mem_block_t *block)
234{
235 /* Unregister the block */
236 list_remove(&block->link);
237 mem_allocated -= block->size + sizeof(mem_block_t);
238 mem_blocks_count--;
239
240 /* Free the memory */
241 free(block->addr);
242 check_consistency("free_block (a)");
243 free(block);
244 check_consistency("free_block (b)");
245}
246
247/** Calculate expected value
248 *
249 * Compute the expected value of a byte located at @pos in memory
250 * block described by @block.
251 *
252 * @param block Memory block control structure
253 * @param pos Position in the memory block data area
254 *
255 */
256static inline uint8_t block_expected_value(mem_block_t *block, uint8_t *pos)
257{
258 return ((uintptr_t) block ^ (uintptr_t) pos) & 0xff;
259}
260
261/** Fill block
262 *
263 * Fill the memory block controlled by @block with data.
264 *
265 * @param block Memory block control structure
266 *
267 */
268void fill_block(mem_block_t *block)
269{
270 for (uint8_t *pos = block->addr, *end = pos + block->size;
271 pos < end; pos++)
272 *pos = block_expected_value(block, pos);
273
274 check_consistency("fill_block");
275}
276
277/** Check block
278 *
279 * Check whether the block @block contains the data it was filled with.
280 * Set global error_flag if an error occurs.
281 *
282 * @param block Memory block control structure
283 *
284 */
285void check_block(mem_block_t *block)
286{
287 for (uint8_t *pos = block->addr, *end = pos + block->size;
288 pos < end; pos++) {
289 if (*pos != block_expected_value(block, pos)) {
290 TPRINTF("\nError: Corrupted content of a data block.\n");
291 TSTACKTRACE();
292 error_flag = true;
293 return;
294 }
295 }
296}
297
298/** Get random block
299 *
300 * Select a random memory block from the list of allocated blocks.
301 *
302 * @return Block control structure or NULL if the list is empty.
303 *
304 */
305mem_block_t *get_random_block(void)
306{
307 if (mem_blocks_count == 0)
308 return NULL;
309
310 unsigned long idx = rand() % mem_blocks_count;
311 link_t *entry = list_nth(&mem_blocks, idx);
312
313 if (entry == NULL) {
314 TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
315 TSTACKTRACE();
316 error_flag = true;
317 }
318
319 return list_get_instance(entry, mem_block_t, link);
320}
321
322/** Map memory area
323 *
324 * Map a memory area of @size bytes and add record about it into
325 * the mem_areas list. Return a pointer to the area holder structure or
326 * NULL if the mapping failed.
327 *
328 * @param size Size of the memory area
329 *
330 */
331mem_area_t *map_area(size_t size)
332{
333 /* Allocate the area holder */
334 mem_area_t *area =
335 (mem_area_t *) checked_malloc(sizeof(mem_area_t));
336 if (area == NULL)
337 return NULL;
338
339 link_initialize(&area->link);
340
341 area->addr = as_area_create(AS_AREA_ANY, size,
342 AS_AREA_WRITE | AS_AREA_READ | AS_AREA_CACHEABLE,
343 AS_AREA_UNPAGED);
344 if (area->addr == AS_MAP_FAILED) {
345 free(area);
346 check_consistency("map_area (a)");
347 return NULL;
348 }
349
350 area->size = size;
351
352 /* Register the allocated area */
353 list_append(&area->link, &mem_areas);
354
355 return area;
356}
357
358/** Unmap area
359 *
360 * Unmap the memory area and free the block control structure.
361 * Set the global error_flag if an error occurs.
362 *
363 * @param area Memory area control structure
364 *
365 */
366void unmap_area(mem_area_t *area)
367{
368 /* Unregister the area */
369 list_remove(&area->link);
370
371 /* Free the memory */
372 errno_t ret = as_area_destroy(area->addr);
373 if (ret != EOK)
374 error_flag = true;
375
376 free(area);
377 check_consistency("unmap_area");
378}
379
380/** Calculate expected value
381 *
382 * Compute the expected value of a byte located at @pos in memory
383 * area described by @area.
384 *
385 * @param area Memory area control structure
386 * @param pos Position in the memory area data area
387 *
388 */
389static inline uint8_t area_expected_value(mem_area_t *area, uint8_t *pos)
390{
391 return ((uintptr_t) area ^ (uintptr_t) pos) & 0xaa;
392}
393
394/** Fill area
395 *
396 * Fill the memory area controlled by @area with data.
397 *
398 * @param area Memory area control structure
399 *
400 */
401void fill_area(mem_area_t *area)
402{
403 for (uint8_t *pos = area->addr, *end = pos + area->size;
404 pos < end; pos++)
405 *pos = area_expected_value(area, pos);
406
407 check_consistency("fill_area");
408}
Note: See TracBrowser for help on using the repository browser.