diff options
author | tdeval <> | 2004-08-11 06:22:45 +0000 |
---|---|---|
committer | tdeval <> | 2004-08-11 06:22:45 +0000 |
commit | 65193da08860e45add39313084d63c8d45f79a37 (patch) | |
tree | 908b8c731791529c150a2942a6192563744468bd | |
parent | 6f880eb7fcdbe1fa895d8a32b59128966f46aab2 (diff) | |
download | openbsd-65193da08860e45add39313084d63c8d45f79a37.tar.gz openbsd-65193da08860e45add39313084d63c8d45f79a37.tar.bz2 openbsd-65193da08860e45add39313084d63c8d45f79a37.zip |
Back out to brk(2) version.
The mmap(2) code is cool and it has already uncovered some bugs in other code.
But some issues remain on some archs, and we can't afford that for production.
Don't worry, it will be back soon... I'll make sure of it...
-rw-r--r-- | src/lib/libc/stdlib/malloc.c | 743 |
1 files changed, 189 insertions, 554 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c index aedb4c8f0c..661265bb85 100644 --- a/src/lib/libc/stdlib/malloc.c +++ b/src/lib/libc/stdlib/malloc.c | |||
@@ -8,7 +8,7 @@ | |||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #if defined(LIBC_SCCS) && !defined(lint) | 10 | #if defined(LIBC_SCCS) && !defined(lint) |
11 | static char rcsid[] = "$OpenBSD: malloc.c,v 1.70 2004/08/05 21:55:21 tdeval Exp $"; | 11 | static char rcsid[] = "$OpenBSD: malloc.c,v 1.71 2004/08/11 06:22:45 tdeval Exp $"; |
12 | #endif /* LIBC_SCCS and not lint */ | 12 | #endif /* LIBC_SCCS and not lint */ |
13 | 13 | ||
14 | /* | 14 | /* |
@@ -38,8 +38,6 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.70 2004/08/05 21:55:21 tdeval Exp | |||
38 | #define SOME_JUNK 0xd0 /* as in "Duh" :-) */ | 38 | #define SOME_JUNK 0xd0 /* as in "Duh" :-) */ |
39 | 39 | ||
40 | #include <sys/types.h> | 40 | #include <sys/types.h> |
41 | #include <sys/time.h> | ||
42 | #include <sys/resource.h> | ||
43 | #include <sys/param.h> | 41 | #include <sys/param.h> |
44 | #include <sys/mman.h> | 42 | #include <sys/mman.h> |
45 | #include <sys/uio.h> | 43 | #include <sys/uio.h> |
@@ -81,11 +79,11 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.70 2004/08/05 21:55:21 tdeval Exp | |||
81 | struct pginfo { | 79 | struct pginfo { |
82 | struct pginfo *next; /* next on the free list */ | 80 | struct pginfo *next; /* next on the free list */ |
83 | void *page; /* Pointer to the page */ | 81 | void *page; /* Pointer to the page */ |
84 | u_short size; /* size of this page's chunks */ | 82 | u_short size; /* size of this page's chunks */ |
85 | u_short shift; /* How far to shift for this size chunks */ | 83 | u_short shift; /* How far to shift for this size chunks */ |
86 | u_short free; /* How many free chunks */ | 84 | u_short free; /* How many free chunks */ |
87 | u_short total; /* How many chunk */ | 85 | u_short total; /* How many chunk */ |
88 | u_long bits[1]; /* Which chunks are free */ | 86 | u_long bits[1]; /* Which chunks are free */ |
89 | }; | 87 | }; |
90 | 88 | ||
91 | /* | 89 | /* |
@@ -96,8 +94,8 @@ struct pgfree { | |||
96 | struct pgfree *next; /* next run of free pages */ | 94 | struct pgfree *next; /* next run of free pages */ |
97 | struct pgfree *prev; /* prev run of free pages */ | 95 | struct pgfree *prev; /* prev run of free pages */ |
98 | void *page; /* pointer to free pages */ | 96 | void *page; /* pointer to free pages */ |
99 | void *pdir; /* pointer to the base page's dir */ | 97 | void *end; /* pointer to end of free pages */ |
100 | size_t size; /* number of bytes free */ | 98 | u_long size; /* number of bytes free */ |
101 | }; | 99 | }; |
102 | 100 | ||
103 | /* | 101 | /* |
@@ -142,8 +140,8 @@ struct pgfree { | |||
142 | /* A mask for the offset inside a page. */ | 140 | /* A mask for the offset inside a page. */ |
143 | #define malloc_pagemask ((malloc_pagesize)-1) | 141 | #define malloc_pagemask ((malloc_pagesize)-1) |
144 | 142 | ||
145 | #define pageround(foo) (((foo) + (malloc_pagemask)) & ~malloc_pagemask) | 143 | #define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) |
146 | #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)+malloc_pageshift) | 144 | #define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) |
147 | 145 | ||
148 | /* fd of /dev/zero */ | 146 | /* fd of /dev/zero */ |
149 | #ifdef USE_DEV_ZERO | 147 | #ifdef USE_DEV_ZERO |
@@ -163,22 +161,8 @@ static unsigned int malloc_started; | |||
163 | /* Number of free pages we cache */ | 161 | /* Number of free pages we cache */ |
164 | static unsigned int malloc_cache = 16; | 162 | static unsigned int malloc_cache = 16; |
165 | 163 | ||
166 | /* Structure used for linking discrete directory pages. */ | 164 | /* The offset from pagenumber to index into the page directory */ |
167 | struct pdinfo { | 165 | static u_long malloc_origo; |
168 | struct pginfo **base; | ||
169 | struct pdinfo *prev; | ||
170 | struct pdinfo *next; | ||
171 | u_long dirnum; | ||
172 | }; | ||
173 | static struct pdinfo *last_dir; /* Caches to the last and previous */ | ||
174 | static struct pdinfo *prev_dir; /* referenced directory pages. */ | ||
175 | |||
176 | static size_t pdi_off; | ||
177 | static u_long pdi_mod; | ||
178 | #define PD_IDX(num) ((num) / (malloc_pagesize/sizeof(struct pginfo *))) | ||
179 | #define PD_OFF(num) ((num) & ((malloc_pagesize/sizeof(struct pginfo *))-1)) | ||
180 | #define PI_IDX(index) ((index) / pdi_mod) | ||
181 | #define PI_OFF(index) ((index) % pdi_mod) | ||
182 | 166 | ||
183 | /* The last index in the page directory we care about */ | 167 | /* The last index in the page directory we care about */ |
184 | static u_long last_index; | 168 | static u_long last_index; |
@@ -247,144 +231,72 @@ void utrace(struct ut *, int); | |||
247 | /* Status of malloc. */ | 231 | /* Status of malloc. */ |
248 | static int malloc_active; | 232 | static int malloc_active; |
249 | 233 | ||
250 | /* Allocated memory. */ | 234 | /* my last break. */ |
251 | static size_t malloc_used; | ||
252 | |||
253 | /* My last break. */ | ||
254 | static void *malloc_brk; | 235 | static void *malloc_brk; |
255 | 236 | ||
256 | /* One location cache for free-list holders. */ | 237 | /* one location cache for free-list holders */ |
257 | static struct pgfree *px; | 238 | static struct pgfree *px; |
258 | 239 | ||
259 | /* Compile-time options. */ | 240 | /* compile-time options */ |
260 | char *malloc_options; | 241 | char *malloc_options; |
261 | 242 | ||
262 | /* Name of the current public function. */ | 243 | /* Name of the current public function */ |
263 | static char *malloc_func; | 244 | static char *malloc_func; |
264 | 245 | ||
265 | /* Macro for mmap. */ | 246 | /* Macro for mmap */ |
266 | #define MMAP(size) \ | 247 | #define MMAP(size) \ |
267 | mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ | 248 | mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ |
268 | MMAP_FD, (off_t)0) | 249 | MMAP_FD, (off_t)0) |
269 | 250 | ||
270 | /* | 251 | /* |
271 | * Necessary function declarations. | 252 | * Necessary function declarations |
272 | */ | 253 | */ |
254 | static int extend_pgdir(u_long index); | ||
273 | static void *imalloc(size_t size); | 255 | static void *imalloc(size_t size); |
274 | static void ifree(void *ptr); | 256 | static void ifree(void *ptr); |
275 | static void *irealloc(void *ptr, size_t size); | 257 | static void *irealloc(void *ptr, size_t size); |
276 | static void *malloc_bytes(size_t size); | 258 | static void *malloc_bytes(size_t size); |
277 | 259 | ||
278 | |||
279 | /* | ||
280 | * Function for page directory lookup. | ||
281 | */ | ||
282 | static int | ||
283 | pdir_lookup(u_long index, struct pdinfo **pdi) | ||
284 | { | ||
285 | struct pdinfo *spi; | ||
286 | u_long pidx = PI_IDX(index); | ||
287 | |||
288 | if (last_dir != NULL && PD_IDX(last_dir->dirnum) == pidx) | ||
289 | *pdi = last_dir; | ||
290 | else if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) == pidx) | ||
291 | *pdi = prev_dir; | ||
292 | else if (last_dir != NULL && prev_dir != NULL) { | ||
293 | if ((PD_IDX(last_dir->dirnum) > pidx) ? | ||
294 | (PD_IDX(last_dir->dirnum) - pidx):(pidx - PD_IDX(last_dir->dirnum)) | ||
295 | < (PD_IDX(prev_dir->dirnum) > pidx) ? | ||
296 | (PD_IDX(prev_dir->dirnum) - pidx):(pidx - PD_IDX(prev_dir->dirnum))) | ||
297 | *pdi = last_dir; | ||
298 | else | ||
299 | *pdi = prev_dir; | ||
300 | |||
301 | if (PD_IDX((*pdi)->dirnum) > pidx) { | ||
302 | for (spi=(*pdi)->prev;spi!=NULL && PD_IDX(spi->dirnum)>pidx; | ||
303 | spi=spi->prev) | ||
304 | *pdi = spi; | ||
305 | if (spi != NULL) | ||
306 | *pdi = spi; | ||
307 | } else | ||
308 | for (spi=(*pdi)->next;spi!=NULL && PD_IDX(spi->dirnum)<=pidx; | ||
309 | spi=spi->next) | ||
310 | *pdi = spi; | ||
311 | } else { | ||
312 | *pdi = (struct pdinfo *)((caddr_t)page_dir + pdi_off); | ||
313 | for (spi=*pdi;spi!=NULL && PD_IDX(spi->dirnum)<=pidx;spi=spi->next) | ||
314 | *pdi = spi; | ||
315 | } | ||
316 | |||
317 | return ((PD_IDX((*pdi)->dirnum) == pidx)?0:(PD_IDX((*pdi)->dirnum) > pidx)?1:-1); | ||
318 | } | ||
319 | |||
320 | |||
321 | #ifdef MALLOC_STATS | 260 | #ifdef MALLOC_STATS |
322 | void | 261 | void |
323 | malloc_dump(FILE *fd) | 262 | malloc_dump(FILE *fd) |
324 | { | 263 | { |
325 | struct pginfo **pd; | 264 | struct pginfo **pd; |
326 | struct pgfree *pf; | 265 | struct pgfree *pf; |
327 | struct pdinfo *pi; | ||
328 | int j; | 266 | int j; |
329 | 267 | ||
330 | pd = page_dir; | 268 | pd = page_dir; |
331 | pi = (struct pdinfo *)((caddr_t)pd + pdi_off); | ||
332 | 269 | ||
333 | /* print out all the pages */ | 270 | /* print out all the pages */ |
334 | for(j=0;j<=last_index;) { | 271 | for(j=0;j<=last_index;j++) { |
335 | fprintf(fd, "%08lx %5d ", j << malloc_pageshift, j); | 272 | fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j); |
336 | if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) { | 273 | if (pd[j] == MALLOC_NOT_MINE) { |
337 | for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) { | 274 | for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) |
338 | if (!PI_OFF(++j)) { | 275 | ; |
339 | if ((pi = pi->next) == NULL || | ||
340 | PD_IDX(pi->dirnum) != PI_IDX(j)) break; | ||
341 | pd = pi->base; | ||
342 | j += pdi_mod; | ||
343 | } | ||
344 | } | ||
345 | j--; | 276 | j--; |
346 | fprintf(fd, ".. %5d not mine\n", j); | 277 | fprintf(fd, ".. %5d not mine\n", j); |
347 | } else if (pd[PI_OFF(j)] == MALLOC_FREE) { | 278 | } else if (pd[j] == MALLOC_FREE) { |
348 | for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_FREE;) { | 279 | for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) |
349 | if (!PI_OFF(++j)) { | 280 | ; |
350 | if ((pi = pi->next) == NULL || | ||
351 | PD_IDX(pi->dirnum) != PI_IDX(j)) break; | ||
352 | pd = pi->base; | ||
353 | j += pdi_mod; | ||
354 | } | ||
355 | } | ||
356 | j--; | 281 | j--; |
357 | fprintf(fd, ".. %5d free\n", j); | 282 | fprintf(fd, ".. %5d free\n", j); |
358 | } else if (pd[PI_OFF(j)] == MALLOC_FIRST) { | 283 | } else if (pd[j] == MALLOC_FIRST) { |
359 | for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) { | 284 | for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) |
360 | if (!PI_OFF(++j)) { | 285 | ; |
361 | if ((pi = pi->next) == NULL || | ||
362 | PD_IDX(pi->dirnum) != PI_IDX(j)) break; | ||
363 | pd = pi->base; | ||
364 | j += pdi_mod; | ||
365 | } | ||
366 | } | ||
367 | j--; | 286 | j--; |
368 | fprintf(fd, ".. %5d in use\n", j); | 287 | fprintf(fd, ".. %5d in use\n", j); |
369 | } else if (pd[PI_OFF(j)] < MALLOC_MAGIC) { | 288 | } else if (pd[j] < MALLOC_MAGIC) { |
370 | fprintf(fd, "(%p)\n", pd[PI_OFF(j)]); | 289 | fprintf(fd, "(%p)\n", pd[j]); |
371 | } else { | 290 | } else { |
372 | fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", | 291 | fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", |
373 | pd[PI_OFF(j)], pd[PI_OFF(j)]->free, pd[PI_OFF(j)]->total, | 292 | pd[j], pd[j]->free, pd[j]->total, |
374 | pd[PI_OFF(j)]->size, pd[PI_OFF(j)]->page, pd[PI_OFF(j)]->next); | 293 | pd[j]->size, pd[j]->page, pd[j]->next); |
375 | } | ||
376 | if (!PI_OFF(++j)) { | ||
377 | if ((pi = pi->next) == NULL) | ||
378 | break; | ||
379 | pd = pi->base; | ||
380 | j += (1 + PD_IDX(pi->dirnum) - PI_IDX(j)) * pdi_mod; | ||
381 | } | 294 | } |
382 | } | 295 | } |
383 | 296 | ||
384 | for(pf=free_list.next; pf; pf=pf->next) { | 297 | for(pf=free_list.next; pf; pf=pf->next) { |
385 | fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", | 298 | fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", |
386 | pf, pf->page, pf->page + pf->size, pf->size, | 299 | pf, pf->page, pf->end, pf->size, pf->prev, pf->next); |
387 | pf->prev, pf->next); | ||
388 | if (pf == pf->next) { | 300 | if (pf == pf->next) { |
389 | fprintf(fd, "Free_list loops\n"); | 301 | fprintf(fd, "Free_list loops\n"); |
390 | break; | 302 | break; |
@@ -396,7 +308,10 @@ malloc_dump(FILE *fd) | |||
396 | fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); | 308 | fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); |
397 | fprintf(fd, "Pagesize\t%lu\n", (u_long)malloc_pagesize); | 309 | fprintf(fd, "Pagesize\t%lu\n", (u_long)malloc_pagesize); |
398 | fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); | 310 | fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); |
399 | fprintf(fd, "In use\t%lu\n", (u_long)malloc_used); | 311 | fprintf(fd, "FirstPage\t%ld\n", malloc_origo); |
312 | fprintf(fd, "LastPage\t%ld %lx\n", last_index+malloc_pageshift, | ||
313 | (last_index + malloc_pageshift) << malloc_pageshift); | ||
314 | fprintf(fd, "Break\t%ld\n", (u_long)sbrk(0) >> malloc_pageshift); | ||
400 | } | 315 | } |
401 | #endif /* MALLOC_STATS */ | 316 | #endif /* MALLOC_STATS */ |
402 | 317 | ||
@@ -424,8 +339,7 @@ wrterror(char *p) | |||
424 | malloc_dump(stderr); | 339 | malloc_dump(stderr); |
425 | #endif /* MALLOC_STATS */ | 340 | #endif /* MALLOC_STATS */ |
426 | malloc_active--; | 341 | malloc_active--; |
427 | if (malloc_abort) | 342 | abort(); |
428 | abort(); | ||
429 | } | 343 | } |
430 | 344 | ||
431 | static void | 345 | static void |
@@ -471,86 +385,89 @@ malloc_exit(void) | |||
471 | static void * | 385 | static void * |
472 | map_pages(size_t pages) | 386 | map_pages(size_t pages) |
473 | { | 387 | { |
474 | struct pdinfo *pi, *spi; | 388 | caddr_t result, tail; |
475 | struct pginfo **pd; | ||
476 | u_long pidx,lidx; | ||
477 | void *result, *tail; | ||
478 | u_long index; | ||
479 | 389 | ||
390 | result = (caddr_t)pageround((u_long)sbrk(0)); | ||
480 | pages <<= malloc_pageshift; | 391 | pages <<= malloc_pageshift; |
481 | result = MMAP(pages + malloc_guard); | 392 | if (pages > SIZE_T_MAX - (size_t)result) { |
482 | if (result == MAP_FAILED) { | ||
483 | errno = ENOMEM; | ||
484 | #ifdef MALLOC_EXTRA_SANITY | 393 | #ifdef MALLOC_EXTRA_SANITY |
485 | wrtwarning("(ES): map_pages fails\n"); | 394 | wrtwarning("(ES): overflow in map_pages fails\n"); |
486 | #endif /* MALLOC_EXTRA_SANITY */ | 395 | #endif /* MALLOC_EXTRA_SANITY */ |
396 | errno = ENOMEM; | ||
487 | return (NULL); | 397 | return (NULL); |
488 | } | 398 | } |
489 | tail = result + pages + malloc_guard; | 399 | tail = result + pages + malloc_guard; |
490 | if (malloc_guard) | ||
491 | mprotect(result + pages, malloc_guard, PROT_NONE); | ||
492 | |||
493 | if (tail > malloc_brk) | ||
494 | malloc_brk = tail; | ||
495 | if ((index = ptr2index(tail) - 1) > last_index) | ||
496 | last_index = index; | ||
497 | |||
498 | /* Insert directory pages, if needed. */ | ||
499 | pidx = PI_IDX(ptr2index(result)); | ||
500 | lidx = PI_IDX(index); | ||
501 | 400 | ||
502 | pdir_lookup(ptr2index(result), &pi); | 401 | if (brk(tail) == (char *)-1) { |
503 | |||
504 | for (index=pidx,spi=pi;index<=lidx;index++) { | ||
505 | if (pi == NULL || PD_IDX(pi->dirnum) != index) { | ||
506 | if ((pd = MMAP(malloc_pagesize)) == MAP_FAILED) { | ||
507 | errno = ENOMEM; | ||
508 | munmap(result, tail - result); | ||
509 | #ifdef MALLOC_EXTRA_SANITY | 402 | #ifdef MALLOC_EXTRA_SANITY |
510 | wrtwarning("(ES): map_pages fails\n"); | 403 | wrtwarning("(ES): map_pages fails\n"); |
511 | #endif /* MALLOC_EXTRA_SANITY */ | ||
512 | return (NULL); | ||
513 | } | ||
514 | memset(pd, 0, malloc_pagesize); | ||
515 | pi = (struct pdinfo *)((caddr_t)pd + pdi_off); | ||
516 | pi->base = pd; | ||
517 | pi->prev = spi; | ||
518 | pi->next = spi->next; | ||
519 | pi->dirnum = index * (malloc_pagesize/sizeof(struct pginfo *)); | ||
520 | |||
521 | if (spi->next != NULL) | ||
522 | spi->next->prev = pi; | ||
523 | spi->next = pi; | ||
524 | } | ||
525 | if (index > pidx && index < lidx) { | ||
526 | pi->dirnum += pdi_mod; | ||
527 | } else if (index == pidx) { | ||
528 | if (pidx == lidx) { | ||
529 | pi->dirnum += (tail - result) >> malloc_pageshift; | ||
530 | } else { | ||
531 | pi->dirnum += pdi_mod - PI_OFF(ptr2index(result)); | ||
532 | } | ||
533 | } else { | ||
534 | pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1; | ||
535 | } | ||
536 | #ifdef MALLOC_EXTRA_SANITY | ||
537 | if (PD_OFF(pi->dirnum) > pdi_mod || PD_IDX(pi->dirnum) > index) { | ||
538 | wrterror("(ES): pages directory overflow\n"); | ||
539 | errno = EFAULT; | ||
540 | return (NULL); | ||
541 | } | ||
542 | #endif /* MALLOC_EXTRA_SANITY */ | 404 | #endif /* MALLOC_EXTRA_SANITY */ |
543 | if (index == pidx && pi != last_dir) { | 405 | return (NULL); |
544 | prev_dir = last_dir; | ||
545 | last_dir = pi; | ||
546 | } | ||
547 | spi = pi; | ||
548 | pi = spi->next; | ||
549 | } | 406 | } |
407 | if (malloc_guard) | ||
408 | mprotect(result + pages, malloc_pagesize, PROT_NONE); | ||
409 | |||
410 | last_index = ptr2index(tail) - 1; | ||
411 | malloc_brk = tail; | ||
412 | |||
413 | if ((last_index+1) >= malloc_ninfo && !extend_pgdir(last_index)) | ||
414 | return (NULL); | ||
550 | 415 | ||
551 | return (result); | 416 | return (result); |
552 | } | 417 | } |
553 | 418 | ||
419 | /* | ||
420 | * Extend page directory | ||
421 | */ | ||
422 | static int | ||
423 | extend_pgdir(u_long index) | ||
424 | { | ||
425 | struct pginfo **new, **old; | ||
426 | size_t i, oldlen; | ||
427 | |||
428 | /* Make it this many pages */ | ||
429 | i = index * sizeof *page_dir; | ||
430 | i /= malloc_pagesize; | ||
431 | i += 2; | ||
432 | |||
433 | /* remember the old mapping size */ | ||
434 | oldlen = malloc_ninfo * sizeof *page_dir; | ||
435 | |||
436 | /* | ||
437 | * NOTE: we allocate new pages and copy the directory rather than tempt | ||
438 | * fate by trying to "grow" the region.. There is nothing to prevent | ||
439 | * us from accidently re-mapping space that's been allocated by our caller | ||
440 | * via dlopen() or other mmap(). | ||
441 | * | ||
442 | * The copy problem is not too bad, as there is 4K of page index per | ||
443 | * 4MB of malloc arena. | ||
444 | * | ||
445 | * We can totally avoid the copy if we open a file descriptor to associate | ||
446 | * the anon mappings with. Then, when we remap the pages at the new | ||
447 | * address, the old pages will be "magically" remapped.. But this means | ||
448 | * keeping open a "secret" file descriptor..... | ||
449 | */ | ||
450 | |||
451 | /* Get new pages */ | ||
452 | new = (struct pginfo**) MMAP(i * malloc_pagesize); | ||
453 | if (new == MAP_FAILED) | ||
454 | return (0); | ||
455 | |||
456 | /* Copy the old stuff */ | ||
457 | memcpy(new, page_dir, | ||
458 | malloc_ninfo * sizeof *page_dir); | ||
459 | |||
460 | /* register the new size */ | ||
461 | malloc_ninfo = i * malloc_pagesize / sizeof *page_dir; | ||
462 | |||
463 | /* swap the pointers */ | ||
464 | old = page_dir; | ||
465 | page_dir = new; | ||
466 | |||
467 | /* Now free the old stuff */ | ||
468 | munmap(old, oldlen); | ||
469 | return (1); | ||
470 | } | ||
554 | 471 | ||
555 | /* | 472 | /* |
556 | * Initialize the world | 473 | * Initialize the world |
@@ -603,12 +520,12 @@ malloc_init(void) | |||
603 | case 'h': malloc_hint = 0; break; | 520 | case 'h': malloc_hint = 0; break; |
604 | case 'H': malloc_hint = 1; break; | 521 | case 'H': malloc_hint = 1; break; |
605 | #endif /* __FreeBSD__ */ | 522 | #endif /* __FreeBSD__ */ |
523 | case 'r': malloc_realloc = 0; break; | ||
524 | case 'R': malloc_realloc = 1; break; | ||
606 | case 'j': malloc_junk = 0; break; | 525 | case 'j': malloc_junk = 0; break; |
607 | case 'J': malloc_junk = 1; break; | 526 | case 'J': malloc_junk = 1; break; |
608 | case 'n': malloc_silent = 0; break; | 527 | case 'n': malloc_silent = 0; break; |
609 | case 'N': malloc_silent = 1; break; | 528 | case 'N': malloc_silent = 1; break; |
610 | case 'r': malloc_realloc = 0; break; | ||
611 | case 'R': malloc_realloc = 1; break; | ||
612 | #ifdef __FreeBSD__ | 529 | #ifdef __FreeBSD__ |
613 | case 'u': malloc_utrace = 0; break; | 530 | case 'u': malloc_utrace = 0; break; |
614 | case 'U': malloc_utrace = 1; break; | 531 | case 'U': malloc_utrace = 1; break; |
@@ -644,21 +561,17 @@ malloc_init(void) | |||
644 | /* Allocate one page for the page directory */ | 561 | /* Allocate one page for the page directory */ |
645 | page_dir = (struct pginfo **) MMAP(malloc_pagesize); | 562 | page_dir = (struct pginfo **) MMAP(malloc_pagesize); |
646 | 563 | ||
647 | if (page_dir == MAP_FAILED) { | 564 | if (page_dir == MAP_FAILED) |
648 | wrterror("mmap(2) failed, check limits\n"); | 565 | wrterror("mmap(2) failed, check limits\n"); |
649 | errno = ENOMEM; | ||
650 | return; | ||
651 | } | ||
652 | 566 | ||
653 | pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1); | 567 | /* |
654 | pdi_mod = pdi_off / sizeof(struct pginfo *); | 568 | * We need a maximum of malloc_pageshift buckets, steal these from the |
655 | 569 | * front of the page_directory; | |
656 | last_dir = (struct pdinfo *)((caddr_t)page_dir + pdi_off); | 570 | */ |
657 | last_dir->base = page_dir; | 571 | malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift; |
658 | last_dir->prev = last_dir->next = NULL; | 572 | malloc_origo -= malloc_pageshift; |
659 | last_dir->dirnum = malloc_pageshift; | ||
660 | 573 | ||
661 | malloc_ninfo = pdi_mod; | 574 | malloc_ninfo = malloc_pagesize / sizeof *page_dir; |
662 | 575 | ||
663 | /* Been here, done that */ | 576 | /* Been here, done that */ |
664 | malloc_started++; | 577 | malloc_started++; |
@@ -670,6 +583,11 @@ malloc_init(void) | |||
670 | 583 | ||
671 | malloc_cache <<= malloc_pageshift; | 584 | malloc_cache <<= malloc_pageshift; |
672 | 585 | ||
586 | /* | ||
587 | * This is a nice hack from Kaleb Keithly (kaleb@x.org). | ||
588 | * We can sbrk(2) further back when we keep this on a low address. | ||
589 | */ | ||
590 | px = (struct pgfree *) imalloc (sizeof *px); | ||
673 | errno = save_errno; | 591 | errno = save_errno; |
674 | } | 592 | } |
675 | 593 | ||
@@ -681,66 +599,30 @@ malloc_pages(size_t size) | |||
681 | { | 599 | { |
682 | void *p, *delay_free = NULL; | 600 | void *p, *delay_free = NULL; |
683 | int i; | 601 | int i; |
684 | struct rlimit rl; | ||
685 | struct pginfo **pd; | ||
686 | struct pdinfo *pi; | ||
687 | u_long pidx; | ||
688 | void *tp; | ||
689 | struct pgfree *pf; | 602 | struct pgfree *pf; |
690 | u_long index; | 603 | u_long index; |
691 | int m; | ||
692 | 604 | ||
693 | size = pageround(size) + malloc_guard; | 605 | size = pageround(size) + malloc_guard; |
694 | 606 | ||
695 | p = NULL; | 607 | p = NULL; |
696 | /* Look for free pages before asking for more */ | 608 | /* Look for free pages before asking for more */ |
697 | for (pf = free_list.next; pf; pf = pf->next) { | 609 | for(pf = free_list.next; pf; pf = pf->next) { |
698 | 610 | ||
699 | #ifdef MALLOC_EXTRA_SANITY | 611 | #ifdef MALLOC_EXTRA_SANITY |
700 | if (pf->size & malloc_pagemask) { | 612 | if (pf->size & malloc_pagemask) |
701 | wrterror("(ES): junk length entry on free_list\n"); | 613 | wrterror("(ES): junk length entry on free_list\n"); |
702 | errno = EFAULT; | 614 | if (!pf->size) |
703 | return (NULL); | ||
704 | } | ||
705 | if (!pf->size) { | ||
706 | wrterror("(ES): zero length entry on free_list\n"); | 615 | wrterror("(ES): zero length entry on free_list\n"); |
707 | errno = EFAULT; | 616 | if (pf->page == pf->end) |
708 | return (NULL); | 617 | wrterror("(ES): zero entry on free_list\n"); |
709 | } | 618 | if (pf->page > pf->end) |
710 | if (pf->page > (pf->page + pf->size)) { | ||
711 | wrterror("(ES): sick entry on free_list\n"); | 619 | wrterror("(ES): sick entry on free_list\n"); |
712 | errno = EFAULT; | 620 | if ((void*)pf->page >= (void*)sbrk(0)) |
713 | return (NULL); | 621 | wrterror("(ES): entry on free_list past brk\n"); |
714 | } | 622 | if (page_dir[ptr2index(pf->page)] != MALLOC_FREE) |
715 | if ((pi = pf->pdir) == NULL) { | ||
716 | wrterror("(ES): invalid page directory on free-list\n"); | ||
717 | errno = EFAULT; | ||
718 | return (NULL); | ||
719 | } | ||
720 | if ((pidx = PI_IDX(ptr2index(pf->page))) != PD_IDX(pi->dirnum)) { | ||
721 | wrterror("(ES): directory index mismatch on free-list\n"); | ||
722 | errno = EFAULT; | ||
723 | return (NULL); | ||
724 | } | ||
725 | pd = pi->base; | ||
726 | if (pd[PI_OFF(ptr2index(pf->page))] != MALLOC_FREE) { | ||
727 | wrterror("(ES): non-free first page on free-list\n"); | 623 | wrterror("(ES): non-free first page on free-list\n"); |
728 | errno = EFAULT; | 624 | if (page_dir[ptr2index(pf->end)-1] != MALLOC_FREE) |
729 | return (NULL); | ||
730 | } | ||
731 | pidx = PI_IDX(ptr2index((pf->page)+(pf->size))-1); | ||
732 | for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next); | ||
733 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
734 | wrterror("(ES): last page not referenced in page directory\n"); | ||
735 | errno = EFAULT; | ||
736 | return (NULL); | ||
737 | } | ||
738 | pd = pi->base; | ||
739 | if (pd[PI_OFF(ptr2index((pf->page)+(pf->size))-1)] != MALLOC_FREE) { | ||
740 | wrterror("(ES): non-free last page on free-list\n"); | 625 | wrterror("(ES): non-free last page on free-list\n"); |
741 | errno = EFAULT; | ||
742 | return (NULL); | ||
743 | } | ||
744 | #endif /* MALLOC_EXTRA_SANITY */ | 626 | #endif /* MALLOC_EXTRA_SANITY */ |
745 | 627 | ||
746 | if (pf->size < size) | 628 | if (pf->size < size) |
@@ -748,7 +630,6 @@ malloc_pages(size_t size) | |||
748 | 630 | ||
749 | if (pf->size == size) { | 631 | if (pf->size == size) { |
750 | p = pf->page; | 632 | p = pf->page; |
751 | pi = pf->pdir; | ||
752 | if (pf->next != NULL) | 633 | if (pf->next != NULL) |
753 | pf->next->prev = pf->prev; | 634 | pf->next->prev = pf->prev; |
754 | pf->prev->next = pf->next; | 635 | pf->prev->next = pf->next; |
@@ -759,34 +640,17 @@ malloc_pages(size_t size) | |||
759 | p = pf->page; | 640 | p = pf->page; |
760 | pf->page = (char *)pf->page + size; | 641 | pf->page = (char *)pf->page + size; |
761 | pf->size -= size; | 642 | pf->size -= size; |
762 | pidx = PI_IDX(ptr2index(pf->page)); | ||
763 | for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next); | ||
764 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
765 | wrterror("(ES): hole in directories\n"); | ||
766 | errno = EFAULT; | ||
767 | return (NULL); | ||
768 | } | ||
769 | tp = pf->pdir; | ||
770 | pf->pdir = pi; | ||
771 | pi = tp; | ||
772 | break; | 643 | break; |
773 | } | 644 | } |
774 | 645 | ||
775 | size -= malloc_guard; | 646 | size -= malloc_guard; |
776 | 647 | ||
777 | #ifdef MALLOC_EXTRA_SANITY | 648 | #ifdef MALLOC_EXTRA_SANITY |
778 | if (p != NULL && pi != NULL) { | 649 | if (p != NULL && page_dir[ptr2index(p)] != MALLOC_FREE) |
779 | pidx = PD_IDX(pi->dirnum); | ||
780 | pd = pi->base; | ||
781 | } | ||
782 | if (p != NULL && pd[PI_OFF(ptr2index(p))] != MALLOC_FREE) { | ||
783 | wrterror("(ES): allocated non-free page on free-list\n"); | 650 | wrterror("(ES): allocated non-free page on free-list\n"); |
784 | errno = EFAULT; | ||
785 | return (NULL); | ||
786 | } | ||
787 | #endif /* MALLOC_EXTRA_SANITY */ | 651 | #endif /* MALLOC_EXTRA_SANITY */ |
788 | 652 | ||
789 | if (p != NULL && (malloc_guard || malloc_freeprot)) | 653 | if ((malloc_guard || malloc_freeprot) && p != NULL) |
790 | mprotect(p, size, PROT_READ|PROT_WRITE); | 654 | mprotect(p, size, PROT_READ|PROT_WRITE); |
791 | 655 | ||
792 | size >>= malloc_pageshift; | 656 | size >>= malloc_pageshift; |
@@ -798,53 +662,9 @@ malloc_pages(size_t size) | |||
798 | if (p != NULL) { | 662 | if (p != NULL) { |
799 | 663 | ||
800 | index = ptr2index(p); | 664 | index = ptr2index(p); |
801 | pidx = PI_IDX(index); | 665 | page_dir[index] = MALLOC_FIRST; |
802 | pdir_lookup(index, &pi); | 666 | for (i=1;i<size;i++) |
803 | #ifdef MALLOC_EXTRA_SANITY | 667 | page_dir[index+i] = MALLOC_FOLLOW; |
804 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
805 | wrterror("(ES): mapped pages not found in directory\n"); | ||
806 | errno = EFAULT; | ||
807 | return (NULL); | ||
808 | } | ||
809 | #endif /* MALLOC_EXTRA_SANITY */ | ||
810 | if (pi != last_dir) { | ||
811 | prev_dir = last_dir; | ||
812 | last_dir = pi; | ||
813 | } | ||
814 | pd = pi->base; | ||
815 | pd[PI_OFF(index)] = MALLOC_FIRST; | ||
816 | for (i=1;i<size;i++) { | ||
817 | if (!PI_OFF(index+i)) { | ||
818 | pidx++; | ||
819 | pi = pi->next; | ||
820 | #ifdef MALLOC_EXTRA_SANITY | ||
821 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
822 | wrterror("(ES): hole in mapped pages directory\n"); | ||
823 | errno = EFAULT; | ||
824 | return (NULL); | ||
825 | } | ||
826 | #endif /* MALLOC_EXTRA_SANITY */ | ||
827 | pd = pi->base; | ||
828 | } | ||
829 | pd[PI_OFF(index+i)] = MALLOC_FOLLOW; | ||
830 | } | ||
831 | if (malloc_guard) { | ||
832 | if (!PI_OFF(index+i)) { | ||
833 | pidx++; | ||
834 | pi = pi->next; | ||
835 | #ifdef MALLOC_EXTRA_SANITY | ||
836 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
837 | wrterror("(ES): hole in mapped pages directory\n"); | ||
838 | errno = EFAULT; | ||
839 | return (NULL); | ||
840 | } | ||
841 | #endif /* MALLOC_EXTRA_SANITY */ | ||
842 | pd = pi->base; | ||
843 | } | ||
844 | pd[PI_OFF(index+i)] = MALLOC_FIRST; | ||
845 | } | ||
846 | |||
847 | malloc_used += size << malloc_pageshift; | ||
848 | 668 | ||
849 | if (malloc_junk) | 669 | if (malloc_junk) |
850 | memset(p, SOME_JUNK, size << malloc_pageshift); | 670 | memset(p, SOME_JUNK, size << malloc_pageshift); |
@@ -867,10 +687,7 @@ malloc_pages(size_t size) | |||
867 | static __inline__ int | 687 | static __inline__ int |
868 | malloc_make_chunks(int bits) | 688 | malloc_make_chunks(int bits) |
869 | { | 689 | { |
870 | struct pginfo *bp; | 690 | struct pginfo *bp; |
871 | struct pginfo **pd; | ||
872 | struct pdinfo *pi; | ||
873 | u_long pidx; | ||
874 | void *pp; | 691 | void *pp; |
875 | int i, k, l; | 692 | int i, k, l; |
876 | 693 | ||
@@ -948,21 +765,7 @@ malloc_make_chunks(int bits) | |||
948 | 765 | ||
949 | /* MALLOC_LOCK */ | 766 | /* MALLOC_LOCK */ |
950 | 767 | ||
951 | pidx = PI_IDX(ptr2index(pp)); | 768 | page_dir[ptr2index(pp)] = bp; |
952 | pdir_lookup(ptr2index(pp), &pi); | ||
953 | #ifdef MALLOC_EXTRA_SANITY | ||
954 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
955 | wrterror("(ES): mapped pages not found in directory\n"); | ||
956 | errno = EFAULT; | ||
957 | return (0); | ||
958 | } | ||
959 | #endif /* MALLOC_EXTRA_SANITY */ | ||
960 | if (pi != last_dir) { | ||
961 | prev_dir = last_dir; | ||
962 | last_dir = pi; | ||
963 | } | ||
964 | pd = pi->base; | ||
965 | pd[PI_OFF(ptr2index(pp))] = bp; | ||
966 | 769 | ||
967 | bp->next = page_dir[bits]; | 770 | bp->next = page_dir[bits]; |
968 | page_dir[bits] = bp; | 771 | page_dir[bits] = bp; |
@@ -1016,7 +819,7 @@ malloc_bytes(size_t size) | |||
1016 | u += u; | 819 | u += u; |
1017 | k++; | 820 | k++; |
1018 | } | 821 | } |
1019 | 822 | ||
1020 | if (malloc_guard) { | 823 | if (malloc_guard) { |
1021 | /* Walk to a random position. */ | 824 | /* Walk to a random position. */ |
1022 | i = arc4random() % bp->free; | 825 | i = arc4random() % bp->free; |
@@ -1029,14 +832,11 @@ malloc_bytes(size_t size) | |||
1029 | k = 0; | 832 | k = 0; |
1030 | } | 833 | } |
1031 | #ifdef MALLOC_EXTRA_SANITY | 834 | #ifdef MALLOC_EXTRA_SANITY |
1032 | if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) { | 835 | if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) |
1033 | wrterror("chunk overflow\n"); | 836 | wrterror("chunk overflow\n"); |
1034 | errno = EFAULT; | ||
1035 | return (NULL); | ||
1036 | } | ||
1037 | #endif /* MALLOC_EXTRA_SANITY */ | 837 | #endif /* MALLOC_EXTRA_SANITY */ |
1038 | if (*lp & u) | 838 | if (*lp & u) |
1039 | i--; | 839 | i--; |
1040 | } | 840 | } |
1041 | } | 841 | } |
1042 | *lp ^= u; | 842 | *lp ^= u; |
@@ -1096,11 +896,9 @@ static void * | |||
1096 | irealloc(void *ptr, size_t size) | 896 | irealloc(void *ptr, size_t size) |
1097 | { | 897 | { |
1098 | void *p; | 898 | void *p; |
1099 | u_long osize, index, i; | 899 | u_long osize, index; |
1100 | struct pginfo **mp; | 900 | struct pginfo **mp; |
1101 | struct pginfo **pd; | 901 | int i; |
1102 | struct pdinfo *pi; | ||
1103 | u_long pidx; | ||
1104 | 902 | ||
1105 | if (suicide) | 903 | if (suicide) |
1106 | abort(); | 904 | abort(); |
@@ -1122,22 +920,7 @@ irealloc(void *ptr, size_t size) | |||
1122 | return (NULL); | 920 | return (NULL); |
1123 | } | 921 | } |
1124 | 922 | ||
1125 | pidx = PI_IDX(index); | 923 | mp = &page_dir[index]; |
1126 | pdir_lookup(index, &pi); | ||
1127 | #ifdef MALLOC_EXTRA_SANITY | ||
1128 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
1129 | wrterror("(ES): mapped pages not found in directory\n"); | ||
1130 | errno = EFAULT; | ||
1131 | return (NULL); | ||
1132 | } | ||
1133 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1134 | if (pi != last_dir) { | ||
1135 | prev_dir = last_dir; | ||
1136 | last_dir = pi; | ||
1137 | } | ||
1138 | |||
1139 | pd = pi->base; | ||
1140 | mp = &pd[PI_OFF(index)]; | ||
1141 | 924 | ||
1142 | if (*mp == MALLOC_FIRST) { /* Page allocation */ | 925 | if (*mp == MALLOC_FIRST) { /* Page allocation */ |
1143 | 926 | ||
@@ -1148,25 +931,8 @@ irealloc(void *ptr, size_t size) | |||
1148 | } | 931 | } |
1149 | 932 | ||
1150 | /* Find the size in bytes */ | 933 | /* Find the size in bytes */ |
1151 | i = index; | 934 | for (osize = malloc_pagesize; *(++mp) == MALLOC_FOLLOW;) |
1152 | if (!PI_OFF(++i)) { | ||
1153 | pi = pi->next; | ||
1154 | if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i)) | ||
1155 | pi = NULL; | ||
1156 | if (pi != NULL) | ||
1157 | pd = pi->base; | ||
1158 | } | ||
1159 | for (osize = malloc_pagesize; | ||
1160 | pi != NULL && pd[PI_OFF(i)] == MALLOC_FOLLOW;) { | ||
1161 | osize += malloc_pagesize; | 935 | osize += malloc_pagesize; |
1162 | if (!PI_OFF(++i)) { | ||
1163 | pi = pi->next; | ||
1164 | if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i)) | ||
1165 | pi = NULL; | ||
1166 | if (pi != NULL) | ||
1167 | pd = pi->base; | ||
1168 | } | ||
1169 | } | ||
1170 | 936 | ||
1171 | if (!malloc_realloc && /* Unless we have to, */ | 937 | if (!malloc_realloc && /* Unless we have to, */ |
1172 | size <= osize && /* .. or are too small, */ | 938 | size <= osize && /* .. or are too small, */ |
@@ -1222,7 +988,6 @@ irealloc(void *ptr, size_t size) | |||
1222 | } | 988 | } |
1223 | ifree(ptr); | 989 | ifree(ptr); |
1224 | } | 990 | } |
1225 | |||
1226 | return (p); | 991 | return (p); |
1227 | } | 992 | } |
1228 | 993 | ||
@@ -1234,9 +999,6 @@ static __inline__ void | |||
1234 | free_pages(void *ptr, u_long index, struct pginfo *info) | 999 | free_pages(void *ptr, u_long index, struct pginfo *info) |
1235 | { | 1000 | { |
1236 | u_long i, l; | 1001 | u_long i, l; |
1237 | struct pginfo **pd; | ||
1238 | struct pdinfo *pi, *spi; | ||
1239 | u_long pidx, lidx; | ||
1240 | struct pgfree *pf, *pt=NULL; | 1002 | struct pgfree *pf, *pt=NULL; |
1241 | void *tail; | 1003 | void *tail; |
1242 | 1004 | ||
@@ -1256,77 +1018,40 @@ free_pages(void *ptr, u_long index, struct pginfo *info) | |||
1256 | } | 1018 | } |
1257 | 1019 | ||
1258 | /* Count how many pages and mark them free at the same time */ | 1020 | /* Count how many pages and mark them free at the same time */ |
1259 | pidx = PI_IDX(index); | 1021 | page_dir[index] = MALLOC_FREE; |
1260 | pdir_lookup(index, &pi); | 1022 | for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++) |
1261 | #ifdef MALLOC_EXTRA_SANITY | 1023 | page_dir[index + i] = MALLOC_FREE; |
1262 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
1263 | wrterror("(ES): mapped pages not found in directory\n"); | ||
1264 | errno = EFAULT; | ||
1265 | return; | ||
1266 | } | ||
1267 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1268 | |||
1269 | spi = pi; /* Save page index for start of region. */ | ||
1270 | |||
1271 | pd = pi->base; | ||
1272 | pd[PI_OFF(index)] = MALLOC_FREE; | ||
1273 | i = 1; | ||
1274 | if (!PI_OFF(index+i)) { | ||
1275 | pi = pi->next; | ||
1276 | if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i)) | ||
1277 | pi = NULL; | ||
1278 | else | ||
1279 | pd = pi->base; | ||
1280 | } | ||
1281 | while (pi != NULL && pd[PI_OFF(index+i)] == MALLOC_FOLLOW) { | ||
1282 | pd[PI_OFF(index+i)] = MALLOC_FREE; | ||
1283 | i++; | ||
1284 | if (!PI_OFF(index+i)) { | ||
1285 | if ((pi=pi->next) == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i)) | ||
1286 | pi = NULL; | ||
1287 | else | ||
1288 | pd = pi->base; | ||
1289 | } | ||
1290 | } | ||
1291 | 1024 | ||
1292 | l = i << malloc_pageshift; | 1025 | l = i << malloc_pageshift; |
1293 | 1026 | ||
1294 | if (malloc_junk) | 1027 | if (malloc_junk) |
1295 | memset(ptr, SOME_JUNK, l); | 1028 | memset(ptr, SOME_JUNK, l); |
1296 | 1029 | ||
1297 | malloc_used -= l; | ||
1298 | if (malloc_guard) { | ||
1299 | #ifdef MALLOC_EXTRA_SANITY | ||
1300 | if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i)) { | ||
1301 | wrterror("(ES): hole in mapped pages directory\n"); | ||
1302 | errno = EFAULT; | ||
1303 | return; | ||
1304 | } | ||
1305 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1306 | pd[PI_OFF(index+i)] = MALLOC_FREE; | ||
1307 | l += malloc_guard; | ||
1308 | } | ||
1309 | tail = (char *)ptr + l; | ||
1310 | |||
1311 | #if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE)) | 1030 | #if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE)) |
1312 | if (malloc_hint) | 1031 | if (malloc_hint) |
1313 | madvise(ptr, l, MADV_FREE); | 1032 | madvise(ptr, l, MADV_FREE); |
1314 | #endif | 1033 | #endif |
1315 | 1034 | ||
1035 | if (malloc_guard) { | ||
1036 | page_dir[index + i] = MALLOC_FREE; | ||
1037 | l += malloc_guard; | ||
1038 | } | ||
1039 | tail = (char *)ptr+l; | ||
1040 | |||
1316 | if (malloc_freeprot) | 1041 | if (malloc_freeprot) |
1317 | mprotect(ptr, l, PROT_NONE); | 1042 | mprotect(ptr, tail - ptr, PROT_NONE); |
1318 | 1043 | ||
1319 | /* Add to free-list. */ | 1044 | /* add to free-list */ |
1320 | if (px == NULL) | 1045 | if (px == NULL) |
1321 | px = imalloc(sizeof *px); /* This cannot fail... */ | 1046 | px = imalloc(sizeof *px); /* This cannot fail... */ |
1322 | px->page = ptr; | 1047 | px->page = ptr; |
1323 | px->pdir = spi; | 1048 | px->end = tail; |
1324 | px->size = l; | 1049 | px->size = l; |
1325 | 1050 | ||
1326 | if (free_list.next == NULL) { | 1051 | if (free_list.next == NULL) { |
1327 | 1052 | ||
1328 | /* Nothing on free list, put this at head. */ | 1053 | /* Nothing on free list, put this at head */ |
1329 | px->next = NULL; | 1054 | px->next = free_list.next; |
1330 | px->prev = &free_list; | 1055 | px->prev = &free_list; |
1331 | free_list.next = px; | 1056 | free_list.next = px; |
1332 | pf = px; | 1057 | pf = px; |
@@ -1336,9 +1061,9 @@ free_pages(void *ptr, u_long index, struct pginfo *info) | |||
1336 | 1061 | ||
1337 | /* Find the right spot, leave pf pointing to the modified entry. */ | 1062 | /* Find the right spot, leave pf pointing to the modified entry. */ |
1338 | 1063 | ||
1339 | for(pf = free_list.next; (pf->page+pf->size) < ptr && pf->next != NULL; | 1064 | for(pf = free_list.next; pf->end < ptr && pf->next != NULL; |
1340 | pf = pf->next) | 1065 | pf = pf->next) |
1341 | ; /* Race ahead here. */ | 1066 | ; /* Race ahead here */ |
1342 | 1067 | ||
1343 | if (pf->page > tail) { | 1068 | if (pf->page > tail) { |
1344 | /* Insert before entry */ | 1069 | /* Insert before entry */ |
@@ -1348,24 +1073,25 @@ free_pages(void *ptr, u_long index, struct pginfo *info) | |||
1348 | px->prev->next = px; | 1073 | px->prev->next = px; |
1349 | pf = px; | 1074 | pf = px; |
1350 | px = NULL; | 1075 | px = NULL; |
1351 | } else if ((pf->page + pf->size) == ptr ) { | 1076 | } else if (pf->end == ptr ) { |
1352 | /* Append to the previous entry. */ | 1077 | /* Append to the previous entry */ |
1078 | pf->end = (char *)pf->end + l; | ||
1353 | pf->size += l; | 1079 | pf->size += l; |
1354 | if (pf->next != NULL && (pf->page + pf->size) == pf->next->page ) { | 1080 | if (pf->next != NULL && pf->end == pf->next->page ) { |
1355 | /* And collapse the next too. */ | 1081 | /* And collapse the next too. */ |
1356 | pt = pf->next; | 1082 | pt = pf->next; |
1083 | pf->end = pt->end; | ||
1357 | pf->size += pt->size; | 1084 | pf->size += pt->size; |
1358 | pf->next = pt->next; | 1085 | pf->next = pt->next; |
1359 | if (pf->next != NULL) | 1086 | if (pf->next != NULL) |
1360 | pf->next->prev = pf; | 1087 | pf->next->prev = pf; |
1361 | } | 1088 | } |
1362 | } else if (pf->page == tail) { | 1089 | } else if (pf->page == tail) { |
1363 | /* Prepend to entry. */ | 1090 | /* Prepend to entry */ |
1364 | pf->size += l; | 1091 | pf->size += l; |
1365 | pf->page = ptr; | 1092 | pf->page = ptr; |
1366 | pf->pdir = spi; | ||
1367 | } else if (pf->next == NULL) { | 1093 | } else if (pf->next == NULL) { |
1368 | /* Append at tail of chain. */ | 1094 | /* Append at tail of chain */ |
1369 | px->next = NULL; | 1095 | px->next = NULL; |
1370 | px->prev = pf; | 1096 | px->prev = pf; |
1371 | pf->next = px; | 1097 | pf->next = px; |
@@ -1373,80 +1099,34 @@ free_pages(void *ptr, u_long index, struct pginfo *info) | |||
1373 | px = NULL; | 1099 | px = NULL; |
1374 | } else { | 1100 | } else { |
1375 | wrterror("freelist is destroyed\n"); | 1101 | wrterror("freelist is destroyed\n"); |
1376 | errno = EFAULT; | ||
1377 | return; | ||
1378 | } | 1102 | } |
1379 | } | 1103 | } |
1380 | 1104 | ||
1381 | if (pf->pdir != last_dir) { | ||
1382 | prev_dir = last_dir; | ||
1383 | last_dir = pf->pdir; | ||
1384 | } | ||
1385 | |||
1386 | /* Return something to OS ? */ | 1105 | /* Return something to OS ? */ |
1387 | if (pf->next == NULL && /* If we're the last one, */ | 1106 | if (pf->next == NULL && /* If we're the last one, */ |
1388 | pf->size > malloc_cache && /* ..and the cache is full, */ | 1107 | pf->size > malloc_cache && /* ..and the cache is full, */ |
1389 | (pf->page + pf->size) == malloc_brk) { /* ..and none behind us, */ | 1108 | pf->end == malloc_brk && /* ..and none behind us, */ |
1109 | malloc_brk == sbrk(0)) { /* ..and it's OK to do... */ | ||
1390 | 1110 | ||
1391 | /* | 1111 | /* |
1392 | * Keep the cache intact. Notice that the '>' above guarantees that | 1112 | * Keep the cache intact. Notice that the '>' above guarantees that |
1393 | * the pf will always have at least one page afterwards. | 1113 | * the pf will always have at least one page afterwards. |
1394 | */ | 1114 | */ |
1395 | if (munmap((char *)pf->page + malloc_cache, pf->size - malloc_cache)!=0) | 1115 | pf->end = (char *)pf->page + malloc_cache; |
1396 | goto not_return; | ||
1397 | tail = pf->page + pf->size; | ||
1398 | lidx = ptr2index(tail) - 1; | ||
1399 | pf->size = malloc_cache; | 1116 | pf->size = malloc_cache; |
1400 | 1117 | ||
1401 | malloc_brk = pf->page + malloc_cache; | 1118 | brk(pf->end); |
1402 | 1119 | malloc_brk = pf->end; | |
1403 | index = ptr2index(malloc_brk); | ||
1404 | |||
1405 | pidx = PI_IDX(index); | ||
1406 | if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) >= pidx) | ||
1407 | prev_dir = NULL; /* Will be wiped out below ! */ | ||
1408 | 1120 | ||
1409 | for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next); | 1121 | index = ptr2index(pf->end); |
1410 | 1122 | ||
1411 | if (pi != NULL && PD_IDX(pi->dirnum) == pidx) { | 1123 | for(i=index;i <= last_index;) |
1412 | pd = pi->base; | 1124 | page_dir[i++] = MALLOC_NOT_MINE; |
1413 | |||
1414 | for(i=index;i <= last_index;) { | ||
1415 | if (pd[PI_OFF(i)] != MALLOC_NOT_MINE) { | ||
1416 | pd[PI_OFF(i)] = MALLOC_NOT_MINE; | ||
1417 | #ifdef MALLOC_EXTRA_SANITY | ||
1418 | if (!PD_OFF(pi->dirnum)) { | ||
1419 | wrterror("(ES): pages directory underflow\n"); | ||
1420 | errno = EFAULT; | ||
1421 | return; | ||
1422 | } | ||
1423 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1424 | pi->dirnum--; | ||
1425 | } | ||
1426 | i++; | ||
1427 | if (!PI_OFF(i)) { | ||
1428 | /* If no page in that dir, free directory page. */ | ||
1429 | if (!PD_OFF(pi->dirnum)) { | ||
1430 | /* Remove from list. */ | ||
1431 | pi->prev->next = pi->next; | ||
1432 | if (pi->next != NULL) | ||
1433 | pi->next->prev = pi->prev; | ||
1434 | pi = pi->next; | ||
1435 | munmap(pd, malloc_pagesize); | ||
1436 | } else | ||
1437 | pi = pi->next; | ||
1438 | if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(i)) | ||
1439 | break; | ||
1440 | pd = pi->base; | ||
1441 | } | ||
1442 | } | ||
1443 | } | ||
1444 | 1125 | ||
1445 | last_index = index - 1; | 1126 | last_index = index - 1; |
1446 | 1127 | ||
1447 | /* XXX: We could realloc/shrink the pagedir here I guess. */ | 1128 | /* XXX: We could realloc/shrink the pagedir here I guess. */ |
1448 | } | 1129 | } |
1449 | not_return: | ||
1450 | if (pt != NULL) | 1130 | if (pt != NULL) |
1451 | ifree(pt); | 1131 | ifree(pt); |
1452 | } | 1132 | } |
@@ -1461,9 +1141,6 @@ free_bytes(void *ptr, int index, struct pginfo *info) | |||
1461 | { | 1141 | { |
1462 | int i; | 1142 | int i; |
1463 | struct pginfo **mp; | 1143 | struct pginfo **mp; |
1464 | struct pginfo **pd; | ||
1465 | struct pdinfo *pi; | ||
1466 | u_long pidx; | ||
1467 | void *vp; | 1144 | void *vp; |
1468 | 1145 | ||
1469 | /* Find the chunk number on the page */ | 1146 | /* Find the chunk number on the page */ |
@@ -1495,8 +1172,7 @@ free_bytes(void *ptr, int index, struct pginfo *info) | |||
1495 | /* Page became non-full */ | 1172 | /* Page became non-full */ |
1496 | 1173 | ||
1497 | /* Insert in address order */ | 1174 | /* Insert in address order */ |
1498 | while (*mp != NULL && (*mp)->next != NULL && | 1175 | while (*mp && (*mp)->next && (*mp)->next->page < info->page) |
1499 | (*mp)->next->page < info->page) | ||
1500 | mp = &(*mp)->next; | 1176 | mp = &(*mp)->next; |
1501 | info->next = *mp; | 1177 | info->next = *mp; |
1502 | *mp = info; | 1178 | *mp = info; |
@@ -1510,32 +1186,14 @@ free_bytes(void *ptr, int index, struct pginfo *info) | |||
1510 | while (*mp != info) { | 1186 | while (*mp != info) { |
1511 | mp = &((*mp)->next); | 1187 | mp = &((*mp)->next); |
1512 | #ifdef MALLOC_EXTRA_SANITY | 1188 | #ifdef MALLOC_EXTRA_SANITY |
1513 | if (!*mp) { | 1189 | if (!*mp) |
1514 | wrterror("(ES): Not on queue\n"); | 1190 | wrterror("(ES): Not on queue\n"); |
1515 | errno = EFAULT; | ||
1516 | return; | ||
1517 | } | ||
1518 | #endif /* MALLOC_EXTRA_SANITY */ | 1191 | #endif /* MALLOC_EXTRA_SANITY */ |
1519 | } | 1192 | } |
1520 | *mp = info->next; | 1193 | *mp = info->next; |
1521 | 1194 | ||
1522 | /* Free the page & the info structure if need be */ | 1195 | /* Free the page & the info structure if need be */ |
1523 | pidx = PI_IDX(ptr2index(info->page)); | 1196 | page_dir[ptr2index(info->page)] = MALLOC_FIRST; |
1524 | pdir_lookup(ptr2index(info->page), &pi); | ||
1525 | #ifdef MALLOC_EXTRA_SANITY | ||
1526 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
1527 | wrterror("(ES): mapped pages not found in directory\n"); | ||
1528 | errno = EFAULT; | ||
1529 | return; | ||
1530 | } | ||
1531 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1532 | if (pi != last_dir) { | ||
1533 | prev_dir = last_dir; | ||
1534 | last_dir = pi; | ||
1535 | } | ||
1536 | |||
1537 | pd = pi->base; | ||
1538 | pd[PI_OFF(ptr2index(info->page))] = MALLOC_FIRST; | ||
1539 | 1197 | ||
1540 | /* If the page was mprotected, unprotect it before releasing it */ | 1198 | /* If the page was mprotected, unprotect it before releasing it */ |
1541 | if (info->size == 0) { | 1199 | if (info->size == 0) { |
@@ -1553,9 +1211,6 @@ static void | |||
1553 | ifree(void *ptr) | 1211 | ifree(void *ptr) |
1554 | { | 1212 | { |
1555 | struct pginfo *info; | 1213 | struct pginfo *info; |
1556 | struct pginfo **pd; | ||
1557 | struct pdinfo *pi; | ||
1558 | u_long pidx; | ||
1559 | u_long index; | 1214 | u_long index; |
1560 | 1215 | ||
1561 | /* This is legal */ | 1216 | /* This is legal */ |
@@ -1583,22 +1238,7 @@ ifree(void *ptr) | |||
1583 | return; | 1238 | return; |
1584 | } | 1239 | } |
1585 | 1240 | ||
1586 | pidx = PI_IDX(index); | 1241 | info = page_dir[index]; |
1587 | pdir_lookup(index, &pi); | ||
1588 | #ifdef MALLOC_EXTRA_SANITY | ||
1589 | if (pi == NULL || PD_IDX(pi->dirnum) != pidx) { | ||
1590 | wrterror("(ES): mapped pages not found in directory\n"); | ||
1591 | errno = EFAULT; | ||
1592 | return; | ||
1593 | } | ||
1594 | #endif /* MALLOC_EXTRA_SANITY */ | ||
1595 | if (pi != last_dir) { | ||
1596 | prev_dir = last_dir; | ||
1597 | last_dir = pi; | ||
1598 | } | ||
1599 | |||
1600 | pd = pi->base; | ||
1601 | info = pd[PI_OFF(index)]; | ||
1602 | 1242 | ||
1603 | if (info < MALLOC_MAGIC) | 1243 | if (info < MALLOC_MAGIC) |
1604 | free_pages(ptr, index, info); | 1244 | free_pages(ptr, index, info); |
@@ -1617,10 +1257,9 @@ malloc_recurse(void) | |||
1617 | { | 1257 | { |
1618 | static int noprint; | 1258 | static int noprint; |
1619 | 1259 | ||
1620 | if (noprint == 0) { | 1260 | if (noprint == 0) |
1621 | noprint = 1; | ||
1622 | wrtwarning("recursive call\n"); | 1261 | wrtwarning("recursive call\n"); |
1623 | } | 1262 | noprint = 1; |
1624 | malloc_active--; | 1263 | malloc_active--; |
1625 | _MALLOC_UNLOCK(); | 1264 | _MALLOC_UNLOCK(); |
1626 | errno = EDEADLK; | 1265 | errno = EDEADLK; |
@@ -1644,10 +1283,8 @@ malloc(size_t size) | |||
1644 | UTRACE(0, size, r); | 1283 | UTRACE(0, size, r); |
1645 | malloc_active--; | 1284 | malloc_active--; |
1646 | _MALLOC_UNLOCK(); | 1285 | _MALLOC_UNLOCK(); |
1647 | if (malloc_xmalloc && r == NULL) { | 1286 | if (malloc_xmalloc && r == NULL) |
1648 | wrterror("out of memory\n"); | 1287 | wrterror("out of memory\n"); |
1649 | errno = ENOMEM; | ||
1650 | } | ||
1651 | return (r); | 1288 | return (r); |
1652 | } | 1289 | } |
1653 | 1290 | ||
@@ -1686,9 +1323,7 @@ realloc(void *ptr, size_t size) | |||
1686 | UTRACE(ptr, size, r); | 1323 | UTRACE(ptr, size, r); |
1687 | malloc_active--; | 1324 | malloc_active--; |
1688 | _MALLOC_UNLOCK(); | 1325 | _MALLOC_UNLOCK(); |
1689 | if (malloc_xmalloc && r == NULL) { | 1326 | if (malloc_xmalloc && r == NULL) |
1690 | wrterror("out of memory\n"); | 1327 | wrterror("out of memory\n"); |
1691 | errno = ENOMEM; | ||
1692 | } | ||
1693 | return (r); | 1328 | return (r); |
1694 | } | 1329 | } |