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