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.
35
#include "../tester.h"
38
* The test consists of several phases which differ in the size of blocks
39
* they allocate. The size of blocks is given as a range of minimum and
40
* maximum allowed size. Each of the phases is divided into 3 subphases which
41
* differ in the probability of free and alloc actions. Second subphase is
42
* started when malloc returns 'out of memory' or when MAX_ALLOC is reached.
43
* Third subphase is started after a given number of cycles. The third subphase
44
* as well as the whole phase ends when all memory blocks are released.
49
* @array array to determine the size of
51
* Returns the size of @array in array elements.
53
#define sizeof_array(array) \
54
(sizeof(array) / sizeof((array)[0]))
56
#define MAX_ALLOC (16 * 1024 * 1024)
59
* Subphase control structures: subphase termination conditions,
60
* probabilities of individual actions, subphase control structure.
64
unsigned int max_cycles;
65
unsigned int no_memory;
66
unsigned int no_allocated;
77
sp_action_prob_s prob;
82
* Phase control structures: The minimum and maximum block size that
83
* can be allocated during the phase execution, phase control structure.
87
size_t min_block_size;
88
size_t max_block_size;
93
ph_alloc_size_s alloc;
94
subphase_s *subphases;
99
* Subphases are defined separately here. This is for two reasons:
100
* 1) data are not duplicated, 2) we don't have to state beforehand
101
* how many subphases a phase contains.
103
static subphase_s subphases_32B[] = {
105
.name = "Allocation",
117
.name = "Alloc/Dealloc",
129
.name = "Deallocation",
142
static subphase_s subphases_128K[] = {
144
.name = "Allocation",
156
.name = "Alloc/Dealloc",
168
.name = "Deallocation",
181
static subphase_s subphases_default[] = {
183
.name = "Allocation",
195
.name = "Alloc/Dealloc",
207
.name = "Deallocation",
224
static phase_s phases[] = {
226
.name = "32 B memory blocks",
228
.min_block_size = 32,
231
.subphases = subphases_32B
234
.name = "128 KB memory blocks",
236
.min_block_size = 128 * 1024,
237
.max_block_size = 128 * 1024
239
.subphases = subphases_128K
242
.name = "2500 B memory blocks",
244
.min_block_size = 2500,
245
.max_block_size = 2500
247
.subphases = subphases_default
250
.name = "1 B .. 250000 B memory blocks",
253
.max_block_size = 250000
255
.subphases = subphases_default
261
* Global error flag. The flag is set if an error
262
* is encountered (overlapping blocks, inconsistent
265
static bool error_flag = false;
268
* Memory accounting: the amount of allocated memory and the
269
* number and list of allocated blocks.
271
static size_t mem_allocated;
272
static size_t mem_blocks_count;
274
static LIST_INITIALIZE(mem_blocks);
277
/* Address of the start of the block */
280
/* Size of the memory block */
283
/* link to other blocks */
287
typedef mem_block_s *mem_block_t;
292
* Initializes the memory accounting structures.
295
static void init_mem(void)
298
mem_blocks_count = 0;
302
static bool overlap_match(link_t *entry, void *addr, size_t size)
304
mem_block_t mblk = list_get_instance(entry, mem_block_s, link);
306
/* Entry block control structure <mbeg, mend) */
307
uint8_t *mbeg = (uint8_t *) mblk;
308
uint8_t *mend = (uint8_t *) mblk + sizeof(mem_block_s);
310
/* Entry block memory <bbeg, bend) */
311
uint8_t *bbeg = (uint8_t *) mblk->addr;
312
uint8_t *bend = (uint8_t *) mblk->addr + mblk->size;
314
/* Data block <dbeg, dend) */
315
uint8_t *dbeg = (uint8_t *) addr;
316
uint8_t *dend = (uint8_t *) addr + size;
318
/* Check for overlaps */
319
if (((mbeg >= dbeg) && (mbeg < dend)) ||
320
((mend > dbeg) && (mend <= dend)) ||
321
((bbeg >= dbeg) && (bbeg < dend)) ||
322
((bend > dbeg) && (bend <= dend)))
331
* Test whether a block starting at @addr overlaps with another, previously
332
* allocated memory block or its control structure.
334
* @param addr Initial address of the block
335
* @param size Size of the block
337
* @return false if the block does not overlap.
340
static int test_overlap(void *addr, size_t size)
345
for (entry = mem_blocks.next; entry != &mem_blocks; entry = entry->next) {
346
if (overlap_match(entry, addr, size)) {
358
* Allocate @size bytes of memory and check whether the chunk comes
359
* from the non-mapped memory region and whether the chunk overlaps
360
* with other, previously allocated, chunks.
362
* @param size Amount of memory to allocate
364
* @return NULL if the allocation failed. Sets the global error_flag to
365
* true if the allocation succeeded but is illegal.
368
static void *checked_malloc(size_t size)
372
/* Allocate the chunk of memory */
377
/* Check for overlaps with other chunks */
378
if (test_overlap(data, size)) {
379
TPRINTF("\nError: Allocated block overlaps with another "
380
"previously allocated block.\n");
390
* Allocate a block of memory of @size bytes and add record about it into
391
* the mem_blocks list. Return a pointer to the block holder structure or
392
* NULL if the allocation failed.
394
* If the allocation is illegal (e.g. the memory does not come from the
395
* right region or some of the allocated blocks overlap with others),
396
* set the global error_flag.
398
* @param size Size of the memory block
401
static mem_block_t alloc_block(size_t size)
403
/* Check for allocation limit */
404
if (mem_allocated >= MAX_ALLOC)
407
/* Allocate the block holder */
408
mem_block_t block = (mem_block_t) checked_malloc(sizeof(mem_block_s));
412
link_initialize(&block->link);
414
/* Allocate the block memory */
415
block->addr = checked_malloc(size);
416
if (block->addr == NULL) {
423
/* Register the allocated block */
424
list_append(&block->link, &mem_blocks);
425
mem_allocated += size + sizeof(mem_block_s);
434
* Free the block of memory and the block control structure allocated by
435
* alloc_block. Set the global error_flag if an error occurs.
437
* @param block Block control structure
440
static void free_block(mem_block_t block)
442
/* Unregister the block */
443
list_remove(&block->link);
444
mem_allocated -= block->size + sizeof(mem_block_s);
447
/* Free the memory */
455
* Compute the expected value of a byte located at @pos in memory
456
* block described by @blk.
458
* @param blk Memory block control structure
459
* @param pos Position in the memory block data area
462
static inline uint8_t expected_value(mem_block_t blk, uint8_t *pos)
464
return ((unsigned long) blk ^ (unsigned long) pos) & 0xff;
470
* Fill the memory block controlled by @blk with data.
472
* @param blk Memory block control structure
475
static void fill_block(mem_block_t blk)
480
for (pos = blk->addr, end = pos + blk->size; pos < end; pos++)
481
*pos = expected_value(blk, pos);
487
* Check whether the block @blk contains the data it was filled with.
488
* Set global error_flag if an error occurs.
490
* @param blk Memory block control structure
493
static void check_block(mem_block_t blk)
498
for (pos = blk->addr, end = pos + blk->size; pos < end; pos++) {
499
if (*pos != expected_value (blk, pos)) {
500
TPRINTF("\nError: Corrupted content of a data block.\n");
508
static link_t *list_get_nth(link_t *list, unsigned int i)
510
unsigned int cnt = 0;
513
for (entry = list->next; entry != list; entry = entry->next) {
526
* Select a random memory block from the list of allocated blocks.
528
* @return Block control structure or NULL if the list is empty.
531
static mem_block_t get_random_block(void)
533
if (mem_blocks_count == 0)
536
unsigned int blkidx = rand() % mem_blocks_count;
537
link_t *entry = list_get_nth(&mem_blocks, blkidx);
540
TPRINTF("\nError: Corrupted list of allocated memory blocks.\n");
544
return list_get_instance(entry, mem_block_s, link);
548
#define RETURN_IF_ERROR \
555
static void do_subphase(phase_s *phase, subphase_s *subphase)
558
for (cycles = 0; /* always */; cycles++) {
560
if (subphase->cond.max_cycles &&
561
cycles >= subphase->cond.max_cycles) {
563
* We have performed the required number of
564
* cycles. End the current subphase.
570
* Decide whether we alloc or free memory in this step.
572
unsigned int rnd = rand() % 100;
573
if (rnd < subphase->prob.alloc) {
574
/* Compute a random number lying in interval <min_block_size, max_block_size> */
575
int alloc = phase->alloc.min_block_size +
576
(rand() % (phase->alloc.max_block_size - phase->alloc.min_block_size + 1));
578
mem_block_t blk = alloc_block(alloc);
583
if (subphase->cond.no_memory) {
584
/* We filled the memory. Proceed to next subphase */
593
} else if (rnd < subphase->prob.free) {
594
mem_block_t blk = get_random_block();
597
if (subphase->cond.no_allocated) {
598
/* We free all the memory. Proceed to next subphase. */
613
TPRINTF("\n.. finished.\n");
617
static void do_phase(phase_s *phase)
621
for (subno = 0; subno < 3; subno++) {
622
subphase_s *subphase = & phase->subphases [subno];
624
TPRINTF(".. Sub-phase %u (%s)\n", subno + 1, subphase->name);
625
do_subphase(phase, subphase);
630
char *test_malloc1(void)
634
unsigned int phaseno;
635
for (phaseno = 0; phaseno < sizeof_array(phases); phaseno++) {
636
phase_s *phase = &phases[phaseno];
638
TPRINTF("Entering phase %u (%s)\n", phaseno + 1, phase->name);
644
TPRINTF("Phase finished.\n");
648
return "Test failed";