summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortdeval <>2004-08-11 06:22:45 +0000
committertdeval <>2004-08-11 06:22:45 +0000
commit65193da08860e45add39313084d63c8d45f79a37 (patch)
tree908b8c731791529c150a2942a6192563744468bd
parent6f880eb7fcdbe1fa895d8a32b59128966f46aab2 (diff)
downloadopenbsd-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.c743
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)
11static char rcsid[] = "$OpenBSD: malloc.c,v 1.70 2004/08/05 21:55:21 tdeval Exp $"; 11static 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
81struct pginfo { 79struct 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 */
164static unsigned int malloc_cache = 16; 162static 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 */
167struct pdinfo { 165static u_long malloc_origo;
168 struct pginfo **base;
169 struct pdinfo *prev;
170 struct pdinfo *next;
171 u_long dirnum;
172};
173static struct pdinfo *last_dir; /* Caches to the last and previous */
174static struct pdinfo *prev_dir; /* referenced directory pages. */
175
176static size_t pdi_off;
177static 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 */
184static u_long last_index; 168static u_long last_index;
@@ -247,144 +231,72 @@ void utrace(struct ut *, int);
247/* Status of malloc. */ 231/* Status of malloc. */
248static int malloc_active; 232static int malloc_active;
249 233
250/* Allocated memory. */ 234/* my last break. */
251static size_t malloc_used;
252
253/* My last break. */
254static void *malloc_brk; 235static void *malloc_brk;
255 236
256/* One location cache for free-list holders. */ 237/* one location cache for free-list holders */
257static struct pgfree *px; 238static struct pgfree *px;
258 239
259/* Compile-time options. */ 240/* compile-time options */
260char *malloc_options; 241char *malloc_options;
261 242
262/* Name of the current public function. */ 243/* Name of the current public function */
263static char *malloc_func; 244static 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 */
254static int extend_pgdir(u_long index);
273static void *imalloc(size_t size); 255static void *imalloc(size_t size);
274static void ifree(void *ptr); 256static void ifree(void *ptr);
275static void *irealloc(void *ptr, size_t size); 257static void *irealloc(void *ptr, size_t size);
276static void *malloc_bytes(size_t size); 258static void *malloc_bytes(size_t size);
277 259
278
279/*
280 * Function for page directory lookup.
281 */
282static int
283pdir_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
322void 261void
323malloc_dump(FILE *fd) 262malloc_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
431static void 345static void
@@ -471,86 +385,89 @@ malloc_exit(void)
471static void * 385static void *
472map_pages(size_t pages) 386map_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 */
422static int
423extend_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)
867static __inline__ int 687static __inline__ int
868malloc_make_chunks(int bits) 688malloc_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 *
1096irealloc(void *ptr, size_t size) 896irealloc(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
1234free_pages(void *ptr, u_long index, struct pginfo *info) 999free_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 }
1449not_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
1553ifree(void *ptr) 1211ifree(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}