summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authortdeval <>2004-08-01 08:45:39 +0000
committertdeval <>2004-08-01 08:45:39 +0000
commit14931f8ab7a337e1d1f0d6ff78c8d42ffeaf0189 (patch)
tree5ff217da56dae9d26e4b7e73a8acaf8e65a09535 /src/lib
parentba97f2fb05e82ce73f63500dca64cd2dd402f1f8 (diff)
downloadopenbsd-14931f8ab7a337e1d1f0d6ff78c8d42ffeaf0189.tar.gz
openbsd-14931f8ab7a337e1d1f0d6ff78c8d42ffeaf0189.tar.bz2
openbsd-14931f8ab7a337e1d1f0d6ff78c8d42ffeaf0189.zip
After a long gestation period, here comes our custom version of malloc(3)
using mmap(2) instead of sbrk(2). To make a long story short, using mmap(2) in malloc(3) allows us to draw all the benefits from our mmap(2)'s randomization feature, closing the effort we did for returning memory blocks from random addresses. Tested for a long time by many, thanks to them. Go for it ! deraadt@
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libc/stdlib/malloc.c656
1 files changed, 475 insertions, 181 deletions
diff --git a/src/lib/libc/stdlib/malloc.c b/src/lib/libc/stdlib/malloc.c
index ffb74717e2..139c99aa6d 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.67 2004/04/12 09:25:11 tdeval Exp $"; 11static char rcsid[] = "$OpenBSD: malloc.c,v 1.68 2004/08/01 08:45:39 tdeval Exp $";
12#endif /* LIBC_SCCS and not lint */ 12#endif /* LIBC_SCCS and not lint */
13 13
14/* 14/*
@@ -38,6 +38,8 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.67 2004/04/12 09:25:11 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>
41#include <sys/param.h> 43#include <sys/param.h>
42#include <sys/mman.h> 44#include <sys/mman.h>
43#include <sys/uio.h> 45#include <sys/uio.h>
@@ -79,11 +81,11 @@ static char rcsid[] = "$OpenBSD: malloc.c,v 1.67 2004/04/12 09:25:11 tdeval Exp
79struct pginfo { 81struct pginfo {
80 struct pginfo *next; /* next on the free list */ 82 struct pginfo *next; /* next on the free list */
81 void *page; /* Pointer to the page */ 83 void *page; /* Pointer to the page */
82 u_short size; /* size of this page's chunks */ 84 u_short size; /* size of this page's chunks */
83 u_short shift; /* How far to shift for this size chunks */ 85 u_short shift; /* How far to shift for this size chunks */
84 u_short free; /* How many free chunks */ 86 u_short free; /* How many free chunks */
85 u_short total; /* How many chunk */ 87 u_short total; /* How many chunk */
86 u_long bits[1]; /* Which chunks are free */ 88 u_long bits[1]; /* Which chunks are free */
87}; 89};
88 90
89/* 91/*
@@ -94,8 +96,8 @@ struct pgfree {
94 struct pgfree *next; /* next run of free pages */ 96 struct pgfree *next; /* next run of free pages */
95 struct pgfree *prev; /* prev run of free pages */ 97 struct pgfree *prev; /* prev run of free pages */
96 void *page; /* pointer to free pages */ 98 void *page; /* pointer to free pages */
97 void *end; /* pointer to end of free pages */ 99 void *pdir; /* pointer to the base page's dir */
98 u_long size; /* number of bytes free */ 100 size_t size; /* number of bytes free */
99}; 101};
100 102
101/* 103/*
@@ -140,8 +142,8 @@ struct pgfree {
140/* A mask for the offset inside a page. */ 142/* A mask for the offset inside a page. */
141#define malloc_pagemask ((malloc_pagesize)-1) 143#define malloc_pagemask ((malloc_pagesize)-1)
142 144
143#define pageround(foo) (((foo) + (malloc_pagemask))&(~(malloc_pagemask))) 145#define pageround(foo) (((foo) + (malloc_pagemask)) & ~malloc_pagemask)
144#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)-malloc_origo) 146#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)+malloc_pageshift)
145 147
146/* fd of /dev/zero */ 148/* fd of /dev/zero */
147#ifdef USE_DEV_ZERO 149#ifdef USE_DEV_ZERO
@@ -161,8 +163,22 @@ static unsigned int malloc_started;
161/* Number of free pages we cache */ 163/* Number of free pages we cache */
162static unsigned int malloc_cache = 16; 164static unsigned int malloc_cache = 16;
163 165
164/* The offset from pagenumber to index into the page directory */ 166/* Structure used for linking discrete directory pages. */
165static u_long malloc_origo; 167struct pdinfo {
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)
166 182
167/* The last index in the page directory we care about */ 183/* The last index in the page directory we care about */
168static u_long last_index; 184static u_long last_index;
@@ -231,72 +247,144 @@ void utrace(struct ut *, int);
231/* Status of malloc. */ 247/* Status of malloc. */
232static int malloc_active; 248static int malloc_active;
233 249
234/* my last break. */ 250/* Allocated memory. */
251static size_t malloc_used;
252
253/* My last break. */
235static void *malloc_brk; 254static void *malloc_brk;
236 255
237/* one location cache for free-list holders */ 256/* One location cache for free-list holders. */
238static struct pgfree *px; 257static struct pgfree *px;
239 258
240/* compile-time options */ 259/* Compile-time options. */
241char *malloc_options; 260char *malloc_options;
242 261
243/* Name of the current public function */ 262/* Name of the current public function. */
244static char *malloc_func; 263static char *malloc_func;
245 264
246/* Macro for mmap */ 265/* Macro for mmap. */
247#define MMAP(size) \ 266#define MMAP(size) \
248 mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \ 267 mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \
249 MMAP_FD, (off_t)0) 268 MMAP_FD, (off_t)0)
250 269
251/* 270/*
252 * Necessary function declarations 271 * Necessary function declarations.
253 */ 272 */
254static int extend_pgdir(u_long index);
255static void *imalloc(size_t size); 273static void *imalloc(size_t size);
256static void ifree(void *ptr); 274static void ifree(void *ptr);
257static void *irealloc(void *ptr, size_t size); 275static void *irealloc(void *ptr, size_t size);
258static void *malloc_bytes(size_t size); 276static void *malloc_bytes(size_t size);
259 277
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
260#ifdef MALLOC_STATS 321#ifdef MALLOC_STATS
261void 322void
262malloc_dump(FILE *fd) 323malloc_dump(FILE *fd)
263{ 324{
264 struct pginfo **pd; 325 struct pginfo **pd;
265 struct pgfree *pf; 326 struct pgfree *pf;
327 struct pdinfo *pi;
266 int j; 328 int j;
267 329
268 pd = page_dir; 330 pd = page_dir;
331 pi = (struct pdinfo *)((caddr_t)pd + pdi_off);
269 332
270 /* print out all the pages */ 333 /* print out all the pages */
271 for(j=0;j<=last_index;j++) { 334 for(j=0;j<=last_index;) {
272 fprintf(fd, "%08lx %5d ", (j+malloc_origo) << malloc_pageshift, j); 335 fprintf(fd, "%08lx %5d ", j << malloc_pageshift, j);
273 if (pd[j] == MALLOC_NOT_MINE) { 336 if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) {
274 for(j++;j<=last_index && pd[j] == MALLOC_NOT_MINE;j++) 337 for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) {
275 ; 338 if (!PI_OFF(++j)) {
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 }
276 j--; 345 j--;
277 fprintf(fd, ".. %5d not mine\n", j); 346 fprintf(fd, ".. %5d not mine\n", j);
278 } else if (pd[j] == MALLOC_FREE) { 347 } else if (pd[PI_OFF(j)] == MALLOC_FREE) {
279 for(j++;j<=last_index && pd[j] == MALLOC_FREE;j++) 348 for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_FREE;) {
280 ; 349 if (!PI_OFF(++j)) {
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 }
281 j--; 356 j--;
282 fprintf(fd, ".. %5d free\n", j); 357 fprintf(fd, ".. %5d free\n", j);
283 } else if (pd[j] == MALLOC_FIRST) { 358 } else if (pd[PI_OFF(j)] == MALLOC_FIRST) {
284 for(j++;j<=last_index && pd[j] == MALLOC_FOLLOW;j++) 359 for(j++;j<=last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) {
285 ; 360 if (!PI_OFF(++j)) {
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 }
286 j--; 367 j--;
287 fprintf(fd, ".. %5d in use\n", j); 368 fprintf(fd, ".. %5d in use\n", j);
288 } else if (pd[j] < MALLOC_MAGIC) { 369 } else if (pd[PI_OFF(j)] < MALLOC_MAGIC) {
289 fprintf(fd, "(%p)\n", pd[j]); 370 fprintf(fd, "(%p)\n", pd[PI_OFF(j)]);
290 } else { 371 } else {
291 fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n", 372 fprintf(fd, "%p %d (of %d) x %d @ %p --> %p\n",
292 pd[j], pd[j]->free, pd[j]->total, 373 pd[PI_OFF(j)], pd[PI_OFF(j)]->free, pd[PI_OFF(j)]->total,
293 pd[j]->size, pd[j]->page, pd[j]->next); 374 pd[PI_OFF(j)]->size, pd[PI_OFF(j)]->page, pd[PI_OFF(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;
294 } 381 }
295 } 382 }
296 383
297 for(pf=free_list.next; pf; pf=pf->next) { 384 for(pf=free_list.next; pf; pf=pf->next) {
298 fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n", 385 fprintf(fd, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
299 pf, pf->page, pf->end, pf->size, pf->prev, pf->next); 386 pf, pf->page, pf->page + pf->size, pf->size,
387 pf->prev, pf->next);
300 if (pf == pf->next) { 388 if (pf == pf->next) {
301 fprintf(fd, "Free_list loops\n"); 389 fprintf(fd, "Free_list loops\n");
302 break; 390 break;
@@ -308,10 +396,7 @@ malloc_dump(FILE *fd)
308 fprintf(fd, "Maxsize\t%d\n", malloc_maxsize); 396 fprintf(fd, "Maxsize\t%d\n", malloc_maxsize);
309 fprintf(fd, "Pagesize\t%lu\n", (u_long)malloc_pagesize); 397 fprintf(fd, "Pagesize\t%lu\n", (u_long)malloc_pagesize);
310 fprintf(fd, "Pageshift\t%d\n", malloc_pageshift); 398 fprintf(fd, "Pageshift\t%d\n", malloc_pageshift);
311 fprintf(fd, "FirstPage\t%ld\n", malloc_origo); 399 fprintf(fd, "In use\t%lu\n", (u_long)malloc_used);
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);
315} 400}
316#endif /* MALLOC_STATS */ 401#endif /* MALLOC_STATS */
317 402
@@ -385,90 +470,84 @@ malloc_exit(void)
385static void * 470static void *
386map_pages(size_t pages) 471map_pages(size_t pages)
387{ 472{
388 caddr_t result, tail; 473 struct pdinfo *pi, *spi;
474 struct pginfo **pd;
475 u_long pidx,lidx;
476 void *result, *tail;
477 u_long index;
389 478
390 result = (caddr_t)pageround((u_long)sbrk(0));
391 pages <<= malloc_pageshift; 479 pages <<= malloc_pageshift;
392 if (pages > SIZE_T_MAX - (size_t)result) { 480 result = MMAP(pages + malloc_guard);
393#ifdef MALLOC_EXTRA_SANITY 481 if (result == MAP_FAILED) {
394 wrtwarning("(ES): overflow in map_pages fails\n");
395#endif /* MALLOC_EXTRA_SANITY */
396 errno = ENOMEM; 482 errno = ENOMEM;
397 return (NULL);
398 }
399 tail = result + pages + malloc_guard;
400
401 if (brk(tail) == (char *)-1) {
402#ifdef MALLOC_EXTRA_SANITY 483#ifdef MALLOC_EXTRA_SANITY
403 wrtwarning("(ES): map_pages fails\n"); 484 wrtwarning("(ES): map_pages fails\n");
404#endif /* MALLOC_EXTRA_SANITY */ 485#endif /* MALLOC_EXTRA_SANITY */
405 return (NULL); 486 return (NULL);
406 } 487 }
488 tail = result + pages + malloc_guard;
407 if (malloc_guard) 489 if (malloc_guard)
408 mprotect(result + pages, malloc_pagesize, PROT_NONE); 490 mprotect(result + pages, malloc_guard, PROT_NONE);
409
410 last_index = ptr2index(tail) - 1;
411 malloc_brk = tail;
412 491
413 if ((last_index+1) >= malloc_ninfo && !extend_pgdir(last_index)) 492 if (tail > malloc_brk)
414 return (NULL); 493 malloc_brk = tail;
494 if ((index = ptr2index(tail) - 1) > last_index)
495 last_index = index;
415 496
416 return (result); 497 /* Insert directory pages, if needed. */
417} 498 pidx = PI_IDX(ptr2index(result));
499 lidx = PI_IDX(index);
418 500
419/* 501 pdir_lookup(ptr2index(result), &pi);
420 * Extend page directory
421 */
422static int
423extend_pgdir(u_long index)
424{
425 struct pginfo **new, **old;
426 size_t i, oldlen;
427 502
428 /* Make it this many pages */ 503 for (index=pidx,spi=pi;index<=lidx;index++) {
429 i = index * sizeof *page_dir; 504 if (pi == NULL || PD_IDX(pi->dirnum) != index) {
430 i /= malloc_pagesize; 505 if ((pd = MMAP(malloc_pagesize)) == MAP_FAILED) {
431 i += 2; 506 errno = ENOMEM;
432 507 munmap(result, tail - result);
433 /* remember the old mapping size */ 508#ifdef MALLOC_EXTRA_SANITY
434 oldlen = malloc_ninfo * sizeof *page_dir; 509 wrtwarning("(ES): map_pages fails\n");
435 510#endif /* MALLOC_EXTRA_SANITY */
436 /* 511 return (NULL);
437 * NOTE: we allocate new pages and copy the directory rather than tempt 512 }
438 * fate by trying to "grow" the region.. There is nothing to prevent 513 memset(pd, 0, malloc_pagesize);
439 * us from accidently re-mapping space that's been allocated by our caller 514 pi = (struct pdinfo *)((caddr_t)pd + pdi_off);
440 * via dlopen() or other mmap(). 515 pi->base = pd;
441 * 516 pi->prev = spi;
442 * The copy problem is not too bad, as there is 4K of page index per 517 pi->next = spi->next;
443 * 4MB of malloc arena. 518 pi->dirnum = index * (malloc_pagesize/sizeof(struct pginfo *));
444 * 519
445 * We can totally avoid the copy if we open a file descriptor to associate 520 if (spi->next != NULL)
446 * the anon mappings with. Then, when we remap the pages at the new 521 spi->next->prev = pi;
447 * address, the old pages will be "magically" remapped.. But this means 522 spi->next = pi;
448 * keeping open a "secret" file descriptor..... 523 }
449 */ 524 if (index > pidx && index < lidx) {
450 525 pi->dirnum += pdi_mod;
451 /* Get new pages */ 526 } else if (index == pidx) {
452 new = (struct pginfo**) MMAP(i * malloc_pagesize); 527 if (pidx == lidx) {
453 if (new == MAP_FAILED) 528 pi->dirnum += (tail - result) >> malloc_pageshift;
454 return (0); 529 } else {
455 530 pi->dirnum += pdi_mod - PI_OFF(ptr2index(result));
456 /* Copy the old stuff */ 531 }
457 memcpy(new, page_dir, 532 } else {
458 malloc_ninfo * sizeof *page_dir); 533 pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1;
459 534 }
460 /* register the new size */ 535#ifdef MALLOC_EXTRA_SANITY
461 malloc_ninfo = i * malloc_pagesize / sizeof *page_dir; 536 if (PD_OFF(pi->dirnum) > pdi_mod || PD_IDX(pi->dirnum) > index)
462 537 wrterror("(ES): pages directory overflow\n");
463 /* swap the pointers */ 538#endif /* MALLOC_EXTRA_SANITY */
464 old = page_dir; 539 if (index == pidx && pi != last_dir) {
465 page_dir = new; 540 prev_dir = last_dir;
541 last_dir = pi;
542 }
543 spi = pi;
544 pi = spi->next;
545 }
466 546
467 /* Now free the old stuff */ 547 return (result);
468 munmap(old, oldlen);
469 return (1);
470} 548}
471 549
550
472/* 551/*
473 * Initialize the world 552 * Initialize the world
474 */ 553 */
@@ -520,12 +599,12 @@ malloc_init(void)
520 case 'h': malloc_hint = 0; break; 599 case 'h': malloc_hint = 0; break;
521 case 'H': malloc_hint = 1; break; 600 case 'H': malloc_hint = 1; break;
522#endif /* __FreeBSD__ */ 601#endif /* __FreeBSD__ */
523 case 'r': malloc_realloc = 0; break;
524 case 'R': malloc_realloc = 1; break;
525 case 'j': malloc_junk = 0; break; 602 case 'j': malloc_junk = 0; break;
526 case 'J': malloc_junk = 1; break; 603 case 'J': malloc_junk = 1; break;
527 case 'n': malloc_silent = 0; break; 604 case 'n': malloc_silent = 0; break;
528 case 'N': malloc_silent = 1; break; 605 case 'N': malloc_silent = 1; break;
606 case 'r': malloc_realloc = 0; break;
607 case 'R': malloc_realloc = 1; break;
529#ifdef __FreeBSD__ 608#ifdef __FreeBSD__
530 case 'u': malloc_utrace = 0; break; 609 case 'u': malloc_utrace = 0; break;
531 case 'U': malloc_utrace = 1; break; 610 case 'U': malloc_utrace = 1; break;
@@ -564,14 +643,15 @@ malloc_init(void)
564 if (page_dir == MAP_FAILED) 643 if (page_dir == MAP_FAILED)
565 wrterror("mmap(2) failed, check limits\n"); 644 wrterror("mmap(2) failed, check limits\n");
566 645
567 /* 646 pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1);
568 * We need a maximum of malloc_pageshift buckets, steal these from the 647 pdi_mod = pdi_off / sizeof(struct pginfo *);
569 * front of the page_directory; 648
570 */ 649 last_dir = (struct pdinfo *)((caddr_t)page_dir + pdi_off);
571 malloc_origo = ((u_long)pageround((u_long)sbrk(0))) >> malloc_pageshift; 650 last_dir->base = page_dir;
572 malloc_origo -= malloc_pageshift; 651 last_dir->prev = last_dir->next = NULL;
652 last_dir->dirnum = malloc_pageshift;
573 653
574 malloc_ninfo = malloc_pagesize / sizeof *page_dir; 654 malloc_ninfo = pdi_mod;
575 655
576 /* Been here, done that */ 656 /* Been here, done that */
577 malloc_started++; 657 malloc_started++;
@@ -583,11 +663,6 @@ malloc_init(void)
583 663
584 malloc_cache <<= malloc_pageshift; 664 malloc_cache <<= malloc_pageshift;
585 665
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);
591 errno = save_errno; 666 errno = save_errno;
592} 667}
593 668
@@ -599,29 +674,49 @@ malloc_pages(size_t size)
599{ 674{
600 void *p, *delay_free = NULL; 675 void *p, *delay_free = NULL;
601 int i; 676 int i;
677 struct rlimit rl;
678 struct pginfo **pd;
679 struct pdinfo *pi;
680 u_long pidx;
681 void *tp;
602 struct pgfree *pf; 682 struct pgfree *pf;
603 u_long index; 683 u_long index;
684 int m;
604 685
605 size = pageround(size) + malloc_guard; 686 size = pageround(size) + malloc_guard;
606 687
688 if (getrlimit(RLIMIT_DATA, &rl) == -1)
689 wrterror("process limits not available\n");
690 if (rl.rlim_cur != RLIM_INFINITY &&
691 size > ((size_t)rl.rlim_cur - malloc_used)) {
692 errno = ENOMEM;
693 return (NULL);
694 }
695
607 p = NULL; 696 p = NULL;
608 /* Look for free pages before asking for more */ 697 /* Look for free pages before asking for more */
609 for(pf = free_list.next; pf; pf = pf->next) { 698 for (pf = free_list.next; pf; pf = pf->next) {
610 699
611#ifdef MALLOC_EXTRA_SANITY 700#ifdef MALLOC_EXTRA_SANITY
612 if (pf->size & malloc_pagemask) 701 if (pf->size & malloc_pagemask)
613 wrterror("(ES): junk length entry on free_list\n"); 702 wrterror("(ES): junk length entry on free_list\n");
614 if (!pf->size) 703 if (!pf->size)
615 wrterror("(ES): zero length entry on free_list\n"); 704 wrterror("(ES): zero length entry on free_list\n");
616 if (pf->page == pf->end) 705 if (pf->page > (pf->page + pf->size))
617 wrterror("(ES): zero entry on free_list\n");
618 if (pf->page > pf->end)
619 wrterror("(ES): sick entry on free_list\n"); 706 wrterror("(ES): sick entry on free_list\n");
620 if ((void*)pf->page >= (void*)sbrk(0)) 707 if ((pi = pf->pdir) == NULL)
621 wrterror("(ES): entry on free_list past brk\n"); 708 wrterror("(ES): invalid page directory on free-list\n");
622 if (page_dir[ptr2index(pf->page)] != MALLOC_FREE) 709 if ((pidx = PI_IDX(ptr2index(pf->page))) != PD_IDX(pi->dirnum))
710 wrterror("(ES): directory index mismatch on free-list\n");
711 pd = pi->base;
712 if (pd[PI_OFF(ptr2index(pf->page))] != MALLOC_FREE)
623 wrterror("(ES): non-free first page on free-list\n"); 713 wrterror("(ES): non-free first page on free-list\n");
624 if (page_dir[ptr2index(pf->end)-1] != MALLOC_FREE) 714 pidx = PI_IDX(ptr2index((pf->page)+(pf->size))-1);
715 for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next);
716 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
717 wrterror("(ES): last page not referenced in page directory\n");
718 pd = pi->base;
719 if (pd[PI_OFF(ptr2index((pf->page)+(pf->size))-1)] != MALLOC_FREE)
625 wrterror("(ES): non-free last page on free-list\n"); 720 wrterror("(ES): non-free last page on free-list\n");
626#endif /* MALLOC_EXTRA_SANITY */ 721#endif /* MALLOC_EXTRA_SANITY */
627 722
@@ -630,6 +725,7 @@ malloc_pages(size_t size)
630 725
631 if (pf->size == size) { 726 if (pf->size == size) {
632 p = pf->page; 727 p = pf->page;
728 pi = pf->pdir;
633 if (pf->next != NULL) 729 if (pf->next != NULL)
634 pf->next->prev = pf->prev; 730 pf->next->prev = pf->prev;
635 pf->prev->next = pf->next; 731 pf->prev->next = pf->next;
@@ -640,17 +736,28 @@ malloc_pages(size_t size)
640 p = pf->page; 736 p = pf->page;
641 pf->page = (char *)pf->page + size; 737 pf->page = (char *)pf->page + size;
642 pf->size -= size; 738 pf->size -= size;
739 pidx = PI_IDX(ptr2index(pf->page));
740 for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next);
741 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
742 wrterror("(ES): hole in directories\n");
743 tp = pf->pdir;
744 pf->pdir = pi;
745 pi = tp;
643 break; 746 break;
644 } 747 }
645 748
646 size -= malloc_guard; 749 size -= malloc_guard;
647 750
648#ifdef MALLOC_EXTRA_SANITY 751#ifdef MALLOC_EXTRA_SANITY
649 if (p != NULL && page_dir[ptr2index(p)] != MALLOC_FREE) 752 if (p != NULL && pi != NULL) {
753 pidx = PD_IDX(pi->dirnum);
754 pd = pi->base;
755 }
756 if (p != NULL && pd[PI_OFF(ptr2index(p))] != MALLOC_FREE)
650 wrterror("(ES): allocated non-free page on free-list\n"); 757 wrterror("(ES): allocated non-free page on free-list\n");
651#endif /* MALLOC_EXTRA_SANITY */ 758#endif /* MALLOC_EXTRA_SANITY */
652 759
653 if ((malloc_guard || malloc_freeprot) && p != NULL) 760 if (p != NULL && (malloc_guard || malloc_freeprot))
654 mprotect(p, size, PROT_READ|PROT_WRITE); 761 mprotect(p, size, PROT_READ|PROT_WRITE);
655 762
656 size >>= malloc_pageshift; 763 size >>= malloc_pageshift;
@@ -662,9 +769,44 @@ malloc_pages(size_t size)
662 if (p != NULL) { 769 if (p != NULL) {
663 770
664 index = ptr2index(p); 771 index = ptr2index(p);
665 page_dir[index] = MALLOC_FIRST; 772 pidx = PI_IDX(index);
666 for (i=1;i<size;i++) 773 pdir_lookup(index, &pi);
667 page_dir[index+i] = MALLOC_FOLLOW; 774#ifdef MALLOC_EXTRA_SANITY
775 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
776 wrterror("(ES): mapped pages not found in directory\n");
777#endif /* MALLOC_EXTRA_SANITY */
778 if (pi != last_dir) {
779 prev_dir = last_dir;
780 last_dir = pi;
781 }
782 pd = pi->base;
783 pd[PI_OFF(index)] = MALLOC_FIRST;
784 for (i=1;i<size;i++) {
785 if (!PI_OFF(index+i)) {
786 pidx++;
787 pi = pi->next;
788#ifdef MALLOC_EXTRA_SANITY
789 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
790 wrterror("(ES): hole in mapped pages directory\n");
791#endif /* MALLOC_EXTRA_SANITY */
792 pd = pi->base;
793 }
794 pd[PI_OFF(index+i)] = MALLOC_FOLLOW;
795 }
796 if (malloc_guard) {
797 if (!PI_OFF(index+i)) {
798 pidx++;
799 pi = pi->next;
800#ifdef MALLOC_EXTRA_SANITY
801 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
802 wrterror("(ES): hole in mapped pages directory\n");
803#endif /* MALLOC_EXTRA_SANITY */
804 pd = pi->base;
805 }
806 pd[PI_OFF(index+i)] = MALLOC_FIRST;
807 }
808
809 malloc_used += size << malloc_pageshift;
668 810
669 if (malloc_junk) 811 if (malloc_junk)
670 memset(p, SOME_JUNK, size << malloc_pageshift); 812 memset(p, SOME_JUNK, size << malloc_pageshift);
@@ -687,7 +829,10 @@ malloc_pages(size_t size)
687static __inline__ int 829static __inline__ int
688malloc_make_chunks(int bits) 830malloc_make_chunks(int bits)
689{ 831{
690 struct pginfo *bp; 832 struct pginfo *bp;
833 struct pginfo **pd;
834 struct pdinfo *pi;
835 u_long pidx;
691 void *pp; 836 void *pp;
692 int i, k, l; 837 int i, k, l;
693 838
@@ -765,7 +910,18 @@ malloc_make_chunks(int bits)
765 910
766 /* MALLOC_LOCK */ 911 /* MALLOC_LOCK */
767 912
768 page_dir[ptr2index(pp)] = bp; 913 pidx = PI_IDX(ptr2index(pp));
914 pdir_lookup(ptr2index(pp), &pi);
915#ifdef MALLOC_EXTRA_SANITY
916 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
917 wrterror("(ES): mapped pages not found in directory\n");
918#endif /* MALLOC_EXTRA_SANITY */
919 if (pi != last_dir) {
920 prev_dir = last_dir;
921 last_dir = pi;
922 }
923 pd = pi->base;
924 pd[PI_OFF(ptr2index(pp))] = bp;
769 925
770 bp->next = page_dir[bits]; 926 bp->next = page_dir[bits];
771 page_dir[bits] = bp; 927 page_dir[bits] = bp;
@@ -819,7 +975,7 @@ malloc_bytes(size_t size)
819 u += u; 975 u += u;
820 k++; 976 k++;
821 } 977 }
822 978
823 if (malloc_guard) { 979 if (malloc_guard) {
824 /* Walk to a random position. */ 980 /* Walk to a random position. */
825 i = arc4random() % bp->free; 981 i = arc4random() % bp->free;
@@ -832,11 +988,11 @@ malloc_bytes(size_t size)
832 k = 0; 988 k = 0;
833 } 989 }
834#ifdef MALLOC_EXTRA_SANITY 990#ifdef MALLOC_EXTRA_SANITY
835 if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS) 991 if (lp - bp->bits > (bp->total - 1) / MALLOC_BITS)
836 wrterror("chunk overflow\n"); 992 wrterror("chunk overflow\n");
837#endif /* MALLOC_EXTRA_SANITY */ 993#endif /* MALLOC_EXTRA_SANITY */
838 if (*lp & u) 994 if (*lp & u)
839 i--; 995 i--;
840 } 996 }
841 } 997 }
842 *lp ^= u; 998 *lp ^= u;
@@ -896,9 +1052,11 @@ static void *
896irealloc(void *ptr, size_t size) 1052irealloc(void *ptr, size_t size)
897{ 1053{
898 void *p; 1054 void *p;
899 u_long osize, index; 1055 u_long osize, index, i;
900 struct pginfo **mp; 1056 struct pginfo **mp;
901 int i; 1057 struct pginfo **pd;
1058 struct pdinfo *pi;
1059 u_long pidx;
902 1060
903 if (suicide) 1061 if (suicide)
904 abort(); 1062 abort();
@@ -920,7 +1078,19 @@ irealloc(void *ptr, size_t size)
920 return (NULL); 1078 return (NULL);
921 } 1079 }
922 1080
923 mp = &page_dir[index]; 1081 pidx = PI_IDX(index);
1082 pdir_lookup(index, &pi);
1083#ifdef MALLOC_EXTRA_SANITY
1084 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
1085 wrterror("(ES): mapped pages not found in directory\n");
1086#endif /* MALLOC_EXTRA_SANITY */
1087 if (pi != last_dir) {
1088 prev_dir = last_dir;
1089 last_dir = pi;
1090 }
1091
1092 pd = pi->base;
1093 mp = &pd[PI_OFF(index)];
924 1094
925 if (*mp == MALLOC_FIRST) { /* Page allocation */ 1095 if (*mp == MALLOC_FIRST) { /* Page allocation */
926 1096
@@ -931,8 +1101,25 @@ irealloc(void *ptr, size_t size)
931 } 1101 }
932 1102
933 /* Find the size in bytes */ 1103 /* Find the size in bytes */
934 for (osize = malloc_pagesize; *(++mp) == MALLOC_FOLLOW;) 1104 i = index;
1105 if (!PI_OFF(++i)) {
1106 pi = pi->next;
1107 if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
1108 pi = NULL;
1109 if (pi != NULL)
1110 pd = pi->base;
1111 }
1112 for (osize = malloc_pagesize;
1113 pi != NULL && pd[PI_OFF(i)] == MALLOC_FOLLOW;) {
935 osize += malloc_pagesize; 1114 osize += malloc_pagesize;
1115 if (!PI_OFF(++i)) {
1116 pi = pi->next;
1117 if (pi != NULL && PD_IDX(pi->dirnum) != PI_IDX(i))
1118 pi = NULL;
1119 if (pi != NULL)
1120 pd = pi->base;
1121 }
1122 }
936 1123
937 if (!malloc_realloc && /* Unless we have to, */ 1124 if (!malloc_realloc && /* Unless we have to, */
938 size <= osize && /* .. or are too small, */ 1125 size <= osize && /* .. or are too small, */
@@ -988,6 +1175,7 @@ irealloc(void *ptr, size_t size)
988 } 1175 }
989 ifree(ptr); 1176 ifree(ptr);
990 } 1177 }
1178
991 return (p); 1179 return (p);
992} 1180}
993 1181
@@ -999,6 +1187,9 @@ static __inline__ void
999free_pages(void *ptr, u_long index, struct pginfo *info) 1187free_pages(void *ptr, u_long index, struct pginfo *info)
1000{ 1188{
1001 u_long i, l; 1189 u_long i, l;
1190 struct pginfo **pd;
1191 struct pdinfo *pi, *spi;
1192 u_long pidx, lidx;
1002 struct pgfree *pf, *pt=NULL; 1193 struct pgfree *pf, *pt=NULL;
1003 void *tail; 1194 void *tail;
1004 1195
@@ -1018,40 +1209,71 @@ free_pages(void *ptr, u_long index, struct pginfo *info)
1018 } 1209 }
1019 1210
1020 /* Count how many pages and mark them free at the same time */ 1211 /* Count how many pages and mark them free at the same time */
1021 page_dir[index] = MALLOC_FREE; 1212 pidx = PI_IDX(index);
1022 for (i = 1; page_dir[index+i] == MALLOC_FOLLOW; i++) 1213 pdir_lookup(index, &pi);
1023 page_dir[index + i] = MALLOC_FREE; 1214#ifdef MALLOC_EXTRA_SANITY
1215 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
1216 wrterror("(ES): mapped pages not found in directory\n");
1217#endif /* MALLOC_EXTRA_SANITY */
1218
1219 spi = pi; /* Save page index for start of region. */
1220
1221 pd = pi->base;
1222 pd[PI_OFF(index)] = MALLOC_FREE;
1223 i = 1;
1224 if (!PI_OFF(index+i)) {
1225 pi = pi->next;
1226 if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i))
1227 pi = NULL;
1228 else
1229 pd = pi->base;
1230 }
1231 while (pi != NULL && pd[PI_OFF(index+i)] == MALLOC_FOLLOW) {
1232 pd[PI_OFF(index+i)] = MALLOC_FREE;
1233 i++;
1234 if (!PI_OFF(index+i)) {
1235 if ((pi=pi->next) == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i))
1236 pi = NULL;
1237 else
1238 pd = pi->base;
1239 }
1240 }
1024 1241
1025 l = i << malloc_pageshift; 1242 l = i << malloc_pageshift;
1026 1243
1027 if (malloc_junk) 1244 if (malloc_junk)
1028 memset(ptr, SOME_JUNK, l); 1245 memset(ptr, SOME_JUNK, l);
1029 1246
1247 malloc_used -= l;
1248 if (malloc_guard) {
1249#ifdef MALLOC_EXTRA_SANITY
1250 if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(index+i))
1251 wrterror("(ES): hole in mapped pages directory\n");
1252#endif /* MALLOC_EXTRA_SANITY */
1253 pd[PI_OFF(index+i)] = MALLOC_FREE;
1254 l += malloc_guard;
1255 }
1256 tail = (char *)ptr + l;
1257
1030#if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE)) 1258#if defined(__FreeBSD__) || (defined(__OpenBSD__) && defined(MADV_FREE))
1031 if (malloc_hint) 1259 if (malloc_hint)
1032 madvise(ptr, l, MADV_FREE); 1260 madvise(ptr, l, MADV_FREE);
1033#endif 1261#endif
1034 1262
1035 if (malloc_guard) {
1036 page_dir[index + i] = MALLOC_FREE;
1037 l += malloc_guard;
1038 }
1039 tail = (char *)ptr+l;
1040
1041 if (malloc_freeprot) 1263 if (malloc_freeprot)
1042 mprotect(ptr, tail - ptr, PROT_NONE); 1264 mprotect(ptr, l, PROT_NONE);
1043 1265
1044 /* add to free-list */ 1266 /* Add to free-list. */
1045 if (px == NULL) 1267 if (px == NULL)
1046 px = imalloc(sizeof *px); /* This cannot fail... */ 1268 px = imalloc(sizeof *px); /* This cannot fail... */
1047 px->page = ptr; 1269 px->page = ptr;
1048 px->end = tail; 1270 px->pdir = spi;
1049 px->size = l; 1271 px->size = l;
1050 1272
1051 if (free_list.next == NULL) { 1273 if (free_list.next == NULL) {
1052 1274
1053 /* Nothing on free list, put this at head */ 1275 /* Nothing on free list, put this at head. */
1054 px->next = free_list.next; 1276 px->next = NULL;
1055 px->prev = &free_list; 1277 px->prev = &free_list;
1056 free_list.next = px; 1278 free_list.next = px;
1057 pf = px; 1279 pf = px;
@@ -1061,9 +1283,9 @@ free_pages(void *ptr, u_long index, struct pginfo *info)
1061 1283
1062 /* Find the right spot, leave pf pointing to the modified entry. */ 1284 /* Find the right spot, leave pf pointing to the modified entry. */
1063 1285
1064 for(pf = free_list.next; pf->end < ptr && pf->next != NULL; 1286 for(pf = free_list.next; (pf->page+pf->size) < ptr && pf->next != NULL;
1065 pf = pf->next) 1287 pf = pf->next)
1066 ; /* Race ahead here */ 1288 ; /* Race ahead here. */
1067 1289
1068 if (pf->page > tail) { 1290 if (pf->page > tail) {
1069 /* Insert before entry */ 1291 /* Insert before entry */
@@ -1073,25 +1295,24 @@ free_pages(void *ptr, u_long index, struct pginfo *info)
1073 px->prev->next = px; 1295 px->prev->next = px;
1074 pf = px; 1296 pf = px;
1075 px = NULL; 1297 px = NULL;
1076 } else if (pf->end == ptr ) { 1298 } else if ((pf->page + pf->size) == ptr ) {
1077 /* Append to the previous entry */ 1299 /* Append to the previous entry. */
1078 pf->end = (char *)pf->end + l;
1079 pf->size += l; 1300 pf->size += l;
1080 if (pf->next != NULL && pf->end == pf->next->page ) { 1301 if (pf->next != NULL && (pf->page + pf->size) == pf->next->page ) {
1081 /* And collapse the next too. */ 1302 /* And collapse the next too. */
1082 pt = pf->next; 1303 pt = pf->next;
1083 pf->end = pt->end;
1084 pf->size += pt->size; 1304 pf->size += pt->size;
1085 pf->next = pt->next; 1305 pf->next = pt->next;
1086 if (pf->next != NULL) 1306 if (pf->next != NULL)
1087 pf->next->prev = pf; 1307 pf->next->prev = pf;
1088 } 1308 }
1089 } else if (pf->page == tail) { 1309 } else if (pf->page == tail) {
1090 /* Prepend to entry */ 1310 /* Prepend to entry. */
1091 pf->size += l; 1311 pf->size += l;
1092 pf->page = ptr; 1312 pf->page = ptr;
1313 pf->pdir = spi;
1093 } else if (pf->next == NULL) { 1314 } else if (pf->next == NULL) {
1094 /* Append at tail of chain */ 1315 /* Append at tail of chain. */
1095 px->next = NULL; 1316 px->next = NULL;
1096 px->prev = pf; 1317 px->prev = pf;
1097 pf->next = px; 1318 pf->next = px;
@@ -1102,31 +1323,72 @@ free_pages(void *ptr, u_long index, struct pginfo *info)
1102 } 1323 }
1103 } 1324 }
1104 1325
1326 if (pf->pdir != last_dir) {
1327 prev_dir = last_dir;
1328 last_dir = pf->pdir;
1329 }
1330
1105 /* Return something to OS ? */ 1331 /* Return something to OS ? */
1106 if (pf->next == NULL && /* If we're the last one, */ 1332 if (pf->next == NULL && /* If we're the last one, */
1107 pf->size > malloc_cache && /* ..and the cache is full, */ 1333 pf->size > malloc_cache && /* ..and the cache is full, */
1108 pf->end == malloc_brk && /* ..and none behind us, */ 1334 (pf->page + pf->size) == malloc_brk) { /* ..and none behind us, */
1109 malloc_brk == sbrk(0)) { /* ..and it's OK to do... */
1110 1335
1111 /* 1336 /*
1112 * Keep the cache intact. Notice that the '>' above guarantees that 1337 * Keep the cache intact. Notice that the '>' above guarantees that
1113 * the pf will always have at least one page afterwards. 1338 * the pf will always have at least one page afterwards.
1114 */ 1339 */
1115 pf->end = (char *)pf->page + malloc_cache; 1340 if (munmap((char *)pf->page + malloc_cache, pf->size - malloc_cache)!=0)
1341 goto not_return;
1342 tail = pf->page + pf->size;
1343 lidx = ptr2index(tail) - 1;
1116 pf->size = malloc_cache; 1344 pf->size = malloc_cache;
1117 1345
1118 brk(pf->end); 1346 malloc_brk = pf->page + malloc_cache;
1119 malloc_brk = pf->end;
1120 1347
1121 index = ptr2index(pf->end); 1348 index = ptr2index(malloc_brk);
1122 1349
1123 for(i=index;i <= last_index;) 1350 pidx = PI_IDX(index);
1124 page_dir[i++] = MALLOC_NOT_MINE; 1351 if (PD_IDX(prev_dir->dirnum) >= pidx)
1352 prev_dir = NULL; /* Will be wiped out below ! */
1353
1354 for (pi=pf->pdir; pi!=NULL && PD_IDX(pi->dirnum)<pidx; pi=pi->next);
1355
1356 if (pi != NULL && PD_IDX(pi->dirnum) == pidx) {
1357 pd = pi->base;
1358
1359 for(i=index;i <= last_index;) {
1360 if (pd[PI_OFF(i)] != MALLOC_NOT_MINE) {
1361 pd[PI_OFF(i)] = MALLOC_NOT_MINE;
1362#ifdef MALLOC_EXTRA_SANITY
1363 if (!PD_OFF(pi->dirnum))
1364 wrterror("(ES): pages directory underflow\n");
1365#endif /* MALLOC_EXTRA_SANITY */
1366 pi->dirnum--;
1367 }
1368 i++;
1369 if (!PI_OFF(i)) {
1370 /* If no page in that dir, free directory page. */
1371 if (!PD_OFF(pi->dirnum)) {
1372 /* Remove from list. */
1373 pi->prev->next = pi->next;
1374 if (pi->next != NULL)
1375 pi->next->prev = pi->prev;
1376 pi = pi->next;
1377 munmap(pd, malloc_pagesize);
1378 } else
1379 pi = pi->next;
1380 if (pi == NULL || PD_IDX(pi->dirnum) != PI_IDX(i))
1381 break;
1382 pd = pi->base;
1383 }
1384 }
1385 }
1125 1386
1126 last_index = index - 1; 1387 last_index = index - 1;
1127 1388
1128 /* XXX: We could realloc/shrink the pagedir here I guess. */ 1389 /* XXX: We could realloc/shrink the pagedir here I guess. */
1129 } 1390 }
1391not_return:
1130 if (pt != NULL) 1392 if (pt != NULL)
1131 ifree(pt); 1393 ifree(pt);
1132} 1394}
@@ -1141,6 +1403,9 @@ free_bytes(void *ptr, int index, struct pginfo *info)
1141{ 1403{
1142 int i; 1404 int i;
1143 struct pginfo **mp; 1405 struct pginfo **mp;
1406 struct pginfo **pd;
1407 struct pdinfo *pi;
1408 u_long pidx;
1144 void *vp; 1409 void *vp;
1145 1410
1146 /* Find the chunk number on the page */ 1411 /* Find the chunk number on the page */
@@ -1172,7 +1437,8 @@ free_bytes(void *ptr, int index, struct pginfo *info)
1172 /* Page became non-full */ 1437 /* Page became non-full */
1173 1438
1174 /* Insert in address order */ 1439 /* Insert in address order */
1175 while (*mp && (*mp)->next && (*mp)->next->page < info->page) 1440 while (*mp != NULL && (*mp)->next != NULL &&
1441 (*mp)->next->page < info->page)
1176 mp = &(*mp)->next; 1442 mp = &(*mp)->next;
1177 info->next = *mp; 1443 info->next = *mp;
1178 *mp = info; 1444 *mp = info;
@@ -1193,7 +1459,19 @@ free_bytes(void *ptr, int index, struct pginfo *info)
1193 *mp = info->next; 1459 *mp = info->next;
1194 1460
1195 /* Free the page & the info structure if need be */ 1461 /* Free the page & the info structure if need be */
1196 page_dir[ptr2index(info->page)] = MALLOC_FIRST; 1462 pidx = PI_IDX(ptr2index(info->page));
1463 pdir_lookup(ptr2index(info->page), &pi);
1464#ifdef MALLOC_EXTRA_SANITY
1465 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
1466 wrterror("(ES): mapped pages not found in directory\n");
1467#endif /* MALLOC_EXTRA_SANITY */
1468 if (pi != last_dir) {
1469 prev_dir = last_dir;
1470 last_dir = pi;
1471 }
1472
1473 pd = pi->base;
1474 pd[PI_OFF(ptr2index(info->page))] = MALLOC_FIRST;
1197 1475
1198 /* If the page was mprotected, unprotect it before releasing it */ 1476 /* If the page was mprotected, unprotect it before releasing it */
1199 if (info->size == 0) { 1477 if (info->size == 0) {
@@ -1211,6 +1489,9 @@ static void
1211ifree(void *ptr) 1489ifree(void *ptr)
1212{ 1490{
1213 struct pginfo *info; 1491 struct pginfo *info;
1492 struct pginfo **pd;
1493 struct pdinfo *pi;
1494 u_long pidx;
1214 u_long index; 1495 u_long index;
1215 1496
1216 /* This is legal */ 1497 /* This is legal */
@@ -1238,7 +1519,19 @@ ifree(void *ptr)
1238 return; 1519 return;
1239 } 1520 }
1240 1521
1241 info = page_dir[index]; 1522 pidx = PI_IDX(index);
1523 pdir_lookup(index, &pi);
1524#ifdef MALLOC_EXTRA_SANITY
1525 if (pi == NULL || PD_IDX(pi->dirnum) != pidx)
1526 wrterror("(ES): mapped pages not found in directory\n");
1527#endif /* MALLOC_EXTRA_SANITY */
1528 if (pi != last_dir) {
1529 prev_dir = last_dir;
1530 last_dir = pi;
1531 }
1532
1533 pd = pi->base;
1534 info = pd[PI_OFF(index)];
1242 1535
1243 if (info < MALLOC_MAGIC) 1536 if (info < MALLOC_MAGIC)
1244 free_pages(ptr, index, info); 1537 free_pages(ptr, index, info);
@@ -1257,9 +1550,10 @@ malloc_recurse(void)
1257{ 1550{
1258 static int noprint; 1551 static int noprint;
1259 1552
1260 if (noprint == 0) 1553 if (noprint == 0) {
1554 noprint = 1;
1261 wrtwarning("recursive call\n"); 1555 wrtwarning("recursive call\n");
1262 noprint = 1; 1556 }
1263 malloc_active--; 1557 malloc_active--;
1264 _MALLOC_UNLOCK(); 1558 _MALLOC_UNLOCK();
1265 errno = EDEADLK; 1559 errno = EDEADLK;