diff options
Diffstat (limited to 'malloc')
| -rw-r--r-- | malloc/Makefile | 29 | ||||
| -rw-r--r-- | malloc/arena.c | 62 | ||||
| -rw-r--r-- | malloc/hooks.c | 95 | ||||
| -rw-r--r-- | malloc/malloc.c | 400 | ||||
| -rw-r--r-- | malloc/malloc.h | 7 | ||||
| -rw-r--r-- | malloc/tst-interpose-aux-nothread.c | 20 | ||||
| -rw-r--r-- | malloc/tst-interpose-aux-thread.c | 20 | ||||
| -rw-r--r-- | malloc/tst-interpose-aux.c | 270 | ||||
| -rw-r--r-- | malloc/tst-interpose-aux.h | 30 | ||||
| -rw-r--r-- | malloc/tst-interpose-nothread.c | 20 | ||||
| -rw-r--r-- | malloc/tst-interpose-skeleton.c | 204 | ||||
| -rw-r--r-- | malloc/tst-interpose-static-nothread.c | 19 | ||||
| -rw-r--r-- | malloc/tst-interpose-static-thread.c | 19 | ||||
| -rw-r--r-- | malloc/tst-interpose-thread.c | 20 | ||||
| -rw-r--r-- | malloc/tst-mallocstate.c | 505 |
15 files changed, 1421 insertions, 299 deletions
diff --git a/malloc/Makefile b/malloc/Makefile index 761a976fa3..f34c2a75ba 100644 --- a/malloc/Makefile +++ b/malloc/Makefile @@ -30,7 +30,15 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer \ tst-malloc-backtrace tst-malloc-thread-exit \ tst-malloc-thread-fail tst-malloc-fork-deadlock \ - tst-mallocfork2 + tst-mallocfork2 \ + tst-interpose-nothread \ + tst-interpose-thread \ + +tests-static := \ + tst-interpose-static-nothread \ + tst-interpose-static-thread \ + +tests += $(tests-static) test-srcs = tst-mtrace routines = malloc morecore mcheck mtrace obstack \ @@ -44,6 +52,15 @@ non-lib.a := libmcheck.a extra-libs = libmemusage libmtracectl extra-libs-others = $(extra-libs) +# Helper objects for some tests. +extra-tests-objs += \ + tst-interpose-aux-nothread.o \ + tst-interpose-aux-thread.o \ + +test-extras = \ + tst-interpose-aux-nothread \ + tst-interpose-aux-thread \ + libmemusage-routines = memusage libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes)) @@ -71,6 +88,9 @@ $(objpfx)tst-malloc-thread-exit: $(shared-thread-library) $(objpfx)tst-malloc-thread-fail: $(shared-thread-library) $(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library) +# Export the __malloc_initialize_hook variable to libc.so. +LDFLAGS-tst-mallocstate = -rdynamic + # These should be removed by `make clean'. extra-objs = mcheck-init.o libmcheck.a @@ -189,3 +209,10 @@ $(foreach o,$(all-object-suffixes),$(objpfx)malloc$(o)): arena.c hooks.c # Compile the tests with a flag which suppresses the mallopt call in # the test skeleton. $(tests:%=$(objpfx)%.o): CPPFLAGS += -DTEST_NO_MALLOPT + +$(objpfx)tst-interpose-nothread: $(objpfx)tst-interpose-aux-nothread.o +$(objpfx)tst-interpose-thread: \ + $(objpfx)tst-interpose-aux-thread.o $(shared-thread-library) +$(objpfx)tst-interpose-static-nothread: $(objpfx)tst-interpose-aux-nothread.o +$(objpfx)tst-interpose-static-thread: \ + $(objpfx)tst-interpose-aux-thread.o $(static-thread-library) diff --git a/malloc/arena.c b/malloc/arena.c index 6c23c8e107..ada1a7245e 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -73,7 +73,7 @@ static __thread mstate thread_arena attribute_tls_model_ie; members of struct malloc_state objects. No other locks must be acquired after free_list_lock has been acquired. */ -static mutex_t free_list_lock = _LIBC_LOCK_INITIALIZER; +__libc_lock_define_initialized (static, free_list_lock); static size_t narenas = 1; static mstate free_list; @@ -89,7 +89,7 @@ static mstate free_list; acquired, no arena lock must have been acquired, but it is permitted to acquire arena locks subsequently, while list_lock is acquired. */ -static mutex_t list_lock = _LIBC_LOCK_INITIALIZER; +__libc_lock_define_initialized (static, list_lock); /* Already initialized? */ int __malloc_initialized = -1; @@ -112,7 +112,7 @@ int __malloc_initialized = -1; #define arena_lock(ptr, size) do { \ if (ptr && !arena_is_corrupt (ptr)) \ - (void) mutex_lock (&ptr->mutex); \ + __libc_lock_lock (ptr->mutex); \ else \ ptr = arena_get2 ((size), NULL); \ } while (0) @@ -122,7 +122,7 @@ int __malloc_initialized = -1; #define heap_for_ptr(ptr) \ ((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1))) #define arena_for_chunk(ptr) \ - (chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena) + (chunk_main_arena (ptr) ? &main_arena : heap_for_ptr (ptr)->ar_ptr) /**************************************************************************/ @@ -145,11 +145,11 @@ __malloc_fork_lock_parent (void) /* We do not acquire free_list_lock here because we completely reconstruct free_list in __malloc_fork_unlock_child. */ - (void) mutex_lock (&list_lock); + __libc_lock_lock (list_lock); for (mstate ar_ptr = &main_arena;; ) { - (void) mutex_lock (&ar_ptr->mutex); + __libc_lock_lock (ar_ptr->mutex); ar_ptr = ar_ptr->next; if (ar_ptr == &main_arena) break; @@ -165,12 +165,12 @@ __malloc_fork_unlock_parent (void) for (mstate ar_ptr = &main_arena;; ) { - (void) mutex_unlock (&ar_ptr->mutex); + __libc_lock_unlock (ar_ptr->mutex); ar_ptr = ar_ptr->next; if (ar_ptr == &main_arena) break; } - (void) mutex_unlock (&list_lock); + __libc_lock_unlock (list_lock); } void @@ -182,13 +182,13 @@ __malloc_fork_unlock_child (void) /* Push all arenas to the free list, except thread_arena, which is attached to the current thread. */ - mutex_init (&free_list_lock); + __libc_lock_init (free_list_lock); if (thread_arena != NULL) thread_arena->attached_threads = 1; free_list = NULL; for (mstate ar_ptr = &main_arena;; ) { - mutex_init (&ar_ptr->mutex); + __libc_lock_init (ar_ptr->mutex); if (ar_ptr != thread_arena) { /* This arena is no longer attached to any thread. */ @@ -201,7 +201,7 @@ __malloc_fork_unlock_child (void) break; } - mutex_init (&list_lock); + __libc_lock_init (list_lock); } /* Initialization routine. */ @@ -574,12 +574,12 @@ heap_trim (heap_info *heap, size_t pad) /* fencepost must be properly aligned. */ misalign = ((long) p) & MALLOC_ALIGN_MASK; p = chunk_at_offset (prev_heap, prev_size - misalign); - assert (p->size == (0 | PREV_INUSE)); /* must be fencepost */ + assert (chunksize_nomask (p) == (0 | PREV_INUSE)); /* must be fencepost */ p = prev_chunk (p); new_size = chunksize (p) + (MINSIZE - 2 * SIZE_SZ) + misalign; assert (new_size > 0 && new_size < (long) (2 * MINSIZE)); if (!prev_inuse (p)) - new_size += p->prev_size; + new_size += prev_size (p); assert (new_size > 0 && new_size < HEAP_MAX_SIZE); if (new_size + (HEAP_MAX_SIZE - prev_heap->size) < pad + MINSIZE + pagesz) break; @@ -682,9 +682,9 @@ _int_new_arena (size_t size) LIBC_PROBE (memory_arena_new, 2, a, size); mstate replaced_arena = thread_arena; thread_arena = a; - mutex_init (&a->mutex); + __libc_lock_init (a->mutex); - (void) mutex_lock (&list_lock); + __libc_lock_lock (list_lock); /* Add the new arena to the global list. */ a->next = main_arena.next; @@ -694,11 +694,11 @@ _int_new_arena (size_t size) atomic_write_barrier (); main_arena.next = a; - (void) mutex_unlock (&list_lock); + __libc_lock_unlock (list_lock); - (void) mutex_lock (&free_list_lock); + __libc_lock_lock (free_list_lock); detach_arena (replaced_arena); - (void) mutex_unlock (&free_list_lock); + __libc_lock_unlock (free_list_lock); /* Lock this arena. NB: Another thread may have been attached to this arena because the arena is now accessible from the @@ -710,7 +710,7 @@ _int_new_arena (size_t size) but this could result in a deadlock with __malloc_fork_lock_parent. */ - (void) mutex_lock (&a->mutex); + __libc_lock_lock (a->mutex); return a; } @@ -724,7 +724,7 @@ get_free_list (void) mstate result = free_list; if (result != NULL) { - (void) mutex_lock (&free_list_lock); + __libc_lock_lock (free_list_lock); result = free_list; if (result != NULL) { @@ -736,12 +736,12 @@ get_free_list (void) detach_arena (replaced_arena); } - (void) mutex_unlock (&free_list_lock); + __libc_lock_unlock (free_list_lock); if (result != NULL) { LIBC_PROBE (memory_arena_reuse_free_list, 1, result); - (void) mutex_lock (&result->mutex); + __libc_lock_lock (result->mutex); thread_arena = result; } } @@ -786,7 +786,7 @@ reused_arena (mstate avoid_arena) result = next_to_use; do { - if (!arena_is_corrupt (result) && !mutex_trylock (&result->mutex)) + if (!arena_is_corrupt (result) && !__libc_lock_trylock (result->mutex)) goto out; /* FIXME: This is a data race, see _int_new_arena. */ @@ -813,14 +813,14 @@ reused_arena (mstate avoid_arena) /* No arena available without contention. Wait for the next in line. */ LIBC_PROBE (memory_arena_reuse_wait, 3, &result->mutex, result, avoid_arena); - (void) mutex_lock (&result->mutex); + __libc_lock_lock (result->mutex); out: /* Attach the arena to the current thread. */ { /* Update the arena thread attachment counters. */ mstate replaced_arena = thread_arena; - (void) mutex_lock (&free_list_lock); + __libc_lock_lock (free_list_lock); detach_arena (replaced_arena); /* We may have picked up an arena on the free list. We need to @@ -835,7 +835,7 @@ out: ++result->attached_threads; - (void) mutex_unlock (&free_list_lock); + __libc_lock_unlock (free_list_lock); } LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena); @@ -906,17 +906,17 @@ arena_get_retry (mstate ar_ptr, size_t bytes) LIBC_PROBE (memory_arena_retry, 2, bytes, ar_ptr); if (ar_ptr != &main_arena) { - (void) mutex_unlock (&ar_ptr->mutex); + __libc_lock_unlock (ar_ptr->mutex); /* Don't touch the main arena if it is corrupt. */ if (arena_is_corrupt (&main_arena)) return NULL; ar_ptr = &main_arena; - (void) mutex_lock (&ar_ptr->mutex); + __libc_lock_lock (ar_ptr->mutex); } else { - (void) mutex_unlock (&ar_ptr->mutex); + __libc_lock_unlock (ar_ptr->mutex); ar_ptr = arena_get2 (bytes, ar_ptr); } @@ -931,7 +931,7 @@ arena_thread_freeres (void) if (a != NULL) { - (void) mutex_lock (&free_list_lock); + __libc_lock_lock (free_list_lock); /* If this was the last attached thread for this arena, put the arena on the free list. */ assert (a->attached_threads > 0); @@ -940,7 +940,7 @@ arena_thread_freeres (void) a->next_free = free_list; free_list = a; } - (void) mutex_unlock (&free_list_lock); + __libc_lock_unlock (free_list_lock); } } text_set_element (__libc_thread_subfreeres, arena_thread_freeres); diff --git a/malloc/hooks.c b/malloc/hooks.c index caa1e70d13..12995d3f0c 100644 --- a/malloc/hooks.c +++ b/malloc/hooks.c @@ -192,7 +192,7 @@ mem2chunk_check (void *mem, unsigned char **magic_p) ((char *) p < mp_.sbrk_base || ((char *) p + sz) >= (mp_.sbrk_base + main_arena.system_mem))) || sz < MINSIZE || sz & MALLOC_ALIGN_MASK || !inuse (p) || - (!prev_inuse (p) && (p->prev_size & MALLOC_ALIGN_MASK || + (!prev_inuse (p) && ((prev_size (p) & MALLOC_ALIGN_MASK) != 0 || (contig && (char *) prev_chunk (p) < mp_.sbrk_base) || next_chunk (prev_chunk (p)) != p))) return NULL; @@ -215,9 +215,9 @@ mem2chunk_check (void *mem, unsigned char **magic_p) offset != 0x20 && offset != 0x40 && offset != 0x80 && offset != 0x100 && offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 && offset < 0x2000) || - !chunk_is_mmapped (p) || (p->size & PREV_INUSE) || - ((((unsigned long) p - p->prev_size) & page_mask) != 0) || - ((p->prev_size + sz) & page_mask) != 0) + !chunk_is_mmapped (p) || prev_inuse (p) || + ((((unsigned long) p - prev_size (p)) & page_mask) != 0) || + ((prev_size (p) + sz) & page_mask) != 0) return NULL; for (sz -= 1; (c = ((unsigned char *) p)[sz]) != magic; sz -= c) @@ -291,9 +291,9 @@ malloc_check (size_t sz, const void *caller) return NULL; } - (void) mutex_lock (&main_arena.mutex); + __libc_lock_lock (main_arena.mutex); victim = (top_check () >= 0) ? _int_malloc (&main_arena, sz + 1) : NULL; - (void) mutex_unlock (&main_arena.mutex); + __libc_lock_unlock (main_arena.mutex); return mem2mem_check (victim, sz); } @@ -305,11 +305,11 @@ free_check (void *mem, const void *caller) if (!mem) return; - (void) mutex_lock (&main_arena.mutex); + __libc_lock_lock (main_arena.mutex); p = mem2chunk_check (mem, NULL); if (!p) { - (void) mutex_unlock (&main_arena.mutex); + __libc_lock_unlock (main_arena.mutex); malloc_printerr (check_action, "free(): invalid pointer", mem, &main_arena); @@ -317,12 +317,12 @@ free_check (void *mem, const void *caller) } if (chunk_is_mmapped (p)) { - (void) mutex_unlock (&main_arena.mutex); + __libc_lock_unlock (main_arena.mutex); munmap_chunk (p); return; } _int_free (&main_arena, p, 1); - (void) mutex_unlock (&main_arena.mutex); + __libc_lock_unlock (main_arena.mutex); } static void * @@ -345,9 +345,9 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) free_check (oldmem, NULL); return NULL; } - (void) mutex_lock (&main_arena.mutex); + __libc_lock_lock (main_arena.mutex); const mchunkptr oldp = mem2chunk_check (oldmem, &magic_p); - (void) mutex_unlock (&main_arena.mutex); + __libc_lock_unlock (main_arena.mutex); if (!oldp) { malloc_printerr (check_action, "realloc(): invalid pointer", oldmem, @@ -357,7 +357,7 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) const INTERNAL_SIZE_T oldsize = chunksize (oldp); checked_request2size (bytes + 1, nb); - (void) mutex_lock (&main_arena.mutex); + __libc_lock_lock (main_arena.mutex); if (chunk_is_mmapped (oldp)) { @@ -400,7 +400,7 @@ realloc_check (void *oldmem, size_t bytes, const void *caller) if (newmem == NULL) *magic_p ^= 0xFF; - (void) mutex_unlock (&main_arena.mutex); + __libc_lock_unlock (main_arena.mutex); return mem2mem_check (newmem, bytes); } @@ -440,13 +440,14 @@ memalign_check (size_t alignment, size_t bytes, const void *caller) alignment = a; } - (void) mutex_lock (&main_arena.mutex); + __libc_lock_lock (main_arena.mutex); mem = (top_check () >= 0) ? _int_memalign (&main_arena, alignment, bytes + 1) : NULL; - (void) mutex_unlock (&main_arena.mutex); + __libc_lock_unlock (main_arena.mutex); return mem2mem_check (mem, bytes); } +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25) /* Get/set state: malloc_get_state() records the current state of all malloc variables (_except_ for the actual heap contents and `hook' @@ -492,60 +493,21 @@ struct malloc_save_state unsigned long narenas; }; +/* Dummy implementation which always fails. We need to provide this + symbol so that existing Emacs binaries continue to work with + BIND_NOW. */ void * -__malloc_get_state (void) +attribute_compat_text_section +malloc_get_state (void) { - struct malloc_save_state *ms; - int i; - mbinptr b; - - ms = (struct malloc_save_state *) __libc_malloc (sizeof (*ms)); - if (!ms) - return 0; - - (void) mutex_lock (&main_arena.mutex); - malloc_consolidate (&main_arena); - ms->magic = MALLOC_STATE_MAGIC; - ms->version = MALLOC_STATE_VERSION; - ms->av[0] = 0; - ms->av[1] = 0; /* used to be binblocks, now no longer used */ - ms->av[2] = top (&main_arena); - ms->av[3] = 0; /* used to be undefined */ - for (i = 1; i < NBINS; i++) - { - b = bin_at (&main_arena, i); - if (first (b) == b) - ms->av[2 * i + 2] = ms->av[2 * i + 3] = 0; /* empty bin */ - else - { - ms->av[2 * i + 2] = first (b); - ms->av[2 * i + 3] = last (b); - } - } - ms->sbrk_base = mp_.sbrk_base; - ms->sbrked_mem_bytes = main_arena.system_mem; - ms->trim_threshold = mp_.trim_threshold; - ms->top_pad = mp_.top_pad; - ms->n_mmaps_max = mp_.n_mmaps_max; - ms->mmap_threshold = mp_.mmap_threshold; - ms->check_action = check_action; - ms->max_sbrked_mem = main_arena.max_system_mem; - ms->max_total_mem = 0; - ms->n_mmaps = mp_.n_mmaps; - ms->max_n_mmaps = mp_.max_n_mmaps; - ms->mmapped_mem = mp_.mmapped_mem; - ms->max_mmapped_mem = mp_.max_mmapped_mem; - ms->using_malloc_checking = using_malloc_checking; - ms->max_fast = get_max_fast (); - ms->arena_test = mp_.arena_test; - ms->arena_max = mp_.arena_max; - ms->narenas = narenas; - (void) mutex_unlock (&main_arena.mutex); - return (void *) ms; + __set_errno (ENOSYS); + return NULL; } +compat_symbol (libc, malloc_get_state, malloc_get_state, GLIBC_2_0); int -__malloc_set_state (void *msptr) +attribute_compat_text_section +malloc_set_state (void *msptr) { struct malloc_save_state *ms = (struct malloc_save_state *) msptr; @@ -612,6 +574,9 @@ __malloc_set_state (void *msptr) return 0; } +compat_symbol (libc, malloc_set_state, malloc_set_state, GLIBC_2_0); + +#endif /* SHLIB_COMPAT */ /* * Local variables: diff --git a/malloc/malloc.c b/malloc/malloc.c index 1fa9487f18..bd8a1d4bb8 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -273,8 +273,9 @@ #define MALLOC_DEBUG 0 #endif -#define USE_TCACHE 1 - +#ifndef USE_TCACHE +#define USE_TCACHE 0 +#endif #if USE_TCACHE /* we want 64 entries */ #define MAX_TCACHE_SIZE (MALLOC_ALIGNMENT * 63) @@ -1067,7 +1068,7 @@ typedef struct __malloc_trace_map_entry_s { #define TRACE_COUNT_TO_MAPPING_IDX(count) ((count) % TRACE_N_PER_MAPPING) /* Global mutex for the trace buffer tree itself. */ -mutex_t __malloc_trace_mutex; +libc_lock_define_initialized (static, __malloc_trace_mutex); /* Global counter, "full" when equal to TRACE_MAX_COUNT. Points to the next available slot, so POST-INCREMENT it. */ @@ -1174,7 +1175,7 @@ __mtb_trace_record (void) /* START W: Switch window. */ /* W1. Acquire the global window lock. */ - (void) mutex_lock (&__malloc_trace_mutex); + __libc_lock_lock (__malloc_trace_mutex); /* W2. If the thread-local window number is not -1, decrement the reference counter for the current thread window. */ @@ -1216,7 +1217,7 @@ __mtb_trace_record (void) /* FIXME: Better handling of errors? */ __libc_message (0, "Can't open trace buffer file %s\n", __malloc_trace_filename); atomic_store_release (&__malloc_trace_enabled, 0); - (void) mutex_unlock (&__malloc_trace_mutex); + __libc_lock_unlock (__malloc_trace_mutex); return; } @@ -1234,7 +1235,7 @@ __mtb_trace_record (void) /* FIXME: Better handling of errors? */ __libc_message (0, "Can't map trace_buffer file %s\n", __malloc_trace_filename); atomic_store_release (&__malloc_trace_enabled, 0); - (void) mutex_unlock (&__malloc_trace_mutex); + __libc_lock_unlock (__malloc_trace_mutex); return; } @@ -1253,7 +1254,7 @@ __mtb_trace_record (void) __malloc_trace_last_num = new_window; /* W8. Release the global window lock. */ - (void) mutex_unlock (&__malloc_trace_mutex); + __libc_lock_unlock (__malloc_trace_mutex); /* W9. Continue at T1. */ goto alg_t1; @@ -1302,7 +1303,7 @@ __malloc_trace_init (char *filename) __malloc_trace_buffer = (__malloc_trace_map_entry *) mapping; - mutex_init (&__malloc_trace_mutex); + __libc_lock_init (__malloc_trace_mutex); __malloc_trace_count = 0; __mtb_trace_entry (__MTB_TYPE_MAGIC, sizeof(void *), (void *)0x1234); @@ -1457,8 +1458,8 @@ size_t __malloc_trace_sync (void) { return 0; } struct malloc_chunk { - INTERNAL_SIZE_T prev_size; /* Size of previous chunk (if free). */ - INTERNAL_SIZE_T size; /* Size in bytes, including overhead. */ + INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk (if free). */ + INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if free. */ struct malloc_chunk* bk; @@ -1487,18 +1488,19 @@ struct malloc_chunk { chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk, if allocated | | + | Size of previous chunk, if unallocated (P clear) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of chunk, in bytes |M|P| + |
