2 * Copyright (c) 2009 Martin Decky
3 * Copyright (c) 2009 Tomas Bures
4 * Copyright (c) 2009 Lubomir Bulej
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
38 #include "../tester.h"
42 * Global error flag. The flag is set if an error
43 * is encountered (overlapping blocks, inconsistent
46 bool error_flag
= false;
49 * Memory accounting: the amount of allocated memory and the
50 * number and list of allocated blocks.
53 size_t mem_blocks_count
;
55 static LIST_INITIALIZE(mem_blocks
);
56 static LIST_INITIALIZE(mem_areas
);
58 /** Initializes the memory accounting structures.
67 /** Cleanup all allocated memory blocks and mapped areas.
69 * Set the global error_flag if an error occurs.
76 while ((link
= list_first(&mem_blocks
)) != NULL
) {
77 mem_block_t
*block
= list_get_instance(link
, mem_block_t
, link
);
81 while ((link
= list_first(&mem_areas
)) != NULL
) {
82 mem_area_t
*area
= list_get_instance(link
, mem_area_t
, link
);
87 static bool overlap_match(mem_block_t
*block
, void *addr
, size_t size
)
89 /* Entry block control structure <mbeg, mend) */
90 uint8_t *mbeg
= (uint8_t *) block
;
91 uint8_t *mend
= (uint8_t *) block
+ sizeof(mem_block_t
);
93 /* Entry block memory <bbeg, bend) */
94 uint8_t *bbeg
= (uint8_t *) block
->addr
;
95 uint8_t *bend
= (uint8_t *) block
->addr
+ block
->size
;
97 /* Data block <dbeg, dend) */
98 uint8_t *dbeg
= (uint8_t *) addr
;
99 uint8_t *dend
= (uint8_t *) addr
+ size
;
101 /* Check for overlaps */
102 if (((mbeg
>= dbeg
) && (mbeg
< dend
)) ||
103 ((mend
> dbeg
) && (mend
<= dend
)) ||
104 ((bbeg
>= dbeg
) && (bbeg
< dend
)) ||
105 ((bend
> dbeg
) && (bend
<= dend
)))
113 * Test whether a block starting at @addr overlaps with another,
114 * previously allocated memory block or its control structure.
116 * @param addr Initial address of the block
117 * @param size Size of the block
119 * @return False if the block does not overlap.
122 static int test_overlap(void *addr
, size_t size
)
126 list_foreach(mem_blocks
, link
, mem_block_t
, block
) {
127 if (overlap_match(block
, addr
, size
)) {
136 static void check_consistency(const char *loc
)
138 /* Check heap consistency */
139 void *prob
= heap_check();
141 TPRINTF("\nError: Heap inconsistency at %p in %s.\n",
150 * Allocate @size bytes of memory and check whether the chunk comes
151 * from the non-mapped memory region and whether the chunk overlaps
152 * with other, previously allocated, chunks.
154 * @param size Amount of memory to allocate
156 * @return NULL if the allocation failed. Sets the global error_flag to
157 * true if the allocation succeeded but is illegal.
160 static void *checked_malloc(size_t size
)
164 /* Allocate the chunk of memory */
166 check_consistency("checked_malloc");
170 /* Check for overlaps with other chunks */
171 if (test_overlap(data
, size
)) {
172 TPRINTF("\nError: Allocated block overlaps with another "
173 "previously allocated block.\n");
183 * Allocate a block of memory of @size bytes and add record about it into
184 * the mem_blocks list. Return a pointer to the block holder structure or
185 * NULL if the allocation failed.
187 * If the allocation is illegal (e.g. the memory does not come from the
188 * right region or some of the allocated blocks overlap with others),
189 * set the global error_flag.
191 * @param size Size of the memory block
194 mem_block_t
*alloc_block(size_t size
)
196 /* Check for allocation limit */
197 if (mem_allocated
>= MAX_ALLOC
)
200 /* Allocate the block holder */
202 (mem_block_t
*) checked_malloc(sizeof(mem_block_t
));
206 link_initialize(&block
->link
);
208 /* Allocate the block memory */
209 block
->addr
= checked_malloc(size
);
210 if (block
->addr
== NULL
) {
212 check_consistency("alloc_block");
218 /* Register the allocated block */
219 list_append(&block
->link
, &mem_blocks
);
220 mem_allocated
+= size
+ sizeof(mem_block_t
);
228 * Free the block of memory and the block control structure allocated by
229 * alloc_block. Set the global error_flag if an error occurs.
231 * @param block Block control structure
234 void free_block(mem_block_t
*block
)
236 /* Unregister the block */
237 list_remove(&block
->link
);
238 mem_allocated
-= block
->size
+ sizeof(mem_block_t
);
241 /* Free the memory */
243 check_consistency("free_block (a)");
245 check_consistency("free_block (b)");
248 /** Calculate expected value
250 * Compute the expected value of a byte located at @pos in memory
251 * block described by @block.
253 * @param block Memory block control structure
254 * @param pos Position in the memory block data area
257 static inline uint8_t block_expected_value(mem_block_t
*block
, uint8_t *pos
)
259 return ((uintptr_t) block
^ (uintptr_t) pos
) & 0xff;
264 * Fill the memory block controlled by @block with data.
266 * @param block Memory block control structure
269 void fill_block(mem_block_t
*block
)
271 for (uint8_t *pos
= block
->addr
, *end
= pos
+ block
->size
;
273 *pos
= block_expected_value(block
, pos
);
275 check_consistency("fill_block");
280 * Check whether the block @block contains the data it was filled with.
281 * Set global error_flag if an error occurs.
283 * @param block Memory block control structure
286 void check_block(mem_block_t
*block
)
288 for (uint8_t *pos
= block
->addr
, *end
= pos
+ block
->size
;
290 if (*pos
!= block_expected_value(block
, pos
)) {
291 TPRINTF("\nError: Corrupted content of a data block.\n");
301 * Select a random memory block from the list of allocated blocks.
303 * @return Block control structure or NULL if the list is empty.
306 mem_block_t
*get_random_block(void)
308 if (mem_blocks_count
== 0)
311 unsigned long idx
= rand() % mem_blocks_count
;
312 link_t
*entry
= list_nth(&mem_blocks
, idx
);
315 TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
320 return list_get_instance(entry
, mem_block_t
, link
);
325 * Map a memory area of @size bytes and add record about it into
326 * the mem_areas list. Return a pointer to the area holder structure or
327 * NULL if the mapping failed.
329 * @param size Size of the memory area
332 mem_area_t
*map_area(size_t size
)
334 /* Allocate the area holder */
336 (mem_area_t
*) checked_malloc(sizeof(mem_area_t
));
340 link_initialize(&area
->link
);
342 area
->addr
= as_area_create(AS_AREA_ANY
, size
,
343 AS_AREA_WRITE
| AS_AREA_READ
| AS_AREA_CACHEABLE
,
345 if (area
->addr
== AS_MAP_FAILED
) {
347 check_consistency("map_area (a)");
353 /* Register the allocated area */
354 list_append(&area
->link
, &mem_areas
);
361 * Unmap the memory area and free the block control structure.
362 * Set the global error_flag if an error occurs.
364 * @param area Memory area control structure
367 void unmap_area(mem_area_t
*area
)
369 /* Unregister the area */
370 list_remove(&area
->link
);
372 /* Free the memory */
373 errno_t ret
= as_area_destroy(area
->addr
);
378 check_consistency("unmap_area");
381 /** Calculate expected value
383 * Compute the expected value of a byte located at @pos in memory
384 * area described by @area.
386 * @param area Memory area control structure
387 * @param pos Position in the memory area data area
390 static inline uint8_t area_expected_value(mem_area_t
*area
, uint8_t *pos
)
392 return ((uintptr_t) area
^ (uintptr_t) pos
) & 0xaa;
397 * Fill the memory area controlled by @area with data.
399 * @param area Memory area control structure
402 void fill_area(mem_area_t
*area
)
404 for (uint8_t *pos
= area
->addr
, *end
= pos
+ area
->size
;
406 *pos
= area_expected_value(area
, pos
);
408 check_consistency("fill_area");