release.sh: restore -jJAILDIR option
[minix.git] / lib / libc / minix / minix-malloc-debug.c
blob0fbb70410709a517213ead0dcf72274dc83973c8
1 /* pointless without assertions */
2 #ifdef NDEBUG
3 #undef NDEBUG
4 #endif
6 #include <assert.h>
7 #include <machine/vm.h>
8 #include <machine/vmparam.h>
9 #include <minix/minlib.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <unistd.h>
15 #define mmap minix_mmap
16 #define munmap minix_munmap
18 #include "malloc-debug.h"
20 #if 0
21 #include <stdio.h>
22 static int reenter;
23 #define LOG(args) if (!reenter) { reenter++; printf args; reenter--; }
24 #else
25 #define LOG(args)
26 #endif
28 struct block {
29 size_t size;
30 unsigned magic;
33 static u8_t *ptr_min, *ptr_max;
35 #define MIN(x, y) ((x) < (y) ? (x) : (y))
37 static unsigned long page_round_down(unsigned long x)
39 return x - x % PAGE_SIZE;
42 static unsigned long page_round_up(unsigned long x)
44 unsigned long rem;
46 rem = x % PAGE_SIZE;
47 if (rem)
48 x += PAGE_SIZE - rem;
50 return x;
53 #define page_round_down_ptr(x) ((u8_t *) page_round_down((unsigned long) (x)))
54 #define page_round_up_ptr(x) ((u8_t *) page_round_up((unsigned long) (x)))
56 static unsigned long block_compute_magic(struct block *block)
58 return (unsigned long) block + block->size + 0xDEADBEEFUL;
61 static size_t block_get_totalsize(size_t size)
63 return page_round_up(sizeof(struct block) + size);
66 static u8_t *block_get_endptr(struct block *block)
68 return (u8_t *) block + block_get_totalsize(block->size);
71 static u8_t *block_get_dataptr(struct block *block)
73 return block_get_endptr(block) - block->size;
76 static void block_check(struct block *block)
78 u8_t *dataptr, *p;
80 /* check location */
81 assert(block);
82 assert(!((unsigned long) block % PAGE_SIZE));
83 assert((u8_t *) block >= ptr_min);
84 assert((u8_t *) block <= ptr_max);
86 /* check size */
87 assert(block->size > 0);
89 /* check fillers */
90 assert(block->magic == block_compute_magic(block));
91 dataptr = block_get_dataptr(block);
92 for (p = (u8_t *) (block + 1); p < dataptr; p++)
93 assert(*p == ((unsigned long) p & 0xff));
96 static struct block *block_alloc(size_t size)
98 struct block *block;
99 u8_t *dataptr, *p, *ptr;
100 unsigned page_index, page_index_max;
101 size_t sizerem, totalsize;
102 u64_t tsc;
104 LOG(("block_alloc; size=0x%x\n", size));
105 assert(size > 0);
107 /* round size up to machine word size */
108 sizerem = size % sizeof(long);
109 if (sizerem)
110 size += sizeof(long) - sizerem;
112 /* initialize address range */
113 if (!ptr_min && !ptr_max) {
114 /* keep a safe distance from areas that are in use:
115 * - 4MB from the break (should not change if traditional
116 * malloc is not used so a small margin is sufficient
117 * - 256MB from the stack (big margin because memory beyond
118 * this may be allocated by mmap when the address space
119 * starts to fill up)
121 ptr_min = page_round_up_ptr((u8_t *) sbrk(0) + 0x400000);
122 ptr_max = page_round_down_ptr((u8_t *) &size - 0x10000000);
124 assert(ptr_min);
125 assert(ptr_max);
126 assert(ptr_min < ptr_max);
128 /* select address at random */
129 #ifdef __NBSD_LIBC
130 tsc = 0;
131 #else
132 tsc = 0;
133 /* LSC Broken for now... */
134 /* read_tsc_64(&tsc); */
135 #endif
136 totalsize = block_get_totalsize(size);
137 page_index_max = (ptr_max - ptr_min - totalsize) / PAGE_SIZE;
138 page_index = (page_index_max > 0) ? (ex64lo(tsc) % page_index_max) : 0;
139 ptr = ptr_min + page_index * PAGE_SIZE;
141 /* allocate block */
142 block = (struct block *) mmap(
143 ptr, /* addr */
144 totalsize, /* len */
145 PROT_READ|PROT_WRITE, /* prot */
146 MAP_PREALLOC, /* flags */
147 -1, /* fd */
148 0); /* offset */
149 if (block == MAP_FAILED) {
150 /* mmap call failed */
151 abort();
154 /* block may not be at the requested location if that is in use */
155 if (ptr_min > (u8_t *) block)
156 ptr_min = (u8_t *) block;
158 if (ptr_max < (u8_t *) block)
159 ptr_max = (u8_t *) block;
161 /* initialize block, including fillers */
162 block->size = size;
163 block->magic = block_compute_magic(block);
164 dataptr = block_get_dataptr(block);
165 for (p = (u8_t *) (block + 1); p < dataptr; p++)
166 *p = ((unsigned long) p & 0xff);
168 LOG(("block_alloc; block=0x%x\n", block));
169 return block;
172 static struct block *block_find(const void *ptr)
174 struct block *block;
176 LOG(("block_find; ptr=0x%x\n", ptr));
177 assert(ptr);
179 /* locate block based on pointer, then check whether it is valid */
180 block = (struct block *) page_round_down(
181 (unsigned long) ((struct block *) __UNCONST(ptr) - 1));
182 block_check(block);
183 LOG(("block_find; block=0x%x\n", block));
184 return block;
187 static void block_free(struct block *block)
189 LOG(("block_free; block=0x%x\n", block));
190 assert(block);
192 /* simply unmap the block */
193 if (munmap(block, block_get_totalsize(block->size)) < 0) {
194 /* munmap call failed */
195 abort();
199 void *_dbg_malloc(size_t size)
201 struct block *newblock;
202 u8_t *ptr;
204 LOG(("_dbg_malloc; size=0x%x\n", size));
205 assert(size > 0); /* enforced by regular malloc */
207 newblock = block_alloc(size);
208 if (!newblock)
209 return NULL;
211 ptr = block_get_dataptr(newblock);
212 LOG(("_dbg_malloc; ptr=0x%x\n", ptr));
213 return ptr;
216 void *_dbg_realloc(void *oldp, size_t size)
218 u8_t *newp;
219 struct block *oldblock, *newblock;
221 LOG(("_dbg_realloc; oldp=0x%x; size=0x%x\n", oldp, size));
222 assert(oldp); /* enforced by regular realloc */
223 assert(size > 0); /* enforced by regular realloc */
225 /* always allocate new block */
226 newblock = block_alloc(size);
227 if (!newblock)
228 return NULL;
230 /* copy the data */
231 oldblock = block_find(oldp);
232 memcpy(block_get_dataptr(newblock),
233 block_get_dataptr(oldblock),
234 MIN(newblock->size, oldblock->size));
236 /* deallocate old block */
237 block_free(oldblock);
239 newp = block_get_dataptr(newblock);
240 LOG(("_dbg_realloc; newp=0x%x\n", newp));
241 return newp;
244 void _dbg_free(void *ptr)
246 LOG(("_dbg_free; ptr=0x%x\n", ptr));
247 assert(ptr); /* enforced by regular free */
249 /* find the block and free it */
250 block_free(block_find(ptr));
252 LOG(("_dbg_free done\n"));