comparison src/stdlib/SDL_malloc.c @ 1895:c121d94672cb

SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 10 Jul 2006 21:04:37 +0000
parents 8dfa9a6d69a5
children 55e987d8e1b5
comparison
equal deleted inserted replaced
1894:c69cee13dd76 1895:c121d94672cb
475 */ 475 */
476 476
477 #ifndef WIN32 477 #ifndef WIN32
478 #ifdef _WIN32 478 #ifdef _WIN32
479 #define WIN32 1 479 #define WIN32 1
480 #endif /* _WIN32 */ 480 #endif /* _WIN32 */
481 #endif /* WIN32 */ 481 #endif /* WIN32 */
482 #ifdef WIN32 482 #ifdef WIN32
483 #define WIN32_LEAN_AND_MEAN 483 #define WIN32_LEAN_AND_MEAN
484 #include <windows.h> 484 #include <windows.h>
485 #define HAVE_MMAP 1 485 #define HAVE_MMAP 1
486 #define HAVE_MORECORE 0 486 #define HAVE_MORECORE 0
489 #define LACKS_SYS_MMAN_H 489 #define LACKS_SYS_MMAN_H
490 #define LACKS_STRING_H 490 #define LACKS_STRING_H
491 #define LACKS_STRINGS_H 491 #define LACKS_STRINGS_H
492 #define LACKS_SYS_TYPES_H 492 #define LACKS_SYS_TYPES_H
493 #define LACKS_ERRNO_H 493 #define LACKS_ERRNO_H
494 #define LACKS_FCNTL_H 494 #define LACKS_FCNTL_H
495 #define MALLOC_FAILURE_ACTION 495 #define MALLOC_FAILURE_ACTION
496 #define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */ 496 #define MMAP_CLEARS 0 /* WINCE and some others apparently don't clear */
497 #endif /* WIN32 */ 497 #endif /* WIN32 */
498 498
499 #if defined(DARWIN) || defined(_DARWIN) 499 #if defined(DARWIN) || defined(_DARWIN)
500 /* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ 500 /* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
501 #ifndef HAVE_MORECORE 501 #ifndef HAVE_MORECORE
502 #define HAVE_MORECORE 0 502 #define HAVE_MORECORE 0
503 #define HAVE_MMAP 1 503 #define HAVE_MMAP 1
504 #endif /* HAVE_MORECORE */ 504 #endif /* HAVE_MORECORE */
505 #endif /* DARWIN */ 505 #endif /* DARWIN */
506 506
507 #ifndef LACKS_SYS_TYPES_H 507 #ifndef LACKS_SYS_TYPES_H
508 #include <sys/types.h> /* For size_t */ 508 #include <sys/types.h> /* For size_t */
509 #endif /* LACKS_SYS_TYPES_H */ 509 #endif /* LACKS_SYS_TYPES_H */
510 510
511 /* The maximum possible size_t value has all bits set */ 511 /* The maximum possible size_t value has all bits set */
512 #define MAX_SIZE_T (~(size_t)0) 512 #define MAX_SIZE_T (~(size_t)0)
513 513
514 #ifndef ONLY_MSPACES 514 #ifndef ONLY_MSPACES
515 #define ONLY_MSPACES 0 515 #define ONLY_MSPACES 0
516 #endif /* ONLY_MSPACES */ 516 #endif /* ONLY_MSPACES */
517 #ifndef MSPACES 517 #ifndef MSPACES
518 #if ONLY_MSPACES 518 #if ONLY_MSPACES
519 #define MSPACES 1 519 #define MSPACES 1
520 #else /* ONLY_MSPACES */ 520 #else /* ONLY_MSPACES */
521 #define MSPACES 0 521 #define MSPACES 0
522 #endif /* ONLY_MSPACES */ 522 #endif /* ONLY_MSPACES */
523 #endif /* MSPACES */ 523 #endif /* MSPACES */
524 #ifndef MALLOC_ALIGNMENT 524 #ifndef MALLOC_ALIGNMENT
525 #define MALLOC_ALIGNMENT ((size_t)8U) 525 #define MALLOC_ALIGNMENT ((size_t)8U)
526 #endif /* MALLOC_ALIGNMENT */ 526 #endif /* MALLOC_ALIGNMENT */
527 #ifndef FOOTERS 527 #ifndef FOOTERS
528 #define FOOTERS 0 528 #define FOOTERS 0
529 #endif /* FOOTERS */ 529 #endif /* FOOTERS */
530 #ifndef ABORT 530 #ifndef ABORT
531 #define ABORT abort() 531 #define ABORT abort()
532 #endif /* ABORT */ 532 #endif /* ABORT */
533 #ifndef ABORT_ON_ASSERT_FAILURE 533 #ifndef ABORT_ON_ASSERT_FAILURE
534 #define ABORT_ON_ASSERT_FAILURE 1 534 #define ABORT_ON_ASSERT_FAILURE 1
535 #endif /* ABORT_ON_ASSERT_FAILURE */ 535 #endif /* ABORT_ON_ASSERT_FAILURE */
536 #ifndef PROCEED_ON_ERROR 536 #ifndef PROCEED_ON_ERROR
537 #define PROCEED_ON_ERROR 0 537 #define PROCEED_ON_ERROR 0
538 #endif /* PROCEED_ON_ERROR */ 538 #endif /* PROCEED_ON_ERROR */
539 #ifndef USE_LOCKS 539 #ifndef USE_LOCKS
540 #define USE_LOCKS 0 540 #define USE_LOCKS 0
541 #endif /* USE_LOCKS */ 541 #endif /* USE_LOCKS */
542 #ifndef INSECURE 542 #ifndef INSECURE
543 #define INSECURE 0 543 #define INSECURE 0
544 #endif /* INSECURE */ 544 #endif /* INSECURE */
545 #ifndef HAVE_MMAP 545 #ifndef HAVE_MMAP
546 #define HAVE_MMAP 1 546 #define HAVE_MMAP 1
547 #endif /* HAVE_MMAP */ 547 #endif /* HAVE_MMAP */
548 #ifndef MMAP_CLEARS 548 #ifndef MMAP_CLEARS
549 #define MMAP_CLEARS 1 549 #define MMAP_CLEARS 1
550 #endif /* MMAP_CLEARS */ 550 #endif /* MMAP_CLEARS */
551 #ifndef HAVE_MREMAP 551 #ifndef HAVE_MREMAP
552 #ifdef linux 552 #ifdef linux
553 #define HAVE_MREMAP 1 553 #define HAVE_MREMAP 1
554 #else /* linux */ 554 #else /* linux */
555 #define HAVE_MREMAP 0 555 #define HAVE_MREMAP 0
556 #endif /* linux */ 556 #endif /* linux */
557 #endif /* HAVE_MREMAP */ 557 #endif /* HAVE_MREMAP */
558 #ifndef MALLOC_FAILURE_ACTION 558 #ifndef MALLOC_FAILURE_ACTION
559 #define MALLOC_FAILURE_ACTION errno = ENOMEM; 559 #define MALLOC_FAILURE_ACTION errno = ENOMEM;
560 #endif /* MALLOC_FAILURE_ACTION */ 560 #endif /* MALLOC_FAILURE_ACTION */
561 #ifndef HAVE_MORECORE 561 #ifndef HAVE_MORECORE
562 #if ONLY_MSPACES 562 #if ONLY_MSPACES
563 #define HAVE_MORECORE 0 563 #define HAVE_MORECORE 0
564 #else /* ONLY_MSPACES */ 564 #else /* ONLY_MSPACES */
565 #define HAVE_MORECORE 1 565 #define HAVE_MORECORE 1
566 #endif /* ONLY_MSPACES */ 566 #endif /* ONLY_MSPACES */
567 #endif /* HAVE_MORECORE */ 567 #endif /* HAVE_MORECORE */
568 #if !HAVE_MORECORE 568 #if !HAVE_MORECORE
569 #define MORECORE_CONTIGUOUS 0 569 #define MORECORE_CONTIGUOUS 0
570 #else /* !HAVE_MORECORE */ 570 #else /* !HAVE_MORECORE */
571 #ifndef MORECORE 571 #ifndef MORECORE
572 #define MORECORE sbrk 572 #define MORECORE sbrk
573 #endif /* MORECORE */ 573 #endif /* MORECORE */
574 #ifndef MORECORE_CONTIGUOUS 574 #ifndef MORECORE_CONTIGUOUS
575 #define MORECORE_CONTIGUOUS 1 575 #define MORECORE_CONTIGUOUS 1
576 #endif /* MORECORE_CONTIGUOUS */ 576 #endif /* MORECORE_CONTIGUOUS */
577 #endif /* HAVE_MORECORE */ 577 #endif /* HAVE_MORECORE */
578 #ifndef DEFAULT_GRANULARITY 578 #ifndef DEFAULT_GRANULARITY
579 #if MORECORE_CONTIGUOUS 579 #if MORECORE_CONTIGUOUS
580 #define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ 580 #define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */
581 #else /* MORECORE_CONTIGUOUS */ 581 #else /* MORECORE_CONTIGUOUS */
582 #define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) 582 #define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
583 #endif /* MORECORE_CONTIGUOUS */ 583 #endif /* MORECORE_CONTIGUOUS */
584 #endif /* DEFAULT_GRANULARITY */ 584 #endif /* DEFAULT_GRANULARITY */
585 #ifndef DEFAULT_TRIM_THRESHOLD 585 #ifndef DEFAULT_TRIM_THRESHOLD
586 #ifndef MORECORE_CANNOT_TRIM 586 #ifndef MORECORE_CANNOT_TRIM
587 #define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) 587 #define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
588 #else /* MORECORE_CANNOT_TRIM */ 588 #else /* MORECORE_CANNOT_TRIM */
589 #define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T 589 #define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
590 #endif /* MORECORE_CANNOT_TRIM */ 590 #endif /* MORECORE_CANNOT_TRIM */
591 #endif /* DEFAULT_TRIM_THRESHOLD */ 591 #endif /* DEFAULT_TRIM_THRESHOLD */
592 #ifndef DEFAULT_MMAP_THRESHOLD 592 #ifndef DEFAULT_MMAP_THRESHOLD
593 #if HAVE_MMAP 593 #if HAVE_MMAP
594 #define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) 594 #define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
595 #else /* HAVE_MMAP */ 595 #else /* HAVE_MMAP */
596 #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T 596 #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
597 #endif /* HAVE_MMAP */ 597 #endif /* HAVE_MMAP */
598 #endif /* DEFAULT_MMAP_THRESHOLD */ 598 #endif /* DEFAULT_MMAP_THRESHOLD */
599 #ifndef USE_BUILTIN_FFS 599 #ifndef USE_BUILTIN_FFS
600 #define USE_BUILTIN_FFS 0 600 #define USE_BUILTIN_FFS 0
601 #endif /* USE_BUILTIN_FFS */ 601 #endif /* USE_BUILTIN_FFS */
602 #ifndef USE_DEV_RANDOM 602 #ifndef USE_DEV_RANDOM
603 #define USE_DEV_RANDOM 0 603 #define USE_DEV_RANDOM 0
604 #endif /* USE_DEV_RANDOM */ 604 #endif /* USE_DEV_RANDOM */
605 #ifndef NO_MALLINFO 605 #ifndef NO_MALLINFO
606 #define NO_MALLINFO 0 606 #define NO_MALLINFO 0
607 #endif /* NO_MALLINFO */ 607 #endif /* NO_MALLINFO */
608 #ifndef MALLINFO_FIELD_TYPE 608 #ifndef MALLINFO_FIELD_TYPE
609 #define MALLINFO_FIELD_TYPE size_t 609 #define MALLINFO_FIELD_TYPE size_t
610 #endif /* MALLINFO_FIELD_TYPE */ 610 #endif /* MALLINFO_FIELD_TYPE */
611 611
612 #define memset SDL_memset 612 #define memset SDL_memset
613 #define memcpy SDL_memcpy 613 #define memcpy SDL_memcpy
614 #define malloc SDL_malloc 614 #define malloc SDL_malloc
615 #define calloc SDL_calloc 615 #define calloc SDL_calloc
656 656
657 #ifdef HAVE_USR_INCLUDE_MALLOC_H 657 #ifdef HAVE_USR_INCLUDE_MALLOC_H
658 #include "/usr/include/malloc.h" 658 #include "/usr/include/malloc.h"
659 #else /* HAVE_USR_INCLUDE_MALLOC_H */ 659 #else /* HAVE_USR_INCLUDE_MALLOC_H */
660 660
661 struct mallinfo { 661 struct mallinfo
662 MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ 662 {
663 MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ 663 MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
664 MALLINFO_FIELD_TYPE smblks; /* always 0 */ 664 MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
665 MALLINFO_FIELD_TYPE hblks; /* always 0 */ 665 MALLINFO_FIELD_TYPE smblks; /* always 0 */
666 MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ 666 MALLINFO_FIELD_TYPE hblks; /* always 0 */
667 MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ 667 MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
668 MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ 668 MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
669 MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ 669 MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
670 MALLINFO_FIELD_TYPE fordblks; /* total free space */ 670 MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
671 MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ 671 MALLINFO_FIELD_TYPE fordblks; /* total free space */
672 MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
672 }; 673 };
673 674
674 #endif /* HAVE_USR_INCLUDE_MALLOC_H */ 675 #endif /* HAVE_USR_INCLUDE_MALLOC_H */
675 #endif /* NO_MALLINFO */ 676 #endif /* NO_MALLINFO */
676 677
677 #ifdef __cplusplus 678 #ifdef __cplusplus
678 extern "C" { 679 extern "C"
679 #endif /* __cplusplus */ 680 {
681 #endif /* __cplusplus */
680 682
681 #if !ONLY_MSPACES 683 #if !ONLY_MSPACES
682 684
683 /* ------------------- Declarations of public routines ------------------- */ 685 /* ------------------- Declarations of public routines ------------------- */
684 686
697 #define dlmalloc_usable_size malloc_usable_size 699 #define dlmalloc_usable_size malloc_usable_size
698 #define dlmalloc_footprint malloc_footprint 700 #define dlmalloc_footprint malloc_footprint
699 #define dlmalloc_max_footprint malloc_max_footprint 701 #define dlmalloc_max_footprint malloc_max_footprint
700 #define dlindependent_calloc independent_calloc 702 #define dlindependent_calloc independent_calloc
701 #define dlindependent_comalloc independent_comalloc 703 #define dlindependent_comalloc independent_comalloc
702 #endif /* USE_DL_PREFIX */ 704 #endif /* USE_DL_PREFIX */
703 705
704 706
705 /* 707 /*
706 malloc(size_t n) 708 malloc(size_t n)
707 Returns a pointer to a newly allocated chunk of at least n bytes, or 709 Returns a pointer to a newly allocated chunk of at least n bytes, or
714 arguments that would be negative if signed are interpreted as 716 arguments that would be negative if signed are interpreted as
715 requests for huge amounts of space, which will often fail. The 717 requests for huge amounts of space, which will often fail. The
716 maximum supported value of n differs across systems, but is in all 718 maximum supported value of n differs across systems, but is in all
717 cases less than the maximum representable value of a size_t. 719 cases less than the maximum representable value of a size_t.
718 */ 720 */
719 void* dlmalloc(size_t); 721 void *dlmalloc(size_t);
720 722
721 /* 723 /*
722 free(void* p) 724 free(void* p)
723 Releases the chunk of memory pointed to by p, that had been previously 725 Releases the chunk of memory pointed to by p, that had been previously
724 allocated using malloc or a related routine such as realloc. 726 allocated using malloc or a related routine such as realloc.
725 It has no effect if p is null. If p was not malloced or already 727 It has no effect if p is null. If p was not malloced or already
726 freed, free(p) will by default cause the current program to abort. 728 freed, free(p) will by default cause the current program to abort.
727 */ 729 */
728 void dlfree(void*); 730 void dlfree(void *);
729 731
730 /* 732 /*
731 calloc(size_t n_elements, size_t element_size); 733 calloc(size_t n_elements, size_t element_size);
732 Returns a pointer to n_elements * element_size bytes, with all locations 734 Returns a pointer to n_elements * element_size bytes, with all locations
733 set to zero. 735 set to zero.
734 */ 736 */
735 void* dlcalloc(size_t, size_t); 737 void *dlcalloc(size_t, size_t);
736 738
737 /* 739 /*
738 realloc(void* p, size_t n) 740 realloc(void* p, size_t n)
739 Returns a pointer to a chunk of size n that contains the same data 741 Returns a pointer to a chunk of size n that contains the same data
740 as does chunk p up to the minimum of (n, p's size) bytes, or null 742 as does chunk p up to the minimum of (n, p's size) bytes, or null
755 757
756 The old unix realloc convention of allowing the last-free'd chunk 758 The old unix realloc convention of allowing the last-free'd chunk
757 to be used as an argument to realloc is not supported. 759 to be used as an argument to realloc is not supported.
758 */ 760 */
759 761
760 void* dlrealloc(void*, size_t); 762 void *dlrealloc(void *, size_t);
761 763
762 /* 764 /*
763 memalign(size_t alignment, size_t n); 765 memalign(size_t alignment, size_t n);
764 Returns a pointer to a newly allocated chunk of n bytes, aligned 766 Returns a pointer to a newly allocated chunk of n bytes, aligned
765 in accord with the alignment argument. 767 in accord with the alignment argument.
769 8-byte alignment is guaranteed by normal malloc calls, so don't 771 8-byte alignment is guaranteed by normal malloc calls, so don't
770 bother calling memalign with an argument of 8 or less. 772 bother calling memalign with an argument of 8 or less.
771 773
772 Overreliance on memalign is a sure way to fragment space. 774 Overreliance on memalign is a sure way to fragment space.
773 */ 775 */
774 void* dlmemalign(size_t, size_t); 776 void *dlmemalign(size_t, size_t);
775 777
776 /* 778 /*
777 valloc(size_t n); 779 valloc(size_t n);
778 Equivalent to memalign(pagesize, n), where pagesize is the page 780 Equivalent to memalign(pagesize, n), where pagesize is the page
779 size of the system. If the pagesize is unknown, 4096 is used. 781 size of the system. If the pagesize is unknown, 4096 is used.
780 */ 782 */
781 void* dlvalloc(size_t); 783 void *dlvalloc(size_t);
782 784
783 /* 785 /*
784 mallopt(int parameter_number, int parameter_value) 786 mallopt(int parameter_number, int parameter_value)
785 Sets tunable parameters The format is to provide a 787 Sets tunable parameters The format is to provide a
786 (parameter-number, parameter-value) pair. mallopt then sets the 788 (parameter-number, parameter-value) pair. mallopt then sets the
796 Symbol param # default allowed param values 798 Symbol param # default allowed param values
797 M_TRIM_THRESHOLD -1 2*1024*1024 any (MAX_SIZE_T disables) 799 M_TRIM_THRESHOLD -1 2*1024*1024 any (MAX_SIZE_T disables)
798 M_GRANULARITY -2 page size any power of 2 >= page size 800 M_GRANULARITY -2 page size any power of 2 >= page size
799 M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) 801 M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
800 */ 802 */
801 int dlmallopt(int, int); 803 int dlmallopt(int, int);
802 804
803 /* 805 /*
804 malloc_footprint(); 806 malloc_footprint();
805 Returns the number of bytes obtained from the system. The total 807 Returns the number of bytes obtained from the system. The total
806 number of bytes allocated by malloc, realloc etc., is less than this 808 number of bytes allocated by malloc, realloc etc., is less than this
807 value. Unlike mallinfo, this function returns only a precomputed 809 value. Unlike mallinfo, this function returns only a precomputed
808 result, so can be called frequently to monitor memory consumption. 810 result, so can be called frequently to monitor memory consumption.
809 Even if locks are otherwise defined, this function does not use them, 811 Even if locks are otherwise defined, this function does not use them,
810 so results might not be up to date. 812 so results might not be up to date.
811 */ 813 */
812 size_t dlmalloc_footprint(void); 814 size_t dlmalloc_footprint(void);
813 815
814 /* 816 /*
815 malloc_max_footprint(); 817 malloc_max_footprint();
816 Returns the maximum number of bytes obtained from the system. This 818 Returns the maximum number of bytes obtained from the system. This
817 value will be greater than current footprint if deallocated space 819 value will be greater than current footprint if deallocated space
820 this function returns only a precomputed result, so can be called 822 this function returns only a precomputed result, so can be called
821 frequently to monitor memory consumption. Even if locks are 823 frequently to monitor memory consumption. Even if locks are
822 otherwise defined, this function does not use them, so results might 824 otherwise defined, this function does not use them, so results might
823 not be up to date. 825 not be up to date.
824 */ 826 */
825 size_t dlmalloc_max_footprint(void); 827 size_t dlmalloc_max_footprint(void);
826 828
827 #if !NO_MALLINFO 829 #if !NO_MALLINFO
828 /* 830 /*
829 mallinfo() 831 mallinfo()
830 Returns (by copy) a struct containing various summary statistics: 832 Returns (by copy) a struct containing various summary statistics:
845 847
846 Because these fields are ints, but internal bookkeeping may 848 Because these fields are ints, but internal bookkeeping may
847 be kept as longs, the reported values may wrap around zero and 849 be kept as longs, the reported values may wrap around zero and
848 thus be inaccurate. 850 thus be inaccurate.
849 */ 851 */
850 struct mallinfo dlmallinfo(void); 852 struct mallinfo dlmallinfo(void);
851 #endif /* NO_MALLINFO */ 853 #endif /* NO_MALLINFO */
852 854
853 /* 855 /*
854 independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); 856 independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
855 857
856 independent_calloc is similar to calloc, but instead of returning a 858 independent_calloc is similar to calloc, but instead of returning a
900 pool[i]->next = pool[i+1]; 902 pool[i]->next = pool[i+1];
901 free(pool); // Can now free the array (or not, if it is needed later) 903 free(pool); // Can now free the array (or not, if it is needed later)
902 return first; 904 return first;
903 } 905 }
904 */ 906 */
905 void** dlindependent_calloc(size_t, size_t, void**); 907 void **dlindependent_calloc(size_t, size_t, void **);
906 908
907 /* 909 /*
908 independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); 910 independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
909 911
910 independent_comalloc allocates, all at once, a set of n_elements 912 independent_comalloc allocates, all at once, a set of n_elements
961 963
962 Overuse of independent_comalloc can increase overall memory usage, 964 Overuse of independent_comalloc can increase overall memory usage,
963 since it cannot reuse existing noncontiguous small chunks that 965 since it cannot reuse existing noncontiguous small chunks that
964 might be available for some of the elements. 966 might be available for some of the elements.
965 */ 967 */
966 void** dlindependent_comalloc(size_t, size_t*, void**); 968 void **dlindependent_comalloc(size_t, size_t *, void **);
967 969
968 970
969 /* 971 /*
970 pvalloc(size_t n); 972 pvalloc(size_t n);
971 Equivalent to valloc(minimum-page-that-holds(n)), that is, 973 Equivalent to valloc(minimum-page-that-holds(n)), that is,
972 round up n to nearest pagesize. 974 round up n to nearest pagesize.
973 */ 975 */
974 void* dlpvalloc(size_t); 976 void *dlpvalloc(size_t);
975 977
976 /* 978 /*
977 malloc_trim(size_t pad); 979 malloc_trim(size_t pad);
978 980
979 If possible, gives memory back to the system (via negative arguments 981 If possible, gives memory back to the system (via negative arguments
992 trailing space to service future expected allocations without having 994 trailing space to service future expected allocations without having
993 to re-obtain memory from the system. 995 to re-obtain memory from the system.
994 996
995 Malloc_trim returns 1 if it actually released any memory, else 0. 997 Malloc_trim returns 1 if it actually released any memory, else 0.
996 */ 998 */
997 int dlmalloc_trim(size_t); 999 int dlmalloc_trim(size_t);
998 1000
999 /* 1001 /*
1000 malloc_usable_size(void* p); 1002 malloc_usable_size(void* p);
1001 1003
1002 Returns the number of bytes you can actually use in 1004 Returns the number of bytes you can actually use in
1008 debugging and assertions, for example: 1010 debugging and assertions, for example:
1009 1011
1010 p = malloc(n); 1012 p = malloc(n);
1011 assert(malloc_usable_size(p) >= 256); 1013 assert(malloc_usable_size(p) >= 256);
1012 */ 1014 */
1013 size_t dlmalloc_usable_size(void*); 1015 size_t dlmalloc_usable_size(void *);
1014 1016
1015 /* 1017 /*
1016 malloc_stats(); 1018 malloc_stats();
1017 Prints on stderr the amount of space obtained from the system (both 1019 Prints on stderr the amount of space obtained from the system (both
1018 via sbrk and mmap), the maximum amount (which may be more than 1020 via sbrk and mmap), the maximum amount (which may be more than
1029 (normally sbrk) outside of malloc. 1031 (normally sbrk) outside of malloc.
1030 1032
1031 malloc_stats prints only the most commonly interesting statistics. 1033 malloc_stats prints only the most commonly interesting statistics.
1032 More information can be obtained by calling mallinfo. 1034 More information can be obtained by calling mallinfo.
1033 */ 1035 */
1034 void dlmalloc_stats(void); 1036 void dlmalloc_stats(void);
1035 1037
1036 #endif /* ONLY_MSPACES */ 1038 #endif /* ONLY_MSPACES */
1037 1039
1038 #if MSPACES 1040 #if MSPACES
1039 1041
1040 /* 1042 /*
1041 mspace is an opaque type representing an independent 1043 mspace is an opaque type representing an independent
1042 region of space that supports mspace_malloc, etc. 1044 region of space that supports mspace_malloc, etc.
1043 */ 1045 */
1044 typedef void* mspace; 1046 typedef void *mspace;
1045 1047
1046 /* 1048 /*
1047 create_mspace creates and returns a new independent space with the 1049 create_mspace creates and returns a new independent space with the
1048 given initial capacity, or, if 0, the default granularity size. It 1050 given initial capacity, or, if 0, the default granularity size. It
1049 returns null if there is no system memory available to create the 1051 returns null if there is no system memory available to create the
1052 dynamically as needed to service mspace_malloc requests. You can 1054 dynamically as needed to service mspace_malloc requests. You can
1053 control the sizes of incremental increases of this space by 1055 control the sizes of incremental increases of this space by
1054 compiling with a different DEFAULT_GRANULARITY or dynamically 1056 compiling with a different DEFAULT_GRANULARITY or dynamically
1055 setting with mallopt(M_GRANULARITY, value). 1057 setting with mallopt(M_GRANULARITY, value).
1056 */ 1058 */
1057 mspace create_mspace(size_t capacity, int locked); 1059 mspace create_mspace(size_t capacity, int locked);
1058 1060
1059 /* 1061 /*
1060 destroy_mspace destroys the given space, and attempts to return all 1062 destroy_mspace destroys the given space, and attempts to return all
1061 of its memory back to the system, returning the total number of 1063 of its memory back to the system, returning the total number of
1062 bytes freed. After destruction, the results of access to all memory 1064 bytes freed. After destruction, the results of access to all memory
1063 used by the space become undefined. 1065 used by the space become undefined.
1064 */ 1066 */
1065 size_t destroy_mspace(mspace msp); 1067 size_t destroy_mspace(mspace msp);
1066 1068
1067 /* 1069 /*
1068 create_mspace_with_base uses the memory supplied as the initial base 1070 create_mspace_with_base uses the memory supplied as the initial base
1069 of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this 1071 of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
1070 space is used for bookkeeping, so the capacity must be at least this 1072 space is used for bookkeeping, so the capacity must be at least this
1071 large. (Otherwise 0 is returned.) When this initial space is 1073 large. (Otherwise 0 is returned.) When this initial space is
1072 exhausted, additional memory will be obtained from the system. 1074 exhausted, additional memory will be obtained from the system.
1073 Destroying this space will deallocate all additionally allocated 1075 Destroying this space will deallocate all additionally allocated
1074 space (if possible) but not the initial base. 1076 space (if possible) but not the initial base.
1075 */ 1077 */
1076 mspace create_mspace_with_base(void* base, size_t capacity, int locked); 1078 mspace create_mspace_with_base(void *base, size_t capacity, int locked);
1077 1079
1078 /* 1080 /*
1079 mspace_malloc behaves as malloc, but operates within 1081 mspace_malloc behaves as malloc, but operates within
1080 the given space. 1082 the given space.
1081 */ 1083 */
1082 void* mspace_malloc(mspace msp, size_t bytes); 1084 void *mspace_malloc(mspace msp, size_t bytes);
1083 1085
1084 /* 1086 /*
1085 mspace_free behaves as free, but operates within 1087 mspace_free behaves as free, but operates within
1086 the given space. 1088 the given space.
1087 1089
1088 If compiled with FOOTERS==1, mspace_free is not actually needed. 1090 If compiled with FOOTERS==1, mspace_free is not actually needed.
1089 free may be called instead of mspace_free because freed chunks from 1091 free may be called instead of mspace_free because freed chunks from
1090 any space are handled by their originating spaces. 1092 any space are handled by their originating spaces.
1091 */ 1093 */
1092 void mspace_free(mspace msp, void* mem); 1094 void mspace_free(mspace msp, void *mem);
1093 1095
1094 /* 1096 /*
1095 mspace_realloc behaves as realloc, but operates within 1097 mspace_realloc behaves as realloc, but operates within
1096 the given space. 1098 the given space.
1097 1099
1098 If compiled with FOOTERS==1, mspace_realloc is not actually 1100 If compiled with FOOTERS==1, mspace_realloc is not actually
1099 needed. realloc may be called instead of mspace_realloc because 1101 needed. realloc may be called instead of mspace_realloc because
1100 realloced chunks from any space are handled by their originating 1102 realloced chunks from any space are handled by their originating
1101 spaces. 1103 spaces.
1102 */ 1104 */
1103 void* mspace_realloc(mspace msp, void* mem, size_t newsize); 1105 void *mspace_realloc(mspace msp, void *mem, size_t newsize);
1104 1106
1105 /* 1107 /*
1106 mspace_calloc behaves as calloc, but operates within 1108 mspace_calloc behaves as calloc, but operates within
1107 the given space. 1109 the given space.
1108 */ 1110 */
1109 void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); 1111 void *mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
1110 1112
1111 /* 1113 /*
1112 mspace_memalign behaves as memalign, but operates within 1114 mspace_memalign behaves as memalign, but operates within
1113 the given space. 1115 the given space.
1114 */ 1116 */
1115 void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); 1117 void *mspace_memalign(mspace msp, size_t alignment, size_t bytes);
1116 1118
1117 /* 1119 /*
1118 mspace_independent_calloc behaves as independent_calloc, but 1120 mspace_independent_calloc behaves as independent_calloc, but
1119 operates within the given space. 1121 operates within the given space.
1120 */ 1122 */
1121 void** mspace_independent_calloc(mspace msp, size_t n_elements, 1123 void **mspace_independent_calloc(mspace msp, size_t n_elements,
1122 size_t elem_size, void* chunks[]); 1124 size_t elem_size, void *chunks[]);
1123 1125
1124 /* 1126 /*
1125 mspace_independent_comalloc behaves as independent_comalloc, but 1127 mspace_independent_comalloc behaves as independent_comalloc, but
1126 operates within the given space. 1128 operates within the given space.
1127 */ 1129 */
1128 void** mspace_independent_comalloc(mspace msp, size_t n_elements, 1130 void **mspace_independent_comalloc(mspace msp, size_t n_elements,
1129 size_t sizes[], void* chunks[]); 1131 size_t sizes[], void *chunks[]);
1130 1132
1131 /* 1133 /*
1132 mspace_footprint() returns the number of bytes obtained from the 1134 mspace_footprint() returns the number of bytes obtained from the
1133 system for this space. 1135 system for this space.
1134 */ 1136 */
1135 size_t mspace_footprint(mspace msp); 1137 size_t mspace_footprint(mspace msp);
1136 1138
1137 /* 1139 /*
1138 mspace_max_footprint() returns the peak number of bytes obtained from the 1140 mspace_max_footprint() returns the peak number of bytes obtained from the
1139 system for this space. 1141 system for this space.
1140 */ 1142 */
1141 size_t mspace_max_footprint(mspace msp); 1143 size_t mspace_max_footprint(mspace msp);
1142 1144
1143 1145
1144 #if !NO_MALLINFO 1146 #if !NO_MALLINFO
1145 /* 1147 /*
1146 mspace_mallinfo behaves as mallinfo, but reports properties of 1148 mspace_mallinfo behaves as mallinfo, but reports properties of
1147 the given space. 1149 the given space.
1148 */ 1150 */
1149 struct mallinfo mspace_mallinfo(mspace msp); 1151 struct mallinfo mspace_mallinfo(mspace msp);
1150 #endif /* NO_MALLINFO */ 1152 #endif /* NO_MALLINFO */
1151 1153
1152 /* 1154 /*
1153 mspace_malloc_stats behaves as malloc_stats, but reports 1155 mspace_malloc_stats behaves as malloc_stats, but reports
1154 properties of the given space. 1156 properties of the given space.
1155 */ 1157 */
1156 void mspace_malloc_stats(mspace msp); 1158 void mspace_malloc_stats(mspace msp);
1157 1159
1158 /* 1160 /*
1159 mspace_trim behaves as malloc_trim, but 1161 mspace_trim behaves as malloc_trim, but
1160 operates within the given space. 1162 operates within the given space.
1161 */ 1163 */
1162 int mspace_trim(mspace msp, size_t pad); 1164 int mspace_trim(mspace msp, size_t pad);
1163 1165
1164 /* 1166 /*
1165 An alias for mallopt. 1167 An alias for mallopt.
1166 */ 1168 */
1167 int mspace_mallopt(int, int); 1169 int mspace_mallopt(int, int);
1168 1170
1169 #endif /* MSPACES */ 1171 #endif /* MSPACES */
1170 1172
1171 #ifdef __cplusplus 1173 #ifdef __cplusplus
1172 }; /* end of extern "C" */ 1174 }; /* end of extern "C" */
1173 #endif /* __cplusplus */ 1175 #endif /* __cplusplus */
1174 1176
1175 /* 1177 /*
1176 ======================================================================== 1178 ========================================================================
1177 To make a fully customizable malloc.h header file, cut everything 1179 To make a fully customizable malloc.h header file, cut everything
1183 /* #include "malloc.h" */ 1185 /* #include "malloc.h" */
1184 1186
1185 /*------------------------------ internal #includes ---------------------- */ 1187 /*------------------------------ internal #includes ---------------------- */
1186 1188
1187 #ifdef _MSC_VER 1189 #ifdef _MSC_VER
1188 #pragma warning( disable : 4146 ) /* no "unsigned" warnings */ 1190 #pragma warning( disable : 4146 ) /* no "unsigned" warnings */
1189 #endif /* _MSC_VER */ 1191 #endif /* _MSC_VER */
1190 1192
1191 #ifndef LACKS_STDIO_H 1193 #ifndef LACKS_STDIO_H
1192 #include <stdio.h> /* for printing in malloc_stats */ 1194 #include <stdio.h> /* for printing in malloc_stats */
1193 #endif 1195 #endif
1194 1196
1195 #ifndef LACKS_ERRNO_H 1197 #ifndef LACKS_ERRNO_H
1196 #include <errno.h> /* for MALLOC_FAILURE_ACTION */ 1198 #include <errno.h> /* for MALLOC_FAILURE_ACTION */
1197 #endif /* LACKS_ERRNO_H */ 1199 #endif /* LACKS_ERRNO_H */
1198 #if FOOTERS 1200 #if FOOTERS
1199 #include <time.h> /* for magic initialization */ 1201 #include <time.h> /* for magic initialization */
1200 #endif /* FOOTERS */ 1202 #endif /* FOOTERS */
1201 #ifndef LACKS_STDLIB_H 1203 #ifndef LACKS_STDLIB_H
1202 #include <stdlib.h> /* for abort() */ 1204 #include <stdlib.h> /* for abort() */
1203 #endif /* LACKS_STDLIB_H */ 1205 #endif /* LACKS_STDLIB_H */
1204 #ifdef DEBUG 1206 #ifdef DEBUG
1205 #if ABORT_ON_ASSERT_FAILURE 1207 #if ABORT_ON_ASSERT_FAILURE
1206 #define assert(x) if(!(x)) ABORT 1208 #define assert(x) if(!(x)) ABORT
1207 #else /* ABORT_ON_ASSERT_FAILURE */ 1209 #else /* ABORT_ON_ASSERT_FAILURE */
1208 #include <assert.h> 1210 #include <assert.h>
1209 #endif /* ABORT_ON_ASSERT_FAILURE */ 1211 #endif /* ABORT_ON_ASSERT_FAILURE */
1210 #else /* DEBUG */ 1212 #else /* DEBUG */
1211 #define assert(x) 1213 #define assert(x)
1212 #endif /* DEBUG */ 1214 #endif /* DEBUG */
1213 #ifndef LACKS_STRING_H 1215 #ifndef LACKS_STRING_H
1214 #include <string.h> /* for memset etc */ 1216 #include <string.h> /* for memset etc */
1215 #endif /* LACKS_STRING_H */ 1217 #endif /* LACKS_STRING_H */
1216 #if USE_BUILTIN_FFS 1218 #if USE_BUILTIN_FFS
1217 #ifndef LACKS_STRINGS_H 1219 #ifndef LACKS_STRINGS_H
1218 #include <strings.h> /* for ffs */ 1220 #include <strings.h> /* for ffs */
1219 #endif /* LACKS_STRINGS_H */ 1221 #endif /* LACKS_STRINGS_H */
1220 #endif /* USE_BUILTIN_FFS */ 1222 #endif /* USE_BUILTIN_FFS */
1221 #if HAVE_MMAP 1223 #if HAVE_MMAP
1222 #ifndef LACKS_SYS_MMAN_H 1224 #ifndef LACKS_SYS_MMAN_H
1223 #include <sys/mman.h> /* for mmap */ 1225 #include <sys/mman.h> /* for mmap */
1224 #endif /* LACKS_SYS_MMAN_H */ 1226 #endif /* LACKS_SYS_MMAN_H */
1225 #ifndef LACKS_FCNTL_H 1227 #ifndef LACKS_FCNTL_H
1226 #include <fcntl.h> 1228 #include <fcntl.h>
1227 #endif /* LACKS_FCNTL_H */ 1229 #endif /* LACKS_FCNTL_H */
1228 #endif /* HAVE_MMAP */ 1230 #endif /* HAVE_MMAP */
1229 #if HAVE_MORECORE 1231 #if HAVE_MORECORE
1230 #ifndef LACKS_UNISTD_H 1232 #ifndef LACKS_UNISTD_H
1231 #include <unistd.h> /* for sbrk */ 1233 #include <unistd.h> /* for sbrk */
1232 #else /* LACKS_UNISTD_H */ 1234 #else /* LACKS_UNISTD_H */
1233 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) 1235 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
1234 extern void* sbrk(ptrdiff_t); 1236 extern void *sbrk(ptrdiff_t);
1235 #endif /* FreeBSD etc */ 1237 #endif /* FreeBSD etc */
1236 #endif /* LACKS_UNISTD_H */ 1238 #endif /* LACKS_UNISTD_H */
1237 #endif /* HAVE_MMAP */ 1239 #endif /* HAVE_MMAP */
1238 1240
1239 #ifndef WIN32 1241 #ifndef WIN32
1240 #ifndef malloc_getpagesize 1242 #ifndef malloc_getpagesize
1241 # ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ 1243 # ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
1242 # ifndef _SC_PAGE_SIZE 1244 # ifndef _SC_PAGE_SIZE
1243 # define _SC_PAGE_SIZE _SC_PAGESIZE 1245 # define _SC_PAGE_SIZE _SC_PAGESIZE
1244 # endif 1246 # endif
1245 # endif 1247 # endif
1246 # ifdef _SC_PAGE_SIZE 1248 # ifdef _SC_PAGE_SIZE
1247 # define malloc_getpagesize sysconf(_SC_PAGE_SIZE) 1249 # define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
1248 # else 1250 # else
1249 # if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) 1251 # if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
1250 extern size_t getpagesize(); 1252 extern size_t getpagesize();
1251 # define malloc_getpagesize getpagesize() 1253 # define malloc_getpagesize getpagesize()
1252 # else 1254 # else
1253 # ifdef WIN32 /* use supplied emulation of getpagesize */ 1255 # ifdef WIN32 /* use supplied emulation of getpagesize */
1254 # define malloc_getpagesize getpagesize() 1256 # define malloc_getpagesize getpagesize()
1255 # else 1257 # else
1256 # ifndef LACKS_SYS_PARAM_H 1258 # ifndef LACKS_SYS_PARAM_H
1257 # include <sys/param.h> 1259 # include <sys/param.h>
1258 # endif 1260 # endif
1319 */ 1321 */
1320 1322
1321 1323
1322 /* MORECORE and MMAP must return MFAIL on failure */ 1324 /* MORECORE and MMAP must return MFAIL on failure */
1323 #define MFAIL ((void*)(MAX_SIZE_T)) 1325 #define MFAIL ((void*)(MAX_SIZE_T))
1324 #define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ 1326 #define CMFAIL ((char*)(MFAIL)) /* defined for convenience */
1325 1327
1326 #if !HAVE_MMAP 1328 #if !HAVE_MMAP
1327 #define IS_MMAPPED_BIT (SIZE_T_ZERO) 1329 #define IS_MMAPPED_BIT (SIZE_T_ZERO)
1328 #define USE_MMAP_BIT (SIZE_T_ZERO) 1330 #define USE_MMAP_BIT (SIZE_T_ZERO)
1329 #define CALL_MMAP(s) MFAIL 1331 #define CALL_MMAP(s) MFAIL
1347 /* 1349 /*
1348 Nearly all versions of mmap support MAP_ANONYMOUS, so the following 1350 Nearly all versions of mmap support MAP_ANONYMOUS, so the following
1349 is unlikely to be needed, but is supplied just in case. 1351 is unlikely to be needed, but is supplied just in case.
1350 */ 1352 */
1351 #define MMAP_FLAGS (MAP_PRIVATE) 1353 #define MMAP_FLAGS (MAP_PRIVATE)
1352 static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ 1354 static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
1353 #define CALL_MMAP(s) ((dev_zero_fd < 0) ? \ 1355 #define CALL_MMAP(s) ((dev_zero_fd < 0) ? \
1354 (dev_zero_fd = open("/dev/zero", O_RDWR), \ 1356 (dev_zero_fd = open("/dev/zero", O_RDWR), \
1355 mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ 1357 mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
1356 mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) 1358 mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
1357 #endif /* MAP_ANONYMOUS */ 1359 #endif /* MAP_ANONYMOUS */
1358 1360
1359 #define DIRECT_MMAP(s) CALL_MMAP(s) 1361 #define DIRECT_MMAP(s) CALL_MMAP(s)
1360 #else /* WIN32 */ 1362 #else /* WIN32 */
1361 1363
1362 /* Win32 MMAP via VirtualAlloc */ 1364 /* Win32 MMAP via VirtualAlloc */
1363 static void* win32mmap(size_t size) { 1365 static void *
1364 void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); 1366 win32mmap(size_t size)
1365 return (ptr != 0)? ptr: MFAIL; 1367 {
1368 void *ptr =
1369 VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
1370 return (ptr != 0) ? ptr : MFAIL;
1366 } 1371 }
1367 1372
1368 /* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ 1373 /* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
1369 static void* win32direct_mmap(size_t size) { 1374 static void *
1370 void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, 1375 win32direct_mmap(size_t size)
1371 PAGE_READWRITE); 1376 {
1372 return (ptr != 0)? ptr: MFAIL; 1377 void *ptr = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT | MEM_TOP_DOWN,
1378 PAGE_READWRITE);
1379 return (ptr != 0) ? ptr : MFAIL;
1373 } 1380 }
1374 1381
1375 /* This function supports releasing coalesed segments */ 1382 /* This function supports releasing coalesed segments */
1376 static int win32munmap(void* ptr, size_t size) { 1383 static int
1377 MEMORY_BASIC_INFORMATION minfo; 1384 win32munmap(void *ptr, size_t size)
1378 char* cptr = ptr; 1385 {
1379 while (size) { 1386 MEMORY_BASIC_INFORMATION minfo;
1380 if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) 1387 char *cptr = ptr;
1381 return -1; 1388 while (size) {
1382 if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || 1389 if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
1383 minfo.State != MEM_COMMIT || minfo.RegionSize > size) 1390 return -1;
1384 return -1; 1391 if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
1385 if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) 1392 minfo.State != MEM_COMMIT || minfo.RegionSize > size)
1386 return -1; 1393 return -1;
1387 cptr += minfo.RegionSize; 1394 if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
1388 size -= minfo.RegionSize; 1395 return -1;
1389 } 1396 cptr += minfo.RegionSize;
1390 return 0; 1397 size -= minfo.RegionSize;
1398 }
1399 return 0;
1391 } 1400 }
1392 1401
1393 #define CALL_MMAP(s) win32mmap(s) 1402 #define CALL_MMAP(s) win32mmap(s)
1394 #define CALL_MUNMAP(a, s) win32munmap((a), (s)) 1403 #define CALL_MUNMAP(a, s) win32munmap((a), (s))
1395 #define DIRECT_MMAP(s) win32direct_mmap(s) 1404 #define DIRECT_MMAP(s) win32direct_mmap(s)
1396 #endif /* WIN32 */ 1405 #endif /* WIN32 */
1397 #endif /* HAVE_MMAP */ 1406 #endif /* HAVE_MMAP */
1398 1407
1399 #if HAVE_MMAP && HAVE_MREMAP 1408 #if HAVE_MMAP && HAVE_MREMAP
1400 #define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) 1409 #define CALL_MREMAP(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
1401 #else /* HAVE_MMAP && HAVE_MREMAP */ 1410 #else /* HAVE_MMAP && HAVE_MREMAP */
1402 #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL 1411 #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
1403 #endif /* HAVE_MMAP && HAVE_MREMAP */ 1412 #endif /* HAVE_MMAP && HAVE_MREMAP */
1404 1413
1405 #if HAVE_MORECORE 1414 #if HAVE_MORECORE
1406 #define CALL_MORECORE(S) MORECORE(S) 1415 #define CALL_MORECORE(S) MORECORE(S)
1407 #else /* HAVE_MORECORE */ 1416 #else /* HAVE_MORECORE */
1408 #define CALL_MORECORE(S) MFAIL 1417 #define CALL_MORECORE(S) MFAIL
1409 #endif /* HAVE_MORECORE */ 1418 #endif /* HAVE_MORECORE */
1410 1419
1411 /* mstate bit set if continguous morecore disabled or failed */ 1420 /* mstate bit set if continguous morecore disabled or failed */
1412 #define USE_NONCONTIGUOUS_BIT (4U) 1421 #define USE_NONCONTIGUOUS_BIT (4U)
1452 Because lock-protected regions have bounded times, and there 1461 Because lock-protected regions have bounded times, and there
1453 are no recursive lock calls, we can use simple spinlocks. 1462 are no recursive lock calls, we can use simple spinlocks.
1454 */ 1463 */
1455 1464
1456 #define MLOCK_T long 1465 #define MLOCK_T long
1457 static int win32_acquire_lock (MLOCK_T *sl) { 1466 static int
1458 for (;;) { 1467 win32_acquire_lock(MLOCK_T * sl)
1468 {
1469 for (;;) {
1459 #ifdef InterlockedCompareExchangePointer 1470 #ifdef InterlockedCompareExchangePointer
1460 if (!InterlockedCompareExchange(sl, 1, 0)) 1471 if (!InterlockedCompareExchange(sl, 1, 0))
1461 return 0; 1472 return 0;
1462 #else /* Use older void* version */ 1473 #else /* Use older void* version */
1463 if (!InterlockedCompareExchange((void**)sl, (void*)1, (void*)0)) 1474 if (!InterlockedCompareExchange((void **) sl, (void *) 1, (void *) 0))
1464 return 0; 1475 return 0;
1465 #endif /* InterlockedCompareExchangePointer */ 1476 #endif /* InterlockedCompareExchangePointer */
1466 Sleep (0); 1477 Sleep(0);
1467 } 1478 }
1468 } 1479 }
1469 1480
1470 static void win32_release_lock (MLOCK_T *sl) { 1481 static void
1471 InterlockedExchange (sl, 0); 1482 win32_release_lock(MLOCK_T * sl)
1483 {
1484 InterlockedExchange(sl, 0);
1472 } 1485 }
1473 1486
1474 #define INITIAL_LOCK(l) *(l)=0 1487 #define INITIAL_LOCK(l) *(l)=0
1475 #define ACQUIRE_LOCK(l) win32_acquire_lock(l) 1488 #define ACQUIRE_LOCK(l) win32_acquire_lock(l)
1476 #define RELEASE_LOCK(l) win32_release_lock(l) 1489 #define RELEASE_LOCK(l) win32_release_lock(l)
1479 #endif /* HAVE_MORECORE */ 1492 #endif /* HAVE_MORECORE */
1480 static MLOCK_T magic_init_mutex; 1493 static MLOCK_T magic_init_mutex;
1481 #endif /* WIN32 */ 1494 #endif /* WIN32 */
1482 1495
1483 #define USE_LOCK_BIT (2U) 1496 #define USE_LOCK_BIT (2U)
1484 #else /* USE_LOCKS */ 1497 #else /* USE_LOCKS */
1485 #define USE_LOCK_BIT (0U) 1498 #define USE_LOCK_BIT (0U)
1486 #define INITIAL_LOCK(l) 1499 #define INITIAL_LOCK(l)
1487 #endif /* USE_LOCKS */ 1500 #endif /* USE_LOCKS */
1488 1501
1489 #if USE_LOCKS && HAVE_MORECORE 1502 #if USE_LOCKS && HAVE_MORECORE
1495 #endif /* USE_LOCKS && HAVE_MORECORE */ 1508 #endif /* USE_LOCKS && HAVE_MORECORE */
1496 1509
1497 #if USE_LOCKS 1510 #if USE_LOCKS
1498 #define ACQUIRE_MAGIC_INIT_LOCK() ACQUIRE_LOCK(&magic_init_mutex); 1511 #define ACQUIRE_MAGIC_INIT_LOCK() ACQUIRE_LOCK(&magic_init_mutex);
1499 #define RELEASE_MAGIC_INIT_LOCK() RELEASE_LOCK(&magic_init_mutex); 1512 #define RELEASE_MAGIC_INIT_LOCK() RELEASE_LOCK(&magic_init_mutex);
1500 #else /* USE_LOCKS */ 1513 #else /* USE_LOCKS */
1501 #define ACQUIRE_MAGIC_INIT_LOCK() 1514 #define ACQUIRE_MAGIC_INIT_LOCK()
1502 #define RELEASE_MAGIC_INIT_LOCK() 1515 #define RELEASE_MAGIC_INIT_LOCK()
1503 #endif /* USE_LOCKS */ 1516 #endif /* USE_LOCKS */
1504 1517
1505 1518
1638 chunk is trailed by the first two fields of a fake next-chunk 1651 chunk is trailed by the first two fields of a fake next-chunk
1639 for sake of usage checks. 1652 for sake of usage checks.
1640 1653
1641 */ 1654 */
1642 1655
1643 struct malloc_chunk { 1656 struct malloc_chunk
1644 size_t prev_foot; /* Size of previous chunk (if free). */ 1657 {
1645 size_t head; /* Size and inuse bits. */ 1658 size_t prev_foot; /* Size of previous chunk (if free). */
1646 struct malloc_chunk* fd; /* double links -- used only if free. */ 1659 size_t head; /* Size and inuse bits. */
1647 struct malloc_chunk* bk; 1660 struct malloc_chunk *fd; /* double links -- used only if free. */
1661 struct malloc_chunk *bk;
1648 }; 1662 };
1649 1663
1650 typedef struct malloc_chunk mchunk; 1664 typedef struct malloc_chunk mchunk;
1651 typedef struct malloc_chunk* mchunkptr; 1665 typedef struct malloc_chunk *mchunkptr;
1652 typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ 1666 typedef struct malloc_chunk *sbinptr; /* The type of bins of chunks */
1653 typedef size_t bindex_t; /* Described below */ 1667 typedef size_t bindex_t; /* Described below */
1654 typedef unsigned int binmap_t; /* Described below */ 1668 typedef unsigned int binmap_t; /* Described below */
1655 typedef unsigned int flag_t; /* The type of various bit flag sets */ 1669 typedef unsigned int flag_t; /* The type of various bit flag sets */
1656 1670
1657 /* ------------------- Chunks sizes and alignments ----------------------- */ 1671 /* ------------------- Chunks sizes and alignments ----------------------- */
1658 1672
1659 #define MCHUNK_SIZE (sizeof(mchunk)) 1673 #define MCHUNK_SIZE (sizeof(mchunk))
1660 1674
1843 bins. Under current bin calculations, this ranges from 6 up to 21 1857 bins. Under current bin calculations, this ranges from 6 up to 21
1844 (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case 1858 (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
1845 is of course much better. 1859 is of course much better.
1846 */ 1860 */
1847 1861
1848 struct malloc_tree_chunk { 1862 struct malloc_tree_chunk
1849 /* The first four fields must be compatible with malloc_chunk */ 1863 {
1850 size_t prev_foot; 1864 /* The first four fields must be compatible with malloc_chunk */
1851 size_t head; 1865 size_t prev_foot;
1852 struct malloc_tree_chunk* fd; 1866 size_t head;
1853 struct malloc_tree_chunk* bk; 1867 struct malloc_tree_chunk *fd;
1854 1868 struct malloc_tree_chunk *bk;
1855 struct malloc_tree_chunk* child[2]; 1869
1856 struct malloc_tree_chunk* parent; 1870 struct malloc_tree_chunk *child[2];
1857 bindex_t index; 1871 struct malloc_tree_chunk *parent;
1872 bindex_t index;
1858 }; 1873 };
1859 1874
1860 typedef struct malloc_tree_chunk tchunk; 1875 typedef struct malloc_tree_chunk tchunk;
1861 typedef struct malloc_tree_chunk* tchunkptr; 1876 typedef struct malloc_tree_chunk *tchunkptr;
1862 typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ 1877 typedef struct malloc_tree_chunk *tbinptr; /* The type of bins of trees */
1863 1878
1864 /* A little helper macro for trees */ 1879 /* A little helper macro for trees */
1865 #define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) 1880 #define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
1866 1881
1867 /* ----------------------------- Segments -------------------------------- */ 1882 /* ----------------------------- Segments -------------------------------- */
1919 * If neither bit is set, then the segment was obtained using 1934 * If neither bit is set, then the segment was obtained using
1920 MORECORE so can be merged with surrounding MORECORE'd segments 1935 MORECORE so can be merged with surrounding MORECORE'd segments
1921 and deallocated/trimmed using MORECORE with negative arguments. 1936 and deallocated/trimmed using MORECORE with negative arguments.
1922 */ 1937 */
1923 1938
1924 struct malloc_segment { 1939 struct malloc_segment
1925 char* base; /* base address */ 1940 {
1926 size_t size; /* allocated size */ 1941 char *base; /* base address */
1927 struct malloc_segment* next; /* ptr to next segment */ 1942 size_t size; /* allocated size */
1928 flag_t sflags; /* mmap and extern flag */ 1943 struct malloc_segment *next; /* ptr to next segment */
1944 flag_t sflags; /* mmap and extern flag */
1929 }; 1945 };
1930 1946
1931 #define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT) 1947 #define is_mmapped_segment(S) ((S)->sflags & IS_MMAPPED_BIT)
1932 #define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) 1948 #define is_extern_segment(S) ((S)->sflags & EXTERN_BIT)
1933 1949
1934 typedef struct malloc_segment msegment; 1950 typedef struct malloc_segment msegment;
1935 typedef struct malloc_segment* msegmentptr; 1951 typedef struct malloc_segment *msegmentptr;
1936 1952
1937 /* ---------------------------- malloc_state ----------------------------- */ 1953 /* ---------------------------- malloc_state ----------------------------- */
1938 1954
1939 /* 1955 /*
1940 A malloc_state holds all of the bookkeeping for a space. 1956 A malloc_state holds all of the bookkeeping for a space.
2017 #define TREEBIN_SHIFT (8U) 2033 #define TREEBIN_SHIFT (8U)
2018 #define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) 2034 #define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT)
2019 #define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) 2035 #define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE)
2020 #define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) 2036 #define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
2021 2037
2022 struct malloc_state { 2038 struct malloc_state
2023 binmap_t smallmap; 2039 {
2024 binmap_t treemap; 2040 binmap_t smallmap;
2025 size_t dvsize; 2041 binmap_t treemap;
2026 size_t topsize; 2042 size_t dvsize;
2027 char* least_addr; 2043 size_t topsize;
2028 mchunkptr dv; 2044 char *least_addr;
2029 mchunkptr top; 2045 mchunkptr dv;
2030 size_t trim_check; 2046 mchunkptr top;
2031 size_t magic; 2047 size_t trim_check;
2032 mchunkptr smallbins[(NSMALLBINS+1)*2]; 2048 size_t magic;
2033 tbinptr treebins[NTREEBINS]; 2049 mchunkptr smallbins[(NSMALLBINS + 1) * 2];
2034 size_t footprint; 2050 tbinptr treebins[NTREEBINS];
2035 size_t max_footprint; 2051 size_t footprint;
2036 flag_t mflags; 2052 size_t max_footprint;
2053 flag_t mflags;
2037 #if USE_LOCKS 2054 #if USE_LOCKS
2038 MLOCK_T mutex; /* locate lock among fields that rarely change */ 2055 MLOCK_T mutex; /* locate lock among fields that rarely change */
2039 #endif /* USE_LOCKS */ 2056 #endif /* USE_LOCKS */
2040 msegment seg; 2057 msegment seg;
2041 }; 2058 };
2042 2059
2043 typedef struct malloc_state* mstate; 2060 typedef struct malloc_state *mstate;
2044 2061
2045 /* ------------- Global malloc_state and malloc_params ------------------- */ 2062 /* ------------- Global malloc_state and malloc_params ------------------- */
2046 2063
2047 /* 2064 /*
2048 malloc_params holds global properties, including those that can be 2065 malloc_params holds global properties, including those that can be
2049 dynamically set using mallopt. There is a single instance, mparams, 2066 dynamically set using mallopt. There is a single instance, mparams,
2050 initialized in init_mparams. 2067 initialized in init_mparams.
2051 */ 2068 */
2052 2069
2053 struct malloc_params { 2070 struct malloc_params
2054 size_t magic; 2071 {
2055 size_t page_size; 2072 size_t magic;
2056 size_t granularity; 2073 size_t page_size;
2057 size_t mmap_threshold; 2074 size_t granularity;
2058 size_t trim_threshold; 2075 size_t mmap_threshold;
2059 flag_t default_mflags; 2076 size_t trim_threshold;
2077 flag_t default_mflags;
2060 }; 2078 };
2061 2079
2062 static struct malloc_params mparams; 2080 static struct malloc_params mparams;
2063 2081
2064 /* The global malloc_state used for all non-"mspace" calls */ 2082 /* The global malloc_state used for all non-"mspace" calls */
2103 /* True if segment S holds address A */ 2121 /* True if segment S holds address A */
2104 #define segment_holds(S, A)\ 2122 #define segment_holds(S, A)\
2105 ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) 2123 ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
2106 2124
2107 /* Return segment holding given address */ 2125 /* Return segment holding given address */
2108 static msegmentptr segment_holding(mstate m, char* addr) { 2126 static msegmentptr
2109 msegmentptr sp = &m->seg; 2127 segment_holding(mstate m, char *addr)
2110 for (;;) { 2128 {
2111 if (addr >= sp->base && addr < sp->base + sp->size) 2129 msegmentptr sp = &m->seg;
2112 return sp; 2130 for (;;) {
2113 if ((sp = sp->next) == 0) 2131 if (addr >= sp->base && addr < sp->base + sp->size)
2114 return 0; 2132 return sp;
2115 } 2133 if ((sp = sp->next) == 0)
2134 return 0;
2135 }
2116 } 2136 }
2117 2137
2118 /* Return true if segment contains a segment link */ 2138 /* Return true if segment contains a segment link */
2119 static int has_segment_link(mstate m, msegmentptr ss) { 2139 static int
2120 msegmentptr sp = &m->seg; 2140 has_segment_link(mstate m, msegmentptr ss)
2121 for (;;) { 2141 {
2122 if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) 2142 msegmentptr sp = &m->seg;
2123 return 1; 2143 for (;;) {
2124 if ((sp = sp->next) == 0) 2144 if ((char *) sp >= ss->base && (char *) sp < ss->base + ss->size)
2125 return 0; 2145 return 1;
2126 } 2146 if ((sp = sp->next) == 0)
2147 return 0;
2148 }
2127 } 2149 }
2128 2150
2129 #ifndef MORECORE_CANNOT_TRIM 2151 #ifndef MORECORE_CANNOT_TRIM
2130 #define should_trim(M,s) ((s) > (M)->trim_check) 2152 #define should_trim(M,s) ((s) > (M)->trim_check)
2131 #else /* MORECORE_CANNOT_TRIM */ 2153 #else /* MORECORE_CANNOT_TRIM */
2132 #define should_trim(M,s) (0) 2154 #define should_trim(M,s) (0)
2133 #endif /* MORECORE_CANNOT_TRIM */ 2155 #endif /* MORECORE_CANNOT_TRIM */
2134 2156
2135 /* 2157 /*
2136 TOP_FOOT_SIZE is padding at the end of a segment, including space 2158 TOP_FOOT_SIZE is padding at the end of a segment, including space
2158 #define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } 2180 #define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
2159 #else /* USE_LOCKS */ 2181 #else /* USE_LOCKS */
2160 2182
2161 #ifndef PREACTION 2183 #ifndef PREACTION
2162 #define PREACTION(M) (0) 2184 #define PREACTION(M) (0)
2163 #endif /* PREACTION */ 2185 #endif /* PREACTION */
2164 2186
2165 #ifndef POSTACTION 2187 #ifndef POSTACTION
2166 #define POSTACTION(M) 2188 #define POSTACTION(M)
2167 #endif /* POSTACTION */ 2189 #endif /* POSTACTION */
2168 2190
2169 #endif /* USE_LOCKS */ 2191 #endif /* USE_LOCKS */
2170 2192
2171 /* 2193 /*
2172 CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. 2194 CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
2216 #define check_top_chunk(M,P) do_check_top_chunk(M,P) 2238 #define check_top_chunk(M,P) do_check_top_chunk(M,P)
2217 #define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) 2239 #define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
2218 #define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) 2240 #define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P)
2219 #define check_malloc_state(M) do_check_malloc_state(M) 2241 #define check_malloc_state(M) do_check_malloc_state(M)
2220 2242
2221 static void do_check_any_chunk(mstate m, mchunkptr p); 2243 static void do_check_any_chunk(mstate m, mchunkptr p);
2222 static void do_check_top_chunk(mstate m, mchunkptr p); 2244 static void do_check_top_chunk(mstate m, mchunkptr p);
2223 static void do_check_mmapped_chunk(mstate m, mchunkptr p); 2245 static void do_check_mmapped_chunk(mstate m, mchunkptr p);
2224 static void do_check_inuse_chunk(mstate m, mchunkptr p); 2246 static void do_check_inuse_chunk(mstate m, mchunkptr p);
2225 static void do_check_free_chunk(mstate m, mchunkptr p); 2247 static void do_check_free_chunk(mstate m, mchunkptr p);
2226 static void do_check_malloced_chunk(mstate m, void* mem, size_t s); 2248 static void do_check_malloced_chunk(mstate m, void *mem, size_t s);
2227 static void do_check_tree(mstate m, tchunkptr t); 2249 static void do_check_tree(mstate m, tchunkptr t);
2228 static void do_check_treebin(mstate m, bindex_t i); 2250 static void do_check_treebin(mstate m, bindex_t i);
2229 static void do_check_smallbin(mstate m, bindex_t i); 2251 static void do_check_smallbin(mstate m, bindex_t i);
2230 static void do_check_malloc_state(mstate m); 2252 static void do_check_malloc_state(mstate m);
2231 static int bin_find(mstate m, mchunkptr x); 2253 static int bin_find(mstate m, mchunkptr x);
2232 static size_t traverse_and_check(mstate m); 2254 static size_t traverse_and_check(mstate m);
2233 #endif /* DEBUG */ 2255 #endif /* DEBUG */
2234 2256
2235 /* ---------------------------- Indexing Bins ---------------------------- */ 2257 /* ---------------------------- Indexing Bins ---------------------------- */
2236 2258
2392 #endif /* !INSECURE */ 2414 #endif /* !INSECURE */
2393 2415
2394 #if (FOOTERS && !INSECURE) 2416 #if (FOOTERS && !INSECURE)
2395 /* Check if (alleged) mstate m has expected magic field */ 2417 /* Check if (alleged) mstate m has expected magic field */
2396 #define ok_magic(M) ((M)->magic == mparams.magic) 2418 #define ok_magic(M) ((M)->magic == mparams.magic)
2397 #else /* (FOOTERS && !INSECURE) */ 2419 #else /* (FOOTERS && !INSECURE) */
2398 #define ok_magic(M) (1) 2420 #define ok_magic(M) (1)
2399 #endif /* (FOOTERS && !INSECURE) */ 2421 #endif /* (FOOTERS && !INSECURE) */
2400 2422
2401 2423
2402 /* In gcc, use __builtin_expect to minimize impact of checks */ 2424 /* In gcc, use __builtin_expect to minimize impact of checks */
2457 #endif /* !FOOTERS */ 2479 #endif /* !FOOTERS */
2458 2480
2459 /* ---------------------------- setting mparams -------------------------- */ 2481 /* ---------------------------- setting mparams -------------------------- */
2460 2482
2461 /* Initialize mparams */ 2483 /* Initialize mparams */
2462 static int init_mparams(void) { 2484 static int
2463 if (mparams.page_size == 0) { 2485 init_mparams(void)
2464 size_t s; 2486 {
2465 2487 if (mparams.page_size == 0) {
2466 mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; 2488 size_t s;
2467 mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; 2489
2490 mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
2491 mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
2468 #if MORECORE_CONTIGUOUS 2492 #if MORECORE_CONTIGUOUS
2469 mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; 2493 mparams.default_mflags = USE_LOCK_BIT | USE_MMAP_BIT;
2470 #else /* MORECORE_CONTIGUOUS */ 2494 #else /* MORECORE_CONTIGUOUS */
2471 mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; 2495 mparams.default_mflags =
2496 USE_LOCK_BIT | USE_MMAP_BIT | USE_NONCONTIGUOUS_BIT;
2472 #endif /* MORECORE_CONTIGUOUS */ 2497 #endif /* MORECORE_CONTIGUOUS */
2473 2498
2474 #if (FOOTERS && !INSECURE) 2499 #if (FOOTERS && !INSECURE)
2475 { 2500 {
2476 #if USE_DEV_RANDOM 2501 #if USE_DEV_RANDOM
2477 int fd; 2502 int fd;
2478 unsigned char buf[sizeof(size_t)]; 2503 unsigned char buf[sizeof(size_t)];
2479 /* Try to use /dev/urandom, else fall back on using time */ 2504 /* Try to use /dev/urandom, else fall back on using time */
2480 if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && 2505 if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
2481 read(fd, buf, sizeof(buf)) == sizeof(buf)) { 2506 read(fd, buf, sizeof(buf)) == sizeof(buf)) {
2482 s = *((size_t *) buf); 2507 s = *((size_t *) buf);
2483 close(fd); 2508 close(fd);
2484 } 2509 } else
2485 else
2486 #endif /* USE_DEV_RANDOM */ 2510 #endif /* USE_DEV_RANDOM */
2487 s = (size_t)(time(0) ^ (size_t)0x55555555U); 2511 s = (size_t) (time(0) ^ (size_t) 0x55555555U);
2488 2512
2489 s |= (size_t)8U; /* ensure nonzero */ 2513 s |= (size_t) 8U; /* ensure nonzero */
2490 s &= ~(size_t)7U; /* improve chances of fault for bad values */ 2514 s &= ~(size_t) 7U; /* improve chances of fault for bad values */
2491 2515
2492 } 2516 }
2493 #else /* (FOOTERS && !INSECURE) */ 2517 #else /* (FOOTERS && !INSECURE) */
2494 s = (size_t)0x58585858U; 2518 s = (size_t) 0x58585858U;
2495 #endif /* (FOOTERS && !INSECURE) */ 2519 #endif /* (FOOTERS && !INSECURE) */
2496 ACQUIRE_MAGIC_INIT_LOCK(); 2520 ACQUIRE_MAGIC_INIT_LOCK();
2497 if (mparams.magic == 0) { 2521 if (mparams.magic == 0) {
2498 mparams.magic = s; 2522 mparams.magic = s;
2499 /* Set up lock for main malloc area */ 2523 /* Set up lock for main malloc area */
2500 INITIAL_LOCK(&gm->mutex); 2524 INITIAL_LOCK(&gm->mutex);
2501 gm->mflags = mparams.default_mflags; 2525 gm->mflags = mparams.default_mflags;
2502 } 2526 }
2503 RELEASE_MAGIC_INIT_LOCK(); 2527 RELEASE_MAGIC_INIT_LOCK();
2504 2528
2505 #ifndef WIN32 2529 #ifndef WIN32
2506 mparams.page_size = malloc_getpagesize; 2530 mparams.page_size = malloc_getpagesize;
2507 mparams.granularity = ((DEFAULT_GRANULARITY != 0)? 2531 mparams.granularity = ((DEFAULT_GRANULARITY != 0) ?
2508 DEFAULT_GRANULARITY : mparams.page_size); 2532 DEFAULT_GRANULARITY : mparams.page_size);
2509 #else /* WIN32 */ 2533 #else /* WIN32 */
2510 { 2534 {
2511 SYSTEM_INFO system_info; 2535 SYSTEM_INFO system_info;
2512 GetSystemInfo(&system_info); 2536 GetSystemInfo(&system_info);
2513 mparams.page_size = system_info.dwPageSize; 2537 mparams.page_size = system_info.dwPageSize;
2514 mparams.granularity = system_info.dwAllocationGranularity; 2538 mparams.granularity = system_info.dwAllocationGranularity;
2515 } 2539 }
2516 #endif /* WIN32 */ 2540 #endif /* WIN32 */
2517 2541
2518 /* Sanity-check configuration: 2542 /* Sanity-check configuration:
2519 size_t must be unsigned and as wide as pointer type. 2543 size_t must be unsigned and as wide as pointer type.
2520 ints must be at least 4 bytes. 2544 ints must be at least 4 bytes.
2521 alignment must be at least 8. 2545 alignment must be at least 8.
2522 Alignment, min chunk size, and page size must all be powers of 2. 2546 Alignment, min chunk size, and page size must all be powers of 2.
2523 */ 2547 */
2524 if ((sizeof(size_t) != sizeof(char*)) || 2548 if ((sizeof(size_t) != sizeof(char *)) ||
2525 (MAX_SIZE_T < MIN_CHUNK_SIZE) || 2549 (MAX_SIZE_T < MIN_CHUNK_SIZE) ||
2526 (sizeof(int) < 4) || 2550 (sizeof(int) < 4) ||
2527 (MALLOC_ALIGNMENT < (size_t)8U) || 2551 (MALLOC_ALIGNMENT < (size_t) 8U) ||
2528 ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || 2552 ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT - SIZE_T_ONE)) != 0) ||
2529 ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || 2553 ((MCHUNK_SIZE & (MCHUNK_SIZE - SIZE_T_ONE)) != 0) ||
2530 ((mparams.granularity & (mparams.granularity-SIZE_T_ONE)) != 0) || 2554 ((mparams.granularity & (mparams.granularity - SIZE_T_ONE)) != 0)
2531 ((mparams.page_size & (mparams.page_size-SIZE_T_ONE)) != 0)) 2555 || ((mparams.page_size & (mparams.page_size - SIZE_T_ONE)) != 0))
2532 ABORT; 2556 ABORT;
2533 } 2557 }
2534 return 0; 2558 return 0;
2535 } 2559 }
2536 2560
2537 /* support for mallopt */ 2561 /* support for mallopt */
2538 static int change_mparam(int param_number, int value) { 2562 static int
2539 size_t val = (size_t)value; 2563 change_mparam(int param_number, int value)
2540 init_mparams(); 2564 {
2541 switch(param_number) { 2565 size_t val = (size_t) value;
2542 case M_TRIM_THRESHOLD: 2566 init_mparams();
2543 mparams.trim_threshold = val; 2567 switch (param_number) {
2544 return 1; 2568 case M_TRIM_THRESHOLD:
2545 case M_GRANULARITY: 2569 mparams.trim_threshold = val;
2546 if (val >= mparams.page_size && ((val & (val-1)) == 0)) { 2570 return 1;
2547 mparams.granularity = val; 2571 case M_GRANULARITY:
2548 return 1; 2572 if (val >= mparams.page_size && ((val & (val - 1)) == 0)) {
2549 } 2573 mparams.granularity = val;
2550 else 2574 return 1;
2551 return 0; 2575 } else
2552 case M_MMAP_THRESHOLD: 2576 return 0;
2553 mparams.mmap_threshold = val; 2577 case M_MMAP_THRESHOLD:
2554 return 1; 2578 mparams.mmap_threshold = val;
2555 default: 2579 return 1;
2556 return 0; 2580 default:
2557 } 2581 return 0;
2582 }
2558 } 2583 }
2559 2584
2560 #if DEBUG 2585 #if DEBUG
2561 /* ------------------------- Debugging Support --------------------------- */ 2586 /* ------------------------- Debugging Support --------------------------- */
2562 2587
2563 /* Check properties of any chunk, whether free, inuse, mmapped etc */ 2588 /* Check properties of any chunk, whether free, inuse, mmapped etc */
2564 static void do_check_any_chunk(mstate m, mchunkptr p) { 2589 static void
2565 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); 2590 do_check_any_chunk(mstate m, mchunkptr p)
2566 assert(ok_address(m, p)); 2591 {
2592 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
2593 assert(ok_address(m, p));
2567 } 2594 }
2568 2595
2569 /* Check properties of top chunk */ 2596 /* Check properties of top chunk */
2570 static void do_check_top_chunk(mstate m, mchunkptr p) { 2597 static void
2571 msegmentptr sp = segment_holding(m, (char*)p); 2598 do_check_top_chunk(mstate m, mchunkptr p)
2572 size_t sz = chunksize(p); 2599 {
2573 assert(sp != 0); 2600 msegmentptr sp = segment_holding(m, (char *) p);
2574 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); 2601 size_t sz = chunksize(p);
2575 assert(ok_address(m, p)); 2602 assert(sp != 0);
2576 assert(sz == m->topsize); 2603 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
2577 assert(sz > 0); 2604 assert(ok_address(m, p));
2578 assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); 2605 assert(sz == m->topsize);
2579 assert(pinuse(p)); 2606 assert(sz > 0);
2580 assert(!next_pinuse(p)); 2607 assert(sz == ((sp->base + sp->size) - (char *) p) - TOP_FOOT_SIZE);
2608 assert(pinuse(p));
2609 assert(!next_pinuse(p));
2581 } 2610 }
2582 2611
2583 /* Check properties of (inuse) mmapped chunks */ 2612 /* Check properties of (inuse) mmapped chunks */
2584 static void do_check_mmapped_chunk(mstate m, mchunkptr p) { 2613 static void
2585 size_t sz = chunksize(p); 2614 do_check_mmapped_chunk(mstate m, mchunkptr p)
2586 size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD); 2615 {
2587 assert(is_mmapped(p)); 2616 size_t sz = chunksize(p);
2588 assert(use_mmap(m)); 2617 size_t len = (sz + (p->prev_foot & ~IS_MMAPPED_BIT) + MMAP_FOOT_PAD);
2589 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); 2618 assert(is_mmapped(p));
2590 assert(ok_address(m, p)); 2619 assert(use_mmap(m));
2591 assert(!is_small(sz)); 2620 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
2592 assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); 2621 assert(ok_address(m, p));
2593 assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); 2622 assert(!is_small(sz));
2594 assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); 2623 assert((len & (mparams.page_size - SIZE_T_ONE)) == 0);
2624 assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
2625 assert(chunk_plus_offset(p, sz + SIZE_T_SIZE)->head == 0);
2595 } 2626 }
2596 2627
2597 /* Check properties of inuse chunks */ 2628 /* Check properties of inuse chunks */
2598 static void do_check_inuse_chunk(mstate m, mchunkptr p) { 2629 static void
2599 do_check_any_chunk(m, p); 2630 do_check_inuse_chunk(mstate m, mchunkptr p)
2600 assert(cinuse(p)); 2631 {
2601 assert(next_pinuse(p)); 2632 do_check_any_chunk(m, p);
2602 /* If not pinuse and not mmapped, previous chunk has OK offset */ 2633 assert(cinuse(p));
2603 assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); 2634 assert(next_pinuse(p));
2604 if (is_mmapped(p)) 2635 /* If not pinuse and not mmapped, previous chunk has OK offset */
2605 do_check_mmapped_chunk(m, p); 2636 assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
2637 if (is_mmapped(p))
2638 do_check_mmapped_chunk(m, p);
2606 } 2639 }
2607 2640
2608 /* Check properties of free chunks */ 2641 /* Check properties of free chunks */
2609 static void do_check_free_chunk(mstate m, mchunkptr p) { 2642 static void
2610 size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); 2643 do_check_free_chunk(mstate m, mchunkptr p)
2611 mchunkptr next = chunk_plus_offset(p, sz); 2644 {
2612 do_check_any_chunk(m, p); 2645 size_t sz = p->head & ~(PINUSE_BIT | CINUSE_BIT);
2613 assert(!cinuse(p)); 2646 mchunkptr next = chunk_plus_offset(p, sz);
2614 assert(!next_pinuse(p)); 2647 do_check_any_chunk(m, p);
2615 assert (!is_mmapped(p)); 2648 assert(!cinuse(p));
2616 if (p != m->dv && p != m->top) { 2649 assert(!next_pinuse(p));
2617 if (sz >= MIN_CHUNK_SIZE) { 2650 assert(!is_mmapped(p));
2618 assert((sz & CHUNK_ALIGN_MASK) == 0); 2651 if (p != m->dv && p != m->top) {
2619 assert(is_aligned(chunk2mem(p))); 2652 if (sz >= MIN_CHUNK_SIZE) {
2620 assert(next->prev_foot == sz); 2653 assert((sz & CHUNK_ALIGN_MASK) == 0);
2621 assert(pinuse(p)); 2654 assert(is_aligned(chunk2mem(p)));
2622 assert (next == m->top || cinuse(next)); 2655 assert(next->prev_foot == sz);
2623 assert(p->fd->bk == p); 2656 assert(pinuse(p));
2624 assert(p->bk->fd == p); 2657 assert(next == m->top || cinuse(next));
2625 } 2658 assert(p->fd->bk == p);
2626 else /* markers are always of size SIZE_T_SIZE */ 2659 assert(p->bk->fd == p);
2627 assert(sz == SIZE_T_SIZE); 2660 } else /* markers are always of size SIZE_T_SIZE */
2628 } 2661 assert(sz == SIZE_T_SIZE);
2662 }
2629 } 2663 }
2630 2664
2631 /* Check properties of malloced chunks at the point they are malloced */ 2665 /* Check properties of malloced chunks at the point they are malloced */
2632 static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { 2666 static void
2633 if (mem != 0) { 2667 do_check_malloced_chunk(mstate m, void *mem, size_t s)
2634 mchunkptr p = mem2chunk(mem); 2668 {
2635 size_t sz = p->head & ~(PINUSE_BIT|CINUSE_BIT); 2669 if (mem != 0) {
2636 do_check_inuse_chunk(m, p); 2670 mchunkptr p = mem2chunk(mem);
2637 assert((sz & CHUNK_ALIGN_MASK) == 0); 2671 size_t sz = p->head & ~(PINUSE_BIT | CINUSE_BIT);
2638 assert(sz >= MIN_CHUNK_SIZE); 2672 do_check_inuse_chunk(m, p);
2639 assert(sz >= s); 2673 assert((sz & CHUNK_ALIGN_MASK) == 0);
2640 /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ 2674 assert(sz >= MIN_CHUNK_SIZE);
2641 assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); 2675 assert(sz >= s);
2642 } 2676 /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
2677 assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
2678 }
2643 } 2679 }
2644 2680
2645 /* Check a tree and its subtrees. */ 2681 /* Check a tree and its subtrees. */
2646 static void do_check_tree(mstate m, tchunkptr t) { 2682 static void
2647 tchunkptr head = 0; 2683 do_check_tree(mstate m, tchunkptr t)
2648 tchunkptr u = t; 2684 {
2649 bindex_t tindex = t->index; 2685 tchunkptr head = 0;
2650 size_t tsize = chunksize(t); 2686 tchunkptr u = t;
2651 bindex_t idx; 2687 bindex_t tindex = t->index;
2652 compute_tree_index(tsize, idx); 2688 size_t tsize = chunksize(t);
2653 assert(tindex == idx); 2689 bindex_t idx;
2654 assert(tsize >= MIN_LARGE_SIZE); 2690 compute_tree_index(tsize, idx);
2655 assert(tsize >= minsize_for_tree_index(idx)); 2691 assert(tindex == idx);
2656 assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); 2692 assert(tsize >= MIN_LARGE_SIZE);
2657 2693 assert(tsize >= minsize_for_tree_index(idx));
2658 do { /* traverse through chain of same-sized nodes */ 2694 assert((idx == NTREEBINS - 1)
2659 do_check_any_chunk(m, ((mchunkptr)u)); 2695 || (tsize < minsize_for_tree_index((idx + 1))));
2660 assert(u->index == tindex); 2696
2661 assert(chunksize(u) == tsize); 2697 do { /* traverse through chain of same-sized nodes */
2662 assert(!cinuse(u)); 2698 do_check_any_chunk(m, ((mchunkptr) u));
2663 assert(!next_pinuse(u)); 2699 assert(u->index == tindex);
2664 assert(u->fd->bk == u); 2700 assert(chunksize(u) == tsize);
2665 assert(u->bk->fd == u); 2701 assert(!cinuse(u));
2666 if (u->parent == 0) { 2702 assert(!next_pinuse(u));
2667 assert(u->child[0] == 0); 2703 assert(u->fd->bk == u);
2668 assert(u->child[1] == 0); 2704 assert(u->bk->fd == u);
2669 } 2705 if (u->parent == 0) {
2670 else { 2706 assert(u->child[0] == 0);
2671 assert(head == 0); /* only one node on chain has parent */ 2707 assert(u->child[1] == 0);
2672 head = u; 2708 } else {
2673 assert(u->parent != u); 2709 assert(head == 0); /* only one node on chain has parent */
2674 assert (u->parent->child[0] == u || 2710 head = u;
2675 u->parent->child[1] == u || 2711 assert(u->parent != u);
2676 *((tbinptr*)(u->parent)) == u); 2712 assert(u->parent->child[0] == u ||
2677 if (u->child[0] != 0) { 2713 u->parent->child[1] == u ||
2678 assert(u->child[0]->parent == u); 2714 *((tbinptr *) (u->parent)) == u);
2679 assert(u->child[0] != u); 2715 if (u->child[0] != 0) {
2680 do_check_tree(m, u->child[0]); 2716 assert(u->child[0]->parent == u);
2681 } 2717 assert(u->child[0] != u);
2682 if (u->child[1] != 0) { 2718 do_check_tree(m, u->child[0]);
2683 assert(u->child[1]->parent == u); 2719 }
2684 assert(u->child[1] != u); 2720 if (u->child[1] != 0) {
2685 do_check_tree(m, u->child[1]); 2721 assert(u->child[1]->parent == u);
2686 } 2722 assert(u->child[1] != u);
2687 if (u->child[0] != 0 && u->child[1] != 0) { 2723 do_check_tree(m, u->child[1]);
2688 assert(chunksize(u->child[0]) < chunksize(u->child[1])); 2724 }
2689 } 2725 if (u->child[0] != 0 && u->child[1] != 0) {
2690 } 2726 assert(chunksize(u->child[0]) < chunksize(u->child[1]));
2691 u = u->fd; 2727 }
2692 } while (u != t); 2728 }
2693 assert(head != 0); 2729 u = u->fd;
2730 }
2731 while (u != t);
2732 assert(head != 0);
2694 } 2733 }
2695 2734
2696 /* Check all the chunks in a treebin. */ 2735 /* Check all the chunks in a treebin. */
2697 static void do_check_treebin(mstate m, bindex_t i) { 2736 static void
2698 tbinptr* tb = treebin_at(m, i); 2737 do_check_treebin(mstate m, bindex_t i)
2699 tchunkptr t = *tb; 2738 {
2700 int empty = (m->treemap & (1U << i)) == 0; 2739 tbinptr *tb = treebin_at(m, i);
2701 if (t == 0) 2740 tchunkptr t = *tb;
2702 assert(empty); 2741 int empty = (m->treemap & (1U << i)) == 0;
2703 if (!empty) 2742 if (t == 0)
2704 do_check_tree(m, t); 2743 assert(empty);
2744 if (!empty)
2745 do_check_tree(m, t);
2705 } 2746 }
2706 2747
2707 /* Check all the chunks in a smallbin. */ 2748 /* Check all the chunks in a smallbin. */
2708 static void do_check_smallbin(mstate m, bindex_t i) { 2749 static void
2709 sbinptr b = smallbin_at(m, i); 2750 do_check_smallbin(mstate m, bindex_t i)
2710 mchunkptr p = b->bk; 2751 {
2711 unsigned int empty = (m->smallmap & (1U << i)) == 0; 2752 sbinptr b = smallbin_at(m, i);
2712 if (p == b) 2753 mchunkptr p = b->bk;
2713 assert(empty); 2754 unsigned int empty = (m->smallmap & (1U << i)) == 0;
2714 if (!empty) { 2755 if (p == b)
2715 for (; p != b; p = p->bk) { 2756 assert(empty);
2716 size_t size = chunksize(p); 2757 if (!empty) {
2717 mchunkptr q; 2758 for (; p != b; p = p->bk) {
2718 /* each chunk claims to be free */ 2759 size_t size = chunksize(p);
2719 do_check_free_chunk(m, p); 2760 mchunkptr q;
2720 /* chunk belongs in bin */ 2761 /* each chunk claims to be free */
2721 assert(small_index(size) == i); 2762 do_check_free_chunk(m, p);
2722 assert(p->bk == b || chunksize(p->bk) == chunksize(p)); 2763 /* chunk belongs in bin */
2723 /* chunk is followed by an inuse chunk */ 2764 assert(small_index(size) == i);
2724 q = next_chunk(p); 2765 assert(p->bk == b || chunksize(p->bk) == chunksize(p));
2725 if (q->head != FENCEPOST_HEAD) 2766 /* chunk is followed by an inuse chunk */
2726 do_check_inuse_chunk(m, q); 2767 q = next_chunk(p);
2727 } 2768 if (q->head != FENCEPOST_HEAD)
2728 } 2769 do_check_inuse_chunk(m, q);
2770 }
2771 }
2729 } 2772 }
2730 2773
2731 /* Find x in a bin. Used in other check functions. */ 2774 /* Find x in a bin. Used in other check functions. */
2732 static int bin_find(mstate m, mchunkptr x) { 2775 static int
2733 size_t size = chunksize(x); 2776 bin_find(mstate m, mchunkptr x)
2734 if (is_small(size)) { 2777 {
2735 bindex_t sidx = small_index(size); 2778 size_t size = chunksize(x);
2736 sbinptr b = smallbin_at(m, sidx); 2779 if (is_small(size)) {
2737 if (smallmap_is_marked(m, sidx)) { 2780 bindex_t sidx = small_index(size);
2738 mchunkptr p = b; 2781 sbinptr b = smallbin_at(m, sidx);
2739 do { 2782 if (smallmap_is_marked(m, sidx)) {
2740 if (p == x) 2783 mchunkptr p = b;
2741 return 1; 2784 do {
2742 } while ((p = p->fd) != b); 2785 if (p == x)
2743 } 2786 return 1;
2744 } 2787 }
2745 else { 2788 while ((p = p->fd) != b);
2746 bindex_t tidx; 2789 }
2747 compute_tree_index(size, tidx); 2790 } else {
2748 if (treemap_is_marked(m, tidx)) { 2791 bindex_t tidx;
2749 tchunkptr t = *treebin_at(m, tidx); 2792 compute_tree_index(size, tidx);
2750 size_t sizebits = size << leftshift_for_tree_index(tidx); 2793 if (treemap_is_marked(m, tidx)) {
2751 while (t != 0 && chunksize(t) != size) { 2794 tchunkptr t = *treebin_at(m, tidx);
2752 t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; 2795 size_t sizebits = size << leftshift_for_tree_index(tidx);
2753 sizebits <<= 1; 2796 while (t != 0 && chunksize(t) != size) {
2754 } 2797 t = t->child[(sizebits >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1];
2755 if (t != 0) { 2798 sizebits <<= 1;
2756 tchunkptr u = t; 2799 }
2757 do { 2800 if (t != 0) {
2758 if (u == (tchunkptr)x) 2801 tchunkptr u = t;
2759 return 1; 2802 do {
2760 } while ((u = u->fd) != t); 2803 if (u == (tchunkptr) x)
2761 } 2804 return 1;
2762 } 2805 }
2763 } 2806 while ((u = u->fd) != t);
2764 return 0; 2807 }
2808 }
2809 }
2810 return 0;
2765 } 2811 }
2766 2812
2767 /* Traverse each chunk and check it; return total */ 2813 /* Traverse each chunk and check it; return total */
2768 static size_t traverse_and_check(mstate m) { 2814 static size_t
2769 size_t sum = 0; 2815 traverse_and_check(mstate m)
2770 if (is_initialized(m)) { 2816 {
2771 msegmentptr s = &m->seg; 2817 size_t sum = 0;
2772 sum += m->topsize + TOP_FOOT_SIZE; 2818 if (is_initialized(m)) {
2773 while (s != 0) { 2819 msegmentptr s = &m->seg;
2774 mchunkptr q = align_as_chunk(s->base); 2820 sum += m->topsize + TOP_FOOT_SIZE;
2775 mchunkptr lastq = 0; 2821 while (s != 0) {
2776 assert(pinuse(q)); 2822 mchunkptr q = align_as_chunk(s->base);
2777 while (segment_holds(s, q) && 2823 mchunkptr lastq = 0;
2778 q != m->top && q->head != FENCEPOST_HEAD) { 2824 assert(pinuse(q));
2779 sum += chunksize(q); 2825 while (segment_holds(s, q) &&
2780 if (cinuse(q)) { 2826 q != m->top && q->head != FENCEPOST_HEAD) {
2781 assert(!bin_find(m, q)); 2827 sum += chunksize(q);
2782 do_check_inuse_chunk(m, q); 2828 if (cinuse(q)) {
2829 assert(!bin_find(m, q));
2830 do_check_inuse_chunk(m, q);
2831 } else {
2832 assert(q == m->dv || bin_find(m, q));
2833 assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */
2834 do_check_free_chunk(m, q);
2835 }
2836 lastq = q;
2837 q = next_chunk(q);
2838 }
2839 s = s->next;
2783 } 2840 }
2784 else { 2841 }
2785 assert(q == m->dv || bin_find(m, q)); 2842 return sum;
2786 assert(lastq == 0 || cinuse(lastq)); /* Not 2 consecutive free */ 2843 }
2787 do_check_free_chunk(m, q); 2844
2845 /* Check all properties of malloc_state. */
2846 static void
2847 do_check_malloc_state(mstate m)
2848 {
2849 bindex_t i;
2850 size_t total;
2851 /* check bins */
2852 for (i = 0; i < NSMALLBINS; ++i)
2853 do_check_smallbin(m, i);
2854 for (i = 0; i < NTREEBINS; ++i)
2855 do_check_treebin(m, i);
2856
2857 if (m->dvsize != 0) { /* check dv chunk */
2858 do_check_any_chunk(m, m->dv);
2859 assert(m->dvsize == chunksize(m->dv));
2860 assert(m->dvsize >= MIN_CHUNK_SIZE);
2861 assert(bin_find(m, m->dv) == 0);
2862 }
2863
2864 if (m->top != 0) { /* check top chunk */
2865 do_check_top_chunk(m, m->top);
2866 assert(m->topsize == chunksize(m->top));
2867 assert(m->topsize > 0);
2868 assert(bin_find(m, m->top) == 0);
2869 }
2870
2871 total = traverse_and_check(m);
2872 assert(total <= m->footprint);
2873 assert(m->footprint <= m->max_footprint);
2874 }
2875 #endif /* DEBUG */
2876
2877 /* ----------------------------- statistics ------------------------------ */
2878
2879 #if !NO_MALLINFO
2880 static struct mallinfo
2881 internal_mallinfo(mstate m)
2882 {
2883 struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2884 if (!PREACTION(m)) {
2885 check_malloc_state(m);
2886 if (is_initialized(m)) {
2887 size_t nfree = SIZE_T_ONE; /* top always free */
2888 size_t mfree = m->topsize + TOP_FOOT_SIZE;
2889 size_t sum = mfree;
2890 msegmentptr s = &m->seg;
2891 while (s != 0) {
2892 mchunkptr q = align_as_chunk(s->base);
2893 while (segment_holds(s, q) &&
2894 q != m->top && q->head != FENCEPOST_HEAD) {
2895 size_t sz = chunksize(q);
2896 sum += sz;
2897 if (!cinuse(q)) {
2898 mfree += sz;
2899 ++nfree;
2900 }
2901 q = next_chunk(q);
2902 }
2903 s = s->next;
2904 }
2905
2906 nm.arena = sum;
2907 nm.ordblks = nfree;
2908 nm.hblkhd = m->footprint - sum;
2909 nm.usmblks = m->max_footprint;
2910 nm.uordblks = m->footprint - mfree;
2911 nm.fordblks = mfree;
2912 nm.keepcost = m->topsize;
2788 } 2913 }
2789 lastq = q; 2914
2790 q = next_chunk(q); 2915 POSTACTION(m);
2791 } 2916 }
2792 s = s->next; 2917 return nm;
2793 } 2918 }
2794 } 2919 #endif /* !NO_MALLINFO */
2795 return sum; 2920
2796 } 2921 static void
2797 2922 internal_malloc_stats(mstate m)
2798 /* Check all properties of malloc_state. */ 2923 {
2799 static void do_check_malloc_state(mstate m) { 2924 if (!PREACTION(m)) {
2800 bindex_t i; 2925 size_t maxfp = 0;
2801 size_t total; 2926 size_t fp = 0;
2802 /* check bins */ 2927 size_t used = 0;
2803 for (i = 0; i < NSMALLBINS; ++i) 2928 check_malloc_state(m);
2804 do_check_smallbin(m, i); 2929 if (is_initialized(m)) {
2805 for (i = 0; i < NTREEBINS; ++i) 2930 msegmentptr s = &m->seg;
2806 do_check_treebin(m, i); 2931 maxfp = m->max_footprint;
2807 2932 fp = m->footprint;
2808 if (m->dvsize != 0) { /* check dv chunk */ 2933 used = fp - (m->topsize + TOP_FOOT_SIZE);
2809 do_check_any_chunk(m, m->dv); 2934
2810 assert(m->dvsize == chunksize(m->dv)); 2935 while (s != 0) {
2811 assert(m->dvsize >= MIN_CHUNK_SIZE); 2936 mchunkptr q = align_as_chunk(s->base);
2812 assert(bin_find(m, m->dv) == 0); 2937 while (segment_holds(s, q) &&
2813 } 2938 q != m->top && q->head != FENCEPOST_HEAD) {
2814 2939 if (!cinuse(q))
2815 if (m->top != 0) { /* check top chunk */ 2940 used -= chunksize(q);
2816 do_check_top_chunk(m, m->top); 2941 q = next_chunk(q);
2817 assert(m->topsize == chunksize(m->top)); 2942 }
2818 assert(m->topsize > 0); 2943 s = s->next;
2819 assert(bin_find(m, m->top) == 0); 2944 }
2820 }
2821
2822 total = traverse_and_check(m);
2823 assert(total <= m->footprint);
2824 assert(m->footprint <= m->max_footprint);
2825 }
2826 #endif /* DEBUG */
2827
2828 /* ----------------------------- statistics ------------------------------ */
2829
2830 #if !NO_MALLINFO
2831 static struct mallinfo internal_mallinfo(mstate m) {
2832 struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2833 if (!PREACTION(m)) {
2834 check_malloc_state(m);
2835 if (is_initialized(m)) {
2836 size_t nfree = SIZE_T_ONE; /* top always free */
2837 size_t mfree = m->topsize + TOP_FOOT_SIZE;
2838 size_t sum = mfree;
2839 msegmentptr s = &m->seg;
2840 while (s != 0) {
2841 mchunkptr q = align_as_chunk(s->base);
2842 while (segment_holds(s, q) &&
2843 q != m->top && q->head != FENCEPOST_HEAD) {
2844 size_t sz = chunksize(q);
2845 sum += sz;
2846 if (!cinuse(q)) {
2847 mfree += sz;
2848 ++nfree;
2849 }
2850 q = next_chunk(q);
2851 } 2945 }
2852 s = s->next;
2853 }
2854
2855 nm.arena = sum;
2856 nm.ordblks = nfree;
2857 nm.hblkhd = m->footprint - sum;
2858 nm.usmblks = m->max_footprint;
2859 nm.uordblks = m->footprint - mfree;
2860 nm.fordblks = mfree;
2861 nm.keepcost = m->topsize;
2862 }
2863
2864 POSTACTION(m);
2865 }
2866 return nm;
2867 }
2868 #endif /* !NO_MALLINFO */
2869
2870 static void internal_malloc_stats(mstate m) {
2871 if (!PREACTION(m)) {
2872 size_t maxfp = 0;
2873 size_t fp = 0;
2874 size_t used = 0;
2875 check_malloc_state(m);
2876 if (is_initialized(m)) {
2877 msegmentptr s = &m->seg;
2878 maxfp = m->max_footprint;
2879 fp = m->footprint;
2880 used = fp - (m->topsize + TOP_FOOT_SIZE);
2881
2882 while (s != 0) {
2883 mchunkptr q = align_as_chunk(s->base);
2884 while (segment_holds(s, q) &&
2885 q != m->top && q->head != FENCEPOST_HEAD) {
2886 if (!cinuse(q))
2887 used -= chunksize(q);
2888 q = next_chunk(q);
2889 }
2890 s = s->next;
2891 }
2892 }
2893
2894 #ifndef LACKS_STDIO_H 2946 #ifndef LACKS_STDIO_H
2895 fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); 2947 fprintf(stderr, "max system bytes = %10lu\n",
2896 fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); 2948 (unsigned long) (maxfp));
2897 fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); 2949 fprintf(stderr, "system bytes = %10lu\n", (unsigned long) (fp));
2950 fprintf(stderr, "in use bytes = %10lu\n", (unsigned long) (used));
2898 #endif 2951 #endif
2899 2952
2900 POSTACTION(m); 2953 POSTACTION(m);
2901 } 2954 }
2902 } 2955 }
2903 2956
2904 /* ----------------------- Operations on smallbins ----------------------- */ 2957 /* ----------------------- Operations on smallbins ----------------------- */
2905 2958
2906 /* 2959 /*
3160 allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain 3213 allocated to hold a fake next chunk of size SIZE_T_SIZE to maintain
3161 the PINUSE bit so frees can be checked. 3214 the PINUSE bit so frees can be checked.
3162 */ 3215 */
3163 3216
3164 /* Malloc using mmap */ 3217 /* Malloc using mmap */
3165 static void* mmap_alloc(mstate m, size_t nb) { 3218 static void *
3166 size_t mmsize = granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); 3219 mmap_alloc(mstate m, size_t nb)
3167 if (mmsize > nb) { /* Check for wrap around 0 */ 3220 {
3168 char* mm = (char*)(DIRECT_MMAP(mmsize)); 3221 size_t mmsize =
3169 if (mm != CMFAIL) { 3222 granularity_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
3170 size_t offset = align_offset(chunk2mem(mm)); 3223 if (mmsize > nb) { /* Check for wrap around 0 */
3171 size_t psize = mmsize - offset - MMAP_FOOT_PAD; 3224 char *mm = (char *) (DIRECT_MMAP(mmsize));
3172 mchunkptr p = (mchunkptr)(mm + offset); 3225 if (mm != CMFAIL) {
3173 p->prev_foot = offset | IS_MMAPPED_BIT; 3226 size_t offset = align_offset(chunk2mem(mm));
3174 (p)->head = (psize|CINUSE_BIT); 3227 size_t psize = mmsize - offset - MMAP_FOOT_PAD;
3175 mark_inuse_foot(m, p, psize); 3228 mchunkptr p = (mchunkptr) (mm + offset);
3176 chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; 3229 p->prev_foot = offset | IS_MMAPPED_BIT;
3177 chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; 3230 (p)->head = (psize | CINUSE_BIT);
3178 3231 mark_inuse_foot(m, p, psize);
3179 if (mm < m->least_addr) 3232 chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
3180 m->least_addr = mm; 3233 chunk_plus_offset(p, psize + SIZE_T_SIZE)->head = 0;
3181 if ((m->footprint += mmsize) > m->max_footprint) 3234
3182 m->max_footprint = m->footprint; 3235 if (mm < m->least_addr)
3183 assert(is_aligned(chunk2mem(p))); 3236 m->least_addr = mm;
3184 check_mmapped_chunk(m, p); 3237 if ((m->footprint += mmsize) > m->max_footprint)
3185 return chunk2mem(p); 3238 m->max_footprint = m->footprint;
3186 } 3239 assert(is_aligned(chunk2mem(p)));
3187 } 3240 check_mmapped_chunk(m, p);
3188 return 0; 3241 return chunk2mem(p);
3242 }
3243 }
3244 return 0;
3189 } 3245 }
3190 3246
3191 /* Realloc using mmap */ 3247 /* Realloc using mmap */
3192 static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) { 3248 static mchunkptr
3193 size_t oldsize = chunksize(oldp); 3249 mmap_resize(mstate m, mchunkptr oldp, size_t nb)
3194 if (is_small(nb)) /* Can't shrink mmap regions below small size */ 3250 {
3251 size_t oldsize = chunksize(oldp);
3252 if (is_small(nb)) /* Can't shrink mmap regions below small size */
3253 return 0;
3254 /* Keep old chunk if big enough but not too big */
3255 if (oldsize >= nb + SIZE_T_SIZE &&
3256 (oldsize - nb) <= (mparams.granularity << 1))
3257 return oldp;
3258 else {
3259 size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT;
3260 size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
3261 size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES +
3262 CHUNK_ALIGN_MASK);
3263 char *cp = (char *) CALL_MREMAP((char *) oldp - offset,
3264 oldmmsize, newmmsize, 1);
3265 if (cp != CMFAIL) {
3266 mchunkptr newp = (mchunkptr) (cp + offset);
3267 size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
3268 newp->head = (psize | CINUSE_BIT);
3269 mark_inuse_foot(m, newp, psize);
3270 chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
3271 chunk_plus_offset(newp, psize + SIZE_T_SIZE)->head = 0;
3272
3273 if (cp < m->least_addr)
3274 m->least_addr = cp;
3275 if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
3276 m->max_footprint = m->footprint;
3277 check_mmapped_chunk(m, newp);
3278 return newp;
3279 }
3280 }
3195 return 0; 3281 return 0;
3196 /* Keep old chunk if big enough but not too big */
3197 if (oldsize >= nb + SIZE_T_SIZE &&
3198 (oldsize - nb) <= (mparams.granularity << 1))
3199 return oldp;
3200 else {
3201 size_t offset = oldp->prev_foot & ~IS_MMAPPED_BIT;
3202 size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
3203 size_t newmmsize = granularity_align(nb + SIX_SIZE_T_SIZES +
3204 CHUNK_ALIGN_MASK);
3205 char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
3206 oldmmsize, newmmsize, 1);
3207 if (cp != CMFAIL) {
3208 mchunkptr newp = (mchunkptr)(cp + offset);
3209 size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
3210 newp->head = (psize|CINUSE_BIT);
3211 mark_inuse_foot(m, newp, psize);
3212 chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
3213 chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
3214
3215 if (cp < m->least_addr)
3216 m->least_addr = cp;
3217 if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
3218 m->max_footprint = m->footprint;
3219 check_mmapped_chunk(m, newp);
3220 return newp;
3221 }
3222 }
3223 return 0;
3224 } 3282 }
3225 3283
3226 /* -------------------------- mspace management -------------------------- */ 3284 /* -------------------------- mspace management -------------------------- */
3227 3285
3228 /* Initialize top chunk and its size */ 3286 /* Initialize top chunk and its size */
3229 static void init_top(mstate m, mchunkptr p, size_t psize) { 3287 static void
3230 /* Ensure alignment */ 3288 init_top(mstate m, mchunkptr p, size_t psize)
3231 size_t offset = align_offset(chunk2mem(p)); 3289 {
3232 p = (mchunkptr)((char*)p + offset); 3290 /* Ensure alignment */
3233 psize -= offset; 3291 size_t offset = align_offset(chunk2mem(p));
3234 3292 p = (mchunkptr) ((char *) p + offset);
3235 m->top = p; 3293 psize -= offset;
3236 m->topsize = psize; 3294
3237 p->head = psize | PINUSE_BIT; 3295 m->top = p;
3238 /* set size of fake trailing chunk holding overhead space only once */ 3296 m->topsize = psize;
3239 chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; 3297 p->head = psize | PINUSE_BIT;
3240 m->trim_check = mparams.trim_threshold; /* reset on each update */ 3298 /* set size of fake trailing chunk holding overhead space only once */
3299 chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
3300 m->trim_check = mparams.trim_threshold; /* reset on each update */
3241 } 3301 }
3242 3302
3243 /* Initialize bins for a new mstate that is otherwise zeroed out */ 3303 /* Initialize bins for a new mstate that is otherwise zeroed out */
3244 static void init_bins(mstate m) { 3304 static void
3245 /* Establish circular links for smallbins */ 3305 init_bins(mstate m)
3246 bindex_t i; 3306 {
3247 for (i = 0; i < NSMALLBINS; ++i) { 3307 /* Establish circular links for smallbins */
3248 sbinptr bin = smallbin_at(m,i); 3308 bindex_t i;
3249 bin->fd = bin->bk = bin; 3309 for (i = 0; i < NSMALLBINS; ++i) {
3250 } 3310 sbinptr bin = smallbin_at(m, i);
3311 bin->fd = bin->bk = bin;
3312 }
3251 } 3313 }
3252 3314
3253 #if PROCEED_ON_ERROR 3315 #if PROCEED_ON_ERROR
3254 3316
3255 /* default corruption action */ 3317 /* default corruption action */
3256 static void reset_on_error(mstate m) { 3318 static void
3257 int i; 3319 reset_on_error(mstate m)
3258 ++malloc_corruption_error_count; 3320 {
3259 /* Reinitialize fields to forget about all memory */ 3321 int i;
3260 m->smallbins = m->treebins = 0; 3322 ++malloc_corruption_error_count;
3261 m->dvsize = m->topsize = 0; 3323 /* Reinitialize fields to forget about all memory */
3262 m->seg.base = 0; 3324 m->smallbins = m->treebins = 0;
3263 m->seg.size = 0; 3325 m->dvsize = m->topsize = 0;
3264 m->seg.next = 0; 3326 m->seg.base = 0;
3265 m->top = m->dv = 0; 3327 m->seg.size = 0;
3266 for (i = 0; i < NTREEBINS; ++i) 3328 m->seg.next = 0;
3267 *treebin_at(m, i) = 0; 3329 m->top = m->dv = 0;
3268 init_bins(m); 3330 for (i = 0; i < NTREEBINS; ++i)
3331 *treebin_at(m, i) = 0;
3332 init_bins(m);
3269 } 3333 }
3270 #endif /* PROCEED_ON_ERROR */ 3334 #endif /* PROCEED_ON_ERROR */
3271 3335
3272 /* Allocate chunk and prepend remainder with chunk in successor base. */ 3336 /* Allocate chunk and prepend remainder with chunk in successor base. */
3273 static void* prepend_alloc(mstate m, char* newbase, char* oldbase, 3337 static void *
3274 size_t nb) { 3338 prepend_alloc(mstate m, char *newbase, char *oldbase, size_t nb)
3275 mchunkptr p = align_as_chunk(newbase); 3339 {
3276 mchunkptr oldfirst = align_as_chunk(oldbase); 3340 mchunkptr p = align_as_chunk(newbase);
3277 size_t psize = (char*)oldfirst - (char*)p; 3341 mchunkptr oldfirst = align_as_chunk(oldbase);
3278 mchunkptr q = chunk_plus_offset(p, nb); 3342 size_t psize = (char *) oldfirst - (char *) p;
3279 size_t qsize = psize - nb; 3343 mchunkptr q = chunk_plus_offset(p, nb);
3280 set_size_and_pinuse_of_inuse_chunk(m, p, nb); 3344 size_t qsize = psize - nb;
3281 3345 set_size_and_pinuse_of_inuse_chunk(m, p, nb);
3282 assert((char*)oldfirst > (char*)q); 3346
3283 assert(pinuse(oldfirst)); 3347 assert((char *) oldfirst > (char *) q);
3284 assert(qsize >= MIN_CHUNK_SIZE); 3348 assert(pinuse(oldfirst));
3285 3349 assert(qsize >= MIN_CHUNK_SIZE);
3286 /* consolidate remainder with first chunk of old base */ 3350
3287 if (oldfirst == m->top) { 3351 /* consolidate remainder with first chunk of old base */
3288 size_t tsize = m->topsize += qsize; 3352 if (oldfirst == m->top) {
3289 m->top = q; 3353 size_t tsize = m->topsize += qsize;
3290 q->head = tsize | PINUSE_BIT; 3354 m->top = q;
3291 check_top_chunk(m, q); 3355 q->head = tsize | PINUSE_BIT;
3292 } 3356 check_top_chunk(m, q);
3293 else if (oldfirst == m->dv) { 3357 } else if (oldfirst == m->dv) {
3294 size_t dsize = m->dvsize += qsize; 3358 size_t dsize = m->dvsize += qsize;
3295 m->dv = q; 3359 m->dv = q;
3296 set_size_and_pinuse_of_free_chunk(q, dsize); 3360 set_size_and_pinuse_of_free_chunk(q, dsize);
3297 } 3361 } else {
3298 else { 3362 if (!cinuse(oldfirst)) {
3299 if (!cinuse(oldfirst)) { 3363 size_t nsize = chunksize(oldfirst);
3300 size_t nsize = chunksize(oldfirst); 3364 unlink_chunk(m, oldfirst, nsize);
3301 unlink_chunk(m, oldfirst, nsize); 3365 oldfirst = chunk_plus_offset(oldfirst, nsize);
3302 oldfirst = chunk_plus_offset(oldfirst, nsize); 3366 qsize += nsize;
3303 qsize += nsize; 3367 }
3304 } 3368 set_free_with_pinuse(q, qsize, oldfirst);
3305 set_free_with_pinuse(q, qsize, oldfirst); 3369 insert_chunk(m, q, qsize);
3306 insert_chunk(m, q, qsize); 3370 check_free_chunk(m, q);
3307 check_free_chunk(m, q); 3371 }
3308 } 3372
3309 3373 check_malloced_chunk(m, chunk2mem(p), nb);
3310 check_malloced_chunk(m, chunk2mem(p), nb); 3374 return chunk2mem(p);
3311 return chunk2mem(p);
3312 } 3375 }
3313 3376
3314 3377
3315 /* Add a segment to hold a new noncontiguous region */ 3378 /* Add a segment to hold a new noncontiguous region */
3316 static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { 3379 static void
3317 /* Determine locations and sizes of segment, fenceposts, old top */ 3380 add_segment(mstate m, char *tbase, size_t tsize, flag_t mmapped)
3318 char* old_top = (char*)m->top; 3381 {
3319 msegmentptr oldsp = segment_holding(m, old_top); 3382 /* Determine locations and sizes of segment, fenceposts, old top */
3320 char* old_end = oldsp->base + oldsp->size; 3383 char *old_top = (char *) m->top;
3321 size_t ssize = pad_request(sizeof(struct malloc_segment)); 3384 msegmentptr oldsp = segment_holding(m, old_top);
3322 char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); 3385 char *old_end = oldsp->base + oldsp->size;
3323 size_t offset = align_offset(chunk2mem(rawsp)); 3386 size_t ssize = pad_request(sizeof(struct malloc_segment));
3324 char* asp = rawsp + offset; 3387 char *rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
3325 char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; 3388 size_t offset = align_offset(chunk2mem(rawsp));
3326 mchunkptr sp = (mchunkptr)csp; 3389 char *asp = rawsp + offset;
3327 msegmentptr ss = (msegmentptr)(chunk2mem(sp)); 3390 char *csp = (asp < (old_top + MIN_CHUNK_SIZE)) ? old_top : asp;
3328 mchunkptr tnext = chunk_plus_offset(sp, ssize); 3391 mchunkptr sp = (mchunkptr) csp;
3329 mchunkptr p = tnext; 3392 msegmentptr ss = (msegmentptr) (chunk2mem(sp));
3330 int nfences = 0; 3393 mchunkptr tnext = chunk_plus_offset(sp, ssize);
3331 3394 mchunkptr p = tnext;
3332 /* reset top to new space */ 3395 int nfences = 0;
3333 init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); 3396
3334 3397 /* reset top to new space */
3335 /* Set up segment record */ 3398 init_top(m, (mchunkptr) tbase, tsize - TOP_FOOT_SIZE);
3336 assert(is_aligned(ss)); 3399
3337 set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); 3400 /* Set up segment record */
3338 *ss = m->seg; /* Push current record */ 3401 assert(is_aligned(ss));
3339 m->seg.base = tbase; 3402 set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
3340 m->seg.size = tsize; 3403 *ss = m->seg; /* Push current record */
3341 m->seg.sflags = mmapped; 3404 m->seg.base = tbase;
3342 m->seg.next = ss; 3405 m->seg.size = tsize;
3343 3406 m->seg.sflags = mmapped;
3344 /* Insert trailing fenceposts */ 3407 m->seg.next = ss;
3345 for (;;) { 3408
3346 mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); 3409 /* Insert trailing fenceposts */
3347 p->head = FENCEPOST_HEAD; 3410 for (;;) {
3348 ++nfences; 3411 mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
3349 if ((char*)(&(nextp->head)) < old_end) 3412 p->head = FENCEPOST_HEAD;
3350 p = nextp; 3413 ++nfences;
3351 else 3414 if ((char *) (&(nextp->head)) < old_end)
3352 break; 3415 p = nextp;
3353 } 3416 else
3354 assert(nfences >= 2); 3417 break;
3355 3418 }
3356 /* Insert the rest of old top into a bin as an ordinary free chunk */ 3419 assert(nfences >= 2);
3357 if (csp != old_top) { 3420
3358 mchunkptr q = (mchunkptr)old_top; 3421 /* Insert the rest of old top into a bin as an ordinary free chunk */
3359 size_t psize = csp - old_top; 3422 if (csp != old_top) {
3360 mchunkptr tn = chunk_plus_offset(q, psize); 3423 mchunkptr q = (mchunkptr) old_top;
3361 set_free_with_pinuse(q, psize, tn); 3424 size_t psize = csp - old_top;
3362 insert_chunk(m, q, psize); 3425 mchunkptr tn = chunk_plus_offset(q, psize);
3363 } 3426 set_free_with_pinuse(q, psize, tn);
3364 3427 insert_chunk(m, q, psize);
3365 check_top_chunk(m, m->top); 3428 }
3429
3430 check_top_chunk(m, m->top);
3366 } 3431 }
3367 3432
3368 /* -------------------------- System allocation -------------------------- */ 3433 /* -------------------------- System allocation -------------------------- */
3369 3434
3370 /* Get memory from system using MORECORE or MMAP */ 3435 /* Get memory from system using MORECORE or MMAP */
3371 static void* sys_alloc(mstate m, size_t nb) { 3436 static void *
3372 char* tbase = CMFAIL; 3437 sys_alloc(mstate m, size_t nb)
3373 size_t tsize = 0; 3438 {
3374 flag_t mmap_flag = 0; 3439 char *tbase = CMFAIL;
3375 3440 size_t tsize = 0;
3376 init_mparams(); 3441 flag_t mmap_flag = 0;
3377 3442
3378 /* Directly map large chunks */ 3443 init_mparams();
3379 if (use_mmap(m) && nb >= mparams.mmap_threshold) { 3444
3380 void* mem = mmap_alloc(m, nb); 3445 /* Directly map large chunks */
3381 if (mem != 0) 3446 if (use_mmap(m) && nb >= mparams.mmap_threshold) {
3382 return mem; 3447 void *mem = mmap_alloc(m, nb);
3383 } 3448 if (mem != 0)
3384 3449 return mem;
3385 /* 3450 }
3386 Try getting memory in any of three ways (in most-preferred to 3451
3387 least-preferred order): 3452 /*
3388 1. A call to MORECORE that can normally contiguously extend memory. 3453 Try getting memory in any of three ways (in most-preferred to
3454 least-preferred order):
3455 1. A call to MORECORE that can normally contiguously extend memory.
3389 (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or 3456 (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
3390 or main space is mmapped or a previous contiguous call failed) 3457 or main space is mmapped or a previous contiguous call failed)
3391 2. A call to MMAP new space (disabled if not HAVE_MMAP). 3458 2. A call to MMAP new space (disabled if not HAVE_MMAP).
3392 Note that under the default settings, if MORECORE is unable to 3459 Note that under the default settings, if MORECORE is unable to
3393 fulfill a request, and HAVE_MMAP is true, then mmap is 3460 fulfill a request, and HAVE_MMAP is true, then mmap is
3394 used as a noncontiguous system allocator. This is a useful backup 3461 used as a noncontiguous system allocator. This is a useful backup
3395 strategy for systems with holes in address spaces -- in this case 3462 strategy for systems with holes in address spaces -- in this case
3396 sbrk cannot contiguously expand the heap, but mmap may be able to 3463 sbrk cannot contiguously expand the heap, but mmap may be able to
3397 find space. 3464 find space.
3398 3. A call to MORECORE that cannot usually contiguously extend memory. 3465 3. A call to MORECORE that cannot usually contiguously extend memory.
3399 (disabled if not HAVE_MORECORE) 3466 (disabled if not HAVE_MORECORE)
3400 */ 3467 */
3401 3468
3402 if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { 3469 if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
3403 char* br = CMFAIL; 3470 char *br = CMFAIL;
3404 msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); 3471 msegmentptr ss =
3405 size_t asize = 0; 3472 (m->top == 0) ? 0 : segment_holding(m, (char *) m->top);
3406 ACQUIRE_MORECORE_LOCK(); 3473 size_t asize = 0;
3407 3474 ACQUIRE_MORECORE_LOCK();
3408 if (ss == 0) { /* First time through or recovery */ 3475
3409 char* base = (char*)CALL_MORECORE(0); 3476 if (ss == 0) { /* First time through or recovery */
3410 if (base != CMFAIL) { 3477 char *base = (char *) CALL_MORECORE(0);
3411 asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE); 3478 if (base != CMFAIL) {
3412 /* Adjust to end on a page boundary */ 3479 asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
3413 if (!is_page_aligned(base)) 3480 /* Adjust to end on a page boundary */
3414 asize += (page_align((size_t)base) - (size_t)base); 3481 if (!is_page_aligned(base))
3415 /* Can't call MORECORE if size is negative when treated as signed */ 3482 asize += (page_align((size_t) base) - (size_t) base);
3416 if (asize < HALF_MAX_SIZE_T && 3483 /* Can't call MORECORE if size is negative when treated as signed */
3417 (br = (char*)(CALL_MORECORE(asize))) == base) { 3484 if (asize < HALF_MAX_SIZE_T &&
3418 tbase = base; 3485 (br = (char *) (CALL_MORECORE(asize))) == base) {
3419 tsize = asize; 3486 tbase = base;
3487 tsize = asize;
3488 }
3489 }
3490 } else {
3491 /* Subtract out existing available top space from MORECORE request. */
3492 asize =
3493 granularity_align(nb - m->topsize + TOP_FOOT_SIZE +
3494 SIZE_T_ONE);
3495 /* Use mem here only if it did continuously extend old space */
3496 if (asize < HALF_MAX_SIZE_T &&
3497 (br =
3498 (char *) (CALL_MORECORE(asize))) == ss->base + ss->size) {
3499 tbase = br;
3500 tsize = asize;
3501 }
3420 } 3502 }
3421 } 3503
3422 } 3504 if (tbase == CMFAIL) { /* Cope with partial failure */
3423 else { 3505 if (br != CMFAIL) { /* Try to use/extend the space we did get */
3424 /* Subtract out existing available top space from MORECORE request. */ 3506 if (asize < HALF_MAX_SIZE_T &&
3425 asize = granularity_align(nb - m->topsize + TOP_FOOT_SIZE + SIZE_T_ONE); 3507 asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) {
3426 /* Use mem here only if it did continuously extend old space */ 3508 size_t esize =
3427 if (asize < HALF_MAX_SIZE_T && 3509 granularity_align(nb + TOP_FOOT_SIZE +
3428 (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) { 3510 SIZE_T_ONE - asize);
3429 tbase = br; 3511 if (esize < HALF_MAX_SIZE_T) {
3430 tsize = asize; 3512 char *end = (char *) CALL_MORECORE(esize);
3431 } 3513 if (end != CMFAIL)
3432 } 3514 asize += esize;
3433 3515 else { /* Can't use; try to release */
3434 if (tbase == CMFAIL) { /* Cope with partial failure */ 3516 end = (char *) CALL_MORECORE(-asize);
3435 if (br != CMFAIL) { /* Try to use/extend the space we did get */ 3517 br = CMFAIL;
3436 if (asize < HALF_MAX_SIZE_T && 3518 }
3437 asize < nb + TOP_FOOT_SIZE + SIZE_T_ONE) { 3519 }
3438 size_t esize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE - asize); 3520 }
3439 if (esize < HALF_MAX_SIZE_T) {
3440 char* end = (char*)CALL_MORECORE(esize);
3441 if (end != CMFAIL)
3442 asize += esize;
3443 else { /* Can't use; try to release */
3444 end = (char*)CALL_MORECORE(-asize);
3445 br = CMFAIL;
3446 } 3521 }
3447 } 3522 if (br != CMFAIL) { /* Use the space we did get */
3523 tbase = br;
3524 tsize = asize;
3525 } else
3526 disable_contiguous(m); /* Don't try contiguous path in the future */
3448 } 3527 }
3449 } 3528
3450 if (br != CMFAIL) { /* Use the space we did get */ 3529 RELEASE_MORECORE_LOCK();
3451 tbase = br; 3530 }
3452 tsize = asize; 3531
3453 } 3532 if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */
3454 else 3533 size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE;
3455 disable_contiguous(m); /* Don't try contiguous path in the future */ 3534 size_t rsize = granularity_align(req);
3456 } 3535 if (rsize > nb) { /* Fail if wraps around zero */
3457 3536 char *mp = (char *) (CALL_MMAP(rsize));
3458 RELEASE_MORECORE_LOCK(); 3537 if (mp != CMFAIL) {
3459 } 3538 tbase = mp;
3460 3539 tsize = rsize;
3461 if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ 3540 mmap_flag = IS_MMAPPED_BIT;
3462 size_t req = nb + TOP_FOOT_SIZE + SIZE_T_ONE; 3541 }
3463 size_t rsize = granularity_align(req);
3464 if (rsize > nb) { /* Fail if wraps around zero */
3465 char* mp = (char*)(CALL_MMAP(rsize));
3466 if (mp != CMFAIL) {
3467 tbase = mp;
3468 tsize = rsize;
3469 mmap_flag = IS_MMAPPED_BIT;
3470 }
3471 }
3472 }
3473
3474 if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
3475 size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
3476 if (asize < HALF_MAX_SIZE_T) {
3477 char* br = CMFAIL;
3478 char* end = CMFAIL;
3479 ACQUIRE_MORECORE_LOCK();
3480 br = (char*)(CALL_MORECORE(asize));
3481 end = (char*)(CALL_MORECORE(0));
3482 RELEASE_MORECORE_LOCK();
3483 if (br != CMFAIL && end != CMFAIL && br < end) {
3484 size_t ssize = end - br;
3485 if (ssize > nb + TOP_FOOT_SIZE) {
3486 tbase = br;
3487 tsize = ssize;
3488 } 3542 }
3489 } 3543 }
3490 } 3544
3491 } 3545 if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
3492 3546 size_t asize = granularity_align(nb + TOP_FOOT_SIZE + SIZE_T_ONE);
3493 if (tbase != CMFAIL) { 3547 if (asize < HALF_MAX_SIZE_T) {
3494 3548 char *br = CMFAIL;
3495 if ((m->footprint += tsize) > m->max_footprint) 3549 char *end = CMFAIL;
3496 m->max_footprint = m->footprint; 3550 ACQUIRE_MORECORE_LOCK();
3497 3551 br = (char *) (CALL_MORECORE(asize));
3498 if (!is_initialized(m)) { /* first-time initialization */ 3552 end = (char *) (CALL_MORECORE(0));
3499 m->seg.base = m->least_addr = tbase; 3553 RELEASE_MORECORE_LOCK();
3500 m->seg.size = tsize; 3554 if (br != CMFAIL && end != CMFAIL && br < end) {
3501 m->seg.sflags = mmap_flag; 3555 size_t ssize = end - br;
3502 m->magic = mparams.magic; 3556 if (ssize > nb + TOP_FOOT_SIZE) {
3503 init_bins(m); 3557 tbase = br;
3504 if (is_global(m)) 3558 tsize = ssize;
3505 init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); 3559 }
3506 else { 3560 }
3507 /* Offset top by embedded malloc_state */
3508 mchunkptr mn = next_chunk(mem2chunk(m));
3509 init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
3510 }
3511 }
3512
3513 else {
3514 /* Try to merge with an existing segment */
3515 msegmentptr sp = &m->seg;
3516 while (sp != 0 && tbase != sp->base + sp->size)
3517 sp = sp->next;
3518 if (sp != 0 &&
3519 !is_extern_segment(sp) &&
3520 (sp->sflags & IS_MMAPPED_BIT) == mmap_flag &&
3521 segment_holds(sp, m->top)) { /* append */
3522 sp->size += tsize;
3523 init_top(m, m->top, m->topsize + tsize);
3524 }
3525 else {
3526 if (tbase < m->least_addr)
3527 m->least_addr = tbase;
3528 sp = &m->seg;
3529 while (sp != 0 && sp->base != tbase + tsize)
3530 sp = sp->next;
3531 if (sp != 0 &&
3532 !is_extern_segment(sp) &&
3533 (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) {
3534 char* oldbase = sp->base;
3535 sp->base = tbase;
3536 sp->size += tsize;
3537 return prepend_alloc(m, tbase, oldbase, nb);
3538 } 3561 }
3539 else 3562 }
3540 add_segment(m, tbase, tsize, mmap_flag); 3563
3541 } 3564 if (tbase != CMFAIL) {
3542 } 3565
3543 3566 if ((m->footprint += tsize) > m->max_footprint)
3544 if (nb < m->topsize) { /* Allocate from new or extended top space */ 3567 m->max_footprint = m->footprint;
3545 size_t rsize = m->topsize -= nb; 3568
3546 mchunkptr p = m->top; 3569 if (!is_initialized(m)) { /* first-time initialization */
3547 mchunkptr r = m->top = chunk_plus_offset(p, nb); 3570 m->seg.base = m->least_addr = tbase;
3548 r->head = rsize | PINUSE_BIT; 3571 m->seg.size = tsize;
3549 set_size_and_pinuse_of_inuse_chunk(m, p, nb); 3572 m->seg.sflags = mmap_flag;
3550 check_top_chunk(m, m->top); 3573 m->magic = mparams.magic;
3551 check_malloced_chunk(m, chunk2mem(p), nb); 3574 init_bins(m);
3552 return chunk2mem(p); 3575 if (is_global(m))
3553 } 3576 init_top(m, (mchunkptr) tbase, tsize - TOP_FOOT_SIZE);
3554 } 3577 else {
3555 3578 /* Offset top by embedded malloc_state */
3556 MALLOC_FAILURE_ACTION; 3579 mchunkptr mn = next_chunk(mem2chunk(m));
3557 return 0; 3580 init_top(m, mn,
3558 } 3581 (size_t) ((tbase + tsize) - (char *) mn) -
3559 3582 TOP_FOOT_SIZE);
3560 /* ----------------------- system deallocation -------------------------- */ 3583 }
3561
3562 /* Unmap and unlink any mmapped segments that don't contain used chunks */
3563 static size_t release_unused_segments(mstate m) {
3564 size_t released = 0;
3565 msegmentptr pred = &m->seg;
3566 msegmentptr sp = pred->next;
3567 while (sp != 0) {
3568 char* base = sp->base;
3569 size_t size = sp->size;
3570 msegmentptr next = sp->next;
3571 if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
3572 mchunkptr p = align_as_chunk(base);
3573 size_t psize = chunksize(p);
3574 /* Can unmap if first chunk holds entire segment and not pinned */
3575 if (!cinuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
3576 tchunkptr tp = (tchunkptr)p;
3577 assert(segment_holds(sp, (char*)sp));
3578 if (p == m->dv) {
3579 m->dv = 0;
3580 m->dvsize = 0;
3581 } 3584 }
3585
3582 else { 3586 else {
3583 unlink_large_chunk(m, tp); 3587 /* Try to merge with an existing segment */
3588 msegmentptr sp = &m->seg;
3589 while (sp != 0 && tbase != sp->base + sp->size)
3590 sp = sp->next;
3591 if (sp != 0 && !is_extern_segment(sp) && (sp->sflags & IS_MMAPPED_BIT) == mmap_flag && segment_holds(sp, m->top)) { /* append */
3592 sp->size += tsize;
3593 init_top(m, m->top, m->topsize + tsize);
3594 } else {
3595 if (tbase < m->least_addr)
3596 m->least_addr = tbase;
3597 sp = &m->seg;
3598 while (sp != 0 && sp->base != tbase + tsize)
3599 sp = sp->next;
3600 if (sp != 0 &&
3601 !is_extern_segment(sp) &&
3602 (sp->sflags & IS_MMAPPED_BIT) == mmap_flag) {
3603 char *oldbase = sp->base;
3604 sp->base = tbase;
3605 sp->size += tsize;
3606 return prepend_alloc(m, tbase, oldbase, nb);
3607 } else
3608 add_segment(m, tbase, tsize, mmap_flag);
3609 }
3584 } 3610 }
3585 if (CALL_MUNMAP(base, size) == 0) { 3611
3586 released += size; 3612 if (nb < m->topsize) { /* Allocate from new or extended top space */
3587 m->footprint -= size; 3613 size_t rsize = m->topsize -= nb;
3588 /* unlink obsoleted record */ 3614 mchunkptr p = m->top;
3589 sp = pred; 3615 mchunkptr r = m->top = chunk_plus_offset(p, nb);
3590 sp->next = next; 3616 r->head = rsize | PINUSE_BIT;
3617 set_size_and_pinuse_of_inuse_chunk(m, p, nb);
3618 check_top_chunk(m, m->top);
3619 check_malloced_chunk(m, chunk2mem(p), nb);
3620 return chunk2mem(p);
3591 } 3621 }
3592 else { /* back out if cannot unmap */ 3622 }
3593 insert_large_chunk(m, tp, psize); 3623
3594 }
3595 }
3596 }
3597 pred = sp;
3598 sp = next;
3599 }
3600 return released;
3601 }
3602
3603 static int sys_trim(mstate m, size_t pad) {
3604 size_t released = 0;
3605 if (pad < MAX_REQUEST && is_initialized(m)) {
3606 pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
3607
3608 if (m->topsize > pad) {
3609 /* Shrink top space in granularity-size units, keeping at least one */
3610 size_t unit = mparams.granularity;
3611 size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
3612 SIZE_T_ONE) * unit;
3613 msegmentptr sp = segment_holding(m, (char*)m->top);
3614
3615 if (!is_extern_segment(sp)) {
3616 if (is_mmapped_segment(sp)) {
3617 if (HAVE_MMAP &&
3618 sp->size >= extra &&
3619 !has_segment_link(m, sp)) { /* can't shrink if pinned */
3620 size_t newsize = sp->size - extra;
3621 /* Prefer mremap, fall back to munmap */
3622 if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
3623 (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
3624 released = extra;
3625 }
3626 }
3627 }
3628 else if (HAVE_MORECORE) {
3629 if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
3630 extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
3631 ACQUIRE_MORECORE_LOCK();
3632 {
3633 /* Make sure end of memory is where we last set it. */
3634 char* old_br = (char*)(CALL_MORECORE(0));
3635 if (old_br == sp->base + sp->size) {
3636 char* rel_br = (char*)(CALL_MORECORE(-extra));
3637 char* new_br = (char*)(CALL_MORECORE(0));
3638 if (rel_br != CMFAIL && new_br < old_br)
3639 released = old_br - new_br;
3640 }
3641 }
3642 RELEASE_MORECORE_LOCK();
3643 }
3644 }
3645
3646 if (released != 0) {
3647 sp->size -= released;
3648 m->footprint -= released;
3649 init_top(m, m->top, m->topsize - released);
3650 check_top_chunk(m, m->top);
3651 }
3652 }
3653
3654 /* Unmap any unused mmapped segments */
3655 if (HAVE_MMAP)
3656 released += release_unused_segments(m);
3657
3658 /* On failure, disable autotrim to avoid repeated failed future calls */
3659 if (released == 0)
3660 m->trim_check = MAX_SIZE_T;
3661 }
3662
3663 return (released != 0)? 1 : 0;
3664 }
3665
3666 /* ---------------------------- malloc support --------------------------- */
3667
3668 /* allocate a large request from the best fitting chunk in a treebin */
3669 static void* tmalloc_large(mstate m, size_t nb) {
3670 tchunkptr v = 0;
3671 size_t rsize = -nb; /* Unsigned negation */
3672 tchunkptr t;
3673 bindex_t idx;
3674 compute_tree_index(nb, idx);
3675
3676 if ((t = *treebin_at(m, idx)) != 0) {
3677 /* Traverse tree for this bin looking for node with size == nb */
3678 size_t sizebits = nb << leftshift_for_tree_index(idx);
3679 tchunkptr rst = 0; /* The deepest untaken right subtree */
3680 for (;;) {
3681 tchunkptr rt;
3682 size_t trem = chunksize(t) - nb;
3683 if (trem < rsize) {
3684 v = t;
3685 if ((rsize = trem) == 0)
3686 break;
3687 }
3688 rt = t->child[1];
3689 t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
3690 if (rt != 0 && rt != t)
3691 rst = rt;
3692 if (t == 0) {
3693 t = rst; /* set t to least subtree holding sizes > nb */
3694 break;
3695 }
3696 sizebits <<= 1;
3697 }
3698 }
3699
3700 if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
3701 binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
3702 if (leftbits != 0) {
3703 bindex_t i;
3704 binmap_t leastbit = least_bit(leftbits);
3705 compute_bit2idx(leastbit, i);
3706 t = *treebin_at(m, i);
3707 }
3708 }
3709
3710 while (t != 0) { /* find smallest of tree or subtree */
3711 size_t trem = chunksize(t) - nb;
3712 if (trem < rsize) {
3713 rsize = trem;
3714 v = t;
3715 }
3716 t = leftmost_child(t);
3717 }
3718
3719 /* If dv is a better fit, return 0 so malloc will use it */
3720 if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
3721 if (RTCHECK(ok_address(m, v))) { /* split */
3722 mchunkptr r = chunk_plus_offset(v, nb);
3723 assert(chunksize(v) == rsize + nb);
3724 if (RTCHECK(ok_next(v, r))) {
3725 unlink_large_chunk(m, v);
3726 if (rsize < MIN_CHUNK_SIZE)
3727 set_inuse_and_pinuse(m, v, (rsize + nb));
3728 else {
3729 set_size_and_pinuse_of_inuse_chunk(m, v, nb);
3730 set_size_and_pinuse_of_free_chunk(r, rsize);
3731 insert_chunk(m, r, rsize);
3732 }
3733 return chunk2mem(v);
3734 }
3735 }
3736 CORRUPTION_ERROR_ACTION(m);
3737 }
3738 return 0;
3739 }
3740
3741 /* allocate a small request from the best fitting chunk in a treebin */
3742 static void* tmalloc_small(mstate m, size_t nb) {
3743 tchunkptr t, v;
3744 size_t rsize;
3745 bindex_t i;
3746 binmap_t leastbit = least_bit(m->treemap);
3747 compute_bit2idx(leastbit, i);
3748
3749 v = t = *treebin_at(m, i);
3750 rsize = chunksize(t) - nb;
3751
3752 while ((t = leftmost_child(t)) != 0) {
3753 size_t trem = chunksize(t) - nb;
3754 if (trem < rsize) {
3755 rsize = trem;
3756 v = t;
3757 }
3758 }
3759
3760 if (RTCHECK(ok_address(m, v))) {
3761 mchunkptr r = chunk_plus_offset(v, nb);
3762 assert(chunksize(v) == rsize + nb);
3763 if (RTCHECK(ok_next(v, r))) {
3764 unlink_large_chunk(m, v);
3765 if (rsize < MIN_CHUNK_SIZE)
3766 set_inuse_and_pinuse(m, v, (rsize + nb));
3767 else {
3768 set_size_and_pinuse_of_inuse_chunk(m, v, nb);
3769 set_size_and_pinuse_of_free_chunk(r, rsize);
3770 replace_dv(m, r, rsize);
3771 }
3772 return chunk2mem(v);
3773 }
3774 }
3775
3776 CORRUPTION_ERROR_ACTION(m);
3777 return 0;
3778 }
3779
3780 /* --------------------------- realloc support --------------------------- */
3781
3782 static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
3783 if (bytes >= MAX_REQUEST) {
3784 MALLOC_FAILURE_ACTION; 3624 MALLOC_FAILURE_ACTION;
3785 return 0; 3625 return 0;
3786 } 3626 }
3787 if (!PREACTION(m)) { 3627
3788 mchunkptr oldp = mem2chunk(oldmem); 3628 /* ----------------------- system deallocation -------------------------- */
3789 size_t oldsize = chunksize(oldp); 3629
3790 mchunkptr next = chunk_plus_offset(oldp, oldsize); 3630 /* Unmap and unlink any mmapped segments that don't contain used chunks */
3791 mchunkptr newp = 0; 3631 static size_t
3792 void* extra = 0; 3632 release_unused_segments(mstate m)
3793 3633 {
3794 /* Try to either shrink or extend into top. Else malloc-copy-free */ 3634 size_t released = 0;
3795 3635 msegmentptr pred = &m->seg;
3796 if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) && 3636 msegmentptr sp = pred->next;
3797 ok_next(oldp, next) && ok_pinuse(next))) { 3637 while (sp != 0) {
3798 size_t nb = request2size(bytes); 3638 char *base = sp->base;
3799 if (is_mmapped(oldp)) 3639 size_t size = sp->size;
3800 newp = mmap_resize(m, oldp, nb); 3640 msegmentptr next = sp->next;
3801 else if (oldsize >= nb) { /* already big enough */ 3641 if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
3802 size_t rsize = oldsize - nb; 3642 mchunkptr p = align_as_chunk(base);
3803 newp = oldp; 3643 size_t psize = chunksize(p);
3804 if (rsize >= MIN_CHUNK_SIZE) { 3644 /* Can unmap if first chunk holds entire segment and not pinned */
3805 mchunkptr remainder = chunk_plus_offset(newp, nb); 3645 if (!cinuse(p)
3806 set_inuse(m, newp, nb); 3646 && (char *) p + psize >= base + size - TOP_FOOT_SIZE) {
3807 set_inuse(m, remainder, rsize); 3647 tchunkptr tp = (tchunkptr) p;
3808 extra = chunk2mem(remainder); 3648 assert(segment_holds(sp, (char *) sp));
3649 if (p == m->dv) {
3650 m->dv = 0;
3651 m->dvsize = 0;
3652 } else {
3653 unlink_large_chunk(m, tp);
3654 }
3655 if (CALL_MUNMAP(base, size) == 0) {
3656 released += size;
3657 m->footprint -= size;
3658 /* unlink obsoleted record */
3659 sp = pred;
3660 sp->next = next;
3661 } else { /* back out if cannot unmap */
3662 insert_large_chunk(m, tp, psize);
3663 }
3664 }
3809 } 3665 }
3810 } 3666 pred = sp;
3811 else if (next == m->top && oldsize + m->topsize > nb) { 3667 sp = next;
3812 /* Expand into top */ 3668 }
3813 size_t newsize = oldsize + m->topsize; 3669 return released;
3814 size_t newtopsize = newsize - nb; 3670 }
3815 mchunkptr newtop = chunk_plus_offset(oldp, nb); 3671
3816 set_inuse(m, oldp, nb); 3672 static int
3817 newtop->head = newtopsize |PINUSE_BIT; 3673 sys_trim(mstate m, size_t pad)
3818 m->top = newtop; 3674 {
3819 m->topsize = newtopsize; 3675 size_t released = 0;
3820 newp = oldp; 3676 if (pad < MAX_REQUEST && is_initialized(m)) {
3821 } 3677 pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
3822 } 3678
3823 else { 3679 if (m->topsize > pad) {
3824 USAGE_ERROR_ACTION(m, oldmem); 3680 /* Shrink top space in granularity-size units, keeping at least one */
3825 POSTACTION(m); 3681 size_t unit = mparams.granularity;
3826 return 0; 3682 size_t extra =
3827 } 3683 ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
3684 SIZE_T_ONE) * unit;
3685 msegmentptr sp = segment_holding(m, (char *) m->top);
3686
3687 if (!is_extern_segment(sp)) {
3688 if (is_mmapped_segment(sp)) {
3689 if (HAVE_MMAP && sp->size >= extra && !has_segment_link(m, sp)) { /* can't shrink if pinned */
3690 size_t newsize = sp->size - extra;
3691 /* Prefer mremap, fall back to munmap */
3692 if ((CALL_MREMAP
3693 (sp->base, sp->size, newsize, 0) != MFAIL)
3694 || (CALL_MUNMAP(sp->base + newsize, extra)
3695 == 0)) {
3696 released = extra;
3697 }
3698 }
3699 } else if (HAVE_MORECORE) {
3700 if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
3701 extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
3702 ACQUIRE_MORECORE_LOCK();
3703 {
3704 /* Make sure end of memory is where we last set it. */
3705 char *old_br = (char *) (CALL_MORECORE(0));
3706 if (old_br == sp->base + sp->size) {
3707 char *rel_br = (char *) (CALL_MORECORE(-extra));
3708 char *new_br = (char *) (CALL_MORECORE(0));
3709 if (rel_br != CMFAIL && new_br < old_br)
3710 released = old_br - new_br;
3711 }
3712 }
3713 RELEASE_MORECORE_LOCK();
3714 }
3715 }
3716
3717 if (released != 0) {
3718 sp->size -= released;
3719 m->footprint -= released;
3720 init_top(m, m->top, m->topsize - released);
3721 check_top_chunk(m, m->top);
3722 }
3723 }
3724
3725 /* Unmap any unused mmapped segments */
3726 if (HAVE_MMAP)
3727 released += release_unused_segments(m);
3728
3729 /* On failure, disable autotrim to avoid repeated failed future calls */
3730 if (released == 0)
3731 m->trim_check = MAX_SIZE_T;
3732 }
3733
3734 return (released != 0) ? 1 : 0;
3735 }
3736
3737 /* ---------------------------- malloc support --------------------------- */
3738
3739 /* allocate a large request from the best fitting chunk in a treebin */
3740 static void *
3741 tmalloc_large(mstate m, size_t nb)
3742 {
3743 tchunkptr v = 0;
3744 size_t rsize = -nb; /* Unsigned negation */
3745 tchunkptr t;
3746 bindex_t idx;
3747 compute_tree_index(nb, idx);
3748
3749 if ((t = *treebin_at(m, idx)) != 0) {
3750 /* Traverse tree for this bin looking for node with size == nb */
3751 size_t sizebits = nb << leftshift_for_tree_index(idx);
3752 tchunkptr rst = 0; /* The deepest untaken right subtree */
3753 for (;;) {
3754 tchunkptr rt;
3755 size_t trem = chunksize(t) - nb;
3756 if (trem < rsize) {
3757 v = t;
3758 if ((rsize = trem) == 0)
3759 break;
3760 }
3761 rt = t->child[1];
3762 t = t->child[(sizebits >> (SIZE_T_BITSIZE - SIZE_T_ONE)) & 1];
3763 if (rt != 0 && rt != t)
3764 rst = rt;
3765 if (t == 0) {
3766 t = rst; /* set t to least subtree holding sizes > nb */
3767 break;
3768 }
3769 sizebits <<= 1;
3770 }
3771 }
3772
3773 if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
3774 binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
3775 if (leftbits != 0) {
3776 bindex_t i;
3777 binmap_t leastbit = least_bit(leftbits);
3778 compute_bit2idx(leastbit, i);
3779 t = *treebin_at(m, i);
3780 }
3781 }
3782
3783 while (t != 0) { /* find smallest of tree or subtree */
3784 size_t trem = chunksize(t) - nb;
3785 if (trem < rsize) {
3786 rsize = trem;
3787 v = t;
3788 }
3789 t = leftmost_child(t);
3790 }
3791
3792 /* If dv is a better fit, return 0 so malloc will use it */
3793 if (v != 0 && rsize < (size_t) (m->dvsize - nb)) {
3794 if (RTCHECK(ok_address(m, v))) { /* split */
3795 mchunkptr r = chunk_plus_offset(v, nb);
3796 assert(chunksize(v) == rsize + nb);
3797 if (RTCHECK(ok_next(v, r))) {
3798 unlink_large_chunk(m, v);
3799 if (rsize < MIN_CHUNK_SIZE)
3800 set_inuse_and_pinuse(m, v, (rsize + nb));
3801 else {
3802 set_size_and_pinuse_of_inuse_chunk(m, v, nb);
3803 set_size_and_pinuse_of_free_chunk(r, rsize);
3804 insert_chunk(m, r, rsize);
3805 }
3806 return chunk2mem(v);
3807 }
3808 }
3809 CORRUPTION_ERROR_ACTION(m);
3810 }
3811 return 0;
3812 }
3813
3814 /* allocate a small request from the best fitting chunk in a treebin */
3815 static void *
3816 tmalloc_small(mstate m, size_t nb)
3817 {
3818 tchunkptr t, v;
3819 size_t rsize;
3820 bindex_t i;
3821 binmap_t leastbit = least_bit(m->treemap);
3822 compute_bit2idx(leastbit, i);
3823
3824 v = t = *treebin_at(m, i);
3825 rsize = chunksize(t) - nb;
3826
3827 while ((t = leftmost_child(t)) != 0) {
3828 size_t trem = chunksize(t) - nb;
3829 if (trem < rsize) {
3830 rsize = trem;
3831 v = t;
3832 }
3833 }
3834
3835 if (RTCHECK(ok_address(m, v))) {
3836 mchunkptr r = chunk_plus_offset(v, nb);
3837 assert(chunksize(v) == rsize + nb);
3838 if (RTCHECK(ok_next(v, r))) {
3839 unlink_large_chunk(m, v);
3840 if (rsize < MIN_CHUNK_SIZE)
3841 set_inuse_and_pinuse(m, v, (rsize + nb));
3842 else {
3843 set_size_and_pinuse_of_inuse_chunk(m, v, nb);
3844 set_size_and_pinuse_of_free_chunk(r, rsize);
3845 replace_dv(m, r, rsize);
3846 }
3847 return chunk2mem(v);
3848 }
3849 }
3850
3851 CORRUPTION_ERROR_ACTION(m);
3852 return 0;
3853 }
3854
3855 /* --------------------------- realloc support --------------------------- */
3856
3857 static void *
3858 internal_realloc(mstate m, void *oldmem, size_t bytes)
3859 {
3860 if (bytes >= MAX_REQUEST) {
3861 MALLOC_FAILURE_ACTION;
3862 return 0;
3863 }
3864 if (!PREACTION(m)) {
3865 mchunkptr oldp = mem2chunk(oldmem);
3866 size_t oldsize = chunksize(oldp);
3867 mchunkptr next = chunk_plus_offset(oldp, oldsize);
3868 mchunkptr newp = 0;
3869 void *extra = 0;
3870
3871 /* Try to either shrink or extend into top. Else malloc-copy-free */
3872
3873 if (RTCHECK(ok_address(m, oldp) && ok_cinuse(oldp) &&
3874 ok_next(oldp, next) && ok_pinuse(next))) {
3875 size_t nb = request2size(bytes);
3876 if (is_mmapped(oldp))
3877 newp = mmap_resize(m, oldp, nb);
3878 else if (oldsize >= nb) { /* already big enough */
3879 size_t rsize = oldsize - nb;
3880 newp = oldp;
3881 if (rsize >= MIN_CHUNK_SIZE) {
3882 mchunkptr remainder = chunk_plus_offset(newp, nb);
3883 set_inuse(m, newp, nb);
3884 set_inuse(m, remainder, rsize);
3885 extra = chunk2mem(remainder);
3886 }
3887 } else if (next == m->top && oldsize + m->topsize > nb) {
3888 /* Expand into top */
3889 size_t newsize = oldsize + m->topsize;
3890 size_t newtopsize = newsize - nb;
3891 mchunkptr newtop = chunk_plus_offset(oldp, nb);
3892 set_inuse(m, oldp, nb);
3893 newtop->head = newtopsize | PINUSE_BIT;
3894 m->top = newtop;
3895 m->topsize = newtopsize;
3896 newp = oldp;
3897 }
3898 } else {
3899 USAGE_ERROR_ACTION(m, oldmem);
3900 POSTACTION(m);
3901 return 0;
3902 }
3903
3904 POSTACTION(m);
3905
3906 if (newp != 0) {
3907 if (extra != 0) {
3908 internal_free(m, extra);
3909 }
3910 check_inuse_chunk(m, newp);
3911 return chunk2mem(newp);
3912 } else {
3913 void *newmem = internal_malloc(m, bytes);
3914 if (newmem != 0) {
3915 size_t oc = oldsize - overhead_for(oldp);
3916 memcpy(newmem, oldmem, (oc < bytes) ? oc : bytes);
3917 internal_free(m, oldmem);
3918 }
3919 return newmem;
3920 }
3921 }
3922 return 0;
3923 }
3924
3925 /* --------------------------- memalign support -------------------------- */
3926
3927 static void *
3928 internal_memalign(mstate m, size_t alignment, size_t bytes)
3929 {
3930 if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */
3931 return internal_malloc(m, bytes);
3932 if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
3933 alignment = MIN_CHUNK_SIZE;
3934 if ((alignment & (alignment - SIZE_T_ONE)) != 0) { /* Ensure a power of 2 */
3935 size_t a = MALLOC_ALIGNMENT << 1;
3936 while (a < alignment)
3937 a <<= 1;
3938 alignment = a;
3939 }
3940
3941 if (bytes >= MAX_REQUEST - alignment) {
3942 if (m != 0) { /* Test isn't needed but avoids compiler warning */
3943 MALLOC_FAILURE_ACTION;
3944 }
3945 } else {
3946 size_t nb = request2size(bytes);
3947 size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
3948 char *mem = (char *) internal_malloc(m, req);
3949 if (mem != 0) {
3950 void *leader = 0;
3951 void *trailer = 0;
3952 mchunkptr p = mem2chunk(mem);
3953
3954 if (PREACTION(m))
3955 return 0;
3956 if ((((size_t) (mem)) % alignment) != 0) { /* misaligned */
3957 /*
3958 Find an aligned spot inside chunk. Since we need to give
3959 back leading space in a chunk of at least MIN_CHUNK_SIZE, if
3960 the first calculation places us at a spot with less than
3961 MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
3962 We've allocated enough total room so that this is always
3963 possible.
3964 */
3965 char *br = (char *)
3966 mem2chunk((size_t)
3967 (((size_t)
3968 (mem + alignment -
3969 SIZE_T_ONE)) & -alignment));
3970 char *pos =
3971 ((size_t) (br - (char *) (p)) >=
3972 MIN_CHUNK_SIZE) ? br : br + alignment;
3973 mchunkptr newp = (mchunkptr) pos;
3974 size_t leadsize = pos - (char *) (p);
3975 size_t newsize = chunksize(p) - leadsize;
3976
3977 if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
3978 newp->prev_foot = p->prev_foot + leadsize;
3979 newp->head = (newsize | CINUSE_BIT);
3980 } else { /* Otherwise, give back leader, use the rest */
3981 set_inuse(m, newp, newsize);
3982 set_inuse(m, p, leadsize);
3983 leader = chunk2mem(p);
3984 }
3985 p = newp;
3986 }
3987
3988 /* Give back spare room at the end */
3989 if (!is_mmapped(p)) {
3990 size_t size = chunksize(p);
3991 if (size > nb + MIN_CHUNK_SIZE) {
3992 size_t remainder_size = size - nb;
3993 mchunkptr remainder = chunk_plus_offset(p, nb);
3994 set_inuse(m, p, nb);
3995 set_inuse(m, remainder, remainder_size);
3996 trailer = chunk2mem(remainder);
3997 }
3998 }
3999
4000 assert(chunksize(p) >= nb);
4001 assert((((size_t) (chunk2mem(p))) % alignment) == 0);
4002 check_inuse_chunk(m, p);
4003 POSTACTION(m);
4004 if (leader != 0) {
4005 internal_free(m, leader);
4006 }
4007 if (trailer != 0) {
4008 internal_free(m, trailer);
4009 }
4010 return chunk2mem(p);
4011 }
4012 }
4013 return 0;
4014 }
4015
4016 /* ------------------------ comalloc/coalloc support --------------------- */
4017
4018 static void **
4019 ialloc(mstate m, size_t n_elements, size_t * sizes, int opts, void *chunks[])
4020 {
4021 /*
4022 This provides common support for independent_X routines, handling
4023 all of the combinations that can result.
4024
4025 The opts arg has:
4026 bit 0 set if all elements are same size (using sizes[0])
4027 bit 1 set if elements should be zeroed
4028 */
4029
4030 size_t element_size; /* chunksize of each element, if all same */
4031 size_t contents_size; /* total size of elements */
4032 size_t array_size; /* request size of pointer array */
4033 void *mem; /* malloced aggregate space */
4034 mchunkptr p; /* corresponding chunk */
4035 size_t remainder_size; /* remaining bytes while splitting */
4036 void **marray; /* either "chunks" or malloced ptr array */
4037 mchunkptr array_chunk; /* chunk for malloced ptr array */
4038 flag_t was_enabled; /* to disable mmap */
4039 size_t size;
4040 size_t i;
4041
4042 /* compute array length, if needed */
4043 if (chunks != 0) {
4044 if (n_elements == 0)
4045 return chunks; /* nothing to do */
4046 marray = chunks;
4047 array_size = 0;
4048 } else {
4049 /* if empty req, must still return chunk representing empty array */
4050 if (n_elements == 0)
4051 return (void **) internal_malloc(m, 0);
4052 marray = 0;
4053 array_size = request2size(n_elements * (sizeof(void *)));
4054 }
4055
4056 /* compute total element size */
4057 if (opts & 0x1) { /* all-same-size */
4058 element_size = request2size(*sizes);
4059 contents_size = n_elements * element_size;
4060 } else { /* add up all the sizes */
4061 element_size = 0;
4062 contents_size = 0;
4063 for (i = 0; i != n_elements; ++i)
4064 contents_size += request2size(sizes[i]);
4065 }
4066
4067 size = contents_size + array_size;
4068
4069 /*
4070 Allocate the aggregate chunk. First disable direct-mmapping so
4071 malloc won't use it, since we would not be able to later
4072 free/realloc space internal to a segregated mmap region.
4073 */
4074 was_enabled = use_mmap(m);
4075 disable_mmap(m);
4076 mem = internal_malloc(m, size - CHUNK_OVERHEAD);
4077 if (was_enabled)
4078 enable_mmap(m);
4079 if (mem == 0)
4080 return 0;
4081
4082 if (PREACTION(m))
4083 return 0;
4084 p = mem2chunk(mem);
4085 remainder_size = chunksize(p);
4086
4087 assert(!is_mmapped(p));
4088
4089 if (opts & 0x2) { /* optionally clear the elements */
4090 memset((size_t *) mem, 0, remainder_size - SIZE_T_SIZE - array_size);
4091 }
4092
4093 /* If not provided, allocate the pointer array as final part of chunk */
4094 if (marray == 0) {
4095 size_t array_chunk_size;
4096 array_chunk = chunk_plus_offset(p, contents_size);
4097 array_chunk_size = remainder_size - contents_size;
4098 marray = (void **) (chunk2mem(array_chunk));
4099 set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
4100 remainder_size = contents_size;
4101 }
4102
4103 /* split out elements */
4104 for (i = 0;; ++i) {
4105 marray[i] = chunk2mem(p);
4106 if (i != n_elements - 1) {
4107 if (element_size != 0)
4108 size = element_size;
4109 else
4110 size = request2size(sizes[i]);
4111 remainder_size -= size;
4112 set_size_and_pinuse_of_inuse_chunk(m, p, size);
4113 p = chunk_plus_offset(p, size);
4114 } else { /* the final element absorbs any overallocation slop */
4115 set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
4116 break;
4117 }
4118 }
4119
4120 #if DEBUG
4121 if (marray != chunks) {
4122 /* final element must have exactly exhausted chunk */
4123 if (element_size != 0) {
4124 assert(remainder_size == element_size);
4125 } else {
4126 assert(remainder_size == request2size(sizes[i]));
4127 }
4128 check_inuse_chunk(m, mem2chunk(marray));
4129 }
4130 for (i = 0; i != n_elements; ++i)
4131 check_inuse_chunk(m, mem2chunk(marray[i]));
4132
4133 #endif /* DEBUG */
3828 4134
3829 POSTACTION(m); 4135 POSTACTION(m);
3830 4136 return marray;
3831 if (newp != 0) {
3832 if (extra != 0) {
3833 internal_free(m, extra);
3834 }
3835 check_inuse_chunk(m, newp);
3836 return chunk2mem(newp);
3837 }
3838 else {
3839 void* newmem = internal_malloc(m, bytes);
3840 if (newmem != 0) {
3841 size_t oc = oldsize - overhead_for(oldp);
3842 memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
3843 internal_free(m, oldmem);
3844 }
3845 return newmem;
3846 }
3847 }
3848 return 0;
3849 }
3850
3851 /* --------------------------- memalign support -------------------------- */
3852
3853 static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
3854 if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */
3855 return internal_malloc(m, bytes);
3856 if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
3857 alignment = MIN_CHUNK_SIZE;
3858 if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
3859 size_t a = MALLOC_ALIGNMENT << 1;
3860 while (a < alignment) a <<= 1;
3861 alignment = a;
3862 }
3863
3864 if (bytes >= MAX_REQUEST - alignment) {
3865 if (m != 0) { /* Test isn't needed but avoids compiler warning */
3866 MALLOC_FAILURE_ACTION;
3867 }
3868 }
3869 else {
3870 size_t nb = request2size(bytes);
3871 size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
3872 char* mem = (char*)internal_malloc(m, req);
3873 if (mem != 0) {
3874 void* leader = 0;
3875 void* trailer = 0;
3876 mchunkptr p = mem2chunk(mem);
3877
3878 if (PREACTION(m)) return 0;
3879 if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
3880 /*
3881 Find an aligned spot inside chunk. Since we need to give
3882 back leading space in a chunk of at least MIN_CHUNK_SIZE, if
3883 the first calculation places us at a spot with less than
3884 MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
3885 We've allocated enough total room so that this is always
3886 possible.
3887 */
3888 char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
3889 alignment -
3890 SIZE_T_ONE)) &
3891 -alignment));
3892 char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
3893 br : br+alignment;
3894 mchunkptr newp = (mchunkptr)pos;
3895 size_t leadsize = pos - (char*)(p);
3896 size_t newsize = chunksize(p) - leadsize;
3897
3898 if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
3899 newp->prev_foot = p->prev_foot + leadsize;
3900 newp->head = (newsize|CINUSE_BIT);
3901 }
3902 else { /* Otherwise, give back leader, use the rest */
3903 set_inuse(m, newp, newsize);
3904 set_inuse(m, p, leadsize);
3905 leader = chunk2mem(p);
3906 }
3907 p = newp;
3908 }
3909
3910 /* Give back spare room at the end */
3911 if (!is_mmapped(p)) {
3912 size_t size = chunksize(p);
3913 if (size > nb + MIN_CHUNK_SIZE) {
3914 size_t remainder_size = size - nb;
3915 mchunkptr remainder = chunk_plus_offset(p, nb);
3916 set_inuse(m, p, nb);
3917 set_inuse(m, remainder, remainder_size);
3918 trailer = chunk2mem(remainder);
3919 }
3920 }
3921
3922 assert (chunksize(p) >= nb);
3923 assert((((size_t)(chunk2mem(p))) % alignment) == 0);
3924 check_inuse_chunk(m, p);
3925 POSTACTION(m);
3926 if (leader != 0) {
3927 internal_free(m, leader);
3928 }
3929 if (trailer != 0) {
3930 internal_free(m, trailer);
3931 }
3932 return chunk2mem(p);
3933 }
3934 }
3935 return 0;
3936 }
3937
3938 /* ------------------------ comalloc/coalloc support --------------------- */
3939
3940 static void** ialloc(mstate m,
3941 size_t n_elements,
3942 size_t* sizes,
3943 int opts,
3944 void* chunks[]) {
3945 /*
3946 This provides common support for independent_X routines, handling
3947 all of the combinations that can result.
3948
3949 The opts arg has:
3950 bit 0 set if all elements are same size (using sizes[0])
3951 bit 1 set if elements should be zeroed
3952 */
3953
3954 size_t element_size; /* chunksize of each element, if all same */
3955 size_t contents_size; /* total size of elements */
3956 size_t array_size; /* request size of pointer array */
3957 void* mem; /* malloced aggregate space */
3958 mchunkptr p; /* corresponding chunk */
3959 size_t remainder_size; /* remaining bytes while splitting */
3960 void** marray; /* either "chunks" or malloced ptr array */
3961 mchunkptr array_chunk; /* chunk for malloced ptr array */
3962 flag_t was_enabled; /* to disable mmap */
3963 size_t size;
3964 size_t i;
3965
3966 /* compute array length, if needed */
3967 if (chunks != 0) {
3968 if (n_elements == 0)
3969 return chunks; /* nothing to do */
3970 marray = chunks;
3971 array_size = 0;
3972 }
3973 else {
3974 /* if empty req, must still return chunk representing empty array */
3975 if (n_elements == 0)
3976 return (void**)internal_malloc(m, 0);
3977 marray = 0;
3978 array_size = request2size(n_elements * (sizeof(void*)));
3979 }
3980
3981 /* compute total element size */
3982 if (opts & 0x1) { /* all-same-size */
3983 element_size = request2size(*sizes);
3984 contents_size = n_elements * element_size;
3985 }
3986 else { /* add up all the sizes */
3987 element_size = 0;
3988 contents_size = 0;
3989 for (i = 0; i != n_elements; ++i)
3990 contents_size += request2size(sizes[i]);
3991 }
3992
3993 size = contents_size + array_size;
3994
3995 /*
3996 Allocate the aggregate chunk. First disable direct-mmapping so
3997 malloc won't use it, since we would not be able to later
3998 free/realloc space internal to a segregated mmap region.
3999 */
4000 was_enabled = use_mmap(m);
4001 disable_mmap(m);
4002 mem = internal_malloc(m, size - CHUNK_OVERHEAD);
4003 if (was_enabled)
4004 enable_mmap(m);
4005 if (mem == 0)
4006 return 0;
4007
4008 if (PREACTION(m)) return 0;
4009 p = mem2chunk(mem);
4010 remainder_size = chunksize(p);
4011
4012 assert(!is_mmapped(p));
4013
4014 if (opts & 0x2) { /* optionally clear the elements */
4015 memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
4016 }
4017
4018 /* If not provided, allocate the pointer array as final part of chunk */
4019 if (marray == 0) {
4020 size_t array_chunk_size;
4021 array_chunk = chunk_plus_offset(p, contents_size);
4022 array_chunk_size = remainder_size - contents_size;
4023 marray = (void**) (chunk2mem(array_chunk));
4024 set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
4025 remainder_size = contents_size;
4026 }
4027
4028 /* split out elements */
4029 for (i = 0; ; ++i) {
4030 marray[i] = chunk2mem(p);
4031 if (i != n_elements-1) {
4032 if (element_size != 0)
4033 size = element_size;
4034 else
4035 size = request2size(sizes[i]);
4036 remainder_size -= size;
4037 set_size_and_pinuse_of_inuse_chunk(m, p, size);
4038 p = chunk_plus_offset(p, size);
4039 }
4040 else { /* the final element absorbs any overallocation slop */
4041 set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
4042 break;
4043 }
4044 }
4045
4046 #if DEBUG
4047 if (marray != chunks) {
4048 /* final element must have exactly exhausted chunk */
4049 if (element_size != 0) {
4050 assert(remainder_size == element_size);
4051 }
4052 else {
4053 assert(remainder_size == request2size(sizes[i]));
4054 }
4055 check_inuse_chunk(m, mem2chunk(marray));
4056 }
4057 for (i = 0; i != n_elements; ++i)
4058 check_inuse_chunk(m, mem2chunk(marray[i]));
4059
4060 #endif /* DEBUG */
4061
4062 POSTACTION(m);
4063 return marray;
4064 } 4137 }
4065 4138
4066 4139
4067 /* -------------------------- public routines ---------------------------- */ 4140 /* -------------------------- public routines ---------------------------- */
4068 4141
4069 #if !ONLY_MSPACES 4142 #if !ONLY_MSPACES
4070 4143
4071 void* dlmalloc(size_t bytes) { 4144 void *
4072 /* 4145 dlmalloc(size_t bytes)
4073 Basic algorithm: 4146 {
4074 If a small request (< 256 bytes minus per-chunk overhead): 4147 /*
4148 Basic algorithm:
4149 If a small request (< 256 bytes minus per-chunk overhead):
4075 1. If one exists, use a remainderless chunk in associated smallbin. 4150 1. If one exists, use a remainderless chunk in associated smallbin.
4076 (Remainderless means that there are too few excess bytes to 4151 (Remainderless means that there are too few excess bytes to
4077 represent as a chunk.) 4152 represent as a chunk.)
4078 2. If it is big enough, use the dv chunk, which is normally the 4153 2. If it is big enough, use the dv chunk, which is normally the
4079 chunk adjacent to the one used for the most recent small request. 4154 chunk adjacent to the one used for the most recent small request.
4080 3. If one exists, split the smallest available chunk in a bin, 4155 3. If one exists, split the smallest available chunk in a bin,
4081 saving remainder in dv. 4156 saving remainder in dv.
4082 4. If it is big enough, use the top chunk. 4157 4. If it is big enough, use the top chunk.
4083 5. If available, get memory from system and use it 4158 5. If available, get memory from system and use it
4084 Otherwise, for a large request: 4159 Otherwise, for a large request:
4085 1. Find the smallest available binned chunk that fits, and use it 4160 1. Find the smallest available binned chunk that fits, and use it
4086 if it is better fitting than dv chunk, splitting if necessary. 4161 if it is better fitting than dv chunk, splitting if necessary.
4087 2. If better fitting than any binned chunk, use the dv chunk. 4162 2. If better fitting than any binned chunk, use the dv chunk.
4088 3. If it is big enough, use the top chunk. 4163 3. If it is big enough, use the top chunk.
4089 4. If request size >= mmap threshold, try to directly mmap this chunk. 4164 4. If request size >= mmap threshold, try to directly mmap this chunk.
4090 5. If available, get memory from system and use it 4165 5. If available, get memory from system and use it
4091 4166
4092 The ugly goto's here ensure that postaction occurs along all paths. 4167 The ugly goto's here ensure that postaction occurs along all paths.
4093 */ 4168 */
4094 4169
4095 if (!PREACTION(gm)) { 4170 if (!PREACTION(gm)) {
4096 void* mem; 4171 void *mem;
4097 size_t nb; 4172 size_t nb;
4098 if (bytes <= MAX_SMALL_REQUEST) { 4173 if (bytes <= MAX_SMALL_REQUEST) {
4099 bindex_t idx; 4174 bindex_t idx;
4100 binmap_t smallbits; 4175 binmap_t smallbits;
4101 nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); 4176 nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes);
4102 idx = small_index(nb); 4177 idx = small_index(nb);
4103 smallbits = gm->smallmap >> idx; 4178 smallbits = gm->smallmap >> idx;
4104 4179
4105 if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ 4180 if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
4106 mchunkptr b, p; 4181 mchunkptr b, p;
4107 idx += ~smallbits & 1; /* Uses next bin if idx empty */ 4182 idx += ~smallbits & 1; /* Uses next bin if idx empty */
4108 b = smallbin_at(gm, idx); 4183 b = smallbin_at(gm, idx);
4109 p = b->fd; 4184 p = b->fd;
4110 assert(chunksize(p) == small_index2size(idx)); 4185 assert(chunksize(p) == small_index2size(idx));
4111 unlink_first_small_chunk(gm, b, p, idx); 4186 unlink_first_small_chunk(gm, b, p, idx);
4112 set_inuse_and_pinuse(gm, p, small_index2size(idx)); 4187 set_inuse_and_pinuse(gm, p, small_index2size(idx));
4113 mem = chunk2mem(p); 4188 mem = chunk2mem(p);
4114 check_malloced_chunk(gm, mem, nb); 4189 check_malloced_chunk(gm, mem, nb);
4115 goto postaction; 4190 goto postaction;
4116 } 4191 }
4117 4192
4118 else if (nb > gm->dvsize) { 4193 else if (nb > gm->dvsize) {
4119 if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ 4194 if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
4120 mchunkptr b, p, r; 4195 mchunkptr b, p, r;
4121 size_t rsize; 4196 size_t rsize;
4122 bindex_t i; 4197 bindex_t i;
4123 binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); 4198 binmap_t leftbits =
4124 binmap_t leastbit = least_bit(leftbits); 4199 (smallbits << idx) & left_bits(idx2bit(idx));
4125 compute_bit2idx(leastbit, i); 4200 binmap_t leastbit = least_bit(leftbits);
4126 b = smallbin_at(gm, i); 4201 compute_bit2idx(leastbit, i);
4127 p = b->fd; 4202 b = smallbin_at(gm, i);
4128 assert(chunksize(p) == small_index2size(i)); 4203 p = b->fd;
4129 unlink_first_small_chunk(gm, b, p, i); 4204 assert(chunksize(p) == small_index2size(i));
4130 rsize = small_index2size(i) - nb; 4205 unlink_first_small_chunk(gm, b, p, i);
4131 /* Fit here cannot be remainderless if 4byte sizes */ 4206 rsize = small_index2size(i) - nb;
4132 if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) 4207 /* Fit here cannot be remainderless if 4byte sizes */
4133 set_inuse_and_pinuse(gm, p, small_index2size(i)); 4208 if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
4134 else { 4209 set_inuse_and_pinuse(gm, p, small_index2size(i));
4210 else {
4211 set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
4212 r = chunk_plus_offset(p, nb);
4213 set_size_and_pinuse_of_free_chunk(r, rsize);
4214 replace_dv(gm, r, rsize);
4215 }
4216 mem = chunk2mem(p);
4217 check_malloced_chunk(gm, mem, nb);
4218 goto postaction;
4219 }
4220
4221 else if (gm->treemap != 0
4222 && (mem = tmalloc_small(gm, nb)) != 0) {
4223 check_malloced_chunk(gm, mem, nb);
4224 goto postaction;
4225 }
4226 }
4227 } else if (bytes >= MAX_REQUEST)
4228 nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
4229 else {
4230 nb = pad_request(bytes);
4231 if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
4232 check_malloced_chunk(gm, mem, nb);
4233 goto postaction;
4234 }
4235 }
4236
4237 if (nb <= gm->dvsize) {
4238 size_t rsize = gm->dvsize - nb;
4239 mchunkptr p = gm->dv;
4240 if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
4241 mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
4242 gm->dvsize = rsize;
4243 set_size_and_pinuse_of_free_chunk(r, rsize);
4244 set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
4245 } else { /* exhaust dv */
4246 size_t dvs = gm->dvsize;
4247 gm->dvsize = 0;
4248 gm->dv = 0;
4249 set_inuse_and_pinuse(gm, p, dvs);
4250 }
4251 mem = chunk2mem(p);
4252 check_malloced_chunk(gm, mem, nb);
4253 goto postaction;
4254 }
4255
4256 else if (nb < gm->topsize) { /* Split top */
4257 size_t rsize = gm->topsize -= nb;
4258 mchunkptr p = gm->top;
4259 mchunkptr r = gm->top = chunk_plus_offset(p, nb);
4260 r->head = rsize | PINUSE_BIT;
4135 set_size_and_pinuse_of_inuse_chunk(gm, p, nb); 4261 set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
4136 r = chunk_plus_offset(p, nb); 4262 mem = chunk2mem(p);
4137 set_size_and_pinuse_of_free_chunk(r, rsize); 4263 check_top_chunk(gm, gm->top);
4138 replace_dv(gm, r, rsize); 4264 check_malloced_chunk(gm, mem, nb);
4139 } 4265 goto postaction;
4140 mem = chunk2mem(p);
4141 check_malloced_chunk(gm, mem, nb);
4142 goto postaction;
4143 } 4266 }
4144 4267
4145 else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { 4268 mem = sys_alloc(gm, nb);
4146 check_malloced_chunk(gm, mem, nb); 4269
4147 goto postaction; 4270 postaction:
4271 POSTACTION(gm);
4272 return mem;
4273 }
4274
4275 return 0;
4276 }
4277
4278 void
4279 dlfree(void *mem)
4280 {
4281 /*
4282 Consolidate freed chunks with preceeding or succeeding bordering
4283 free chunks, if they exist, and then place in a bin. Intermixed
4284 with special cases for top, dv, mmapped chunks, and usage errors.
4285 */
4286
4287 if (mem != 0) {
4288 mchunkptr p = mem2chunk(mem);
4289 #if FOOTERS
4290 mstate fm = get_mstate_for(p);
4291 if (!ok_magic(fm)) {
4292 USAGE_ERROR_ACTION(fm, p);
4293 return;
4148 } 4294 }
4149 }
4150 }
4151 else if (bytes >= MAX_REQUEST)
4152 nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
4153 else {
4154 nb = pad_request(bytes);
4155 if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
4156 check_malloced_chunk(gm, mem, nb);
4157 goto postaction;
4158 }
4159 }
4160
4161 if (nb <= gm->dvsize) {
4162 size_t rsize = gm->dvsize - nb;
4163 mchunkptr p = gm->dv;
4164 if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
4165 mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
4166 gm->dvsize = rsize;
4167 set_size_and_pinuse_of_free_chunk(r, rsize);
4168 set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
4169 }
4170 else { /* exhaust dv */
4171 size_t dvs = gm->dvsize;
4172 gm->dvsize = 0;
4173 gm->dv = 0;
4174 set_inuse_and_pinuse(gm, p, dvs);
4175 }
4176 mem = chunk2mem(p);
4177 check_malloced_chunk(gm, mem, nb);
4178 goto postaction;
4179 }
4180
4181 else if (nb < gm->topsize) { /* Split top */
4182 size_t rsize = gm->topsize -= nb;
4183 mchunkptr p = gm->top;
4184 mchunkptr r = gm->top = chunk_plus_offset(p, nb);
4185 r->head = rsize | PINUSE_BIT;
4186 set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
4187 mem = chunk2mem(p);
4188 check_top_chunk(gm, gm->top);
4189 check_malloced_chunk(gm, mem, nb);
4190 goto postaction;
4191 }
4192
4193 mem = sys_alloc(gm, nb);
4194
4195 postaction:
4196 POSTACTION(gm);
4197 return mem;
4198 }
4199
4200 return 0;
4201 }
4202
4203 void dlfree(void* mem) {
4204 /*
4205 Consolidate freed chunks with preceeding or succeeding bordering
4206 free chunks, if they exist, and then place in a bin. Intermixed
4207 with special cases for top, dv, mmapped chunks, and usage errors.
4208 */
4209
4210 if (mem != 0) {
4211 mchunkptr p = mem2chunk(mem);
4212 #if FOOTERS
4213 mstate fm = get_mstate_for(p);
4214 if (!ok_magic(fm)) {
4215 USAGE_ERROR_ACTION(fm, p);
4216 return;
4217 }
4218 #else /* FOOTERS */ 4295 #else /* FOOTERS */
4219 #define fm gm 4296 #define fm gm
4220 #endif /* FOOTERS */ 4297 #endif /* FOOTERS */
4221 if (!PREACTION(fm)) { 4298 if (!PREACTION(fm)) {
4222 check_inuse_chunk(fm, p); 4299 check_inuse_chunk(fm, p);
4223 if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) { 4300 if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
4224 size_t psize = chunksize(p); 4301 size_t psize = chunksize(p);
4225 mchunkptr next = chunk_plus_offset(p, psize); 4302 mchunkptr next = chunk_plus_offset(p, psize);
4226 if (!pinuse(p)) { 4303 if (!pinuse(p)) {
4227 size_t prevsize = p->prev_foot; 4304 size_t prevsize = p->prev_foot;
4228 if ((prevsize & IS_MMAPPED_BIT) != 0) { 4305 if ((prevsize & IS_MMAPPED_BIT) != 0) {
4229 prevsize &= ~IS_MMAPPED_BIT; 4306 prevsize &= ~IS_MMAPPED_BIT;
4230 psize += prevsize + MMAP_FOOT_PAD; 4307 psize += prevsize + MMAP_FOOT_PAD;
4231 if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) 4308 if (CALL_MUNMAP((char *) p - prevsize, psize) == 0)
4232 fm->footprint -= psize; 4309 fm->footprint -= psize;
4233 goto postaction; 4310 goto postaction;
4234 } 4311 } else {
4235 else { 4312 mchunkptr prev = chunk_minus_offset(p, prevsize);
4236 mchunkptr prev = chunk_minus_offset(p, prevsize); 4313 psize += prevsize;
4237 psize += prevsize; 4314 p = prev;
4238 p = prev; 4315 if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
4239 if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ 4316 if (p != fm->dv) {
4240 if (p != fm->dv) { 4317 unlink_chunk(fm, p, prevsize);
4241 unlink_chunk(fm, p, prevsize); 4318 } else if ((next->head & INUSE_BITS) ==
4242 } 4319 INUSE_BITS) {
4243 else if ((next->head & INUSE_BITS) == INUSE_BITS) { 4320 fm->dvsize = psize;
4244 fm->dvsize = psize; 4321 set_free_with_pinuse(p, psize, next);
4245 set_free_with_pinuse(p, psize, next); 4322 goto postaction;
4246 goto postaction; 4323 }
4247 } 4324 } else
4325 goto erroraction;
4326 }
4327 }
4328
4329 if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
4330 if (!cinuse(next)) { /* consolidate forward */
4331 if (next == fm->top) {
4332 size_t tsize = fm->topsize += psize;
4333 fm->top = p;
4334 p->head = tsize | PINUSE_BIT;
4335 if (p == fm->dv) {
4336 fm->dv = 0;
4337 fm->dvsize = 0;
4338 }
4339 if (should_trim(fm, tsize))
4340 sys_trim(fm, 0);
4341 goto postaction;
4342 } else if (next == fm->dv) {
4343 size_t dsize = fm->dvsize += psize;
4344 fm->dv = p;
4345 set_size_and_pinuse_of_free_chunk(p, dsize);
4346 goto postaction;
4347 } else {
4348 size_t nsize = chunksize(next);
4349 psize += nsize;
4350 unlink_chunk(fm, next, nsize);
4351 set_size_and_pinuse_of_free_chunk(p, psize);
4352 if (p == fm->dv) {
4353 fm->dvsize = psize;
4354 goto postaction;
4355 }
4356 }
4357 } else
4358 set_free_with_pinuse(p, psize, next);
4359 insert_chunk(fm, p, psize);
4360 check_free_chunk(fm, p);
4361 goto postaction;
4362 }
4248 } 4363 }
4249 else 4364 erroraction:
4250 goto erroraction; 4365 USAGE_ERROR_ACTION(fm, p);
4251 } 4366 postaction:
4367 POSTACTION(fm);
4252 } 4368 }
4253 4369 }
4254 if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
4255 if (!cinuse(next)) { /* consolidate forward */
4256 if (next == fm->top) {
4257 size_t tsize = fm->topsize += psize;
4258 fm->top = p;
4259 p->head = tsize | PINUSE_BIT;
4260 if (p == fm->dv) {
4261 fm->dv = 0;
4262 fm->dvsize = 0;
4263 }
4264 if (should_trim(fm, tsize))
4265 sys_trim(fm, 0);
4266 goto postaction;
4267 }
4268 else if (next == fm->dv) {
4269 size_t dsize = fm->dvsize += psize;
4270 fm->dv = p;
4271 set_size_and_pinuse_of_free_chunk(p, dsize);
4272 goto postaction;
4273 }
4274 else {
4275 size_t nsize = chunksize(next);
4276 psize += nsize;
4277 unlink_chunk(fm, next, nsize);
4278 set_size_and_pinuse_of_free_chunk(p, psize);
4279 if (p == fm->dv) {
4280 fm->dvsize = psize;
4281 goto postaction;
4282 }
4283 }
4284 }
4285 else
4286 set_free_with_pinuse(p, psize, next);
4287 insert_chunk(fm, p, psize);
4288 check_free_chunk(fm, p);
4289 goto postaction;
4290 }
4291 }
4292 erroraction:
4293 USAGE_ERROR_ACTION(fm, p);
4294 postaction:
4295 POSTACTION(fm);
4296 }
4297 }
4298 #if !FOOTERS 4370 #if !FOOTERS
4299 #undef fm 4371 #undef fm
4300 #endif /* FOOTERS */ 4372 #endif /* FOOTERS */
4301 } 4373 }
4302 4374
4303 void* dlcalloc(size_t n_elements, size_t elem_size) { 4375 void *
4304 void* mem; 4376 dlcalloc(size_t n_elements, size_t elem_size)
4305 size_t req = 0; 4377 {
4306 if (n_elements != 0) { 4378 void *mem;
4307 req = n_elements * elem_size; 4379 size_t req = 0;
4308 if (((n_elements | elem_size) & ~(size_t)0xffff) && 4380 if (n_elements != 0) {
4309 (req / n_elements != elem_size)) 4381 req = n_elements * elem_size;
4310 req = MAX_SIZE_T; /* force downstream failure on overflow */ 4382 if (((n_elements | elem_size) & ~(size_t) 0xffff) &&
4311 } 4383 (req / n_elements != elem_size))
4312 mem = dlmalloc(req); 4384 req = MAX_SIZE_T; /* force downstream failure on overflow */
4313 if (mem != 0 && calloc_must_clear(mem2chunk(mem))) 4385 }
4314 memset(mem, 0, req); 4386 mem = dlmalloc(req);
4315 return mem; 4387 if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
4316 } 4388 memset(mem, 0, req);
4317 4389 return mem;
4318 void* dlrealloc(void* oldmem, size_t bytes) { 4390 }
4319 if (oldmem == 0) 4391
4320 return dlmalloc(bytes); 4392 void *
4393 dlrealloc(void *oldmem, size_t bytes)
4394 {
4395 if (oldmem == 0)
4396 return dlmalloc(bytes);
4321 #ifdef REALLOC_ZERO_BYTES_FREES 4397 #ifdef REALLOC_ZERO_BYTES_FREES
4322 if (bytes == 0) { 4398 if (bytes == 0) {
4323 dlfree(oldmem); 4399 dlfree(oldmem);
4400 return 0;
4401 }
4402 #endif /* REALLOC_ZERO_BYTES_FREES */
4403 else {
4404 #if ! FOOTERS
4405 mstate m = gm;
4406 #else /* FOOTERS */
4407 mstate m = get_mstate_for(mem2chunk(oldmem));
4408 if (!ok_magic(m)) {
4409 USAGE_ERROR_ACTION(m, oldmem);
4410 return 0;
4411 }
4412 #endif /* FOOTERS */
4413 return internal_realloc(m, oldmem, bytes);
4414 }
4415 }
4416
4417 void *
4418 dlmemalign(size_t alignment, size_t bytes)
4419 {
4420 return internal_memalign(gm, alignment, bytes);
4421 }
4422
4423 void **
4424 dlindependent_calloc(size_t n_elements, size_t elem_size, void *chunks[])
4425 {
4426 size_t sz = elem_size; /* serves as 1-element array */
4427 return ialloc(gm, n_elements, &sz, 3, chunks);
4428 }
4429
4430 void **
4431 dlindependent_comalloc(size_t n_elements, size_t sizes[], void *chunks[])
4432 {
4433 return ialloc(gm, n_elements, sizes, 0, chunks);
4434 }
4435
4436 void *
4437 dlvalloc(size_t bytes)
4438 {
4439 size_t pagesz;
4440 init_mparams();
4441 pagesz = mparams.page_size;
4442 return dlmemalign(pagesz, bytes);
4443 }
4444
4445 void *
4446 dlpvalloc(size_t bytes)
4447 {
4448 size_t pagesz;
4449 init_mparams();
4450 pagesz = mparams.page_size;
4451 return dlmemalign(pagesz,
4452 (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
4453 }
4454
4455 int
4456 dlmalloc_trim(size_t pad)
4457 {
4458 int result = 0;
4459 if (!PREACTION(gm)) {
4460 result = sys_trim(gm, pad);
4461 POSTACTION(gm);
4462 }
4463 return result;
4464 }
4465
4466 size_t
4467 dlmalloc_footprint(void)
4468 {
4469 return gm->footprint;
4470 }
4471
4472 size_t
4473 dlmalloc_max_footprint(void)
4474 {
4475 return gm->max_footprint;
4476 }
4477
4478 #if !NO_MALLINFO
4479 struct mallinfo
4480 dlmallinfo(void)
4481 {
4482 return internal_mallinfo(gm);
4483 }
4484 #endif /* NO_MALLINFO */
4485
4486 void
4487 dlmalloc_stats()
4488 {
4489 internal_malloc_stats(gm);
4490 }
4491
4492 size_t
4493 dlmalloc_usable_size(void *mem)
4494 {
4495 if (mem != 0) {
4496 mchunkptr p = mem2chunk(mem);
4497 if (cinuse(p))
4498 return chunksize(p) - overhead_for(p);
4499 }
4324 return 0; 4500 return 0;
4325 } 4501 }
4326 #endif /* REALLOC_ZERO_BYTES_FREES */ 4502
4327 else { 4503 int
4328 #if ! FOOTERS 4504 dlmallopt(int param_number, int value)
4329 mstate m = gm; 4505 {
4330 #else /* FOOTERS */ 4506 return change_mparam(param_number, value);
4331 mstate m = get_mstate_for(mem2chunk(oldmem));
4332 if (!ok_magic(m)) {
4333 USAGE_ERROR_ACTION(m, oldmem);
4334 return 0;
4335 }
4336 #endif /* FOOTERS */
4337 return internal_realloc(m, oldmem, bytes);
4338 }
4339 }
4340
4341 void* dlmemalign(size_t alignment, size_t bytes) {
4342 return internal_memalign(gm, alignment, bytes);
4343 }
4344
4345 void** dlindependent_calloc(size_t n_elements, size_t elem_size,
4346 void* chunks[]) {
4347 size_t sz = elem_size; /* serves as 1-element array */
4348 return ialloc(gm, n_elements, &sz, 3, chunks);
4349 }
4350
4351 void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
4352 void* chunks[]) {
4353 return ialloc(gm, n_elements, sizes, 0, chunks);
4354 }
4355
4356 void* dlvalloc(size_t bytes) {
4357 size_t pagesz;
4358 init_mparams();
4359 pagesz = mparams.page_size;
4360 return dlmemalign(pagesz, bytes);
4361 }
4362
4363 void* dlpvalloc(size_t bytes) {
4364 size_t pagesz;
4365 init_mparams();
4366 pagesz = mparams.page_size;
4367 return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
4368 }
4369
4370 int dlmalloc_trim(size_t pad) {
4371 int result = 0;
4372 if (!PREACTION(gm)) {
4373 result = sys_trim(gm, pad);
4374 POSTACTION(gm);
4375 }
4376 return result;
4377 }
4378
4379 size_t dlmalloc_footprint(void) {
4380 return gm->footprint;
4381 }
4382
4383 size_t dlmalloc_max_footprint(void) {
4384 return gm->max_footprint;
4385 }
4386
4387 #if !NO_MALLINFO
4388 struct mallinfo dlmallinfo(void) {
4389 return internal_mallinfo(gm);
4390 }
4391 #endif /* NO_MALLINFO */
4392
4393 void dlmalloc_stats() {
4394 internal_malloc_stats(gm);
4395 }
4396
4397 size_t dlmalloc_usable_size(void* mem) {
4398 if (mem != 0) {
4399 mchunkptr p = mem2chunk(mem);
4400 if (cinuse(p))
4401 return chunksize(p) - overhead_for(p);
4402 }
4403 return 0;
4404 }
4405
4406 int dlmallopt(int param_number, int value) {
4407 return change_mparam(param_number, value);
4408 } 4507 }
4409 4508
4410 #endif /* !ONLY_MSPACES */ 4509 #endif /* !ONLY_MSPACES */
4411 4510
4412 /* ----------------------------- user mspaces ---------------------------- */ 4511 /* ----------------------------- user mspaces ---------------------------- */
4413 4512
4414 #if MSPACES 4513 #if MSPACES
4415 4514
4416 static mstate init_user_mstate(char* tbase, size_t tsize) { 4515 static mstate
4417 size_t msize = pad_request(sizeof(struct malloc_state)); 4516 init_user_mstate(char *tbase, size_t tsize)
4418 mchunkptr mn; 4517 {
4419 mchunkptr msp = align_as_chunk(tbase); 4518 size_t msize = pad_request(sizeof(struct malloc_state));
4420 mstate m = (mstate)(chunk2mem(msp)); 4519 mchunkptr mn;
4421 memset(m, 0, msize); 4520 mchunkptr msp = align_as_chunk(tbase);
4422 INITIAL_LOCK(&m->mutex); 4521 mstate m = (mstate) (chunk2mem(msp));
4423 msp->head = (msize|PINUSE_BIT|CINUSE_BIT); 4522 memset(m, 0, msize);
4424 m->seg.base = m->least_addr = tbase; 4523 INITIAL_LOCK(&m->mutex);
4425 m->seg.size = m->footprint = m->max_footprint = tsize; 4524 msp->head = (msize | PINUSE_BIT | CINUSE_BIT);
4426 m->magic = mparams.magic; 4525 m->seg.base = m->least_addr = tbase;
4427 m->mflags = mparams.default_mflags; 4526 m->seg.size = m->footprint = m->max_footprint = tsize;
4428 disable_contiguous(m); 4527 m->magic = mparams.magic;
4429 init_bins(m); 4528 m->mflags = mparams.default_mflags;
4430 mn = next_chunk(mem2chunk(m)); 4529 disable_contiguous(m);
4431 init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); 4530 init_bins(m);
4432 check_top_chunk(m, m->top); 4531 mn = next_chunk(mem2chunk(m));
4433 return m; 4532 init_top(m, mn, (size_t) ((tbase + tsize) - (char *) mn) - TOP_FOOT_SIZE);
4434 } 4533 check_top_chunk(m, m->top);
4435 4534 return m;
4436 mspace create_mspace(size_t capacity, int locked) { 4535 }
4437 mstate m = 0; 4536
4438 size_t msize = pad_request(sizeof(struct malloc_state)); 4537 mspace
4439 init_mparams(); /* Ensure pagesize etc initialized */ 4538 create_mspace(size_t capacity, int locked)
4440 4539 {
4441 if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { 4540 mstate m = 0;
4442 size_t rs = ((capacity == 0)? mparams.granularity : 4541 size_t msize = pad_request(sizeof(struct malloc_state));
4443 (capacity + TOP_FOOT_SIZE + msize)); 4542 init_mparams(); /* Ensure pagesize etc initialized */
4444 size_t tsize = granularity_align(rs); 4543
4445 char* tbase = (char*)(CALL_MMAP(tsize)); 4544 if (capacity < (size_t) - (msize + TOP_FOOT_SIZE + mparams.page_size)) {
4446 if (tbase != CMFAIL) { 4545 size_t rs = ((capacity == 0) ? mparams.granularity :
4447 m = init_user_mstate(tbase, tsize); 4546 (capacity + TOP_FOOT_SIZE + msize));
4448 m->seg.sflags = IS_MMAPPED_BIT; 4547 size_t tsize = granularity_align(rs);
4449 set_lock(m, locked); 4548 char *tbase = (char *) (CALL_MMAP(tsize));
4450 } 4549 if (tbase != CMFAIL) {
4451 } 4550 m = init_user_mstate(tbase, tsize);
4452 return (mspace)m; 4551 m->seg.sflags = IS_MMAPPED_BIT;
4453 } 4552 set_lock(m, locked);
4454 4553 }
4455 mspace create_mspace_with_base(void* base, size_t capacity, int locked) { 4554 }
4456 mstate m = 0; 4555 return (mspace) m;
4457 size_t msize = pad_request(sizeof(struct malloc_state)); 4556 }
4458 init_mparams(); /* Ensure pagesize etc initialized */ 4557
4459 4558 mspace
4460 if (capacity > msize + TOP_FOOT_SIZE && 4559 create_mspace_with_base(void *base, size_t capacity, int locked)
4461 capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { 4560 {
4462 m = init_user_mstate((char*)base, capacity); 4561 mstate m = 0;
4463 m->seg.sflags = EXTERN_BIT; 4562 size_t msize = pad_request(sizeof(struct malloc_state));
4464 set_lock(m, locked); 4563 init_mparams(); /* Ensure pagesize etc initialized */
4465 } 4564
4466 return (mspace)m; 4565 if (capacity > msize + TOP_FOOT_SIZE &&
4467 } 4566 capacity < (size_t) - (msize + TOP_FOOT_SIZE + mparams.page_size)) {
4468 4567 m = init_user_mstate((char *) base, capacity);
4469 size_t destroy_mspace(mspace msp) { 4568 m->seg.sflags = EXTERN_BIT;
4470 size_t freed = 0; 4569 set_lock(m, locked);
4471 mstate ms = (mstate)msp; 4570 }
4472 if (ok_magic(ms)) { 4571 return (mspace) m;
4473 msegmentptr sp = &ms->seg; 4572 }
4474 while (sp != 0) { 4573
4475 char* base = sp->base; 4574 size_t
4476 size_t size = sp->size; 4575 destroy_mspace(mspace msp)
4477 flag_t flag = sp->sflags; 4576 {
4478 sp = sp->next; 4577 size_t freed = 0;
4479 if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) && 4578 mstate ms = (mstate) msp;
4480 CALL_MUNMAP(base, size) == 0) 4579 if (ok_magic(ms)) {
4481 freed += size; 4580 msegmentptr sp = &ms->seg;
4482 } 4581 while (sp != 0) {
4483 } 4582 char *base = sp->base;
4484 else { 4583 size_t size = sp->size;
4485 USAGE_ERROR_ACTION(ms,ms); 4584 flag_t flag = sp->sflags;
4486 } 4585 sp = sp->next;
4487 return freed; 4586 if ((flag & IS_MMAPPED_BIT) && !(flag & EXTERN_BIT) &&
4587 CALL_MUNMAP(base, size) == 0)
4588 freed += size;
4589 }
4590 } else {
4591 USAGE_ERROR_ACTION(ms, ms);
4592 }
4593 return freed;
4488 } 4594 }
4489 4595
4490 /* 4596 /*
4491 mspace versions of routines are near-clones of the global 4597 mspace versions of routines are near-clones of the global
4492 versions. This is not so nice but better than the alternatives. 4598 versions. This is not so nice but better than the alternatives.
4493 */ 4599 */
4494 4600
4495 4601
4496 void* mspace_malloc(mspace msp, size_t bytes) { 4602 void *
4497 mstate ms = (mstate)msp; 4603 mspace_malloc(mspace msp, size_t bytes)
4498 if (!ok_magic(ms)) { 4604 {
4499 USAGE_ERROR_ACTION(ms,ms); 4605 mstate ms = (mstate) msp;
4606 if (!ok_magic(ms)) {
4607 USAGE_ERROR_ACTION(ms, ms);
4608 return 0;
4609 }
4610 if (!PREACTION(ms)) {
4611 void *mem;
4612 size_t nb;
4613 if (bytes <= MAX_SMALL_REQUEST) {
4614 bindex_t idx;
4615 binmap_t smallbits;
4616 nb = (bytes < MIN_REQUEST) ? MIN_CHUNK_SIZE : pad_request(bytes);
4617 idx = small_index(nb);
4618 smallbits = ms->smallmap >> idx;
4619
4620 if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
4621 mchunkptr b, p;
4622 idx += ~smallbits & 1; /* Uses next bin if idx empty */
4623 b = smallbin_at(ms, idx);
4624 p = b->fd;
4625 assert(chunksize(p) == small_index2size(idx));
4626 unlink_first_small_chunk(ms, b, p, idx);
4627 set_inuse_and_pinuse(ms, p, small_index2size(idx));
4628 mem = chunk2mem(p);
4629 check_malloced_chunk(ms, mem, nb);
4630 goto postaction;
4631 }
4632
4633 else if (nb > ms->dvsize) {
4634 if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
4635 mchunkptr b, p, r;
4636 size_t rsize;
4637 bindex_t i;
4638 binmap_t leftbits =
4639 (smallbits << idx) & left_bits(idx2bit(idx));
4640 binmap_t leastbit = least_bit(leftbits);
4641 compute_bit2idx(leastbit, i);
4642 b = smallbin_at(ms, i);
4643 p = b->fd;
4644 assert(chunksize(p) == small_index2size(i));
4645 unlink_first_small_chunk(ms, b, p, i);
4646 rsize = small_index2size(i) - nb;
4647 /* Fit here cannot be remainderless if 4byte sizes */
4648 if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
4649 set_inuse_and_pinuse(ms, p, small_index2size(i));
4650 else {
4651 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4652 r = chunk_plus_offset(p, nb);
4653 set_size_and_pinuse_of_free_chunk(r, rsize);
4654 replace_dv(ms, r, rsize);
4655 }
4656 mem = chunk2mem(p);
4657 check_malloced_chunk(ms, mem, nb);
4658 goto postaction;
4659 }
4660
4661 else if (ms->treemap != 0
4662 && (mem = tmalloc_small(ms, nb)) != 0) {
4663 check_malloced_chunk(ms, mem, nb);
4664 goto postaction;
4665 }
4666 }
4667 } else if (bytes >= MAX_REQUEST)
4668 nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
4669 else {
4670 nb = pad_request(bytes);
4671 if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
4672 check_malloced_chunk(ms, mem, nb);
4673 goto postaction;
4674 }
4675 }
4676
4677 if (nb <= ms->dvsize) {
4678 size_t rsize = ms->dvsize - nb;
4679 mchunkptr p = ms->dv;
4680 if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
4681 mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
4682 ms->dvsize = rsize;
4683 set_size_and_pinuse_of_free_chunk(r, rsize);
4684 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4685 } else { /* exhaust dv */
4686 size_t dvs = ms->dvsize;
4687 ms->dvsize = 0;
4688 ms->dv = 0;
4689 set_inuse_and_pinuse(ms, p, dvs);
4690 }
4691 mem = chunk2mem(p);
4692 check_malloced_chunk(ms, mem, nb);
4693 goto postaction;
4694 }
4695
4696 else if (nb < ms->topsize) { /* Split top */
4697 size_t rsize = ms->topsize -= nb;
4698 mchunkptr p = ms->top;
4699 mchunkptr r = ms->top = chunk_plus_offset(p, nb);
4700 r->head = rsize | PINUSE_BIT;
4701 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4702 mem = chunk2mem(p);
4703 check_top_chunk(ms, ms->top);
4704 check_malloced_chunk(ms, mem, nb);
4705 goto postaction;
4706 }
4707
4708 mem = sys_alloc(ms, nb);
4709
4710 postaction:
4711 POSTACTION(ms);
4712 return mem;
4713 }
4714
4500 return 0; 4715 return 0;
4501 } 4716 }
4502 if (!PREACTION(ms)) { 4717
4503 void* mem; 4718 void
4504 size_t nb; 4719 mspace_free(mspace msp, void *mem)
4505 if (bytes <= MAX_SMALL_REQUEST) { 4720 {
4506 bindex_t idx; 4721 if (mem != 0) {
4507 binmap_t smallbits; 4722 mchunkptr p = mem2chunk(mem);
4508 nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); 4723 #if FOOTERS
4509 idx = small_index(nb); 4724 mstate fm = get_mstate_for(p);
4510 smallbits = ms->smallmap >> idx; 4725 #else /* FOOTERS */
4511 4726 mstate fm = (mstate) msp;
4512 if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ 4727 #endif /* FOOTERS */
4513 mchunkptr b, p; 4728 if (!ok_magic(fm)) {
4514 idx += ~smallbits & 1; /* Uses next bin if idx empty */ 4729 USAGE_ERROR_ACTION(fm, p);
4515 b = smallbin_at(ms, idx); 4730 return;
4516 p = b->fd;
4517 assert(chunksize(p) == small_index2size(idx));
4518 unlink_first_small_chunk(ms, b, p, idx);
4519 set_inuse_and_pinuse(ms, p, small_index2size(idx));
4520 mem = chunk2mem(p);
4521 check_malloced_chunk(ms, mem, nb);
4522 goto postaction;
4523 }
4524
4525 else if (nb > ms->dvsize) {
4526 if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
4527 mchunkptr b, p, r;
4528 size_t rsize;
4529 bindex_t i;
4530 binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
4531 binmap_t leastbit = least_bit(leftbits);
4532 compute_bit2idx(leastbit, i);
4533 b = smallbin_at(ms, i);
4534 p = b->fd;
4535 assert(chunksize(p) == small_index2size(i));
4536 unlink_first_small_chunk(ms, b, p, i);
4537 rsize = small_index2size(i) - nb;
4538 /* Fit here cannot be remainderless if 4byte sizes */
4539 if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
4540 set_inuse_and_pinuse(ms, p, small_index2size(i));
4541 else {
4542 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4543 r = chunk_plus_offset(p, nb);
4544 set_size_and_pinuse_of_free_chunk(r, rsize);
4545 replace_dv(ms, r, rsize);
4546 }
4547 mem = chunk2mem(p);
4548 check_malloced_chunk(ms, mem, nb);
4549 goto postaction;
4550 } 4731 }
4551 4732 if (!PREACTION(fm)) {
4552 else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { 4733 check_inuse_chunk(fm, p);
4553 check_malloced_chunk(ms, mem, nb); 4734 if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
4554 goto postaction; 4735 size_t psize = chunksize(p);
4736 mchunkptr next = chunk_plus_offset(p, psize);
4737 if (!pinuse(p)) {
4738 size_t prevsize = p->prev_foot;
4739 if ((prevsize & IS_MMAPPED_BIT) != 0) {
4740 prevsize &= ~IS_MMAPPED_BIT;
4741 psize += prevsize + MMAP_FOOT_PAD;
4742 if (CALL_MUNMAP((char *) p - prevsize, psize) == 0)
4743 fm->footprint -= psize;
4744 goto postaction;
4745 } else {
4746 mchunkptr prev = chunk_minus_offset(p, prevsize);
4747 psize += prevsize;
4748 p = prev;
4749 if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
4750 if (p != fm->dv) {
4751 unlink_chunk(fm, p, prevsize);
4752 } else if ((next->head & INUSE_BITS) ==
4753 INUSE_BITS) {
4754 fm->dvsize = psize;
4755 set_free_with_pinuse(p, psize, next);
4756 goto postaction;
4757 }
4758 } else
4759 goto erroraction;
4760 }
4761 }
4762
4763 if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
4764 if (!cinuse(next)) { /* consolidate forward */
4765 if (next == fm->top) {
4766 size_t tsize = fm->topsize += psize;
4767 fm->top = p;
4768 p->head = tsize | PINUSE_BIT;
4769 if (p == fm->dv) {
4770 fm->dv = 0;
4771 fm->dvsize = 0;
4772 }
4773 if (should_trim(fm, tsize))
4774 sys_trim(fm, 0);
4775 goto postaction;
4776 } else if (next == fm->dv) {
4777 size_t dsize = fm->dvsize += psize;
4778 fm->dv = p;
4779 set_size_and_pinuse_of_free_chunk(p, dsize);
4780 goto postaction;
4781 } else {
4782 size_t nsize = chunksize(next);
4783 psize += nsize;
4784 unlink_chunk(fm, next, nsize);
4785 set_size_and_pinuse_of_free_chunk(p, psize);
4786 if (p == fm->dv) {
4787 fm->dvsize = psize;
4788 goto postaction;
4789 }
4790 }
4791 } else
4792 set_free_with_pinuse(p, psize, next);
4793 insert_chunk(fm, p, psize);
4794 check_free_chunk(fm, p);
4795 goto postaction;
4796 }
4797 }
4798 erroraction:
4799 USAGE_ERROR_ACTION(fm, p);
4800 postaction:
4801 POSTACTION(fm);
4555 } 4802 }
4556 } 4803 }
4557 } 4804 }
4558 else if (bytes >= MAX_REQUEST) 4805
4559 nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ 4806 void *
4807 mspace_calloc(mspace msp, size_t n_elements, size_t elem_size)
4808 {
4809 void *mem;
4810 size_t req = 0;
4811 mstate ms = (mstate) msp;
4812 if (!ok_magic(ms)) {
4813 USAGE_ERROR_ACTION(ms, ms);
4814 return 0;
4815 }
4816 if (n_elements != 0) {
4817 req = n_elements * elem_size;
4818 if (((n_elements | elem_size) & ~(size_t) 0xffff) &&
4819 (req / n_elements != elem_size))
4820 req = MAX_SIZE_T; /* force downstream failure on overflow */
4821 }
4822 mem = internal_malloc(ms, req);
4823 if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
4824 memset(mem, 0, req);
4825 return mem;
4826 }
4827
4828 void *
4829 mspace_realloc(mspace msp, void *oldmem, size_t bytes)
4830 {
4831 if (oldmem == 0)
4832 return mspace_malloc(msp, bytes);
4833 #ifdef REALLOC_ZERO_BYTES_FREES
4834 if (bytes == 0) {
4835 mspace_free(msp, oldmem);
4836 return 0;
4837 }
4838 #endif /* REALLOC_ZERO_BYTES_FREES */
4560 else { 4839 else {
4561 nb = pad_request(bytes);
4562 if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
4563 check_malloced_chunk(ms, mem, nb);
4564 goto postaction;
4565 }
4566 }
4567
4568 if (nb <= ms->dvsize) {
4569 size_t rsize = ms->dvsize - nb;
4570 mchunkptr p = ms->dv;
4571 if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
4572 mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
4573 ms->dvsize = rsize;
4574 set_size_and_pinuse_of_free_chunk(r, rsize);
4575 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4576 }
4577 else { /* exhaust dv */
4578 size_t dvs = ms->dvsize;
4579 ms->dvsize = 0;
4580 ms->dv = 0;
4581 set_inuse_and_pinuse(ms, p, dvs);
4582 }
4583 mem = chunk2mem(p);
4584 check_malloced_chunk(ms, mem, nb);
4585 goto postaction;
4586 }
4587
4588 else if (nb < ms->topsize) { /* Split top */
4589 size_t rsize = ms->topsize -= nb;
4590 mchunkptr p = ms->top;
4591 mchunkptr r = ms->top = chunk_plus_offset(p, nb);
4592 r->head = rsize | PINUSE_BIT;
4593 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4594 mem = chunk2mem(p);
4595 check_top_chunk(ms, ms->top);
4596 check_malloced_chunk(ms, mem, nb);
4597 goto postaction;
4598 }
4599
4600 mem = sys_alloc(ms, nb);
4601
4602 postaction:
4603 POSTACTION(ms);
4604 return mem;
4605 }
4606
4607 return 0;
4608 }
4609
4610 void mspace_free(mspace msp, void* mem) {
4611 if (mem != 0) {
4612 mchunkptr p = mem2chunk(mem);
4613 #if FOOTERS 4840 #if FOOTERS
4614 mstate fm = get_mstate_for(p); 4841 mchunkptr p = mem2chunk(oldmem);
4842 mstate ms = get_mstate_for(p);
4615 #else /* FOOTERS */ 4843 #else /* FOOTERS */
4616 mstate fm = (mstate)msp; 4844 mstate ms = (mstate) msp;
4617 #endif /* FOOTERS */ 4845 #endif /* FOOTERS */
4618 if (!ok_magic(fm)) { 4846 if (!ok_magic(ms)) {
4619 USAGE_ERROR_ACTION(fm, p); 4847 USAGE_ERROR_ACTION(ms, ms);
4620 return; 4848 return 0;
4621 }
4622 if (!PREACTION(fm)) {
4623 check_inuse_chunk(fm, p);
4624 if (RTCHECK(ok_address(fm, p) && ok_cinuse(p))) {
4625 size_t psize = chunksize(p);
4626 mchunkptr next = chunk_plus_offset(p, psize);
4627 if (!pinuse(p)) {
4628 size_t prevsize = p->prev_foot;
4629 if ((prevsize & IS_MMAPPED_BIT) != 0) {
4630 prevsize &= ~IS_MMAPPED_BIT;
4631 psize += prevsize + MMAP_FOOT_PAD;
4632 if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
4633 fm->footprint -= psize;
4634 goto postaction;
4635 }
4636 else {
4637 mchunkptr prev = chunk_minus_offset(p, prevsize);
4638 psize += prevsize;
4639 p = prev;
4640 if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
4641 if (p != fm->dv) {
4642 unlink_chunk(fm, p, prevsize);
4643 }
4644 else if ((next->head & INUSE_BITS) == INUSE_BITS) {
4645 fm->dvsize = psize;
4646 set_free_with_pinuse(p, psize, next);
4647 goto postaction;
4648 }
4649 }
4650 else
4651 goto erroraction;
4652 }
4653 } 4849 }
4654 4850 return internal_realloc(ms, oldmem, bytes);
4655 if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { 4851 }
4656 if (!cinuse(next)) { /* consolidate forward */ 4852 }
4657 if (next == fm->top) { 4853
4658 size_t tsize = fm->topsize += psize; 4854 void *
4659 fm->top = p; 4855 mspace_memalign(mspace msp, size_t alignment, size_t bytes)
4660 p->head = tsize | PINUSE_BIT; 4856 {
4661 if (p == fm->dv) { 4857 mstate ms = (mstate) msp;
4662 fm->dv = 0; 4858 if (!ok_magic(ms)) {
4663 fm->dvsize = 0; 4859 USAGE_ERROR_ACTION(ms, ms);
4664 } 4860 return 0;
4665 if (should_trim(fm, tsize)) 4861 }
4666 sys_trim(fm, 0); 4862 return internal_memalign(ms, alignment, bytes);
4667 goto postaction; 4863 }
4668 } 4864
4669 else if (next == fm->dv) { 4865 void **
4670 size_t dsize = fm->dvsize += psize; 4866 mspace_independent_calloc(mspace msp, size_t n_elements,
4671 fm->dv = p; 4867 size_t elem_size, void *chunks[])
4672 set_size_and_pinuse_of_free_chunk(p, dsize); 4868 {
4673 goto postaction; 4869 size_t sz = elem_size; /* serves as 1-element array */
4674 } 4870 mstate ms = (mstate) msp;
4675 else { 4871 if (!ok_magic(ms)) {
4676 size_t nsize = chunksize(next); 4872 USAGE_ERROR_ACTION(ms, ms);
4677 psize += nsize; 4873 return 0;
4678 unlink_chunk(fm, next, nsize); 4874 }
4679 set_size_and_pinuse_of_free_chunk(p, psize); 4875 return ialloc(ms, n_elements, &sz, 3, chunks);
4680 if (p == fm->dv) { 4876 }
4681 fm->dvsize = psize; 4877
4682 goto postaction; 4878 void **
4683 } 4879 mspace_independent_comalloc(mspace msp, size_t n_elements,
4684 } 4880 size_t sizes[], void *chunks[])
4685 } 4881 {
4686 else 4882 mstate ms = (mstate) msp;
4687 set_free_with_pinuse(p, psize, next); 4883 if (!ok_magic(ms)) {
4688 insert_chunk(fm, p, psize); 4884 USAGE_ERROR_ACTION(ms, ms);
4689 check_free_chunk(fm, p); 4885 return 0;
4690 goto postaction; 4886 }
4887 return ialloc(ms, n_elements, sizes, 0, chunks);
4888 }
4889
4890 int
4891 mspace_trim(mspace msp, size_t pad)
4892 {
4893 int result = 0;
4894 mstate ms = (mstate) msp;
4895 if (ok_magic(ms)) {
4896 if (!PREACTION(ms)) {
4897 result = sys_trim(ms, pad);
4898 POSTACTION(ms);
4691 } 4899 }
4692 } 4900 } else {
4693 erroraction: 4901 USAGE_ERROR_ACTION(ms, ms);
4694 USAGE_ERROR_ACTION(fm, p); 4902 }
4695 postaction: 4903 return result;
4696 POSTACTION(fm); 4904 }
4697 } 4905
4698 } 4906 void
4699 } 4907 mspace_malloc_stats(mspace msp)
4700 4908 {
4701 void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { 4909 mstate ms = (mstate) msp;
4702 void* mem; 4910 if (ok_magic(ms)) {
4703 size_t req = 0; 4911 internal_malloc_stats(ms);
4704 mstate ms = (mstate)msp; 4912 } else {
4705 if (!ok_magic(ms)) { 4913 USAGE_ERROR_ACTION(ms, ms);
4706 USAGE_ERROR_ACTION(ms,ms); 4914 }
4707 return 0; 4915 }
4708 } 4916
4709 if (n_elements != 0) { 4917 size_t
4710 req = n_elements * elem_size; 4918 mspace_footprint(mspace msp)
4711 if (((n_elements | elem_size) & ~(size_t)0xffff) && 4919 {
4712 (req / n_elements != elem_size)) 4920 size_t result;
4713 req = MAX_SIZE_T; /* force downstream failure on overflow */ 4921 mstate ms = (mstate) msp;
4714 } 4922 if (ok_magic(ms)) {
4715 mem = internal_malloc(ms, req); 4923 result = ms->footprint;
4716 if (mem != 0 && calloc_must_clear(mem2chunk(mem))) 4924 }
4717 memset(mem, 0, req); 4925 USAGE_ERROR_ACTION(ms, ms);
4718 return mem; 4926 return result;
4719 } 4927 }
4720 4928
4721 void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { 4929
4722 if (oldmem == 0) 4930 size_t
4723 return mspace_malloc(msp, bytes); 4931 mspace_max_footprint(mspace msp)
4724 #ifdef REALLOC_ZERO_BYTES_FREES 4932 {
4725 if (bytes == 0) { 4933 size_t result;
4726 mspace_free(msp, oldmem); 4934 mstate ms = (mstate) msp;
4727 return 0; 4935 if (ok_magic(ms)) {
4728 } 4936 result = ms->max_footprint;
4729 #endif /* REALLOC_ZERO_BYTES_FREES */ 4937 }
4730 else { 4938 USAGE_ERROR_ACTION(ms, ms);
4731 #if FOOTERS 4939 return result;
4732 mchunkptr p = mem2chunk(oldmem); 4940 }
4733 mstate ms = get_mstate_for(p); 4941
4734 #else /* FOOTERS */ 4942
4735 mstate ms = (mstate)msp; 4943 #if !NO_MALLINFO
4736 #endif /* FOOTERS */ 4944 struct mallinfo
4945 mspace_mallinfo(mspace msp)
4946 {
4947 mstate ms = (mstate) msp;
4737 if (!ok_magic(ms)) { 4948 if (!ok_magic(ms)) {
4738 USAGE_ERROR_ACTION(ms,ms); 4949 USAGE_ERROR_ACTION(ms, ms);
4739 return 0; 4950 }
4740 } 4951 return internal_mallinfo(ms);
4741 return internal_realloc(ms, oldmem, bytes);
4742 }
4743 }
4744
4745 void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
4746 mstate ms = (mstate)msp;
4747 if (!ok_magic(ms)) {
4748 USAGE_ERROR_ACTION(ms,ms);
4749 return 0;
4750 }
4751 return internal_memalign(ms, alignment, bytes);
4752 }
4753
4754 void** mspace_independent_calloc(mspace msp, size_t n_elements,
4755 size_t elem_size, void* chunks[]) {
4756 size_t sz = elem_size; /* serves as 1-element array */
4757 mstate ms = (mstate)msp;
4758 if (!ok_magic(ms)) {
4759 USAGE_ERROR_ACTION(ms,ms);
4760 return 0;
4761 }
4762 return ialloc(ms, n_elements, &sz, 3, chunks);
4763 }
4764
4765 void** mspace_independent_comalloc(mspace msp, size_t n_elements,
4766 size_t sizes[], void* chunks[]) {
4767 mstate ms = (mstate)msp;
4768 if (!ok_magic(ms)) {
4769 USAGE_ERROR_ACTION(ms,ms);
4770 return 0;
4771 }
4772 return ialloc(ms, n_elements, sizes, 0, chunks);
4773 }
4774
4775 int mspace_trim(mspace msp, size_t pad) {
4776 int result = 0;
4777 mstate ms = (mstate)msp;
4778 if (ok_magic(ms)) {
4779 if (!PREACTION(ms)) {
4780 result = sys_trim(ms, pad);
4781 POSTACTION(ms);
4782 }
4783 }
4784 else {
4785 USAGE_ERROR_ACTION(ms,ms);
4786 }
4787 return result;
4788 }
4789
4790 void mspace_malloc_stats(mspace msp) {
4791 mstate ms = (mstate)msp;
4792 if (ok_magic(ms)) {
4793 internal_malloc_stats(ms);
4794 }
4795 else {
4796 USAGE_ERROR_ACTION(ms,ms);
4797 }
4798 }
4799
4800 size_t mspace_footprint(mspace msp) {
4801 size_t result;
4802 mstate ms = (mstate)msp;
4803 if (ok_magic(ms)) {
4804 result = ms->footprint;
4805 }
4806 USAGE_ERROR_ACTION(ms,ms);
4807 return result;
4808 }
4809
4810
4811 size_t mspace_max_footprint(mspace msp) {
4812 size_t result;
4813 mstate ms = (mstate)msp;
4814 if (ok_magic(ms)) {
4815 result = ms->max_footprint;
4816 }
4817 USAGE_ERROR_ACTION(ms,ms);
4818 return result;
4819 }
4820
4821
4822 #if !NO_MALLINFO
4823 struct mallinfo mspace_mallinfo(mspace msp) {
4824 mstate ms = (mstate)msp;
4825 if (!ok_magic(ms)) {
4826 USAGE_ERROR_ACTION(ms,ms);
4827 }
4828 return internal_mallinfo(ms);
4829 } 4952 }
4830 #endif /* NO_MALLINFO */ 4953 #endif /* NO_MALLINFO */
4831 4954
4832 int mspace_mallopt(int param_number, int value) { 4955 int
4833 return change_mparam(param_number, value); 4956 mspace_mallopt(int param_number, int value)
4957 {
4958 return change_mparam(param_number, value);
4834 } 4959 }
4835 4960
4836 #endif /* MSPACES */ 4961 #endif /* MSPACES */
4837 4962
4838 /* -------------------- Alternative MORECORE functions ------------------- */ 4963 /* -------------------- Alternative MORECORE functions ------------------- */
5107 structure of old version, but most details differ.) 5232 structure of old version, but most details differ.)
5108 5233
5109 */ 5234 */
5110 5235
5111 #endif /* !HAVE_MALLOC */ 5236 #endif /* !HAVE_MALLOC */
5237 /* vi: set ts=4 sw=4 expandtab: */