diff options
Diffstat (limited to 'src/gmalloc.c')
| -rw-r--r-- | src/gmalloc.c | 71 |
1 files changed, 41 insertions, 30 deletions
diff --git a/src/gmalloc.c b/src/gmalloc.c index 49f1fafccc0..103c19156be 100644 --- a/src/gmalloc.c +++ b/src/gmalloc.c | |||
| @@ -77,11 +77,6 @@ extern void *(*__morecore) (ptrdiff_t); | |||
| 77 | #ifdef HYBRID_MALLOC | 77 | #ifdef HYBRID_MALLOC |
| 78 | # include "sheap.h" | 78 | # include "sheap.h" |
| 79 | # define DUMPED bss_sbrk_did_unexec | 79 | # define DUMPED bss_sbrk_did_unexec |
| 80 | static bool | ||
| 81 | ALLOCATED_BEFORE_DUMPING (char *p) | ||
| 82 | { | ||
| 83 | return bss_sbrk_buffer <= p && p < bss_sbrk_buffer + STATIC_HEAP_SIZE; | ||
| 84 | } | ||
| 85 | #endif | 80 | #endif |
| 86 | 81 | ||
| 87 | #ifdef __cplusplus | 82 | #ifdef __cplusplus |
| @@ -133,8 +128,13 @@ typedef union | |||
| 133 | /* Heap information for a busy block. */ | 128 | /* Heap information for a busy block. */ |
| 134 | struct | 129 | struct |
| 135 | { | 130 | { |
| 136 | /* Zero for a large (multiblock) object, or positive giving the | 131 | /* Zero for a block that is not one of ours (typically, |
| 137 | logarithm to the base two of the fragment size. */ | 132 | allocated by system malloc), positive for the log base 2 of |
| 133 | the fragment size of a fragmented block, -1 for the first | ||
| 134 | block of a multiblock object, and unspecified for later | ||
| 135 | blocks of that object. Type-0 blocks can be present | ||
| 136 | because the system malloc can be invoked by library | ||
| 137 | functions in an undumped Emacs. */ | ||
| 138 | int type; | 138 | int type; |
| 139 | union | 139 | union |
| 140 | { | 140 | { |
| @@ -166,7 +166,7 @@ extern char *_heapbase; | |||
| 166 | extern malloc_info *_heapinfo; | 166 | extern malloc_info *_heapinfo; |
| 167 | 167 | ||
| 168 | /* Address to block number and vice versa. */ | 168 | /* Address to block number and vice versa. */ |
| 169 | #define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) | 169 | #define BLOCK(A) ((size_t) ((char *) (A) - _heapbase) / BLOCKSIZE + 1) |
| 170 | #define ADDRESS(B) ((void *) (((B) - 1) * BLOCKSIZE + _heapbase)) | 170 | #define ADDRESS(B) ((void *) (((B) - 1) * BLOCKSIZE + _heapbase)) |
| 171 | 171 | ||
| 172 | /* Current search index for the heap table. */ | 172 | /* Current search index for the heap table. */ |
| @@ -491,7 +491,7 @@ register_heapinfo (void) | |||
| 491 | ++_chunks_used; | 491 | ++_chunks_used; |
| 492 | 492 | ||
| 493 | /* Describe the heapinfo block itself in the heapinfo. */ | 493 | /* Describe the heapinfo block itself in the heapinfo. */ |
| 494 | _heapinfo[block].busy.type = 0; | 494 | _heapinfo[block].busy.type = -1; |
| 495 | _heapinfo[block].busy.info.size = blocks; | 495 | _heapinfo[block].busy.info.size = blocks; |
| 496 | /* Leave back-pointers for malloc_find_address. */ | 496 | /* Leave back-pointers for malloc_find_address. */ |
| 497 | while (--blocks > 0) | 497 | while (--blocks > 0) |
| @@ -608,7 +608,7 @@ morecore_nolock (size_t size) | |||
| 608 | PROTECT_MALLOC_STATE (0); | 608 | PROTECT_MALLOC_STATE (0); |
| 609 | 609 | ||
| 610 | /* Check if we need to grow the info table. */ | 610 | /* Check if we need to grow the info table. */ |
| 611 | if ((size_t) BLOCK ((char *) result + size) > heapsize) | 611 | if (heapsize < BLOCK ((char *) result + size)) |
| 612 | { | 612 | { |
| 613 | /* Calculate the new _heapinfo table size. We do not account for the | 613 | /* Calculate the new _heapinfo table size. We do not account for the |
| 614 | added blocks in the table itself, as we hope to place them in | 614 | added blocks in the table itself, as we hope to place them in |
| @@ -617,7 +617,7 @@ morecore_nolock (size_t size) | |||
| 617 | newsize = heapsize; | 617 | newsize = heapsize; |
| 618 | do | 618 | do |
| 619 | newsize *= 2; | 619 | newsize *= 2; |
| 620 | while ((size_t) BLOCK ((char *) result + size) > newsize); | 620 | while (newsize < BLOCK ((char *) result + size)); |
| 621 | 621 | ||
| 622 | /* We must not reuse existing core for the new info table when called | 622 | /* We must not reuse existing core for the new info table when called |
| 623 | from realloc in the case of growing a large block, because the | 623 | from realloc in the case of growing a large block, because the |
| @@ -665,8 +665,7 @@ morecore_nolock (size_t size) | |||
| 665 | 665 | ||
| 666 | /* Is it big enough to record status for its own space? | 666 | /* Is it big enough to record status for its own space? |
| 667 | If so, we win. */ | 667 | If so, we win. */ |
| 668 | if ((size_t) BLOCK ((char *) newinfo | 668 | if (BLOCK ((char *) newinfo + newsize * sizeof (malloc_info)) |
| 669 | + newsize * sizeof (malloc_info)) | ||
| 670 | < newsize) | 669 | < newsize) |
| 671 | break; | 670 | break; |
| 672 | 671 | ||
| @@ -883,7 +882,7 @@ _malloc_internal_nolock (size_t size) | |||
| 883 | --_chunks_free; | 882 | --_chunks_free; |
| 884 | } | 883 | } |
| 885 | 884 | ||
| 886 | _heapinfo[block].busy.type = 0; | 885 | _heapinfo[block].busy.type = -1; |
| 887 | _heapinfo[block].busy.info.size = blocks; | 886 | _heapinfo[block].busy.info.size = blocks; |
| 888 | ++_chunks_used; | 887 | ++_chunks_used; |
| 889 | _bytes_used += blocks * BLOCKSIZE; | 888 | _bytes_used += blocks * BLOCKSIZE; |
| @@ -1026,7 +1025,7 @@ _free_internal_nolock (void *ptr) | |||
| 1026 | type = _heapinfo[block].busy.type; | 1025 | type = _heapinfo[block].busy.type; |
| 1027 | switch (type) | 1026 | switch (type) |
| 1028 | { | 1027 | { |
| 1029 | case 0: | 1028 | case -1: |
| 1030 | /* Get as many statistics as early as we can. */ | 1029 | /* Get as many statistics as early as we can. */ |
| 1031 | --_chunks_used; | 1030 | --_chunks_used; |
| 1032 | _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; | 1031 | _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE; |
| @@ -1187,7 +1186,7 @@ _free_internal_nolock (void *ptr) | |||
| 1187 | prev->prev->next = next; | 1186 | prev->prev->next = next; |
| 1188 | if (next != NULL) | 1187 | if (next != NULL) |
| 1189 | next->prev = prev->prev; | 1188 | next->prev = prev->prev; |
| 1190 | _heapinfo[block].busy.type = 0; | 1189 | _heapinfo[block].busy.type = -1; |
| 1191 | _heapinfo[block].busy.info.size = 1; | 1190 | _heapinfo[block].busy.info.size = 1; |
| 1192 | 1191 | ||
| 1193 | /* Keep the statistics accurate. */ | 1192 | /* Keep the statistics accurate. */ |
| @@ -1326,7 +1325,7 @@ _realloc_internal_nolock (void *ptr, size_t size) | |||
| 1326 | type = _heapinfo[block].busy.type; | 1325 | type = _heapinfo[block].busy.type; |
| 1327 | switch (type) | 1326 | switch (type) |
| 1328 | { | 1327 | { |
| 1329 | case 0: | 1328 | case -1: |
| 1330 | /* Maybe reallocate a large block to a small fragment. */ | 1329 | /* Maybe reallocate a large block to a small fragment. */ |
| 1331 | if (size <= BLOCKSIZE / 2) | 1330 | if (size <= BLOCKSIZE / 2) |
| 1332 | { | 1331 | { |
| @@ -1346,7 +1345,7 @@ _realloc_internal_nolock (void *ptr, size_t size) | |||
| 1346 | { | 1345 | { |
| 1347 | /* The new size is smaller; return | 1346 | /* The new size is smaller; return |
| 1348 | excess memory to the free list. */ | 1347 | excess memory to the free list. */ |
| 1349 | _heapinfo[block + blocks].busy.type = 0; | 1348 | _heapinfo[block + blocks].busy.type = -1; |
| 1350 | _heapinfo[block + blocks].busy.info.size | 1349 | _heapinfo[block + blocks].busy.info.size |
| 1351 | = _heapinfo[block].busy.info.size - blocks; | 1350 | = _heapinfo[block].busy.info.size - blocks; |
| 1352 | _heapinfo[block].busy.info.size = blocks; | 1351 | _heapinfo[block].busy.info.size = blocks; |
| @@ -1721,6 +1720,20 @@ extern void *aligned_alloc (size_t alignment, size_t size); | |||
| 1721 | extern int posix_memalign (void **memptr, size_t alignment, size_t size); | 1720 | extern int posix_memalign (void **memptr, size_t alignment, size_t size); |
| 1722 | #endif | 1721 | #endif |
| 1723 | 1722 | ||
| 1723 | /* Assuming PTR was allocated via the hybrid malloc, return true if | ||
| 1724 | PTR was allocated via gmalloc, not the system malloc. Also, return | ||
| 1725 | true if _heaplimit is zero; this can happen temporarily when | ||
| 1726 | gmalloc calls itself for internal use, and in that case PTR is | ||
| 1727 | already known to be allocated via gmalloc. */ | ||
| 1728 | |||
| 1729 | static bool | ||
| 1730 | allocated_via_gmalloc (void *ptr) | ||
| 1731 | { | ||
| 1732 | size_t block = BLOCK (ptr); | ||
| 1733 | size_t blockmax = _heaplimit - 1; | ||
| 1734 | return block <= blockmax && _heapinfo[block].busy.type != 0; | ||
| 1735 | } | ||
| 1736 | |||
| 1724 | /* See the comments near the beginning of this file for explanations | 1737 | /* See the comments near the beginning of this file for explanations |
| 1725 | of the following functions. */ | 1738 | of the following functions. */ |
| 1726 | 1739 | ||
| @@ -1743,13 +1756,10 @@ hybrid_calloc (size_t nmemb, size_t size) | |||
| 1743 | void | 1756 | void |
| 1744 | hybrid_free (void *ptr) | 1757 | hybrid_free (void *ptr) |
| 1745 | { | 1758 | { |
| 1746 | if (!DUMPED) | 1759 | if (allocated_via_gmalloc (ptr)) |
| 1747 | gfree (ptr); | 1760 | gfree (ptr); |
| 1748 | else if (!ALLOCATED_BEFORE_DUMPING (ptr)) | 1761 | else |
| 1749 | free (ptr); | 1762 | free (ptr); |
| 1750 | /* Otherwise the dumped emacs is trying to free something allocated | ||
| 1751 | before dumping; do nothing. */ | ||
| 1752 | return; | ||
| 1753 | } | 1763 | } |
| 1754 | 1764 | ||
| 1755 | #if defined HAVE_ALIGNED_ALLOC || defined HAVE_POSIX_MEMALIGN | 1765 | #if defined HAVE_ALIGNED_ALLOC || defined HAVE_POSIX_MEMALIGN |
| @@ -1775,19 +1785,20 @@ hybrid_realloc (void *ptr, size_t size) | |||
| 1775 | int type; | 1785 | int type; |
| 1776 | size_t block, oldsize; | 1786 | size_t block, oldsize; |
| 1777 | 1787 | ||
| 1788 | if (!ptr) | ||
| 1789 | return hybrid_malloc (size); | ||
| 1790 | if (!allocated_via_gmalloc (ptr)) | ||
| 1791 | return realloc (ptr, size); | ||
| 1778 | if (!DUMPED) | 1792 | if (!DUMPED) |
| 1779 | return grealloc (ptr, size); | 1793 | return grealloc (ptr, size); |
| 1780 | if (!ALLOCATED_BEFORE_DUMPING (ptr)) | ||
| 1781 | return realloc (ptr, size); | ||
| 1782 | 1794 | ||
| 1783 | /* The dumped emacs is trying to realloc storage allocated before | 1795 | /* The dumped emacs is trying to realloc storage allocated before |
| 1784 | dumping. We just malloc new space and copy the data. */ | 1796 | dumping via gmalloc. Allocate new space and copy the data. Do |
| 1785 | if (size == 0 || ptr == NULL) | 1797 | not bother with gfree (ptr), as that would just waste time. */ |
| 1786 | return malloc (size); | 1798 | block = BLOCK (ptr); |
| 1787 | block = ((char *) ptr - _heapbase) / BLOCKSIZE + 1; | ||
| 1788 | type = _heapinfo[block].busy.type; | 1799 | type = _heapinfo[block].busy.type; |
| 1789 | oldsize = | 1800 | oldsize = |
| 1790 | type == 0 ? _heapinfo[block].busy.info.size * BLOCKSIZE | 1801 | type < 0 ? _heapinfo[block].busy.info.size * BLOCKSIZE |
| 1791 | : (size_t) 1 << type; | 1802 | : (size_t) 1 << type; |
| 1792 | result = malloc (size); | 1803 | result = malloc (size); |
| 1793 | if (result) | 1804 | if (result) |