blob: 451666e4c9cd3954e6358265c318154954df4cc3 [file] [log] [blame]
Dave Barach6a5adc32018-07-04 10:56:23 -04001/*
2 This is a version (aka dlmalloc) of malloc/free/realloc written by
3 Doug Lea and released to the public domain, as explained at
4 http://creativecommons.org/publicdomain/zero/1.0/ Send questions,
5 comments, complaints, performance data, etc to dl@cs.oswego.edu
6*/
7
8#include <vppinfra/dlmalloc.h>
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02009#include <vppinfra/sanitizer.h>
Dave Barach6a5adc32018-07-04 10:56:23 -040010
11/*------------------------------ internal #includes ---------------------- */
12
13#ifdef _MSC_VER
14#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
15#endif /* _MSC_VER */
16#if !NO_MALLOC_STATS
17#include <stdio.h> /* for printing in malloc_stats */
18#endif /* NO_MALLOC_STATS */
19#ifndef LACKS_ERRNO_H
20#include <errno.h> /* for MALLOC_FAILURE_ACTION */
21#endif /* LACKS_ERRNO_H */
22#ifdef DEBUG
23#if DLM_ABORT_ON_ASSERT_FAILURE
24#undef assert
25#define assert(x) if(!(x)) DLM_ABORT
26#else /* DLM_ABORT_ON_ASSERT_FAILURE */
27#include <assert.h>
28#endif /* DLM_ABORT_ON_ASSERT_FAILURE */
29#else /* DEBUG */
30#ifndef assert
31#define assert(x)
32#endif
33#define DEBUG 0
34#endif /* DEBUG */
35#if !defined(WIN32) && !defined(LACKS_TIME_H)
36#include <time.h> /* for magic initialization */
37#endif /* WIN32 */
38#ifndef LACKS_STDLIB_H
39#include <stdlib.h> /* for abort() */
40#endif /* LACKS_STDLIB_H */
41#ifndef LACKS_STRING_H
42#include <string.h> /* for memset etc */
43#endif /* LACKS_STRING_H */
44#if USE_BUILTIN_FFS
45#ifndef LACKS_STRINGS_H
46#include <strings.h> /* for ffs */
47#endif /* LACKS_STRINGS_H */
48#endif /* USE_BUILTIN_FFS */
49#if HAVE_MMAP
50#ifndef LACKS_SYS_MMAN_H
51/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */
52#if (defined(linux) && !defined(__USE_GNU))
53#define __USE_GNU 1
54#include <sys/mman.h> /* for mmap */
55#undef __USE_GNU
56#else
57#include <sys/mman.h> /* for mmap */
58#endif /* linux */
59#endif /* LACKS_SYS_MMAN_H */
60#ifndef LACKS_FCNTL_H
61#include <fcntl.h>
62#endif /* LACKS_FCNTL_H */
63#endif /* HAVE_MMAP */
64#ifndef LACKS_UNISTD_H
65#include <unistd.h> /* for sbrk, sysconf */
66#else /* LACKS_UNISTD_H */
67#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
68extern void* sbrk(ptrdiff_t);
69#endif /* FreeBSD etc */
70#endif /* LACKS_UNISTD_H */
71
72/* Declarations for locking */
73#if USE_LOCKS
74#ifndef WIN32
75#if defined (__SVR4) && defined (__sun) /* solaris */
76#include <thread.h>
77#elif !defined(LACKS_SCHED_H)
78#include <sched.h>
79#endif /* solaris or LACKS_SCHED_H */
80#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS
81#include <pthread.h>
82#endif /* USE_RECURSIVE_LOCKS ... */
83#elif defined(_MSC_VER)
84#ifndef _M_AMD64
85/* These are already defined on AMD64 builds */
86#ifdef __cplusplus
87extern "C" {
88#endif /* __cplusplus */
89LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);
90LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
91#ifdef __cplusplus
92}
93#endif /* __cplusplus */
94#endif /* _M_AMD64 */
95#pragma intrinsic (_InterlockedCompareExchange)
96#pragma intrinsic (_InterlockedExchange)
97#define interlockedcompareexchange _InterlockedCompareExchange
98#define interlockedexchange _InterlockedExchange
99#elif defined(WIN32) && defined(__GNUC__)
100#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b)
101#define interlockedexchange __sync_lock_test_and_set
102#endif /* Win32 */
103#else /* USE_LOCKS */
104#endif /* USE_LOCKS */
105
106#ifndef LOCK_AT_FORK
107#define LOCK_AT_FORK 0
108#endif
109
110/* Declarations for bit scanning on win32 */
111#if defined(_MSC_VER) && _MSC_VER>=1300
112#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */
113#ifdef __cplusplus
114extern "C" {
115#endif /* __cplusplus */
116unsigned char _BitScanForward(unsigned long *index, unsigned long mask);
117unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
118#ifdef __cplusplus
119}
120#endif /* __cplusplus */
121
122#define BitScanForward _BitScanForward
123#define BitScanReverse _BitScanReverse
124#pragma intrinsic(_BitScanForward)
125#pragma intrinsic(_BitScanReverse)
126#endif /* BitScanForward */
127#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */
128
129#ifndef WIN32
130#ifndef malloc_getpagesize
131# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
132# ifndef _SC_PAGE_SIZE
133# define _SC_PAGE_SIZE _SC_PAGESIZE
134# endif
135# endif
136# ifdef _SC_PAGE_SIZE
137# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
138# else
139# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
140 extern size_t getpagesize();
141# define malloc_getpagesize getpagesize()
142# else
143# ifdef WIN32 /* use supplied emulation of getpagesize */
144# define malloc_getpagesize getpagesize()
145# else
146# ifndef LACKS_SYS_PARAM_H
147# include <sys/param.h>
148# endif
149# ifdef EXEC_PAGESIZE
150# define malloc_getpagesize EXEC_PAGESIZE
151# else
152# ifdef NBPG
153# ifndef CLSIZE
154# define malloc_getpagesize NBPG
155# else
156# define malloc_getpagesize (NBPG * CLSIZE)
157# endif
158# else
159# ifdef NBPC
160# define malloc_getpagesize NBPC
161# else
162# ifdef PAGESIZE
163# define malloc_getpagesize PAGESIZE
164# else /* just guess */
165# define malloc_getpagesize ((size_t)4096U)
166# endif
167# endif
168# endif
169# endif
170# endif
171# endif
172# endif
173#endif
174#endif
175
176/* ------------------- size_t and alignment properties -------------------- */
177
178/* The byte and bit size of a size_t */
179#define SIZE_T_SIZE (sizeof(size_t))
180#define SIZE_T_BITSIZE (sizeof(size_t) << 3)
181
182/* Some constants coerced to size_t */
183/* Annoying but necessary to avoid errors on some platforms */
184#define SIZE_T_ZERO ((size_t)0)
185#define SIZE_T_ONE ((size_t)1)
186#define SIZE_T_TWO ((size_t)2)
187#define SIZE_T_FOUR ((size_t)4)
188#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1)
189#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2)
190#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
191#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U)
192
193/* The bit mask value corresponding to MALLOC_ALIGNMENT */
194#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE)
195
196/* True if address a has acceptable alignment */
197#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
198
199/* the number of bytes to offset an address to align it */
200#define align_offset(A)\
201 ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
202 ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
203
204/* -------------------------- MMAP preliminaries ------------------------- */
205
206/*
207 If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
208 checks to fail so compiler optimizer can delete code rather than
209 using so many "#if"s.
210*/
211
212
213/* MORECORE and MMAP must return MFAIL on failure */
214#define MFAIL ((void*)(MAX_SIZE_T))
215#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */
216
217#if HAVE_MMAP
218
219#ifndef WIN32
220#define MUNMAP_DEFAULT(a, s) munmap((a), (s))
221#define MMAP_PROT (PROT_READ|PROT_WRITE)
222#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
223#define MAP_ANONYMOUS MAP_ANON
224#endif /* MAP_ANON */
225#ifdef MAP_ANONYMOUS
226#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)
227#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
228#else /* MAP_ANONYMOUS */
229/*
230 Nearly all versions of mmap support MAP_ANONYMOUS, so the following
231 is unlikely to be needed, but is supplied just in case.
232*/
233#define MMAP_FLAGS (MAP_PRIVATE)
234static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
235#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
236 (dev_zero_fd = open("/dev/zero", O_RDWR), \
237 mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
238 mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
239#endif /* MAP_ANONYMOUS */
240
241#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
242
243#else /* WIN32 */
244
245/* Win32 MMAP via VirtualAlloc */
246static FORCEINLINE void* win32mmap(size_t size) {
247 void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
248 return (ptr != 0)? ptr: MFAIL;
249}
250
251/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
252static FORCEINLINE void* win32direct_mmap(size_t size) {
253 void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
254 PAGE_READWRITE);
255 return (ptr != 0)? ptr: MFAIL;
256}
257
258/* This function supports releasing coalesed segments */
259static FORCEINLINE int win32munmap(void* ptr, size_t size) {
260 MEMORY_BASIC_INFORMATION minfo;
261 char* cptr = (char*)ptr;
262 while (size) {
263 if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
264 return -1;
265 if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
266 minfo.State != MEM_COMMIT || minfo.RegionSize > size)
267 return -1;
268 if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
269 return -1;
270 cptr += minfo.RegionSize;
271 size -= minfo.RegionSize;
272 }
273 return 0;
274}
275
276#define MMAP_DEFAULT(s) win32mmap(s)
277#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s))
278#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s)
279#endif /* WIN32 */
280#endif /* HAVE_MMAP */
281
282#if HAVE_MREMAP
283#ifndef WIN32
284#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
285#endif /* WIN32 */
286#endif /* HAVE_MREMAP */
287
288/**
289 * Define CALL_MORECORE
290 */
291#if HAVE_MORECORE
292 #ifdef MORECORE
293 #define CALL_MORECORE(S) MORECORE(S)
294 #else /* MORECORE */
295 #define CALL_MORECORE(S) MORECORE_DEFAULT(S)
296 #endif /* MORECORE */
297#else /* HAVE_MORECORE */
298 #define CALL_MORECORE(S) MFAIL
299#endif /* HAVE_MORECORE */
300
301/**
302 * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP
303 */
304#if HAVE_MMAP
305 #define USE_MMAP_BIT (SIZE_T_ONE)
306
307 #ifdef MMAP
308 #define CALL_MMAP(s) MMAP(s)
309 #else /* MMAP */
310 #define CALL_MMAP(s) MMAP_DEFAULT(s)
311 #endif /* MMAP */
312 #ifdef MUNMAP
313 #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
314 #else /* MUNMAP */
315 #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s))
316 #endif /* MUNMAP */
317 #ifdef DIRECT_MMAP
318 #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
319 #else /* DIRECT_MMAP */
320 #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)
321 #endif /* DIRECT_MMAP */
322#else /* HAVE_MMAP */
323 #define USE_MMAP_BIT (SIZE_T_ZERO)
324
325 #define MMAP(s) MFAIL
326 #define MUNMAP(a, s) (-1)
327 #define DIRECT_MMAP(s) MFAIL
328 #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
329 #define CALL_MMAP(s) MMAP(s)
330 #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
331#endif /* HAVE_MMAP */
332
333/**
334 * Define CALL_MREMAP
335 */
336#if HAVE_MMAP && HAVE_MREMAP
337 #ifdef MREMAP
338 #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
339 #else /* MREMAP */
340 #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
341 #endif /* MREMAP */
342#else /* HAVE_MMAP && HAVE_MREMAP */
343 #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
344#endif /* HAVE_MMAP && HAVE_MREMAP */
345
Paul Vinciguerraec11b132018-09-24 05:25:00 -0700346/* mstate bit set if contiguous morecore disabled or failed */
Dave Barach6a5adc32018-07-04 10:56:23 -0400347#define USE_NONCONTIGUOUS_BIT (4U)
348
349/* mstate bit set if no expansion allowed */
350#define USE_NOEXPAND_BIT (8U)
351
352/* trace allocations if set */
353#define USE_TRACE_BIT (16U)
354
355/* segment bit set in create_mspace_with_base */
356#define EXTERN_BIT (8U)
357
358
359/* --------------------------- Lock preliminaries ------------------------ */
360
361/*
362 When locks are defined, there is one global lock, plus
363 one per-mspace lock.
364
365 The global lock_ensures that mparams.magic and other unique
366 mparams values are initialized only once. It also protects
367 sequences of calls to MORECORE. In many cases sys_alloc requires
368 two calls, that should not be interleaved with calls by other
369 threads. This does not protect against direct calls to MORECORE
370 by other threads not using this lock, so there is still code to
371 cope the best we can on interference.
372
373 Per-mspace locks surround calls to malloc, free, etc.
374 By default, locks are simple non-reentrant mutexes.
375
376 Because lock-protected regions generally have bounded times, it is
377 OK to use the supplied simple spinlocks. Spinlocks are likely to
378 improve performance for lightly contended applications, but worsen
379 performance under heavy contention.
380
381 If USE_LOCKS is > 1, the definitions of lock routines here are
382 bypassed, in which case you will need to define the type MLOCK_T,
383 and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK
384 and TRY_LOCK. You must also declare a
385 static MLOCK_T malloc_global_mutex = { initialization values };.
386
387*/
388
389#if !USE_LOCKS
390#define USE_LOCK_BIT (0U)
391#define INITIAL_LOCK(l) (0)
392#define DESTROY_LOCK(l) (0)
393#define ACQUIRE_MALLOC_GLOBAL_LOCK()
394#define RELEASE_MALLOC_GLOBAL_LOCK()
395
396#else
397#if USE_LOCKS > 1
398/* ----------------------- User-defined locks ------------------------ */
399/* Define your own lock implementation here */
400/* #define INITIAL_LOCK(lk) ... */
401/* #define DESTROY_LOCK(lk) ... */
402/* #define ACQUIRE_LOCK(lk) ... */
403/* #define RELEASE_LOCK(lk) ... */
404/* #define TRY_LOCK(lk) ... */
405/* static MLOCK_T malloc_global_mutex = ... */
406
407#elif USE_SPIN_LOCKS
408
409/* First, define CAS_LOCK and CLEAR_LOCK on ints */
410/* Note CAS_LOCK defined to return 0 on success */
411
412#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
413#define CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1)
414#define CLEAR_LOCK(sl) __sync_lock_release(sl)
415
416#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
417/* Custom spin locks for older gcc on x86 */
418static FORCEINLINE int x86_cas_lock(int *sl) {
419 int ret;
420 int val = 1;
421 int cmp = 0;
422 __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
423 : "=a" (ret)
424 : "r" (val), "m" (*(sl)), "0"(cmp)
425 : "memory", "cc");
426 return ret;
427}
428
429static FORCEINLINE void x86_clear_lock(int* sl) {
430 assert(*sl != 0);
431 int prev = 0;
432 int ret;
433 __asm__ __volatile__ ("lock; xchgl %0, %1"
434 : "=r" (ret)
435 : "m" (*(sl)), "0"(prev)
436 : "memory");
437}
438
439#define CAS_LOCK(sl) x86_cas_lock(sl)
440#define CLEAR_LOCK(sl) x86_clear_lock(sl)
441
442#else /* Win32 MSC */
443#define CAS_LOCK(sl) interlockedexchange(sl, (LONG)1)
444#define CLEAR_LOCK(sl) interlockedexchange (sl, (LONG)0)
445
446#endif /* ... gcc spins locks ... */
447
448/* How to yield for a spin lock */
449#define SPINS_PER_YIELD 63
450#if defined(_MSC_VER)
451#define SLEEP_EX_DURATION 50 /* delay for yield/sleep */
452#define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE)
453#elif defined (__SVR4) && defined (__sun) /* solaris */
454#define SPIN_LOCK_YIELD thr_yield();
455#elif !defined(LACKS_SCHED_H)
456#define SPIN_LOCK_YIELD sched_yield();
457#else
458#define SPIN_LOCK_YIELD
459#endif /* ... yield ... */
460
461#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0
462/* Plain spin locks use single word (embedded in malloc_states) */
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +0200463CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -0400464static int spin_acquire_lock(int *sl) {
465 int spins = 0;
466 while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) {
467 if ((++spins & SPINS_PER_YIELD) == 0) {
468 SPIN_LOCK_YIELD;
469 }
470 }
471 return 0;
472}
473
474#define MLOCK_T int
475#define TRY_LOCK(sl) !CAS_LOCK(sl)
476#define RELEASE_LOCK(sl) CLEAR_LOCK(sl)
477#define ACQUIRE_LOCK(sl) (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0)
478#define INITIAL_LOCK(sl) (*sl = 0)
479#define DESTROY_LOCK(sl) (0)
480static MLOCK_T malloc_global_mutex = 0;
481
482#else /* USE_RECURSIVE_LOCKS */
483/* types for lock owners */
484#ifdef WIN32
485#define THREAD_ID_T DWORD
486#define CURRENT_THREAD GetCurrentThreadId()
487#define EQ_OWNER(X,Y) ((X) == (Y))
488#else
489/*
490 Note: the following assume that pthread_t is a type that can be
491 initialized to (casted) zero. If this is not the case, you will need to
492 somehow redefine these or not use spin locks.
493*/
494#define THREAD_ID_T pthread_t
495#define CURRENT_THREAD pthread_self()
496#define EQ_OWNER(X,Y) pthread_equal(X, Y)
497#endif
498
499struct malloc_recursive_lock {
500 int sl;
501 unsigned int c;
502 THREAD_ID_T threadid;
503};
504
505#define MLOCK_T struct malloc_recursive_lock
506static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0};
507
508static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) {
509 assert(lk->sl != 0);
510 if (--lk->c == 0) {
511 CLEAR_LOCK(&lk->sl);
512 }
513}
514
515static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) {
516 THREAD_ID_T mythreadid = CURRENT_THREAD;
517 int spins = 0;
518 for (;;) {
519 if (*((volatile int *)(&lk->sl)) == 0) {
520 if (!CAS_LOCK(&lk->sl)) {
521 lk->threadid = mythreadid;
522 lk->c = 1;
523 return 0;
524 }
525 }
526 else if (EQ_OWNER(lk->threadid, mythreadid)) {
527 ++lk->c;
528 return 0;
529 }
530 if ((++spins & SPINS_PER_YIELD) == 0) {
531 SPIN_LOCK_YIELD;
532 }
533 }
534}
535
536static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) {
537 THREAD_ID_T mythreadid = CURRENT_THREAD;
538 if (*((volatile int *)(&lk->sl)) == 0) {
539 if (!CAS_LOCK(&lk->sl)) {
540 lk->threadid = mythreadid;
541 lk->c = 1;
542 return 1;
543 }
544 }
545 else if (EQ_OWNER(lk->threadid, mythreadid)) {
546 ++lk->c;
547 return 1;
548 }
549 return 0;
550}
551
552#define RELEASE_LOCK(lk) recursive_release_lock(lk)
553#define TRY_LOCK(lk) recursive_try_lock(lk)
554#define ACQUIRE_LOCK(lk) recursive_acquire_lock(lk)
555#define INITIAL_LOCK(lk) ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0)
556#define DESTROY_LOCK(lk) (0)
557#endif /* USE_RECURSIVE_LOCKS */
558
559#elif defined(WIN32) /* Win32 critical sections */
560#define MLOCK_T CRITICAL_SECTION
561#define ACQUIRE_LOCK(lk) (EnterCriticalSection(lk), 0)
562#define RELEASE_LOCK(lk) LeaveCriticalSection(lk)
563#define TRY_LOCK(lk) TryEnterCriticalSection(lk)
564#define INITIAL_LOCK(lk) (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000))
565#define DESTROY_LOCK(lk) (DeleteCriticalSection(lk), 0)
566#define NEED_GLOBAL_LOCK_INIT
567
568static MLOCK_T malloc_global_mutex;
569static volatile LONG malloc_global_mutex_status;
570
571/* Use spin loop to initialize global lock */
572static void init_malloc_global_mutex() {
573 for (;;) {
574 long stat = malloc_global_mutex_status;
575 if (stat > 0)
576 return;
577 /* transition to < 0 while initializing, then to > 0) */
578 if (stat == 0 &&
579 interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) {
580 InitializeCriticalSection(&malloc_global_mutex);
581 interlockedexchange(&malloc_global_mutex_status, (LONG)1);
582 return;
583 }
584 SleepEx(0, FALSE);
585 }
586}
587
588#else /* pthreads-based locks */
589#define MLOCK_T pthread_mutex_t
590#define ACQUIRE_LOCK(lk) pthread_mutex_lock(lk)
591#define RELEASE_LOCK(lk) pthread_mutex_unlock(lk)
592#define TRY_LOCK(lk) (!pthread_mutex_trylock(lk))
593#define INITIAL_LOCK(lk) pthread_init_lock(lk)
594#define DESTROY_LOCK(lk) pthread_mutex_destroy(lk)
595
596#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE)
597/* Cope with old-style linux recursive lock initialization by adding */
598/* skipped internal declaration from pthread.h */
599extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,
600 int __kind));
601#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
602#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)
603#endif /* USE_RECURSIVE_LOCKS ... */
604
605static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;
606
607static int pthread_init_lock (MLOCK_T *lk) {
608 pthread_mutexattr_t attr;
609 if (pthread_mutexattr_init(&attr)) return 1;
610#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0
611 if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;
612#endif
613 if (pthread_mutex_init(lk, &attr)) return 1;
614 if (pthread_mutexattr_destroy(&attr)) return 1;
615 return 0;
616}
617
618#endif /* ... lock types ... */
619
620/* Common code for all lock types */
621#define USE_LOCK_BIT (2U)
622
623#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK
624#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex);
625#endif
626
627#ifndef RELEASE_MALLOC_GLOBAL_LOCK
628#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex);
629#endif
630
631#endif /* USE_LOCKS */
632
633/* ----------------------- Chunk representations ------------------------ */
634
635/*
636 (The following includes lightly edited explanations by Colin Plumb.)
637
638 The malloc_chunk declaration below is misleading (but accurate and
639 necessary). It declares a "view" into memory allowing access to
640 necessary fields at known offsets from a given base.
641
642 Chunks of memory are maintained using a `boundary tag' method as
643 originally described by Knuth. (See the paper by Paul Wilson
644 ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
645 techniques.) Sizes of free chunks are stored both in the front of
646 each chunk and at the end. This makes consolidating fragmented
647 chunks into bigger chunks fast. The head fields also hold bits
648 representing whether chunks are free or in use.
649
650 Here are some pictures to make it clearer. They are "exploded" to
651 show that the state of a chunk can be thought of as extending from
652 the high 31 bits of the head field of its header through the
653 prev_foot and PINUSE_BIT bit of the following chunk header.
654
655 A chunk that's in use looks like:
656
657 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
658 | Size of previous chunk (if P = 0) |
659 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
660 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
661 | Size of this chunk 1| +-+
662 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
663 | |
664 +- -+
665 | |
666 +- -+
667 | :
668 +- size - sizeof(size_t) available payload bytes -+
669 : |
670 chunk-> +- -+
671 | |
672 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
673 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
674 | Size of next chunk (may or may not be in use) | +-+
675 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
676
677 And if it's free, it looks like this:
678
679 chunk-> +- -+
680 | User payload (must be in use, or we would have merged!) |
681 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
682 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
683 | Size of this chunk 0| +-+
684 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
685 | Next pointer |
686 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
687 | Prev pointer |
688 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
689 | :
690 +- size - sizeof(struct chunk) unused bytes -+
691 : |
692 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
693 | Size of this chunk |
694 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
695 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
696 | Size of next chunk (must be in use, or we would have merged)| +-+
697 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
698 | :
699 +- User payload -+
700 : |
701 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
702 |0|
703 +-+
704 Note that since we always merge adjacent free chunks, the chunks
705 adjacent to a free chunk must be in use.
706
707 Given a pointer to a chunk (which can be derived trivially from the
708 payload pointer) we can, in O(1) time, find out whether the adjacent
709 chunks are free, and if so, unlink them from the lists that they
710 are on and merge them with the current chunk.
711
712 Chunks always begin on even word boundaries, so the mem portion
713 (which is returned to the user) is also on an even word boundary, and
714 thus at least double-word aligned.
715
716 The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
717 chunk size (which is always a multiple of two words), is an in-use
718 bit for the *previous* chunk. If that bit is *clear*, then the
719 word before the current chunk size contains the previous chunk
720 size, and can be used to find the front of the previous chunk.
721 The very first chunk allocated always has this bit set, preventing
722 access to non-existent (or non-owned) memory. If pinuse is set for
723 any given chunk, then you CANNOT determine the size of the
724 previous chunk, and might even get a memory addressing fault when
725 trying to do so.
726
727 The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
728 the chunk size redundantly records whether the current chunk is
729 inuse (unless the chunk is mmapped). This redundancy enables usage
730 checks within free and realloc, and reduces indirection when freeing
731 and consolidating chunks.
732
733 Each freshly allocated chunk must have both cinuse and pinuse set.
734 That is, each allocated chunk borders either a previously allocated
735 and still in-use chunk, or the base of its memory arena. This is
736 ensured by making all allocations from the `lowest' part of any
737 found chunk. Further, no free chunk physically borders another one,
738 so each free chunk is known to be preceded and followed by either
739 inuse chunks or the ends of memory.
740
741 Note that the `foot' of the current chunk is actually represented
742 as the prev_foot of the NEXT chunk. This makes it easier to
743 deal with alignments etc but can be very confusing when trying
744 to extend or adapt this code.
745
746 The exceptions to all this are
747
748 1. The special chunk `top' is the top-most available chunk (i.e.,
749 the one bordering the end of available memory). It is treated
750 specially. Top is never included in any bin, is used only if
751 no other chunk is available, and is released back to the
752 system if it is very large (see M_TRIM_THRESHOLD). In effect,
753 the top chunk is treated as larger (and thus less well
754 fitting) than any other available chunk. The top chunk
755 doesn't update its trailing size field since there is no next
756 contiguous chunk that would have to index off it. However,
757 space is still allocated for it (TOP_FOOT_SIZE) to enable
758 separation or merging when space is extended.
759
760 3. Chunks allocated via mmap, have both cinuse and pinuse bits
761 cleared in their head fields. Because they are allocated
762 one-by-one, each must carry its own prev_foot field, which is
763 also used to hold the offset this chunk has within its mmapped
764 region, which is needed to preserve alignment. Each mmapped
765 chunk is trailed by the first two fields of a fake next-chunk
766 for sake of usage checks.
767
768*/
769
770struct malloc_chunk {
771 size_t prev_foot; /* Size of previous chunk (if free). */
772 size_t head; /* Size and inuse bits. */
773 struct malloc_chunk* fd; /* double links -- used only if free. */
774 struct malloc_chunk* bk;
775};
776
777typedef struct malloc_chunk mchunk;
778typedef struct malloc_chunk* mchunkptr;
779typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
780typedef unsigned int bindex_t; /* Described below */
781typedef unsigned int binmap_t; /* Described below */
782typedef unsigned int flag_t; /* The type of various bit flag sets */
783
784/* ------------------- Chunks sizes and alignments ----------------------- */
785
786#define MCHUNK_SIZE (sizeof(mchunk))
787
788#if FOOTERS
789#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
790#else /* FOOTERS */
791#define CHUNK_OVERHEAD (SIZE_T_SIZE)
792#endif /* FOOTERS */
793
794/* MMapped chunks need a second word of overhead ... */
795#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
796/* ... and additional padding for fake next-chunk at foot */
797#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES)
798
799/* The smallest size we can malloc is an aligned minimal chunk */
800#define MIN_CHUNK_SIZE\
801 ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
802
803/* conversion from malloc headers to user pointers, and back */
804#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES))
805#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
806/* chunk associated with aligned address A */
807#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A)))
808
809/* Bounds on request (not chunk) sizes. */
810#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2)
811#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
812
813/* pad request bytes into a usable size */
814#define pad_request(req) \
815 (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
816
817/* pad request, checking for minimum (but not maximum) */
818#define request2size(req) \
819 (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
820
821
822/* ------------------ Operations on head and foot fields ----------------- */
823
824/*
825 The head field of a chunk is or'ed with PINUSE_BIT when previous
826 adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
827 use, unless mmapped, in which case both bits are cleared.
828
829 FLAG4_BIT is not used by this malloc, but might be useful in extensions.
830*/
831
832#define PINUSE_BIT (SIZE_T_ONE)
833#define CINUSE_BIT (SIZE_T_TWO)
834#define FLAG4_BIT (SIZE_T_FOUR)
835#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT)
836#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)
837
838/* Head value for fenceposts */
839#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE)
840
841/* extraction of fields from head words */
842#define cinuse(p) ((p)->head & CINUSE_BIT)
843#define pinuse(p) ((p)->head & PINUSE_BIT)
844#define flag4inuse(p) ((p)->head & FLAG4_BIT)
845#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT)
846#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0)
847
848#define chunksize(p) ((p)->head & ~(FLAG_BITS))
849
850#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT)
851#define set_flag4(p) ((p)->head |= FLAG4_BIT)
852#define clear_flag4(p) ((p)->head &= ~FLAG4_BIT)
853
854/* Treat space at ptr +/- offset as a chunk */
855#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
856#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
857
858/* Ptr to next or previous physical malloc_chunk. */
859#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))
860#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
861
862/* extract next chunk's pinuse bit */
863#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT)
864
865/* Get/set size at footer */
866#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot)
867#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
868
869/* Set size, pinuse bit, and foot */
870#define set_size_and_pinuse_of_free_chunk(p, s)\
871 ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
872
873/* Set size, pinuse bit, foot, and clear next pinuse */
874#define set_free_with_pinuse(p, s, n)\
875 (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
876
877/* Get the internal overhead associated with chunk p */
878#define overhead_for(p)\
879 (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
880
881/* Return true if malloced space is not necessarily cleared */
882#if MMAP_CLEARS
883#define calloc_must_clear(p) (!is_mmapped(p))
884#else /* MMAP_CLEARS */
885#define calloc_must_clear(p) (1)
886#endif /* MMAP_CLEARS */
887
888/* ---------------------- Overlaid data structures ----------------------- */
889
890/*
891 When chunks are not in use, they are treated as nodes of either
892 lists or trees.
893
894 "Small" chunks are stored in circular doubly-linked lists, and look
895 like this:
896
897 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
898 | Size of previous chunk |
899 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
900 `head:' | Size of chunk, in bytes |P|
901 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
902 | Forward pointer to next chunk in list |
903 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
904 | Back pointer to previous chunk in list |
905 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
906 | Unused space (may be 0 bytes long) .
907 . .
908 . |
909nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
910 `foot:' | Size of chunk, in bytes |
911 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
912
913 Larger chunks are kept in a form of bitwise digital trees (aka
914 tries) keyed on chunksizes. Because malloc_tree_chunks are only for
915 free chunks greater than 256 bytes, their size doesn't impose any
916 constraints on user chunk sizes. Each node looks like:
917
918 chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
919 | Size of previous chunk |
920 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
921 `head:' | Size of chunk, in bytes |P|
922 mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
923 | Forward pointer to next chunk of same size |
924 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
925 | Back pointer to previous chunk of same size |
926 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
927 | Pointer to left child (child[0]) |
928 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
929 | Pointer to right child (child[1]) |
930 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
931 | Pointer to parent |
932 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
933 | bin index of this chunk |
934 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
935 | Unused space .
936 . |
937nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
938 `foot:' | Size of chunk, in bytes |
939 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
940
941 Each tree holding treenodes is a tree of unique chunk sizes. Chunks
942 of the same size are arranged in a circularly-linked list, with only
943 the oldest chunk (the next to be used, in our FIFO ordering)
944 actually in the tree. (Tree members are distinguished by a non-null
945 parent pointer.) If a chunk with the same size an an existing node
946 is inserted, it is linked off the existing node using pointers that
947 work in the same way as fd/bk pointers of small chunks.
948
949 Each tree contains a power of 2 sized range of chunk sizes (the
950 smallest is 0x100 <= x < 0x180), which is is divided in half at each
951 tree level, with the chunks in the smaller half of the range (0x100
952 <= x < 0x140 for the top nose) in the left subtree and the larger
953 half (0x140 <= x < 0x180) in the right subtree. This is, of course,
954 done by inspecting individual bits.
955
956 Using these rules, each node's left subtree contains all smaller
957 sizes than its right subtree. However, the node at the root of each
958 subtree has no particular ordering relationship to either. (The
959 dividing line between the subtree sizes is based on trie relation.)
960 If we remove the last chunk of a given size from the interior of the
961 tree, we need to replace it with a leaf node. The tree ordering
962 rules permit a node to be replaced by any leaf below it.
963
964 The smallest chunk in a tree (a common operation in a best-fit
965 allocator) can be found by walking a path to the leftmost leaf in
966 the tree. Unlike a usual binary tree, where we follow left child
967 pointers until we reach a null, here we follow the right child
968 pointer any time the left one is null, until we reach a leaf with
969 both child pointers null. The smallest chunk in the tree will be
970 somewhere along that path.
971
972 The worst case number of steps to add, find, or remove a node is
973 bounded by the number of bits differentiating chunks within
974 bins. Under current bin calculations, this ranges from 6 up to 21
975 (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
976 is of course much better.
977*/
978
979struct malloc_tree_chunk {
980 /* The first four fields must be compatible with malloc_chunk */
981 size_t prev_foot;
982 size_t head;
983 struct malloc_tree_chunk* fd;
984 struct malloc_tree_chunk* bk;
985
986 struct malloc_tree_chunk* child[2];
987 struct malloc_tree_chunk* parent;
988 bindex_t index;
989};
990
991typedef struct malloc_tree_chunk tchunk;
992typedef struct malloc_tree_chunk* tchunkptr;
993typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
994
995/* A little helper macro for trees */
996#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
997
998/* ----------------------------- Segments -------------------------------- */
999
1000/*
1001 Each malloc space may include non-contiguous segments, held in a
1002 list headed by an embedded malloc_segment record representing the
1003 top-most space. Segments also include flags holding properties of
1004 the space. Large chunks that are directly allocated by mmap are not
1005 included in this list. They are instead independently created and
1006 destroyed without otherwise keeping track of them.
1007
1008 Segment management mainly comes into play for spaces allocated by
1009 MMAP. Any call to MMAP might or might not return memory that is
1010 adjacent to an existing segment. MORECORE normally contiguously
1011 extends the current space, so this space is almost always adjacent,
1012 which is simpler and faster to deal with. (This is why MORECORE is
1013 used preferentially to MMAP when both are available -- see
1014 sys_alloc.) When allocating using MMAP, we don't use any of the
1015 hinting mechanisms (inconsistently) supported in various
1016 implementations of unix mmap, or distinguish reserving from
1017 committing memory. Instead, we just ask for space, and exploit
1018 contiguity when we get it. It is probably possible to do
1019 better than this on some systems, but no general scheme seems
1020 to be significantly better.
1021
1022 Management entails a simpler variant of the consolidation scheme
1023 used for chunks to reduce fragmentation -- new adjacent memory is
1024 normally prepended or appended to an existing segment. However,
1025 there are limitations compared to chunk consolidation that mostly
1026 reflect the fact that segment processing is relatively infrequent
1027 (occurring only when getting memory from system) and that we
1028 don't expect to have huge numbers of segments:
1029
1030 * Segments are not indexed, so traversal requires linear scans. (It
1031 would be possible to index these, but is not worth the extra
1032 overhead and complexity for most programs on most platforms.)
1033 * New segments are only appended to old ones when holding top-most
1034 memory; if they cannot be prepended to others, they are held in
1035 different segments.
1036
1037 Except for the top-most segment of an mstate, each segment record
1038 is kept at the tail of its segment. Segments are added by pushing
1039 segment records onto the list headed by &mstate.seg for the
1040 containing mstate.
1041
1042 Segment flags control allocation/merge/deallocation policies:
1043 * If EXTERN_BIT set, then we did not allocate this segment,
1044 and so should not try to deallocate or merge with others.
1045 (This currently holds only for the initial segment passed
1046 into create_mspace_with_base.)
1047 * If USE_MMAP_BIT set, the segment may be merged with
1048 other surrounding mmapped segments and trimmed/de-allocated
1049 using munmap.
1050 * If neither bit is set, then the segment was obtained using
1051 MORECORE so can be merged with surrounding MORECORE'd segments
1052 and deallocated/trimmed using MORECORE with negative arguments.
1053*/
1054
1055struct malloc_segment {
1056 char* base; /* base address */
1057 size_t size; /* allocated size */
1058 struct malloc_segment* next; /* ptr to next segment */
1059 flag_t sflags; /* mmap and extern flag */
1060};
1061
1062#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT)
1063#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT)
1064
1065typedef struct malloc_segment msegment;
1066typedef struct malloc_segment* msegmentptr;
1067
1068/* ---------------------------- malloc_state ----------------------------- */
1069
1070/*
1071 A malloc_state holds all of the bookkeeping for a space.
1072 The main fields are:
1073
1074 Top
1075 The topmost chunk of the currently active segment. Its size is
1076 cached in topsize. The actual size of topmost space is
1077 topsize+TOP_FOOT_SIZE, which includes space reserved for adding
1078 fenceposts and segment records if necessary when getting more
1079 space from the system. The size at which to autotrim top is
1080 cached from mparams in trim_check, except that it is disabled if
1081 an autotrim fails.
1082
1083 Designated victim (dv)
1084 This is the preferred chunk for servicing small requests that
1085 don't have exact fits. It is normally the chunk split off most
1086 recently to service another small request. Its size is cached in
1087 dvsize. The link fields of this chunk are not maintained since it
1088 is not kept in a bin.
1089
1090 SmallBins
1091 An array of bin headers for free chunks. These bins hold chunks
1092 with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
1093 chunks of all the same size, spaced 8 bytes apart. To simplify
1094 use in double-linked lists, each bin header acts as a malloc_chunk
1095 pointing to the real first node, if it exists (else pointing to
1096 itself). This avoids special-casing for headers. But to avoid
1097 waste, we allocate only the fd/bk pointers of bins, and then use
1098 repositioning tricks to treat these as the fields of a chunk.
1099
1100 TreeBins
1101 Treebins are pointers to the roots of trees holding a range of
1102 sizes. There are 2 equally spaced treebins for each power of two
1103 from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
1104 larger.
1105
1106 Bin maps
1107 There is one bit map for small bins ("smallmap") and one for
1108 treebins ("treemap). Each bin sets its bit when non-empty, and
1109 clears the bit when empty. Bit operations are then used to avoid
1110 bin-by-bin searching -- nearly all "search" is done without ever
1111 looking at bins that won't be selected. The bit maps
1112 conservatively use 32 bits per map word, even if on 64bit system.
1113 For a good description of some of the bit-based techniques used
1114 here, see Henry S. Warren Jr's book "Hacker's Delight" (and
1115 supplement at http://hackersdelight.org/). Many of these are
1116 intended to reduce the branchiness of paths through malloc etc, as
1117 well as to reduce the number of memory locations read or written.
1118
1119 Segments
1120 A list of segments headed by an embedded malloc_segment record
1121 representing the initial space.
1122
1123 Address check support
1124 The least_addr field is the least address ever obtained from
1125 MORECORE or MMAP. Attempted frees and reallocs of any address less
1126 than this are trapped (unless INSECURE is defined).
1127
1128 Magic tag
1129 A cross-check field that should always hold same value as mparams.magic.
1130
1131 Max allowed footprint
1132 The maximum allowed bytes to allocate from system (zero means no limit)
1133
1134 Flags
1135 Bits recording whether to use MMAP, locks, or contiguous MORECORE
1136
1137 Statistics
1138 Each space keeps track of current and maximum system memory
1139 obtained via MORECORE or MMAP.
1140
1141 Trim support
1142 Fields holding the amount of unused topmost memory that should trigger
1143 trimming, and a counter to force periodic scanning to release unused
1144 non-topmost segments.
1145
1146 Locking
1147 If USE_LOCKS is defined, the "mutex" lock is acquired and released
1148 around every public call using this mspace.
1149
1150 Extension support
1151 A void* pointer and a size_t field that can be used to help implement
1152 extensions to this malloc.
1153*/
1154
1155/* Bin types, widths and sizes */
1156#define NSMALLBINS (32U)
1157#define NTREEBINS (32U)
1158#define SMALLBIN_SHIFT (3U)
1159#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT)
1160#define TREEBIN_SHIFT (8U)
1161#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT)
1162#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE)
1163#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
1164
1165struct malloc_state {
1166 binmap_t smallmap;
1167 binmap_t treemap;
1168 size_t dvsize;
1169 size_t topsize;
1170 char* least_addr;
1171 mchunkptr dv;
1172 mchunkptr top;
1173 size_t trim_check;
1174 size_t release_checks;
1175 size_t magic;
1176 mchunkptr smallbins[(NSMALLBINS+1)*2];
1177 tbinptr treebins[NTREEBINS];
1178 size_t footprint;
1179 size_t max_footprint;
1180 size_t footprint_limit; /* zero means no limit */
1181 flag_t mflags;
1182#if USE_LOCKS
1183 MLOCK_T mutex; /* locate lock among fields that rarely change */
1184#endif /* USE_LOCKS */
1185 msegment seg;
1186 void* extp; /* Unused but available for extensions */
1187 size_t exts;
1188};
1189
1190typedef struct malloc_state* mstate;
1191
1192/* ------------- Global malloc_state and malloc_params ------------------- */
1193
1194/*
1195 malloc_params holds global properties, including those that can be
1196 dynamically set using mallopt. There is a single instance, mparams,
1197 initialized in init_mparams. Note that the non-zeroness of "magic"
1198 also serves as an initialization flag.
1199*/
1200
1201struct malloc_params {
1202 size_t magic;
1203 size_t page_size;
1204 size_t granularity;
1205 size_t mmap_threshold;
1206 size_t trim_threshold;
1207 flag_t default_mflags;
1208};
1209
1210static struct malloc_params mparams;
1211
1212/* Ensure mparams initialized */
1213#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
1214
1215#if !ONLY_MSPACES
1216
1217/* The global malloc_state used for all non-"mspace" calls */
1218static struct malloc_state _gm_;
1219#define gm (&_gm_)
1220#define is_global(M) ((M) == &_gm_)
1221
1222#endif /* !ONLY_MSPACES */
1223
1224#define is_initialized(M) ((M)->top != 0)
1225
1226/* -------------------------- system alloc setup ------------------------- */
1227
1228/* Operations on mflags */
1229
1230#define use_lock(M) ((M)->mflags & USE_LOCK_BIT)
1231#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT)
1232#if USE_LOCKS
1233#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT)
1234#else
1235#define disable_lock(M)
1236#endif
1237
1238#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT)
1239#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT)
1240#if HAVE_MMAP
1241#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT)
1242#else
1243#define disable_mmap(M)
1244#endif
1245
1246#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT)
1247#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT)
1248#define use_noexpand(M) ((M)->mflags & USE_NOEXPAND_BIT)
1249#define disable_expand(M) ((M)->mflags |= USE_NOEXPAND_BIT)
1250#define use_trace(M) ((M)->mflags & USE_TRACE_BIT)
1251#define enable_trace(M) ((M)->mflags |= USE_TRACE_BIT)
1252#define disable_trace(M) ((M)->mflags |= USE_TRACE_BIT)
1253
1254#define set_lock(M,L)\
1255 ((M)->mflags = (L)?\
1256 ((M)->mflags | USE_LOCK_BIT) :\
1257 ((M)->mflags & ~USE_LOCK_BIT))
1258
1259/* page-align a size */
1260#define page_align(S)\
1261 (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
1262
1263/* granularity-align a size */
1264#define granularity_align(S)\
1265 (((S) + (mparams.granularity - SIZE_T_ONE))\
1266 & ~(mparams.granularity - SIZE_T_ONE))
1267
1268
1269/* For mmap, use granularity alignment on windows, else page-align */
1270#ifdef WIN32
1271#define mmap_align(S) granularity_align(S)
1272#else
1273#define mmap_align(S) page_align(S)
1274#endif
1275
1276/* For sys_alloc, enough padding to ensure can malloc request on success */
1277#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)
1278
1279#define is_page_aligned(S)\
1280 (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
1281#define is_granularity_aligned(S)\
1282 (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
1283
1284/* True if segment S holds address A */
1285#define segment_holds(S, A)\
1286 ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
1287
1288/* Return segment holding given address */
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02001289CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04001290static msegmentptr segment_holding(mstate m, char* addr) {
1291 msegmentptr sp = &m->seg;
1292 for (;;) {
1293 if (addr >= sp->base && addr < sp->base + sp->size)
1294 return sp;
1295 if ((sp = sp->next) == 0)
1296 return 0;
1297 }
1298}
1299
1300/* Return true if segment contains a segment link */
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02001301CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04001302static int has_segment_link(mstate m, msegmentptr ss) {
1303 msegmentptr sp = &m->seg;
1304 for (;;) {
1305 if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
1306 return 1;
1307 if ((sp = sp->next) == 0)
1308 return 0;
1309 }
1310}
1311
1312#ifndef MORECORE_CANNOT_TRIM
1313#define should_trim(M,s) ((s) > (M)->trim_check)
1314#else /* MORECORE_CANNOT_TRIM */
1315#define should_trim(M,s) (0)
1316#endif /* MORECORE_CANNOT_TRIM */
1317
1318/*
1319 TOP_FOOT_SIZE is padding at the end of a segment, including space
1320 that may be needed to place segment records and fenceposts when new
1321 noncontiguous segments are added.
1322*/
1323#define TOP_FOOT_SIZE\
1324 (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
1325
1326
1327/* ------------------------------- Hooks -------------------------------- */
1328
1329/*
1330 PREACTION should be defined to return 0 on success, and nonzero on
1331 failure. If you are not using locking, you can redefine these to do
1332 anything you like.
1333*/
1334
1335#if USE_LOCKS
1336#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
1337#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
1338#else /* USE_LOCKS */
1339
1340#ifndef PREACTION
1341#define PREACTION(M) (0)
1342#endif /* PREACTION */
1343
1344#ifndef POSTACTION
1345#define POSTACTION(M)
1346#endif /* POSTACTION */
1347
1348#endif /* USE_LOCKS */
1349
1350/*
1351 CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
1352 USAGE_ERROR_ACTION is triggered on detected bad frees and
1353 reallocs. The argument p is an address that might have triggered the
1354 fault. It is ignored by the two predefined actions, but might be
1355 useful in custom actions that try to help diagnose errors.
1356*/
1357
1358#if PROCEED_ON_ERROR
1359
1360/* A count of the number of corruption errors causing resets */
1361int malloc_corruption_error_count;
1362
1363/* default corruption action */
1364static void reset_on_error(mstate m);
1365
1366#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m)
1367#define USAGE_ERROR_ACTION(m, p)
1368
1369#else /* PROCEED_ON_ERROR */
1370
1371#ifndef CORRUPTION_ERROR_ACTION
1372#define CORRUPTION_ERROR_ACTION(m) DLM_ABORT
1373#endif /* CORRUPTION_ERROR_ACTION */
1374
1375#ifndef USAGE_ERROR_ACTION
1376#define USAGE_ERROR_ACTION(m,p) DLM_ABORT
1377#endif /* USAGE_ERROR_ACTION */
1378
1379#endif /* PROCEED_ON_ERROR */
1380
1381
1382/* -------------------------- Debugging setup ---------------------------- */
1383
1384#if ! DEBUG
1385
1386#define check_free_chunk(M,P)
1387#define check_inuse_chunk(M,P)
1388#define check_malloced_chunk(M,P,N)
1389#define check_mmapped_chunk(M,P)
1390#define check_malloc_state(M)
1391#define check_top_chunk(M,P)
1392
1393#else /* DEBUG */
1394#define check_free_chunk(M,P) do_check_free_chunk(M,P)
1395#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P)
1396#define check_top_chunk(M,P) do_check_top_chunk(M,P)
1397#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
1398#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P)
1399#define check_malloc_state(M) do_check_malloc_state(M)
1400
1401static void do_check_any_chunk(mstate m, mchunkptr p);
1402static void do_check_top_chunk(mstate m, mchunkptr p);
1403static void do_check_mmapped_chunk(mstate m, mchunkptr p);
1404static void do_check_inuse_chunk(mstate m, mchunkptr p);
1405static void do_check_free_chunk(mstate m, mchunkptr p);
1406static void do_check_malloced_chunk(mstate m, void* mem, size_t s);
1407static void do_check_tree(mstate m, tchunkptr t);
1408static void do_check_treebin(mstate m, bindex_t i);
1409static void do_check_smallbin(mstate m, bindex_t i);
1410static void do_check_malloc_state(mstate m);
1411static int bin_find(mstate m, mchunkptr x);
1412static size_t traverse_and_check(mstate m);
1413#endif /* DEBUG */
1414
1415/* ---------------------------- Indexing Bins ---------------------------- */
1416
1417#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
1418#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT)
1419#define small_index2size(i) ((i) << SMALLBIN_SHIFT)
1420#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
1421
1422/* addressing by index. See above about smallbin repositioning */
1423#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
1424#define treebin_at(M,i) (&((M)->treebins[i]))
1425
1426/* assign tree index for size S to variable I. Use x86 asm if possible */
1427#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1428#define compute_tree_index(S, I)\
1429{\
1430 unsigned int X = S >> TREEBIN_SHIFT;\
1431 if (X == 0)\
1432 I = 0;\
1433 else if (X > 0xFFFF)\
1434 I = NTREEBINS-1;\
1435 else {\
1436 unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \
1437 I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
1438 }\
1439}
1440
1441#elif defined (__INTEL_COMPILER)
1442#define compute_tree_index(S, I)\
1443{\
1444 size_t X = S >> TREEBIN_SHIFT;\
1445 if (X == 0)\
1446 I = 0;\
1447 else if (X > 0xFFFF)\
1448 I = NTREEBINS-1;\
1449 else {\
1450 unsigned int K = _bit_scan_reverse (X); \
1451 I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
1452 }\
1453}
1454
1455#elif defined(_MSC_VER) && _MSC_VER>=1300
1456#define compute_tree_index(S, I)\
1457{\
1458 size_t X = S >> TREEBIN_SHIFT;\
1459 if (X == 0)\
1460 I = 0;\
1461 else if (X > 0xFFFF)\
1462 I = NTREEBINS-1;\
1463 else {\
1464 unsigned int K;\
1465 _BitScanReverse((DWORD *) &K, (DWORD) X);\
1466 I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
1467 }\
1468}
1469
1470#else /* GNUC */
1471#define compute_tree_index(S, I)\
1472{\
1473 size_t X = S >> TREEBIN_SHIFT;\
1474 if (X == 0)\
1475 I = 0;\
1476 else if (X > 0xFFFF)\
1477 I = NTREEBINS-1;\
1478 else {\
1479 unsigned int Y = (unsigned int)X;\
1480 unsigned int N = ((Y - 0x100) >> 16) & 8;\
1481 unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
1482 N += K;\
1483 N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
1484 K = 14 - N + ((Y <<= K) >> 15);\
1485 I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
1486 }\
1487}
1488#endif /* GNUC */
1489
1490/* Bit representing maximum resolved size in a treebin at i */
1491#define bit_for_tree_index(i) \
1492 (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
1493
1494/* Shift placing maximum resolved bit in a treebin at i as sign bit */
1495#define leftshift_for_tree_index(i) \
1496 ((i == NTREEBINS-1)? 0 : \
1497 ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
1498
1499/* The size of the smallest chunk held in bin with index i */
1500#define minsize_for_tree_index(i) \
1501 ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \
1502 (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
1503
1504
1505/* ------------------------ Operations on bin maps ----------------------- */
1506
1507/* bit corresponding to given index */
1508#define idx2bit(i) ((binmap_t)(1) << (i))
1509
1510/* Mark/Clear bits with given index */
1511#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i))
1512#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i))
1513#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i))
1514
1515#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i))
1516#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i))
1517#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i))
1518
1519/* isolate the least set bit of a bitmap */
1520#define least_bit(x) ((x) & -(x))
1521
1522/* mask with all bits to left of least bit of x on */
1523#define left_bits(x) ((x<<1) | -(x<<1))
1524
1525/* mask with all bits to left of or equal to least bit of x on */
1526#define same_or_left_bits(x) ((x) | -(x))
1527
1528/* index corresponding to given bit. Use x86 asm if possible */
1529
1530#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
1531#define compute_bit2idx(X, I)\
1532{\
1533 unsigned int J;\
1534 J = __builtin_ctz(X); \
1535 I = (bindex_t)J;\
1536}
1537
1538#elif defined (__INTEL_COMPILER)
1539#define compute_bit2idx(X, I)\
1540{\
1541 unsigned int J;\
1542 J = _bit_scan_forward (X); \
1543 I = (bindex_t)J;\
1544}
1545
1546#elif defined(_MSC_VER) && _MSC_VER>=1300
1547#define compute_bit2idx(X, I)\
1548{\
1549 unsigned int J;\
1550 _BitScanForward((DWORD *) &J, X);\
1551 I = (bindex_t)J;\
1552}
1553
1554#elif USE_BUILTIN_FFS
1555#define compute_bit2idx(X, I) I = ffs(X)-1
1556
1557#else
1558#define compute_bit2idx(X, I)\
1559{\
1560 unsigned int Y = X - 1;\
1561 unsigned int K = Y >> (16-4) & 16;\
1562 unsigned int N = K; Y >>= K;\
1563 N += K = Y >> (8-3) & 8; Y >>= K;\
1564 N += K = Y >> (4-2) & 4; Y >>= K;\
1565 N += K = Y >> (2-1) & 2; Y >>= K;\
1566 N += K = Y >> (1-0) & 1; Y >>= K;\
1567 I = (bindex_t)(N + Y);\
1568}
1569#endif /* GNUC */
1570
1571
1572/* ----------------------- Runtime Check Support ------------------------- */
1573
1574/*
1575 For security, the main invariant is that malloc/free/etc never
1576 writes to a static address other than malloc_state, unless static
1577 malloc_state itself has been corrupted, which cannot occur via
1578 malloc (because of these checks). In essence this means that we
1579 believe all pointers, sizes, maps etc held in malloc_state, but
1580 check all of those linked or offsetted from other embedded data
1581 structures. These checks are interspersed with main code in a way
1582 that tends to minimize their run-time cost.
1583
1584 When FOOTERS is defined, in addition to range checking, we also
1585 verify footer fields of inuse chunks, which can be used guarantee
1586 that the mstate controlling malloc/free is intact. This is a
1587 streamlined version of the approach described by William Robertson
1588 et al in "Run-time Detection of Heap-based Overflows" LISA'03
1589 http://www.usenix.org/events/lisa03/tech/robertson.html The footer
1590 of an inuse chunk holds the xor of its mstate and a random seed,
1591 that is checked upon calls to free() and realloc(). This is
Paul Vinciguerraec11b132018-09-24 05:25:00 -07001592 (probabilistically) unguessable from outside the program, but can be
Dave Barach6a5adc32018-07-04 10:56:23 -04001593 computed by any code successfully malloc'ing any chunk, so does not
1594 itself provide protection against code that has already broken
1595 security through some other means. Unlike Robertson et al, we
1596 always dynamically check addresses of all offset chunks (previous,
1597 next, etc). This turns out to be cheaper than relying on hashes.
1598*/
1599
1600#if !INSECURE
1601/* Check if address a is at least as high as any from MORECORE or MMAP */
1602#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
1603/* Check if address of next chunk n is higher than base chunk p */
1604#define ok_next(p, n) ((char*)(p) < (char*)(n))
1605/* Check if p has inuse status */
1606#define ok_inuse(p) is_inuse(p)
1607/* Check if p has its pinuse bit on */
1608#define ok_pinuse(p) pinuse(p)
1609
1610#else /* !INSECURE */
1611#define ok_address(M, a) (1)
1612#define ok_next(b, n) (1)
1613#define ok_inuse(p) (1)
1614#define ok_pinuse(p) (1)
1615#endif /* !INSECURE */
1616
1617#if (FOOTERS && !INSECURE)
1618/* Check if (alleged) mstate m has expected magic field */
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02001619CLIB_NOSANITIZE_ADDR
Neale Rannsa88c9162018-08-06 08:16:29 -04001620static inline int
1621ok_magic (const mstate m)
1622{
1623 return (m->magic == mparams.magic);
1624}
Dave Barach6a5adc32018-07-04 10:56:23 -04001625#else /* (FOOTERS && !INSECURE) */
1626#define ok_magic(M) (1)
1627#endif /* (FOOTERS && !INSECURE) */
1628
1629/* In gcc, use __builtin_expect to minimize impact of checks */
1630#if !INSECURE
1631#if defined(__GNUC__) && __GNUC__ >= 3
1632#define RTCHECK(e) __builtin_expect(e, 1)
1633#else /* GNUC */
1634#define RTCHECK(e) (e)
1635#endif /* GNUC */
1636#else /* !INSECURE */
1637#define RTCHECK(e) (1)
1638#endif /* !INSECURE */
1639
1640/* macros to set up inuse chunks with or without footers */
1641
1642#if !FOOTERS
1643
1644#define mark_inuse_foot(M,p,s)
1645
1646/* Macros for setting head/foot of non-mmapped chunks */
1647
1648/* Set cinuse bit and pinuse bit of next chunk */
1649#define set_inuse(M,p,s)\
1650 ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
1651 ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
1652
1653/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
1654#define set_inuse_and_pinuse(M,p,s)\
1655 ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
1656 ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
1657
1658/* Set size, cinuse and pinuse bit of this chunk */
1659#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
1660 ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
1661
1662#else /* FOOTERS */
1663
1664/* Set foot of inuse chunk to be xor of mstate and seed */
1665#define mark_inuse_foot(M,p,s)\
1666 (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
1667
1668#define get_mstate_for(p)\
1669 ((mstate)(((mchunkptr)((char*)(p) +\
1670 (chunksize(p))))->prev_foot ^ mparams.magic))
1671
1672#define set_inuse(M,p,s)\
1673 ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
1674 (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
1675 mark_inuse_foot(M,p,s))
1676
1677#define set_inuse_and_pinuse(M,p,s)\
1678 ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
1679 (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
1680 mark_inuse_foot(M,p,s))
1681
1682#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
1683 ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
1684 mark_inuse_foot(M, p, s))
1685
1686#endif /* !FOOTERS */
1687
1688/* ---------------------------- setting mparams -------------------------- */
1689
1690#if LOCK_AT_FORK
1691static void pre_fork(void) { ACQUIRE_LOCK(&(gm)->mutex); }
1692static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); }
1693static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); }
1694#endif /* LOCK_AT_FORK */
1695
1696/* Initialize mparams */
1697static int init_mparams(void) {
1698#ifdef NEED_GLOBAL_LOCK_INIT
1699 if (malloc_global_mutex_status <= 0)
1700 init_malloc_global_mutex();
1701#endif
1702
1703 ACQUIRE_MALLOC_GLOBAL_LOCK();
1704 if (mparams.magic == 0) {
1705 size_t magic;
1706 size_t psize;
1707 size_t gsize;
1708
1709#ifndef WIN32
1710 psize = malloc_getpagesize;
1711 gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);
1712#else /* WIN32 */
1713 {
1714 SYSTEM_INFO system_info;
1715 GetSystemInfo(&system_info);
1716 psize = system_info.dwPageSize;
1717 gsize = ((DEFAULT_GRANULARITY != 0)?
1718 DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
1719 }
1720#endif /* WIN32 */
1721
1722 /* Sanity-check configuration:
1723 size_t must be unsigned and as wide as pointer type.
1724 ints must be at least 4 bytes.
1725 alignment must be at least 8.
1726 Alignment, min chunk size, and page size must all be powers of 2.
1727 */
1728 if ((sizeof(size_t) != sizeof(char*)) ||
1729 (MAX_SIZE_T < MIN_CHUNK_SIZE) ||
1730 (sizeof(int) < 4) ||
1731 (MALLOC_ALIGNMENT < (size_t)8U) ||
1732 ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
1733 ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) ||
1734 ((gsize & (gsize-SIZE_T_ONE)) != 0) ||
1735 ((psize & (psize-SIZE_T_ONE)) != 0))
1736 DLM_ABORT;
1737 mparams.granularity = gsize;
1738 mparams.page_size = psize;
1739 mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
1740 mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
1741#if MORECORE_CONTIGUOUS
1742 mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
1743#else /* MORECORE_CONTIGUOUS */
1744 mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
1745#endif /* MORECORE_CONTIGUOUS */
1746
1747#if !ONLY_MSPACES
1748 /* Set up lock for main malloc area */
1749 gm->mflags = mparams.default_mflags;
1750 (void)INITIAL_LOCK(&gm->mutex);
1751#endif
1752#if LOCK_AT_FORK
1753 pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);
1754#endif
1755
1756 {
Florin Corasd3ca8ff2018-07-28 04:53:30 -07001757#ifndef DLM_MAGIC_CONSTANT
Dave Barach6a5adc32018-07-04 10:56:23 -04001758#if USE_DEV_RANDOM
1759 int fd;
1760 unsigned char buf[sizeof(size_t)];
1761 /* Try to use /dev/urandom, else fall back on using time */
1762 if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
1763 read(fd, buf, sizeof(buf)) == sizeof(buf)) {
1764 magic = *((size_t *) buf);
1765 close(fd);
1766 }
1767 else
1768#endif /* USE_DEV_RANDOM */
1769#ifdef WIN32
1770 magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
1771#elif defined(LACKS_TIME_H)
1772 magic = (size_t)&magic ^ (size_t)0x55555555U;
1773#else
1774 magic = (size_t)(time(0) ^ (size_t)0x55555555U);
1775#endif
1776 magic |= (size_t)8U; /* ensure nonzero */
1777 magic &= ~(size_t)7U; /* improve chances of fault for bad values */
Florin Corasd3ca8ff2018-07-28 04:53:30 -07001778#else
Florin Corasd0554752018-07-27 11:30:46 -07001779 magic = DLM_MAGIC_CONSTANT;
1780#endif
Dave Barach6a5adc32018-07-04 10:56:23 -04001781 /* Until memory modes commonly available, use volatile-write */
1782 (*(volatile size_t *)(&(mparams.magic))) = magic;
1783 }
1784 }
1785
1786 RELEASE_MALLOC_GLOBAL_LOCK();
1787 return 1;
1788}
1789
1790/* support for mallopt */
1791static int change_mparam(int param_number, int value) {
1792 size_t val;
1793 ensure_initialization();
1794 val = (value == -1)? MAX_SIZE_T : (size_t)value;
1795 switch(param_number) {
1796 case M_TRIM_THRESHOLD:
1797 mparams.trim_threshold = val;
1798 return 1;
1799 case M_GRANULARITY:
1800 if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
1801 mparams.granularity = val;
1802 return 1;
1803 }
1804 else
1805 return 0;
1806 case M_MMAP_THRESHOLD:
1807 mparams.mmap_threshold = val;
1808 return 1;
1809 default:
1810 return 0;
1811 }
1812}
1813
1814#if DEBUG
1815/* ------------------------- Debugging Support --------------------------- */
1816
1817/* Check properties of any chunk, whether free, inuse, mmapped etc */
1818static void do_check_any_chunk(mstate m, mchunkptr p) {
1819 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
1820 assert(ok_address(m, p));
1821}
1822
1823/* Check properties of top chunk */
1824static void do_check_top_chunk(mstate m, mchunkptr p) {
1825 msegmentptr sp = segment_holding(m, (char*)p);
1826 size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */
1827 assert(sp != 0);
1828 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
1829 assert(ok_address(m, p));
1830 assert(sz == m->topsize);
1831 assert(sz > 0);
1832 assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
1833 assert(pinuse(p));
1834 assert(!pinuse(chunk_plus_offset(p, sz)));
1835}
1836
1837/* Check properties of (inuse) mmapped chunks */
1838static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
1839 size_t sz = chunksize(p);
1840 size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);
1841 assert(is_mmapped(p));
1842 assert(use_mmap(m));
1843 assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
1844 assert(ok_address(m, p));
1845 assert(!is_small(sz));
1846 assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
1847 assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
1848 assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
1849}
1850
1851/* Check properties of inuse chunks */
1852static void do_check_inuse_chunk(mstate m, mchunkptr p) {
1853 do_check_any_chunk(m, p);
1854 assert(is_inuse(p));
1855 assert(next_pinuse(p));
1856 /* If not pinuse and not mmapped, previous chunk has OK offset */
1857 assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
1858 if (is_mmapped(p))
1859 do_check_mmapped_chunk(m, p);
1860}
1861
1862/* Check properties of free chunks */
1863static void do_check_free_chunk(mstate m, mchunkptr p) {
1864 size_t sz = chunksize(p);
1865 mchunkptr next = chunk_plus_offset(p, sz);
1866 do_check_any_chunk(m, p);
1867 assert(!is_inuse(p));
1868 assert(!next_pinuse(p));
1869 assert (!is_mmapped(p));
1870 if (p != m->dv && p != m->top) {
1871 if (sz >= MIN_CHUNK_SIZE) {
1872 assert((sz & CHUNK_ALIGN_MASK) == 0);
1873 assert(is_aligned(chunk2mem(p)));
1874 assert(next->prev_foot == sz);
1875 assert(pinuse(p));
1876 assert (next == m->top || is_inuse(next));
1877 assert(p->fd->bk == p);
1878 assert(p->bk->fd == p);
1879 }
1880 else /* markers are always of size SIZE_T_SIZE */
1881 assert(sz == SIZE_T_SIZE);
1882 }
1883}
1884
1885/* Check properties of malloced chunks at the point they are malloced */
1886static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
1887 if (mem != 0) {
1888 mchunkptr p = mem2chunk(mem);
1889 size_t sz = p->head & ~INUSE_BITS;
1890 do_check_inuse_chunk(m, p);
1891 assert((sz & CHUNK_ALIGN_MASK) == 0);
1892 assert(sz >= MIN_CHUNK_SIZE);
1893 assert(sz >= s);
1894 /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
1895 assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
1896 }
1897}
1898
1899/* Check a tree and its subtrees. */
1900static void do_check_tree(mstate m, tchunkptr t) {
1901 tchunkptr head = 0;
1902 tchunkptr u = t;
1903 bindex_t tindex = t->index;
1904 size_t tsize = chunksize(t);
1905 bindex_t idx;
1906 compute_tree_index(tsize, idx);
1907 assert(tindex == idx);
1908 assert(tsize >= MIN_LARGE_SIZE);
1909 assert(tsize >= minsize_for_tree_index(idx));
1910 assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
1911
1912 do { /* traverse through chain of same-sized nodes */
1913 do_check_any_chunk(m, ((mchunkptr)u));
1914 assert(u->index == tindex);
1915 assert(chunksize(u) == tsize);
1916 assert(!is_inuse(u));
1917 assert(!next_pinuse(u));
1918 assert(u->fd->bk == u);
1919 assert(u->bk->fd == u);
1920 if (u->parent == 0) {
1921 assert(u->child[0] == 0);
1922 assert(u->child[1] == 0);
1923 }
1924 else {
1925 assert(head == 0); /* only one node on chain has parent */
1926 head = u;
1927 assert(u->parent != u);
1928 assert (u->parent->child[0] == u ||
1929 u->parent->child[1] == u ||
1930 *((tbinptr*)(u->parent)) == u);
1931 if (u->child[0] != 0) {
1932 assert(u->child[0]->parent == u);
1933 assert(u->child[0] != u);
1934 do_check_tree(m, u->child[0]);
1935 }
1936 if (u->child[1] != 0) {
1937 assert(u->child[1]->parent == u);
1938 assert(u->child[1] != u);
1939 do_check_tree(m, u->child[1]);
1940 }
1941 if (u->child[0] != 0 && u->child[1] != 0) {
1942 assert(chunksize(u->child[0]) < chunksize(u->child[1]));
1943 }
1944 }
1945 u = u->fd;
1946 } while (u != t);
1947 assert(head != 0);
1948}
1949
1950/* Check all the chunks in a treebin. */
1951static void do_check_treebin(mstate m, bindex_t i) {
1952 tbinptr* tb = treebin_at(m, i);
1953 tchunkptr t = *tb;
1954 int empty = (m->treemap & (1U << i)) == 0;
1955 if (t == 0)
1956 assert(empty);
1957 if (!empty)
1958 do_check_tree(m, t);
1959}
1960
1961/* Check all the chunks in a smallbin. */
1962static void do_check_smallbin(mstate m, bindex_t i) {
1963 sbinptr b = smallbin_at(m, i);
1964 mchunkptr p = b->bk;
1965 unsigned int empty = (m->smallmap & (1U << i)) == 0;
1966 if (p == b)
1967 assert(empty);
1968 if (!empty) {
1969 for (; p != b; p = p->bk) {
1970 size_t size = chunksize(p);
1971 mchunkptr q;
1972 /* each chunk claims to be free */
1973 do_check_free_chunk(m, p);
1974 /* chunk belongs in bin */
1975 assert(small_index(size) == i);
1976 assert(p->bk == b || chunksize(p->bk) == chunksize(p));
1977 /* chunk is followed by an inuse chunk */
1978 q = next_chunk(p);
1979 if (q->head != FENCEPOST_HEAD)
1980 do_check_inuse_chunk(m, q);
1981 }
1982 }
1983}
1984
1985/* Find x in a bin. Used in other check functions. */
1986static int bin_find(mstate m, mchunkptr x) {
1987 size_t size = chunksize(x);
1988 if (is_small(size)) {
1989 bindex_t sidx = small_index(size);
1990 sbinptr b = smallbin_at(m, sidx);
1991 if (smallmap_is_marked(m, sidx)) {
1992 mchunkptr p = b;
1993 do {
1994 if (p == x)
1995 return 1;
1996 } while ((p = p->fd) != b);
1997 }
1998 }
1999 else {
2000 bindex_t tidx;
2001 compute_tree_index(size, tidx);
2002 if (treemap_is_marked(m, tidx)) {
2003 tchunkptr t = *treebin_at(m, tidx);
2004 size_t sizebits = size << leftshift_for_tree_index(tidx);
2005 while (t != 0 && chunksize(t) != size) {
2006 t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
2007 sizebits <<= 1;
2008 }
2009 if (t != 0) {
2010 tchunkptr u = t;
2011 do {
2012 if (u == (tchunkptr)x)
2013 return 1;
2014 } while ((u = u->fd) != t);
2015 }
2016 }
2017 }
2018 return 0;
2019}
2020
2021/* Traverse each chunk and check it; return total */
2022static size_t traverse_and_check(mstate m) {
2023 size_t sum = 0;
2024 if (is_initialized(m)) {
2025 msegmentptr s = &m->seg;
2026 sum += m->topsize + TOP_FOOT_SIZE;
2027 while (s != 0) {
2028 mchunkptr q = align_as_chunk(s->base);
2029 mchunkptr lastq = 0;
2030 assert(pinuse(q));
2031 while (segment_holds(s, q) &&
2032 q != m->top && q->head != FENCEPOST_HEAD) {
2033 sum += chunksize(q);
2034 if (is_inuse(q)) {
2035 assert(!bin_find(m, q));
2036 do_check_inuse_chunk(m, q);
2037 }
2038 else {
2039 assert(q == m->dv || bin_find(m, q));
2040 assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */
2041 do_check_free_chunk(m, q);
2042 }
2043 lastq = q;
2044 q = next_chunk(q);
2045 }
2046 s = s->next;
2047 }
2048 }
2049 return sum;
2050}
2051
2052
2053/* Check all properties of malloc_state. */
2054static void do_check_malloc_state(mstate m) {
2055 bindex_t i;
2056 size_t total;
2057 /* check bins */
2058 for (i = 0; i < NSMALLBINS; ++i)
2059 do_check_smallbin(m, i);
2060 for (i = 0; i < NTREEBINS; ++i)
2061 do_check_treebin(m, i);
2062
2063 if (m->dvsize != 0) { /* check dv chunk */
2064 do_check_any_chunk(m, m->dv);
2065 assert(m->dvsize == chunksize(m->dv));
2066 assert(m->dvsize >= MIN_CHUNK_SIZE);
2067 assert(bin_find(m, m->dv) == 0);
2068 }
2069
2070 if (m->top != 0) { /* check top chunk */
2071 do_check_top_chunk(m, m->top);
2072 /*assert(m->topsize == chunksize(m->top)); redundant */
2073 assert(m->topsize > 0);
2074 assert(bin_find(m, m->top) == 0);
2075 }
2076
2077 total = traverse_and_check(m);
2078 assert(total <= m->footprint);
2079 assert(m->footprint <= m->max_footprint);
2080}
2081#endif /* DEBUG */
2082
2083/* ----------------------------- statistics ------------------------------ */
2084
2085#if !NO_MALLINFO
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02002086CLIB_NOSANITIZE_ADDR
Dave Barachaf7dd5b2018-08-23 17:08:44 -04002087static struct dlmallinfo internal_mallinfo(mstate m) {
2088 struct dlmallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Dave Barach6a5adc32018-07-04 10:56:23 -04002089 ensure_initialization();
2090 if (!PREACTION(m)) {
2091 check_malloc_state(m);
2092 if (is_initialized(m)) {
2093 size_t nfree = SIZE_T_ONE; /* top always free */
2094 size_t mfree = m->topsize + TOP_FOOT_SIZE;
2095 size_t sum = mfree;
2096 msegmentptr s = &m->seg;
2097 while (s != 0) {
2098 mchunkptr q = align_as_chunk(s->base);
2099 while (segment_holds(s, q) &&
2100 q != m->top && q->head != FENCEPOST_HEAD) {
2101 size_t sz = chunksize(q);
2102 sum += sz;
2103 if (!is_inuse(q)) {
2104 mfree += sz;
2105 ++nfree;
2106 }
2107 q = next_chunk(q);
2108 }
2109 s = s->next;
2110 }
2111
2112 nm.arena = sum;
2113 nm.ordblks = nfree;
2114 nm.hblkhd = m->footprint - sum;
2115 nm.usmblks = m->max_footprint;
2116 nm.uordblks = m->footprint - mfree;
2117 nm.fordblks = mfree;
2118 nm.keepcost = m->topsize;
2119 }
2120
2121 POSTACTION(m);
2122 }
2123 return nm;
2124}
2125#endif /* !NO_MALLINFO */
2126
2127#if !NO_MALLOC_STATS
2128static void internal_malloc_stats(mstate m) {
2129 ensure_initialization();
2130 if (!PREACTION(m)) {
2131 size_t maxfp = 0;
2132 size_t fp = 0;
2133 size_t used = 0;
2134 check_malloc_state(m);
2135 if (is_initialized(m)) {
2136 msegmentptr s = &m->seg;
2137 maxfp = m->max_footprint;
2138 fp = m->footprint;
2139 used = fp - (m->topsize + TOP_FOOT_SIZE);
2140
2141 while (s != 0) {
2142 mchunkptr q = align_as_chunk(s->base);
2143 while (segment_holds(s, q) &&
2144 q != m->top && q->head != FENCEPOST_HEAD) {
2145 if (!is_inuse(q))
2146 used -= chunksize(q);
2147 q = next_chunk(q);
2148 }
2149 s = s->next;
2150 }
2151 }
2152 POSTACTION(m); /* drop lock */
2153 fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
2154 fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp));
2155 fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used));
2156 }
2157}
2158#endif /* NO_MALLOC_STATS */
2159
2160/* ----------------------- Operations on smallbins ----------------------- */
2161
2162/*
2163 Various forms of linking and unlinking are defined as macros. Even
2164 the ones for trees, which are very long but have very short typical
2165 paths. This is ugly but reduces reliance on inlining support of
2166 compilers.
2167*/
2168
2169/* Link a free chunk into a smallbin */
2170#define insert_small_chunk(M, P, S) {\
2171 bindex_t I = small_index(S);\
2172 mchunkptr B = smallbin_at(M, I);\
2173 mchunkptr F = B;\
2174 assert(S >= MIN_CHUNK_SIZE);\
2175 if (!smallmap_is_marked(M, I))\
2176 mark_smallmap(M, I);\
2177 else if (RTCHECK(ok_address(M, B->fd)))\
2178 F = B->fd;\
2179 else {\
2180 CORRUPTION_ERROR_ACTION(M);\
2181 }\
2182 B->fd = P;\
2183 F->bk = P;\
2184 P->fd = F;\
2185 P->bk = B;\
2186}
2187
2188/* Unlink a chunk from a smallbin */
2189#define unlink_small_chunk(M, P, S) {\
2190 mchunkptr F = P->fd;\
2191 mchunkptr B = P->bk;\
2192 bindex_t I = small_index(S);\
2193 assert(P != B);\
2194 assert(P != F);\
2195 assert(chunksize(P) == small_index2size(I));\
2196 if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \
2197 if (B == F) {\
2198 clear_smallmap(M, I);\
2199 }\
2200 else if (RTCHECK(B == smallbin_at(M,I) ||\
2201 (ok_address(M, B) && B->fd == P))) {\
2202 F->bk = B;\
2203 B->fd = F;\
2204 }\
2205 else {\
2206 CORRUPTION_ERROR_ACTION(M);\
2207 }\
2208 }\
2209 else {\
2210 CORRUPTION_ERROR_ACTION(M);\
2211 }\
2212}
2213
2214/* Unlink the first chunk from a smallbin */
2215#define unlink_first_small_chunk(M, B, P, I) {\
2216 mchunkptr F = P->fd;\
2217 assert(P != B);\
2218 assert(P != F);\
2219 assert(chunksize(P) == small_index2size(I));\
2220 if (B == F) {\
2221 clear_smallmap(M, I);\
2222 }\
2223 else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\
2224 F->bk = B;\
2225 B->fd = F;\
2226 }\
2227 else {\
2228 CORRUPTION_ERROR_ACTION(M);\
2229 }\
2230}
2231
2232/* Replace dv node, binning the old one */
2233/* Used only when dvsize known to be small */
2234#define replace_dv(M, P, S) {\
2235 size_t DVS = M->dvsize;\
2236 assert(is_small(DVS));\
2237 if (DVS != 0) {\
2238 mchunkptr DV = M->dv;\
2239 insert_small_chunk(M, DV, DVS);\
2240 }\
2241 M->dvsize = S;\
2242 M->dv = P;\
2243}
2244
2245/* ------------------------- Operations on trees ------------------------- */
2246
2247/* Insert chunk into tree */
2248#define insert_large_chunk(M, X, S) {\
2249 tbinptr* H;\
2250 bindex_t I;\
2251 compute_tree_index(S, I);\
2252 H = treebin_at(M, I);\
2253 X->index = I;\
2254 X->child[0] = X->child[1] = 0;\
2255 if (!treemap_is_marked(M, I)) {\
2256 mark_treemap(M, I);\
2257 *H = X;\
2258 X->parent = (tchunkptr)H;\
2259 X->fd = X->bk = X;\
2260 }\
2261 else {\
2262 tchunkptr T = *H;\
2263 size_t K = S << leftshift_for_tree_index(I);\
2264 for (;;) {\
2265 if (chunksize(T) != S) {\
2266 tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
2267 K <<= 1;\
2268 if (*C != 0)\
2269 T = *C;\
2270 else if (RTCHECK(ok_address(M, C))) {\
2271 *C = X;\
2272 X->parent = T;\
2273 X->fd = X->bk = X;\
2274 break;\
2275 }\
2276 else {\
2277 CORRUPTION_ERROR_ACTION(M);\
2278 break;\
2279 }\
2280 }\
2281 else {\
2282 tchunkptr F = T->fd;\
2283 if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
2284 T->fd = F->bk = X;\
2285 X->fd = F;\
2286 X->bk = T;\
2287 X->parent = 0;\
2288 break;\
2289 }\
2290 else {\
2291 CORRUPTION_ERROR_ACTION(M);\
2292 break;\
2293 }\
2294 }\
2295 }\
2296 }\
2297}
2298
2299/*
2300 Unlink steps:
2301
2302 1. If x is a chained node, unlink it from its same-sized fd/bk links
2303 and choose its bk node as its replacement.
2304 2. If x was the last node of its size, but not a leaf node, it must
2305 be replaced with a leaf node (not merely one with an open left or
2306 right), to make sure that lefts and rights of descendents
2307 correspond properly to bit masks. We use the rightmost descendent
2308 of x. We could use any other leaf, but this is easy to locate and
2309 tends to counteract removal of leftmosts elsewhere, and so keeps
2310 paths shorter than minimally guaranteed. This doesn't loop much
2311 because on average a node in a tree is near the bottom.
2312 3. If x is the base of a chain (i.e., has parent links) relink
2313 x's parent and children to x's replacement (or null if none).
2314*/
2315
2316#define unlink_large_chunk(M, X) {\
2317 tchunkptr XP = X->parent;\
2318 tchunkptr R;\
2319 if (X->bk != X) {\
2320 tchunkptr F = X->fd;\
2321 R = X->bk;\
2322 if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\
2323 F->bk = R;\
2324 R->fd = F;\
2325 }\
2326 else {\
2327 CORRUPTION_ERROR_ACTION(M);\
2328 }\
2329 }\
2330 else {\
2331 tchunkptr* RP;\
2332 if (((R = *(RP = &(X->child[1]))) != 0) ||\
2333 ((R = *(RP = &(X->child[0]))) != 0)) {\
2334 tchunkptr* CP;\
2335 while ((*(CP = &(R->child[1])) != 0) ||\
2336 (*(CP = &(R->child[0])) != 0)) {\
2337 R = *(RP = CP);\
2338 }\
2339 if (RTCHECK(ok_address(M, RP)))\
2340 *RP = 0;\
2341 else {\
2342 CORRUPTION_ERROR_ACTION(M);\
2343 }\
2344 }\
2345 }\
2346 if (XP != 0) {\
2347 tbinptr* H = treebin_at(M, X->index);\
2348 if (X == *H) {\
2349 if ((*H = R) == 0) \
2350 clear_treemap(M, X->index);\
2351 }\
2352 else if (RTCHECK(ok_address(M, XP))) {\
2353 if (XP->child[0] == X) \
2354 XP->child[0] = R;\
2355 else \
2356 XP->child[1] = R;\
2357 }\
2358 else\
2359 CORRUPTION_ERROR_ACTION(M);\
2360 if (R != 0) {\
2361 if (RTCHECK(ok_address(M, R))) {\
2362 tchunkptr C0, C1;\
2363 R->parent = XP;\
2364 if ((C0 = X->child[0]) != 0) {\
2365 if (RTCHECK(ok_address(M, C0))) {\
2366 R->child[0] = C0;\
2367 C0->parent = R;\
2368 }\
2369 else\
2370 CORRUPTION_ERROR_ACTION(M);\
2371 }\
2372 if ((C1 = X->child[1]) != 0) {\
2373 if (RTCHECK(ok_address(M, C1))) {\
2374 R->child[1] = C1;\
2375 C1->parent = R;\
2376 }\
2377 else\
2378 CORRUPTION_ERROR_ACTION(M);\
2379 }\
2380 }\
2381 else\
2382 CORRUPTION_ERROR_ACTION(M);\
2383 }\
2384 }\
2385}
2386
2387/* Relays to large vs small bin operations */
2388
2389#define insert_chunk(M, P, S)\
2390 if (is_small(S)) insert_small_chunk(M, P, S)\
2391 else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
2392
2393#define unlink_chunk(M, P, S)\
2394 if (is_small(S)) unlink_small_chunk(M, P, S)\
2395 else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
2396
2397
2398/* Relays to internal calls to malloc/free from realloc, memalign etc */
2399
2400#if ONLY_MSPACES
2401#define internal_malloc(m, b) mspace_malloc(m, b)
2402#define internal_free(m, mem) mspace_free(m,mem);
2403#else /* ONLY_MSPACES */
2404#if MSPACES
2405#define internal_malloc(m, b)\
2406 ((m == gm)? dlmalloc(b) : mspace_malloc(m, b))
2407#define internal_free(m, mem)\
2408 if (m == gm) dlfree(mem); else mspace_free(m,mem);
2409#else /* MSPACES */
2410#define internal_malloc(m, b) dlmalloc(b)
2411#define internal_free(m, mem) dlfree(mem)
2412#endif /* MSPACES */
2413#endif /* ONLY_MSPACES */
2414
2415/* ----------------------- Direct-mmapping chunks ----------------------- */
2416
2417/*
2418 Directly mmapped chunks are set up with an offset to the start of
2419 the mmapped region stored in the prev_foot field of the chunk. This
2420 allows reconstruction of the required argument to MUNMAP when freed,
2421 and also allows adjustment of the returned chunk to meet alignment
2422 requirements (especially in memalign).
2423*/
2424
2425/* Malloc using mmap */
2426static void* mmap_alloc(mstate m, size_t nb) {
2427 size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
2428 if (m->footprint_limit != 0) {
2429 size_t fp = m->footprint + mmsize;
2430 if (fp <= m->footprint || fp > m->footprint_limit)
2431 return 0;
2432 }
2433 if (mmsize > nb) { /* Check for wrap around 0 */
2434 char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));
2435 if (mm != CMFAIL) {
2436 size_t offset = align_offset(chunk2mem(mm));
2437 size_t psize = mmsize - offset - MMAP_FOOT_PAD;
2438 mchunkptr p = (mchunkptr)(mm + offset);
2439 p->prev_foot = offset;
2440 p->head = psize;
2441 mark_inuse_foot(m, p, psize);
2442 chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
2443 chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
2444
2445 if (m->least_addr == 0 || mm < m->least_addr)
2446 m->least_addr = mm;
2447 if ((m->footprint += mmsize) > m->max_footprint)
2448 m->max_footprint = m->footprint;
2449 assert(is_aligned(chunk2mem(p)));
2450 check_mmapped_chunk(m, p);
2451 return chunk2mem(p);
2452 }
2453 }
2454 return 0;
2455}
2456
2457/* Realloc using mmap */
2458static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {
2459 size_t oldsize = chunksize(oldp);
2460 (void)flags; /* placate people compiling -Wunused */
2461 if (is_small(nb)) /* Can't shrink mmap regions below small size */
2462 return 0;
2463 /* Keep old chunk if big enough but not too big */
2464 if (oldsize >= nb + SIZE_T_SIZE &&
2465 (oldsize - nb) <= (mparams.granularity << 1))
2466 return oldp;
2467 else {
2468 size_t offset = oldp->prev_foot;
2469 size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
2470 size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
2471 char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
2472 oldmmsize, newmmsize, flags);
2473 if (cp != CMFAIL) {
2474 mchunkptr newp = (mchunkptr)(cp + offset);
2475 size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
2476 newp->head = psize;
2477 mark_inuse_foot(m, newp, psize);
2478 chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
2479 chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
2480
2481 if (cp < m->least_addr)
2482 m->least_addr = cp;
2483 if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
2484 m->max_footprint = m->footprint;
2485 check_mmapped_chunk(m, newp);
2486 return newp;
2487 }
2488 }
2489 return 0;
2490}
2491
2492
2493/* -------------------------- mspace management -------------------------- */
2494
2495/* Initialize top chunk and its size */
2496static void init_top(mstate m, mchunkptr p, size_t psize) {
2497 /* Ensure alignment */
2498 size_t offset = align_offset(chunk2mem(p));
2499 p = (mchunkptr)((char*)p + offset);
2500 psize -= offset;
2501
2502 m->top = p;
2503 m->topsize = psize;
2504 p->head = psize | PINUSE_BIT;
2505 /* set size of fake trailing chunk holding overhead space only once */
2506 chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
2507 m->trim_check = mparams.trim_threshold; /* reset on each update */
2508}
2509
2510/* Initialize bins for a new mstate that is otherwise zeroed out */
2511static void init_bins(mstate m) {
2512 /* Establish circular links for smallbins */
2513 bindex_t i;
2514 for (i = 0; i < NSMALLBINS; ++i) {
2515 sbinptr bin = smallbin_at(m,i);
2516 bin->fd = bin->bk = bin;
2517 }
2518}
2519
2520#if PROCEED_ON_ERROR
2521
2522/* default corruption action */
2523static void reset_on_error(mstate m) {
2524 int i;
2525 ++malloc_corruption_error_count;
2526 /* Reinitialize fields to forget about all memory */
2527 m->smallmap = m->treemap = 0;
2528 m->dvsize = m->topsize = 0;
2529 m->seg.base = 0;
2530 m->seg.size = 0;
2531 m->seg.next = 0;
2532 m->top = m->dv = 0;
2533 for (i = 0; i < NTREEBINS; ++i)
2534 *treebin_at(m, i) = 0;
2535 init_bins(m);
2536}
2537#endif /* PROCEED_ON_ERROR */
2538
2539/* Allocate chunk and prepend remainder with chunk in successor base. */
2540static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
2541 size_t nb) {
2542 mchunkptr p = align_as_chunk(newbase);
2543 mchunkptr oldfirst = align_as_chunk(oldbase);
2544 size_t psize = (char*)oldfirst - (char*)p;
2545 mchunkptr q = chunk_plus_offset(p, nb);
2546 size_t qsize = psize - nb;
2547 set_size_and_pinuse_of_inuse_chunk(m, p, nb);
2548
2549 assert((char*)oldfirst > (char*)q);
2550 assert(pinuse(oldfirst));
2551 assert(qsize >= MIN_CHUNK_SIZE);
2552
2553 /* consolidate remainder with first chunk of old base */
2554 if (oldfirst == m->top) {
2555 size_t tsize = m->topsize += qsize;
2556 m->top = q;
2557 q->head = tsize | PINUSE_BIT;
2558 check_top_chunk(m, q);
2559 }
2560 else if (oldfirst == m->dv) {
2561 size_t dsize = m->dvsize += qsize;
2562 m->dv = q;
2563 set_size_and_pinuse_of_free_chunk(q, dsize);
2564 }
2565 else {
2566 if (!is_inuse(oldfirst)) {
2567 size_t nsize = chunksize(oldfirst);
2568 unlink_chunk(m, oldfirst, nsize);
2569 oldfirst = chunk_plus_offset(oldfirst, nsize);
2570 qsize += nsize;
2571 }
2572 set_free_with_pinuse(q, qsize, oldfirst);
2573 insert_chunk(m, q, qsize);
2574 check_free_chunk(m, q);
2575 }
2576
2577 check_malloced_chunk(m, chunk2mem(p), nb);
2578 return chunk2mem(p);
2579}
2580
2581/* Add a segment to hold a new noncontiguous region */
2582static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
2583 /* Determine locations and sizes of segment, fenceposts, old top */
2584 char* old_top = (char*)m->top;
2585 msegmentptr oldsp = segment_holding(m, old_top);
2586 char* old_end = oldsp->base + oldsp->size;
2587 size_t ssize = pad_request(sizeof(struct malloc_segment));
2588 char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
2589 size_t offset = align_offset(chunk2mem(rawsp));
2590 char* asp = rawsp + offset;
2591 char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
2592 mchunkptr sp = (mchunkptr)csp;
2593 msegmentptr ss = (msegmentptr)(chunk2mem(sp));
2594 mchunkptr tnext = chunk_plus_offset(sp, ssize);
2595 mchunkptr p = tnext;
2596 int nfences = 0;
2597
2598 /* reset top to new space */
2599 init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
2600
2601 /* Set up segment record */
2602 assert(is_aligned(ss));
2603 set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
2604 *ss = m->seg; /* Push current record */
2605 m->seg.base = tbase;
2606 m->seg.size = tsize;
2607 m->seg.sflags = mmapped;
2608 m->seg.next = ss;
2609
2610 /* Insert trailing fenceposts */
2611 for (;;) {
2612 mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
2613 p->head = FENCEPOST_HEAD;
2614 ++nfences;
2615 if ((char*)(&(nextp->head)) < old_end)
2616 p = nextp;
2617 else
2618 break;
2619 }
2620 assert(nfences >= 2);
2621
2622 /* Insert the rest of old top into a bin as an ordinary free chunk */
2623 if (csp != old_top) {
2624 mchunkptr q = (mchunkptr)old_top;
2625 size_t psize = csp - old_top;
2626 mchunkptr tn = chunk_plus_offset(q, psize);
2627 set_free_with_pinuse(q, psize, tn);
2628 insert_chunk(m, q, psize);
2629 }
2630
2631 check_top_chunk(m, m->top);
2632}
2633
2634/* -------------------------- System allocation -------------------------- */
2635
2636/* Get memory from system using MORECORE or MMAP */
2637static void* sys_alloc(mstate m, size_t nb) {
2638 char* tbase = CMFAIL;
2639 size_t tsize = 0;
2640 flag_t mmap_flag = 0;
2641 size_t asize; /* allocation size */
2642
2643 ensure_initialization();
2644
2645 if (use_noexpand(m))
2646 return 0;
2647
2648 /* Directly map large chunks, but only if already initialized */
2649 if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) {
2650 void* mem = mmap_alloc(m, nb);
2651 if (mem != 0)
2652 return mem;
2653 }
2654
2655 asize = granularity_align(nb + SYS_ALLOC_PADDING);
2656 if (asize <= nb)
2657 return 0; /* wraparound */
2658 if (m->footprint_limit != 0) {
2659 size_t fp = m->footprint + asize;
2660 if (fp <= m->footprint || fp > m->footprint_limit)
2661 return 0;
2662 }
2663
2664 /*
2665 Try getting memory in any of three ways (in most-preferred to
2666 least-preferred order):
2667 1. A call to MORECORE that can normally contiguously extend memory.
2668 (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
2669 or main space is mmapped or a previous contiguous call failed)
2670 2. A call to MMAP new space (disabled if not HAVE_MMAP).
2671 Note that under the default settings, if MORECORE is unable to
2672 fulfill a request, and HAVE_MMAP is true, then mmap is
2673 used as a noncontiguous system allocator. This is a useful backup
2674 strategy for systems with holes in address spaces -- in this case
2675 sbrk cannot contiguously expand the heap, but mmap may be able to
2676 find space.
2677 3. A call to MORECORE that cannot usually contiguously extend memory.
2678 (disabled if not HAVE_MORECORE)
2679
2680 In all cases, we need to request enough bytes from system to ensure
2681 we can malloc nb bytes upon success, so pad with enough space for
2682 top_foot, plus alignment-pad to make sure we don't lose bytes if
2683 not on boundary, and round this up to a granularity unit.
2684 */
2685
2686 if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
2687 char* br = CMFAIL;
2688 size_t ssize = asize; /* sbrk call size */
2689 msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
2690 ACQUIRE_MALLOC_GLOBAL_LOCK();
2691
2692 if (ss == 0) { /* First time through or recovery */
2693 char* base = (char*)CALL_MORECORE(0);
2694 if (base != CMFAIL) {
2695 size_t fp;
2696 /* Adjust to end on a page boundary */
2697 if (!is_page_aligned(base))
2698 ssize += (page_align((size_t)base) - (size_t)base);
2699 fp = m->footprint + ssize; /* recheck limits */
2700 if (ssize > nb && ssize < HALF_MAX_SIZE_T &&
2701 (m->footprint_limit == 0 ||
2702 (fp > m->footprint && fp <= m->footprint_limit)) &&
2703 (br = (char*)(CALL_MORECORE(ssize))) == base) {
2704 tbase = base;
2705 tsize = ssize;
2706 }
2707 }
2708 }
2709 else {
2710 /* Subtract out existing available top space from MORECORE request. */
2711 ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
2712 /* Use mem here only if it did continuously extend old space */
2713 if (ssize < HALF_MAX_SIZE_T &&
2714 (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) {
2715 tbase = br;
2716 tsize = ssize;
2717 }
2718 }
2719
2720 if (tbase == CMFAIL) { /* Cope with partial failure */
2721 if (br != CMFAIL) { /* Try to use/extend the space we did get */
2722 if (ssize < HALF_MAX_SIZE_T &&
2723 ssize < nb + SYS_ALLOC_PADDING) {
2724 size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize);
2725 if (esize < HALF_MAX_SIZE_T) {
2726 char* end = (char*)CALL_MORECORE(esize);
2727 if (end != CMFAIL)
2728 ssize += esize;
2729 else { /* Can't use; try to release */
2730 (void) CALL_MORECORE(-ssize);
2731 br = CMFAIL;
2732 }
2733 }
2734 }
2735 }
2736 if (br != CMFAIL) { /* Use the space we did get */
2737 tbase = br;
2738 tsize = ssize;
2739 }
2740 else
2741 disable_contiguous(m); /* Don't try contiguous path in the future */
2742 }
2743
2744 RELEASE_MALLOC_GLOBAL_LOCK();
2745 }
2746
2747 if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */
2748 char* mp = (char*)(CALL_MMAP(asize));
2749 if (mp != CMFAIL) {
2750 tbase = mp;
2751 tsize = asize;
2752 mmap_flag = USE_MMAP_BIT;
2753 }
2754 }
2755
2756 if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
2757 if (asize < HALF_MAX_SIZE_T) {
2758 char* br = CMFAIL;
2759 char* end = CMFAIL;
2760 ACQUIRE_MALLOC_GLOBAL_LOCK();
2761 br = (char*)(CALL_MORECORE(asize));
2762 end = (char*)(CALL_MORECORE(0));
2763 RELEASE_MALLOC_GLOBAL_LOCK();
2764 if (br != CMFAIL && end != CMFAIL && br < end) {
2765 size_t ssize = end - br;
2766 if (ssize > nb + TOP_FOOT_SIZE) {
2767 tbase = br;
2768 tsize = ssize;
2769 }
2770 }
2771 }
2772 }
2773
2774 if (tbase != CMFAIL) {
2775
2776 if ((m->footprint += tsize) > m->max_footprint)
2777 m->max_footprint = m->footprint;
2778
2779 if (!is_initialized(m)) { /* first-time initialization */
2780 if (m->least_addr == 0 || tbase < m->least_addr)
2781 m->least_addr = tbase;
2782 m->seg.base = tbase;
2783 m->seg.size = tsize;
2784 m->seg.sflags = mmap_flag;
2785 m->magic = mparams.magic;
2786 m->release_checks = MAX_RELEASE_CHECK_RATE;
2787 init_bins(m);
2788#if !ONLY_MSPACES
2789 if (is_global(m))
2790 init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
2791 else
2792#endif
2793 {
2794 /* Offset top by embedded malloc_state */
2795 mchunkptr mn = next_chunk(mem2chunk(m));
2796 init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
2797 }
2798 }
2799
2800 else {
2801 /* Try to merge with an existing segment */
2802 msegmentptr sp = &m->seg;
2803 /* Only consider most recent segment if traversal suppressed */
2804 while (sp != 0 && tbase != sp->base + sp->size)
2805 sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
2806 if (sp != 0 &&
2807 !is_extern_segment(sp) &&
2808 (sp->sflags & USE_MMAP_BIT) == mmap_flag &&
2809 segment_holds(sp, m->top)) { /* append */
2810 sp->size += tsize;
2811 init_top(m, m->top, m->topsize + tsize);
2812 }
2813 else {
2814 if (tbase < m->least_addr)
2815 m->least_addr = tbase;
2816 sp = &m->seg;
2817 while (sp != 0 && sp->base != tbase + tsize)
2818 sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
2819 if (sp != 0 &&
2820 !is_extern_segment(sp) &&
2821 (sp->sflags & USE_MMAP_BIT) == mmap_flag) {
2822 char* oldbase = sp->base;
2823 sp->base = tbase;
2824 sp->size += tsize;
2825 return prepend_alloc(m, tbase, oldbase, nb);
2826 }
2827 else
2828 add_segment(m, tbase, tsize, mmap_flag);
2829 }
2830 }
2831
2832 if (nb < m->topsize) { /* Allocate from new or extended top space */
2833 size_t rsize = m->topsize -= nb;
2834 mchunkptr p = m->top;
2835 mchunkptr r = m->top = chunk_plus_offset(p, nb);
2836 r->head = rsize | PINUSE_BIT;
2837 set_size_and_pinuse_of_inuse_chunk(m, p, nb);
2838 check_top_chunk(m, m->top);
2839 check_malloced_chunk(m, chunk2mem(p), nb);
2840 return chunk2mem(p);
2841 }
2842 }
2843
2844 MALLOC_FAILURE_ACTION;
2845 return 0;
2846}
2847
2848/* ----------------------- system deallocation -------------------------- */
2849
2850/* Unmap and unlink any mmapped segments that don't contain used chunks */
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02002851CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04002852static size_t release_unused_segments(mstate m) {
2853 size_t released = 0;
2854 int nsegs = 0;
2855 msegmentptr pred = &m->seg;
2856 msegmentptr sp = pred->next;
2857 while (sp != 0) {
2858 char* base = sp->base;
2859 size_t size = sp->size;
2860 msegmentptr next = sp->next;
2861 ++nsegs;
2862 if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
2863 mchunkptr p = align_as_chunk(base);
2864 size_t psize = chunksize(p);
2865 /* Can unmap if first chunk holds entire segment and not pinned */
2866 if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
2867 tchunkptr tp = (tchunkptr)p;
2868 assert(segment_holds(sp, (char*)sp));
2869 if (p == m->dv) {
2870 m->dv = 0;
2871 m->dvsize = 0;
2872 }
2873 else {
2874 unlink_large_chunk(m, tp);
2875 }
2876 if (CALL_MUNMAP(base, size) == 0) {
2877 released += size;
2878 m->footprint -= size;
2879 /* unlink obsoleted record */
2880 sp = pred;
2881 sp->next = next;
2882 }
2883 else { /* back out if cannot unmap */
2884 insert_large_chunk(m, tp, psize);
2885 }
2886 }
2887 }
2888 if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */
2889 break;
2890 pred = sp;
2891 sp = next;
2892 }
2893 /* Reset check counter */
2894 m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)?
2895 (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE);
2896 return released;
2897}
2898
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02002899CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04002900static int sys_trim(mstate m, size_t pad) {
2901 size_t released = 0;
2902 ensure_initialization();
2903 if (pad < MAX_REQUEST && is_initialized(m)) {
2904 pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
2905
2906 if (m->topsize > pad) {
2907 /* Shrink top space in granularity-size units, keeping at least one */
2908 size_t unit = mparams.granularity;
2909 size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
2910 SIZE_T_ONE) * unit;
2911 msegmentptr sp = segment_holding(m, (char*)m->top);
2912
2913 if (!is_extern_segment(sp)) {
2914 if (is_mmapped_segment(sp)) {
2915 if (HAVE_MMAP &&
2916 sp->size >= extra &&
2917 !has_segment_link(m, sp)) { /* can't shrink if pinned */
2918 size_t newsize = sp->size - extra;
2919 (void)newsize; /* placate people compiling -Wunused-variable */
2920 /* Prefer mremap, fall back to munmap */
2921 if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
2922 (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
2923 released = extra;
2924 }
2925 }
2926 }
2927 else if (HAVE_MORECORE) {
2928 if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
2929 extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
2930 ACQUIRE_MALLOC_GLOBAL_LOCK();
2931 {
2932 /* Make sure end of memory is where we last set it. */
2933 char* old_br = (char*)(CALL_MORECORE(0));
2934 if (old_br == sp->base + sp->size) {
2935 char* rel_br = (char*)(CALL_MORECORE(-extra));
2936 char* new_br = (char*)(CALL_MORECORE(0));
2937 if (rel_br != CMFAIL && new_br < old_br)
2938 released = old_br - new_br;
2939 }
2940 }
2941 RELEASE_MALLOC_GLOBAL_LOCK();
2942 }
2943 }
2944
2945 if (released != 0) {
2946 sp->size -= released;
2947 m->footprint -= released;
2948 init_top(m, m->top, m->topsize - released);
2949 check_top_chunk(m, m->top);
2950 }
2951 }
2952
2953 /* Unmap any unused mmapped segments */
2954 if (HAVE_MMAP)
2955 released += release_unused_segments(m);
2956
2957 /* On failure, disable autotrim to avoid repeated failed future calls */
2958 if (released == 0 && m->topsize > m->trim_check)
2959 m->trim_check = MAX_SIZE_T;
2960 }
2961
2962 return (released != 0)? 1 : 0;
2963}
2964
2965/* Consolidate and bin a chunk. Differs from exported versions
2966 of free mainly in that the chunk need not be marked as inuse.
2967*/
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02002968CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04002969static void dispose_chunk(mstate m, mchunkptr p, size_t psize) {
2970 mchunkptr next = chunk_plus_offset(p, psize);
2971 if (!pinuse(p)) {
2972 mchunkptr prev;
2973 size_t prevsize = p->prev_foot;
2974 if (is_mmapped(p)) {
2975 psize += prevsize + MMAP_FOOT_PAD;
2976 if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
2977 m->footprint -= psize;
2978 return;
2979 }
2980 prev = chunk_minus_offset(p, prevsize);
2981 psize += prevsize;
2982 p = prev;
2983 if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */
2984 if (p != m->dv) {
2985 unlink_chunk(m, p, prevsize);
2986 }
2987 else if ((next->head & INUSE_BITS) == INUSE_BITS) {
2988 m->dvsize = psize;
2989 set_free_with_pinuse(p, psize, next);
2990 return;
2991 }
2992 }
2993 else {
2994 CORRUPTION_ERROR_ACTION(m);
2995 return;
2996 }
2997 }
2998 if (RTCHECK(ok_address(m, next))) {
2999 if (!cinuse(next)) { /* consolidate forward */
3000 if (next == m->top) {
3001 size_t tsize = m->topsize += psize;
3002 m->top = p;
3003 p->head = tsize | PINUSE_BIT;
3004 if (p == m->dv) {
3005 m->dv = 0;
3006 m->dvsize = 0;
3007 }
3008 return;
3009 }
3010 else if (next == m->dv) {
3011 size_t dsize = m->dvsize += psize;
3012 m->dv = p;
3013 set_size_and_pinuse_of_free_chunk(p, dsize);
3014 return;
3015 }
3016 else {
3017 size_t nsize = chunksize(next);
3018 psize += nsize;
3019 unlink_chunk(m, next, nsize);
3020 set_size_and_pinuse_of_free_chunk(p, psize);
3021 if (p == m->dv) {
3022 m->dvsize = psize;
3023 return;
3024 }
3025 }
3026 }
3027 else {
3028 set_free_with_pinuse(p, psize, next);
3029 }
3030 insert_chunk(m, p, psize);
3031 }
3032 else {
3033 CORRUPTION_ERROR_ACTION(m);
3034 }
3035}
3036
3037/* ---------------------------- malloc --------------------------- */
3038
3039/* allocate a large request from the best fitting chunk in a treebin */
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02003040CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04003041static void* tmalloc_large(mstate m, size_t nb) {
3042 tchunkptr v = 0;
3043 size_t rsize = -nb; /* Unsigned negation */
3044 tchunkptr t;
3045 bindex_t idx;
3046 compute_tree_index(nb, idx);
3047 if ((t = *treebin_at(m, idx)) != 0) {
3048 /* Traverse tree for this bin looking for node with size == nb */
3049 size_t sizebits = nb << leftshift_for_tree_index(idx);
3050 tchunkptr rst = 0; /* The deepest untaken right subtree */
3051 for (;;) {
3052 tchunkptr rt;
3053 size_t trem = chunksize(t) - nb;
3054 if (trem < rsize) {
3055 v = t;
3056 if ((rsize = trem) == 0)
3057 break;
3058 }
3059 rt = t->child[1];
3060 t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
3061 if (rt != 0 && rt != t)
3062 rst = rt;
3063 if (t == 0) {
3064 t = rst; /* set t to least subtree holding sizes > nb */
3065 break;
3066 }
3067 sizebits <<= 1;
3068 }
3069 }
3070 if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
3071 binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
3072 if (leftbits != 0) {
3073 bindex_t i;
3074 binmap_t leastbit = least_bit(leftbits);
3075 compute_bit2idx(leastbit, i);
3076 t = *treebin_at(m, i);
3077 }
3078 }
3079
3080 while (t != 0) { /* find smallest of tree or subtree */
3081 size_t trem = chunksize(t) - nb;
3082 if (trem < rsize) {
3083 rsize = trem;
3084 v = t;
3085 }
3086 t = leftmost_child(t);
3087 }
3088
3089 /* If dv is a better fit, return 0 so malloc will use it */
3090 if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
3091 if (RTCHECK(ok_address(m, v))) { /* split */
3092 mchunkptr r = chunk_plus_offset(v, nb);
3093 assert(chunksize(v) == rsize + nb);
3094 if (RTCHECK(ok_next(v, r))) {
3095 unlink_large_chunk(m, v);
3096 if (rsize < MIN_CHUNK_SIZE)
3097 set_inuse_and_pinuse(m, v, (rsize + nb));
3098 else {
3099 set_size_and_pinuse_of_inuse_chunk(m, v, nb);
3100 set_size_and_pinuse_of_free_chunk(r, rsize);
3101 insert_chunk(m, r, rsize);
3102 }
3103 return chunk2mem(v);
3104 }
3105 }
3106 CORRUPTION_ERROR_ACTION(m);
3107 }
3108 return 0;
3109}
3110
3111/* allocate a small request from the best fitting chunk in a treebin */
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02003112CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04003113static void* tmalloc_small(mstate m, size_t nb) {
3114 tchunkptr t, v;
3115 size_t rsize;
3116 bindex_t i;
3117 binmap_t leastbit = least_bit(m->treemap);
3118 compute_bit2idx(leastbit, i);
3119 v = t = *treebin_at(m, i);
3120 rsize = chunksize(t) - nb;
3121
3122 while ((t = leftmost_child(t)) != 0) {
3123 size_t trem = chunksize(t) - nb;
3124 if (trem < rsize) {
3125 rsize = trem;
3126 v = t;
3127 }
3128 }
3129
3130 if (RTCHECK(ok_address(m, v))) {
3131 mchunkptr r = chunk_plus_offset(v, nb);
3132 assert(chunksize(v) == rsize + nb);
3133 if (RTCHECK(ok_next(v, r))) {
3134 unlink_large_chunk(m, v);
3135 if (rsize < MIN_CHUNK_SIZE)
3136 set_inuse_and_pinuse(m, v, (rsize + nb));
3137 else {
3138 set_size_and_pinuse_of_inuse_chunk(m, v, nb);
3139 set_size_and_pinuse_of_free_chunk(r, rsize);
3140 replace_dv(m, r, rsize);
3141 }
3142 return chunk2mem(v);
3143 }
3144 }
3145
3146 CORRUPTION_ERROR_ACTION(m);
3147 return 0;
3148}
3149
3150#if !ONLY_MSPACES
3151
3152void* dlmalloc(size_t bytes) {
3153 /*
3154 Basic algorithm:
3155 If a small request (< 256 bytes minus per-chunk overhead):
3156 1. If one exists, use a remainderless chunk in associated smallbin.
3157 (Remainderless means that there are too few excess bytes to
3158 represent as a chunk.)
3159 2. If it is big enough, use the dv chunk, which is normally the
3160 chunk adjacent to the one used for the most recent small request.
3161 3. If one exists, split the smallest available chunk in a bin,
3162 saving remainder in dv.
3163 4. If it is big enough, use the top chunk.
3164 5. If available, get memory from system and use it
3165 Otherwise, for a large request:
3166 1. Find the smallest available binned chunk that fits, and use it
3167 if it is better fitting than dv chunk, splitting if necessary.
3168 2. If better fitting than any binned chunk, use the dv chunk.
3169 3. If it is big enough, use the top chunk.
3170 4. If request size >= mmap threshold, try to directly mmap this chunk.
3171 5. If available, get memory from system and use it
3172
3173 The ugly goto's here ensure that postaction occurs along all paths.
3174 */
3175
3176#if USE_LOCKS
3177 ensure_initialization(); /* initialize in sys_alloc if not using locks */
3178#endif
3179
3180 if (!PREACTION(gm)) {
3181 void* mem;
3182 size_t nb;
3183 if (bytes <= MAX_SMALL_REQUEST) {
3184 bindex_t idx;
3185 binmap_t smallbits;
3186 nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
3187 idx = small_index(nb);
3188 smallbits = gm->smallmap >> idx;
3189
3190 if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
3191 mchunkptr b, p;
3192 idx += ~smallbits & 1; /* Uses next bin if idx empty */
3193 b = smallbin_at(gm, idx);
3194 p = b->fd;
3195 assert(chunksize(p) == small_index2size(idx));
3196 unlink_first_small_chunk(gm, b, p, idx);
3197 set_inuse_and_pinuse(gm, p, small_index2size(idx));
3198 mem = chunk2mem(p);
3199 check_malloced_chunk(gm, mem, nb);
3200 goto postaction;
3201 }
3202
3203 else if (nb > gm->dvsize) {
3204 if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
3205 mchunkptr b, p, r;
3206 size_t rsize;
3207 bindex_t i;
3208 binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
3209 binmap_t leastbit = least_bit(leftbits);
3210 compute_bit2idx(leastbit, i);
3211 b = smallbin_at(gm, i);
3212 p = b->fd;
3213 assert(chunksize(p) == small_index2size(i));
3214 unlink_first_small_chunk(gm, b, p, i);
3215 rsize = small_index2size(i) - nb;
3216 /* Fit here cannot be remainderless if 4byte sizes */
3217 if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
3218 set_inuse_and_pinuse(gm, p, small_index2size(i));
3219 else {
3220 set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
3221 r = chunk_plus_offset(p, nb);
3222 set_size_and_pinuse_of_free_chunk(r, rsize);
3223 replace_dv(gm, r, rsize);
3224 }
3225 mem = chunk2mem(p);
3226 check_malloced_chunk(gm, mem, nb);
3227 goto postaction;
3228 }
3229
3230 else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
3231 check_malloced_chunk(gm, mem, nb);
3232 goto postaction;
3233 }
3234 }
3235 }
3236 else if (bytes >= MAX_REQUEST)
3237 nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
3238 else {
3239 nb = pad_request(bytes);
3240 if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
3241 check_malloced_chunk(gm, mem, nb);
3242 goto postaction;
3243 }
3244 }
3245
3246 if (nb <= gm->dvsize) {
3247 size_t rsize = gm->dvsize - nb;
3248 mchunkptr p = gm->dv;
3249 if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
3250 mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
3251 gm->dvsize = rsize;
3252 set_size_and_pinuse_of_free_chunk(r, rsize);
3253 set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
3254 }
3255 else { /* exhaust dv */
3256 size_t dvs = gm->dvsize;
3257 gm->dvsize = 0;
3258 gm->dv = 0;
3259 set_inuse_and_pinuse(gm, p, dvs);
3260 }
3261 mem = chunk2mem(p);
3262 check_malloced_chunk(gm, mem, nb);
3263 goto postaction;
3264 }
3265
3266 else if (nb < gm->topsize) { /* Split top */
3267 size_t rsize = gm->topsize -= nb;
3268 mchunkptr p = gm->top;
3269 mchunkptr r = gm->top = chunk_plus_offset(p, nb);
3270 r->head = rsize | PINUSE_BIT;
3271 set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
3272 mem = chunk2mem(p);
3273 check_top_chunk(gm, gm->top);
3274 check_malloced_chunk(gm, mem, nb);
3275 goto postaction;
3276 }
3277
3278 mem = sys_alloc(gm, nb);
3279
3280 postaction:
3281 POSTACTION(gm);
3282 return mem;
3283 }
3284
3285 return 0;
3286}
3287
3288/* ---------------------------- free --------------------------- */
3289
3290void dlfree(void* mem) {
3291 /*
Paul Vinciguerraec11b132018-09-24 05:25:00 -07003292 Consolidate freed chunks with preceding or succeeding bordering
Dave Barach6a5adc32018-07-04 10:56:23 -04003293 free chunks, if they exist, and then place in a bin. Intermixed
3294 with special cases for top, dv, mmapped chunks, and usage errors.
3295 */
3296
3297 if (mem != 0) {
3298 mchunkptr p = mem2chunk(mem);
3299#if FOOTERS
3300 mstate fm = get_mstate_for(p);
3301 if (!ok_magic(fm)) {
3302 USAGE_ERROR_ACTION(fm, p);
3303 return;
3304 }
3305#else /* FOOTERS */
3306#define fm gm
3307#endif /* FOOTERS */
3308 if (!PREACTION(fm)) {
3309 check_inuse_chunk(fm, p);
3310 if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
3311 size_t psize = chunksize(p);
3312 mchunkptr next = chunk_plus_offset(p, psize);
3313 if (!pinuse(p)) {
3314 size_t prevsize = p->prev_foot;
3315 if (is_mmapped(p)) {
3316 psize += prevsize + MMAP_FOOT_PAD;
3317 if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
3318 fm->footprint -= psize;
3319 goto postaction;
3320 }
3321 else {
3322 mchunkptr prev = chunk_minus_offset(p, prevsize);
3323 psize += prevsize;
3324 p = prev;
3325 if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
3326 if (p != fm->dv) {
3327 unlink_chunk(fm, p, prevsize);
3328 }
3329 else if ((next->head & INUSE_BITS) == INUSE_BITS) {
3330 fm->dvsize = psize;
3331 set_free_with_pinuse(p, psize, next);
3332 goto postaction;
3333 }
3334 }
3335 else
3336 goto erroraction;
3337 }
3338 }
3339
3340 if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
3341 if (!cinuse(next)) { /* consolidate forward */
3342 if (next == fm->top) {
3343 size_t tsize = fm->topsize += psize;
3344 fm->top = p;
3345 p->head = tsize | PINUSE_BIT;
3346 if (p == fm->dv) {
3347 fm->dv = 0;
3348 fm->dvsize = 0;
3349 }
3350 if (should_trim(fm, tsize))
3351 sys_trim(fm, 0);
3352 goto postaction;
3353 }
3354 else if (next == fm->dv) {
3355 size_t dsize = fm->dvsize += psize;
3356 fm->dv = p;
3357 set_size_and_pinuse_of_free_chunk(p, dsize);
3358 goto postaction;
3359 }
3360 else {
3361 size_t nsize = chunksize(next);
3362 psize += nsize;
3363 unlink_chunk(fm, next, nsize);
3364 set_size_and_pinuse_of_free_chunk(p, psize);
3365 if (p == fm->dv) {
3366 fm->dvsize = psize;
3367 goto postaction;
3368 }
3369 }
3370 }
3371 else
3372 set_free_with_pinuse(p, psize, next);
3373
3374 if (is_small(psize)) {
3375 insert_small_chunk(fm, p, psize);
3376 check_free_chunk(fm, p);
3377 }
3378 else {
3379 tchunkptr tp = (tchunkptr)p;
3380 insert_large_chunk(fm, tp, psize);
3381 check_free_chunk(fm, p);
3382 if (--fm->release_checks == 0)
3383 release_unused_segments(fm);
3384 }
3385 goto postaction;
3386 }
3387 }
3388 erroraction:
3389 USAGE_ERROR_ACTION(fm, p);
3390 postaction:
3391 POSTACTION(fm);
3392 }
3393 }
3394#if !FOOTERS
3395#undef fm
3396#endif /* FOOTERS */
3397}
3398
3399void* dlcalloc(size_t n_elements, size_t elem_size) {
3400 void* mem;
3401 size_t req = 0;
3402 if (n_elements != 0) {
3403 req = n_elements * elem_size;
3404 if (((n_elements | elem_size) & ~(size_t)0xffff) &&
3405 (req / n_elements != elem_size))
3406 req = MAX_SIZE_T; /* force downstream failure on overflow */
3407 }
3408 mem = dlmalloc(req);
3409 if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
3410 memset(mem, 0, req);
3411 return mem;
3412}
3413
3414#endif /* !ONLY_MSPACES */
3415
3416/* ------------ Internal support for realloc, memalign, etc -------------- */
3417
3418/* Try to realloc; only in-place unless can_move true */
3419static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,
3420 int can_move) {
3421 mchunkptr newp = 0;
3422 size_t oldsize = chunksize(p);
3423 mchunkptr next = chunk_plus_offset(p, oldsize);
3424 if (RTCHECK(ok_address(m, p) && ok_inuse(p) &&
3425 ok_next(p, next) && ok_pinuse(next))) {
3426 if (is_mmapped(p)) {
3427 newp = mmap_resize(m, p, nb, can_move);
3428 }
3429 else if (oldsize >= nb) { /* already big enough */
3430 size_t rsize = oldsize - nb;
3431 if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */
3432 mchunkptr r = chunk_plus_offset(p, nb);
3433 set_inuse(m, p, nb);
3434 set_inuse(m, r, rsize);
3435 dispose_chunk(m, r, rsize);
3436 }
3437 newp = p;
3438 }
3439 else if (next == m->top) { /* extend into top */
3440 if (oldsize + m->topsize > nb) {
3441 size_t newsize = oldsize + m->topsize;
3442 size_t newtopsize = newsize - nb;
3443 mchunkptr newtop = chunk_plus_offset(p, nb);
3444 set_inuse(m, p, nb);
3445 newtop->head = newtopsize |PINUSE_BIT;
3446 m->top = newtop;
3447 m->topsize = newtopsize;
3448 newp = p;
3449 }
3450 }
3451 else if (next == m->dv) { /* extend into dv */
3452 size_t dvs = m->dvsize;
3453 if (oldsize + dvs >= nb) {
3454 size_t dsize = oldsize + dvs - nb;
3455 if (dsize >= MIN_CHUNK_SIZE) {
3456 mchunkptr r = chunk_plus_offset(p, nb);
3457 mchunkptr n = chunk_plus_offset(r, dsize);
3458 set_inuse(m, p, nb);
3459 set_size_and_pinuse_of_free_chunk(r, dsize);
3460 clear_pinuse(n);
3461 m->dvsize = dsize;
3462 m->dv = r;
3463 }
3464 else { /* exhaust dv */
3465 size_t newsize = oldsize + dvs;
3466 set_inuse(m, p, newsize);
3467 m->dvsize = 0;
3468 m->dv = 0;
3469 }
3470 newp = p;
3471 }
3472 }
3473 else if (!cinuse(next)) { /* extend into next free chunk */
3474 size_t nextsize = chunksize(next);
3475 if (oldsize + nextsize >= nb) {
3476 size_t rsize = oldsize + nextsize - nb;
3477 unlink_chunk(m, next, nextsize);
3478 if (rsize < MIN_CHUNK_SIZE) {
3479 size_t newsize = oldsize + nextsize;
3480 set_inuse(m, p, newsize);
3481 }
3482 else {
3483 mchunkptr r = chunk_plus_offset(p, nb);
3484 set_inuse(m, p, nb);
3485 set_inuse(m, r, rsize);
3486 dispose_chunk(m, r, rsize);
3487 }
3488 newp = p;
3489 }
3490 }
3491 }
3492 else {
3493 USAGE_ERROR_ACTION(m, chunk2mem(p));
3494 }
3495 return newp;
3496}
3497
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02003498CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04003499static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
3500 void* mem = 0;
3501 if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
3502 alignment = MIN_CHUNK_SIZE;
3503 if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
3504 size_t a = MALLOC_ALIGNMENT << 1;
3505 while (a < alignment) a <<= 1;
3506 alignment = a;
3507 }
3508 if (bytes >= MAX_REQUEST - alignment) {
3509 if (m != 0) { /* Test isn't needed but avoids compiler warning */
3510 MALLOC_FAILURE_ACTION;
3511 }
3512 }
3513 else {
3514 size_t nb = request2size(bytes);
3515 size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
3516 mem = internal_malloc(m, req);
3517 if (mem != 0) {
3518 mchunkptr p = mem2chunk(mem);
3519 if (PREACTION(m))
3520 return 0;
3521 if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */
3522 /*
3523 Find an aligned spot inside chunk. Since we need to give
3524 back leading space in a chunk of at least MIN_CHUNK_SIZE, if
3525 the first calculation places us at a spot with less than
3526 MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
3527 We've allocated enough total room so that this is always
3528 possible.
3529 */
3530 char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment -
3531 SIZE_T_ONE)) &
3532 -alignment));
3533 char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
3534 br : br+alignment;
3535 mchunkptr newp = (mchunkptr)pos;
3536 size_t leadsize = pos - (char*)(p);
3537 size_t newsize = chunksize(p) - leadsize;
3538
3539 if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
3540 newp->prev_foot = p->prev_foot + leadsize;
3541 newp->head = newsize;
3542 }
3543 else { /* Otherwise, give back leader, use the rest */
3544 set_inuse(m, newp, newsize);
3545 set_inuse(m, p, leadsize);
3546 dispose_chunk(m, p, leadsize);
3547 }
3548 p = newp;
3549 }
3550
3551 /* Give back spare room at the end */
3552 if (!is_mmapped(p)) {
3553 size_t size = chunksize(p);
3554 if (size > nb + MIN_CHUNK_SIZE) {
3555 size_t remainder_size = size - nb;
3556 mchunkptr remainder = chunk_plus_offset(p, nb);
3557 set_inuse(m, p, nb);
3558 set_inuse(m, remainder, remainder_size);
3559 dispose_chunk(m, remainder, remainder_size);
3560 }
3561 }
3562
3563 mem = chunk2mem(p);
3564 assert (chunksize(p) >= nb);
3565 assert(((size_t)mem & (alignment - 1)) == 0);
3566 check_inuse_chunk(m, p);
3567 POSTACTION(m);
3568 }
3569 }
3570 return mem;
3571}
3572
3573/*
3574 Common support for independent_X routines, handling
3575 all of the combinations that can result.
3576 The opts arg has:
3577 bit 0 set if all elements are same size (using sizes[0])
3578 bit 1 set if elements should be zeroed
3579*/
3580static void** ialloc(mstate m,
3581 size_t n_elements,
3582 size_t* sizes,
3583 int opts,
3584 void* chunks[]) {
3585
3586 size_t element_size; /* chunksize of each element, if all same */
3587 size_t contents_size; /* total size of elements */
3588 size_t array_size; /* request size of pointer array */
3589 void* mem; /* malloced aggregate space */
3590 mchunkptr p; /* corresponding chunk */
3591 size_t remainder_size; /* remaining bytes while splitting */
3592 void** marray; /* either "chunks" or malloced ptr array */
3593 mchunkptr array_chunk; /* chunk for malloced ptr array */
3594 flag_t was_enabled; /* to disable mmap */
3595 size_t size;
3596 size_t i;
3597
3598 ensure_initialization();
3599 /* compute array length, if needed */
3600 if (chunks != 0) {
3601 if (n_elements == 0)
3602 return chunks; /* nothing to do */
3603 marray = chunks;
3604 array_size = 0;
3605 }
3606 else {
3607 /* if empty req, must still return chunk representing empty array */
3608 if (n_elements == 0)
3609 return (void**)internal_malloc(m, 0);
3610 marray = 0;
3611 array_size = request2size(n_elements * (sizeof(void*)));
3612 }
3613
3614 /* compute total element size */
3615 if (opts & 0x1) { /* all-same-size */
3616 element_size = request2size(*sizes);
3617 contents_size = n_elements * element_size;
3618 }
3619 else { /* add up all the sizes */
3620 element_size = 0;
3621 contents_size = 0;
3622 for (i = 0; i != n_elements; ++i)
3623 contents_size += request2size(sizes[i]);
3624 }
3625
3626 size = contents_size + array_size;
3627
3628 /*
3629 Allocate the aggregate chunk. First disable direct-mmapping so
3630 malloc won't use it, since we would not be able to later
3631 free/realloc space internal to a segregated mmap region.
3632 */
3633 was_enabled = use_mmap(m);
3634 disable_mmap(m);
3635 mem = internal_malloc(m, size - CHUNK_OVERHEAD);
3636 if (was_enabled)
3637 enable_mmap(m);
3638 if (mem == 0)
3639 return 0;
3640
3641 if (PREACTION(m)) return 0;
3642 p = mem2chunk(mem);
3643 remainder_size = chunksize(p);
3644
3645 assert(!is_mmapped(p));
3646
3647 if (opts & 0x2) { /* optionally clear the elements */
3648 memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
3649 }
3650
3651 /* If not provided, allocate the pointer array as final part of chunk */
3652 if (marray == 0) {
3653 size_t array_chunk_size;
3654 array_chunk = chunk_plus_offset(p, contents_size);
3655 array_chunk_size = remainder_size - contents_size;
3656 marray = (void**) (chunk2mem(array_chunk));
3657 set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
3658 remainder_size = contents_size;
3659 }
3660
3661 /* split out elements */
3662 for (i = 0; ; ++i) {
3663 marray[i] = chunk2mem(p);
3664 if (i != n_elements-1) {
3665 if (element_size != 0)
3666 size = element_size;
3667 else
3668 size = request2size(sizes[i]);
3669 remainder_size -= size;
3670 set_size_and_pinuse_of_inuse_chunk(m, p, size);
3671 p = chunk_plus_offset(p, size);
3672 }
3673 else { /* the final element absorbs any overallocation slop */
3674 set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
3675 break;
3676 }
3677 }
3678
3679#if DEBUG
3680 if (marray != chunks) {
3681 /* final element must have exactly exhausted chunk */
3682 if (element_size != 0) {
3683 assert(remainder_size == element_size);
3684 }
3685 else {
3686 assert(remainder_size == request2size(sizes[i]));
3687 }
3688 check_inuse_chunk(m, mem2chunk(marray));
3689 }
3690 for (i = 0; i != n_elements; ++i)
3691 check_inuse_chunk(m, mem2chunk(marray[i]));
3692
3693#endif /* DEBUG */
3694
3695 POSTACTION(m);
3696 return marray;
3697}
3698
3699/* Try to free all pointers in the given array.
3700 Note: this could be made faster, by delaying consolidation,
3701 at the price of disabling some user integrity checks, We
3702 still optimize some consolidations by combining adjacent
3703 chunks before freeing, which will occur often if allocated
3704 with ialloc or the array is sorted.
3705*/
3706static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) {
3707 size_t unfreed = 0;
3708 if (!PREACTION(m)) {
3709 void** a;
3710 void** fence = &(array[nelem]);
3711 for (a = array; a != fence; ++a) {
3712 void* mem = *a;
3713 if (mem != 0) {
3714 mchunkptr p = mem2chunk(mem);
3715 size_t psize = chunksize(p);
3716#if FOOTERS
3717 if (get_mstate_for(p) != m) {
3718 ++unfreed;
3719 continue;
3720 }
3721#endif
3722 check_inuse_chunk(m, p);
3723 *a = 0;
3724 if (RTCHECK(ok_address(m, p) && ok_inuse(p))) {
3725 void ** b = a + 1; /* try to merge with next chunk */
3726 mchunkptr next = next_chunk(p);
3727 if (b != fence && *b == chunk2mem(next)) {
3728 size_t newsize = chunksize(next) + psize;
3729 set_inuse(m, p, newsize);
3730 *b = chunk2mem(p);
3731 }
3732 else
3733 dispose_chunk(m, p, psize);
3734 }
3735 else {
3736 CORRUPTION_ERROR_ACTION(m);
3737 break;
3738 }
3739 }
3740 }
3741 if (should_trim(m, m->topsize))
3742 sys_trim(m, 0);
3743 POSTACTION(m);
3744 }
3745 return unfreed;
3746}
3747
3748/* Traversal */
3749#if MALLOC_INSPECT_ALL
3750static void internal_inspect_all(mstate m,
3751 void(*handler)(void *start,
3752 void *end,
3753 size_t used_bytes,
3754 void* callback_arg),
3755 void* arg) {
3756 if (is_initialized(m)) {
3757 mchunkptr top = m->top;
3758 msegmentptr s;
3759 for (s = &m->seg; s != 0; s = s->next) {
3760 mchunkptr q = align_as_chunk(s->base);
3761 while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) {
3762 mchunkptr next = next_chunk(q);
3763 size_t sz = chunksize(q);
3764 size_t used;
3765 void* start;
3766 if (is_inuse(q)) {
3767 used = sz - CHUNK_OVERHEAD; /* must not be mmapped */
3768 start = chunk2mem(q);
3769 }
3770 else {
3771 used = 0;
3772 if (is_small(sz)) { /* offset by possible bookkeeping */
3773 start = (void*)((char*)q + sizeof(struct malloc_chunk));
3774 }
3775 else {
3776 start = (void*)((char*)q + sizeof(struct malloc_tree_chunk));
3777 }
3778 }
3779 if (start < (void*)next) /* skip if all space is bookkeeping */
3780 handler(start, next, used, arg);
3781 if (q == top)
3782 break;
3783 q = next;
3784 }
3785 }
3786 }
3787}
3788#endif /* MALLOC_INSPECT_ALL */
3789
3790/* ------------------ Exported realloc, memalign, etc -------------------- */
3791
3792#if !ONLY_MSPACES
3793
3794void* dlrealloc(void* oldmem, size_t bytes) {
3795 void* mem = 0;
3796 if (oldmem == 0) {
3797 mem = dlmalloc(bytes);
3798 }
3799 else if (bytes >= MAX_REQUEST) {
3800 MALLOC_FAILURE_ACTION;
3801 }
3802#ifdef REALLOC_ZERO_BYTES_FREES
3803 else if (bytes == 0) {
3804 dlfree(oldmem);
3805 }
3806#endif /* REALLOC_ZERO_BYTES_FREES */
3807 else {
3808 size_t nb = request2size(bytes);
3809 mchunkptr oldp = mem2chunk(oldmem);
3810#if ! FOOTERS
3811 mstate m = gm;
3812#else /* FOOTERS */
3813 mstate m = get_mstate_for(oldp);
3814 if (!ok_magic(m)) {
3815 USAGE_ERROR_ACTION(m, oldmem);
3816 return 0;
3817 }
3818#endif /* FOOTERS */
3819 if (!PREACTION(m)) {
3820 mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);
3821 POSTACTION(m);
3822 if (newp != 0) {
3823 check_inuse_chunk(m, newp);
3824 mem = chunk2mem(newp);
3825 }
3826 else {
3827 mem = internal_malloc(m, bytes);
3828 if (mem != 0) {
3829 size_t oc = chunksize(oldp) - overhead_for(oldp);
3830 memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
3831 internal_free(m, oldmem);
3832 }
3833 }
3834 }
3835 }
3836 return mem;
3837}
3838
3839void* dlrealloc_in_place(void* oldmem, size_t bytes) {
3840 void* mem = 0;
3841 if (oldmem != 0) {
3842 if (bytes >= MAX_REQUEST) {
3843 MALLOC_FAILURE_ACTION;
3844 }
3845 else {
3846 size_t nb = request2size(bytes);
3847 mchunkptr oldp = mem2chunk(oldmem);
3848#if ! FOOTERS
3849 mstate m = gm;
3850#else /* FOOTERS */
3851 mstate m = get_mstate_for(oldp);
3852 if (!ok_magic(m)) {
3853 USAGE_ERROR_ACTION(m, oldmem);
3854 return 0;
3855 }
3856#endif /* FOOTERS */
3857 if (!PREACTION(m)) {
3858 mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);
3859 POSTACTION(m);
3860 if (newp == oldp) {
3861 check_inuse_chunk(m, newp);
3862 mem = oldmem;
3863 }
3864 }
3865 }
3866 }
3867 return mem;
3868}
3869
3870void* dlmemalign(size_t alignment, size_t bytes) {
3871 if (alignment <= MALLOC_ALIGNMENT) {
3872 return dlmalloc(bytes);
3873 }
3874 return internal_memalign(gm, alignment, bytes);
3875}
3876
3877int dlposix_memalign(void** pp, size_t alignment, size_t bytes) {
3878 void* mem = 0;
3879 if (alignment == MALLOC_ALIGNMENT)
3880 mem = dlmalloc(bytes);
3881 else {
3882 size_t d = alignment / sizeof(void*);
3883 size_t r = alignment % sizeof(void*);
3884 if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0)
3885 return EINVAL;
3886 else if (bytes <= MAX_REQUEST - alignment) {
3887 if (alignment < MIN_CHUNK_SIZE)
3888 alignment = MIN_CHUNK_SIZE;
3889 mem = internal_memalign(gm, alignment, bytes);
3890 }
3891 }
3892 if (mem == 0)
3893 return ENOMEM;
3894 else {
3895 *pp = mem;
3896 return 0;
3897 }
3898}
3899
3900void* dlvalloc(size_t bytes) {
3901 size_t pagesz;
3902 ensure_initialization();
3903 pagesz = mparams.page_size;
3904 return dlmemalign(pagesz, bytes);
3905}
3906
3907void* dlpvalloc(size_t bytes) {
3908 size_t pagesz;
3909 ensure_initialization();
3910 pagesz = mparams.page_size;
3911 return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
3912}
3913
3914void** dlindependent_calloc(size_t n_elements, size_t elem_size,
3915 void* chunks[]) {
3916 size_t sz = elem_size; /* serves as 1-element array */
3917 return ialloc(gm, n_elements, &sz, 3, chunks);
3918}
3919
3920void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
3921 void* chunks[]) {
3922 return ialloc(gm, n_elements, sizes, 0, chunks);
3923}
3924
3925size_t dlbulk_free(void* array[], size_t nelem) {
3926 return internal_bulk_free(gm, array, nelem);
3927}
3928
3929#if MALLOC_INSPECT_ALL
3930void dlmalloc_inspect_all(void(*handler)(void *start,
3931 void *end,
3932 size_t used_bytes,
3933 void* callback_arg),
3934 void* arg) {
3935 ensure_initialization();
3936 if (!PREACTION(gm)) {
3937 internal_inspect_all(gm, handler, arg);
3938 POSTACTION(gm);
3939 }
3940}
3941#endif /* MALLOC_INSPECT_ALL */
3942
3943int dlmalloc_trim(size_t pad) {
3944 int result = 0;
3945 ensure_initialization();
3946 if (!PREACTION(gm)) {
3947 result = sys_trim(gm, pad);
3948 POSTACTION(gm);
3949 }
3950 return result;
3951}
3952
3953size_t dlmalloc_footprint(void) {
3954 return gm->footprint;
3955}
3956
3957size_t dlmalloc_max_footprint(void) {
3958 return gm->max_footprint;
3959}
3960
3961size_t dlmalloc_footprint_limit(void) {
3962 size_t maf = gm->footprint_limit;
3963 return maf == 0 ? MAX_SIZE_T : maf;
3964}
3965
3966size_t dlmalloc_set_footprint_limit(size_t bytes) {
3967 size_t result; /* invert sense of 0 */
3968 if (bytes == 0)
3969 result = granularity_align(1); /* Use minimal size */
3970 if (bytes == MAX_SIZE_T)
3971 result = 0; /* disable */
3972 else
3973 result = granularity_align(bytes);
3974 return gm->footprint_limit = result;
3975}
3976
3977#if !NO_MALLINFO
Dave Barachaf7dd5b2018-08-23 17:08:44 -04003978struct dlmallinfo dlmallinfo(void) {
Dave Barach6a5adc32018-07-04 10:56:23 -04003979 return internal_mallinfo(gm);
3980}
3981#endif /* NO_MALLINFO */
3982
3983#if !NO_MALLOC_STATS
3984void dlmalloc_stats() {
3985 internal_malloc_stats(gm);
3986}
3987#endif /* NO_MALLOC_STATS */
3988
3989int dlmallopt(int param_number, int value) {
3990 return change_mparam(param_number, value);
3991}
3992
3993size_t dlmalloc_usable_size(void* mem) {
3994 if (mem != 0) {
3995 mchunkptr p = mem2chunk(mem);
3996 if (is_inuse(p))
3997 return chunksize(p) - overhead_for(p);
3998 }
3999 return 0;
4000}
4001
4002#endif /* !ONLY_MSPACES */
4003
4004/* ----------------------------- user mspaces ---------------------------- */
4005
4006#if MSPACES
4007
4008static mstate init_user_mstate(char* tbase, size_t tsize) {
4009 size_t msize = pad_request(sizeof(struct malloc_state));
4010 mchunkptr mn;
4011 mchunkptr msp = align_as_chunk(tbase);
4012 mstate m = (mstate)(chunk2mem(msp));
4013 memset(m, 0, msize);
4014 (void)INITIAL_LOCK(&m->mutex);
4015 msp->head = (msize|INUSE_BITS);
4016 m->seg.base = m->least_addr = tbase;
4017 m->seg.size = m->footprint = m->max_footprint = tsize;
4018 m->magic = mparams.magic;
4019 m->release_checks = MAX_RELEASE_CHECK_RATE;
4020 m->mflags = mparams.default_mflags;
4021 m->extp = 0;
4022 m->exts = 0;
4023 disable_contiguous(m);
4024 init_bins(m);
4025 mn = next_chunk(mem2chunk(m));
4026 init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
4027 check_top_chunk(m, m->top);
4028 return m;
4029}
4030
4031mspace create_mspace(size_t capacity, int locked) {
4032 mstate m = 0;
4033 size_t msize;
4034 ensure_initialization();
4035 msize = pad_request(sizeof(struct malloc_state));
4036 if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
4037 size_t rs = ((capacity == 0)? mparams.granularity :
4038 (capacity + TOP_FOOT_SIZE + msize));
4039 size_t tsize = granularity_align(rs);
4040 char* tbase = (char*)(CALL_MMAP(tsize));
4041 if (tbase != CMFAIL) {
4042 m = init_user_mstate(tbase, tsize);
4043 m->seg.sflags = USE_MMAP_BIT;
4044 set_lock(m, locked);
4045 }
4046 }
4047 return (mspace)m;
4048}
4049
4050mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
4051 mstate m = 0;
4052 size_t msize;
4053 ensure_initialization();
4054 msize = pad_request(sizeof(struct malloc_state));
4055 if (capacity > msize + TOP_FOOT_SIZE &&
4056 capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
4057 m = init_user_mstate((char*)base, capacity);
4058 m->seg.sflags = EXTERN_BIT;
4059 set_lock(m, locked);
4060 }
4061 return (mspace)m;
4062}
4063
4064int mspace_track_large_chunks(mspace msp, int enable) {
4065 int ret = 0;
4066 mstate ms = (mstate)msp;
4067 if (!PREACTION(ms)) {
4068 if (!use_mmap(ms)) {
4069 ret = 1;
4070 }
4071 if (!enable) {
4072 enable_mmap(ms);
4073 } else {
4074 disable_mmap(ms);
4075 }
4076 POSTACTION(ms);
4077 }
4078 return ret;
4079}
4080
4081size_t destroy_mspace(mspace msp) {
4082 size_t freed = 0;
4083 mstate ms = (mstate)msp;
4084 if (ok_magic(ms)) {
4085 msegmentptr sp = &ms->seg;
4086 (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */
4087 while (sp != 0) {
4088 char* base = sp->base;
4089 size_t size = sp->size;
4090 flag_t flag = sp->sflags;
4091 (void)base; /* placate people compiling -Wunused-variable */
4092 sp = sp->next;
4093 if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&
4094 CALL_MUNMAP(base, size) == 0)
4095 freed += size;
4096 }
4097 }
4098 else {
4099 USAGE_ERROR_ACTION(ms,ms);
4100 }
4101 return freed;
4102}
4103
David Johnsond9818dd2018-12-14 14:53:41 -05004104void mspace_get_address_and_size (mspace msp, char **addrp, size_t *sizep)
Dave Barach6a5adc32018-07-04 10:56:23 -04004105{
4106 mstate ms;
4107 msegment *this_seg;
Dave Barachd67a4282019-06-15 12:46:13 -04004108
Dave Barach6a5adc32018-07-04 10:56:23 -04004109 ms = (mstate)msp;
4110 this_seg = &ms->seg;
4111
David Johnsond9818dd2018-12-14 14:53:41 -05004112 *addrp = this_seg->base;
Dave Barach6a5adc32018-07-04 10:56:23 -04004113 *sizep = this_seg->size;
4114}
4115
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004116CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04004117int mspace_is_heap_object (mspace msp, void *p)
4118{
4119 msegment *this_seg;
4120 char *pp, *base;
4121 mstate ms;
4122
4123 ms = (mstate)msp;
4124
4125 this_seg = &ms->seg;
4126 pp = (char *) p;
4127
4128 while (this_seg)
4129 {
4130 base = this_seg->base;
4131 if (pp >= base && pp < (base + this_seg->size))
4132 return 1;
4133 this_seg = this_seg->next;
4134 }
Dave Barachb76590a2018-08-23 11:23:00 -04004135
4136 if (pp > ms->least_addr && pp <= ms->least_addr + ms->footprint)
4137 return 1;
4138
Dave Barach6a5adc32018-07-04 10:56:23 -04004139 return 0;
4140}
4141
4142void *mspace_least_addr (mspace msp)
4143{
4144 mstate ms = (mstate) msp;
4145 return (void *) ms->least_addr;
4146}
4147
4148void mspace_disable_expand (mspace msp)
4149{
4150 mstate ms = (mstate)msp;
4151
4152 disable_expand (ms);
4153}
4154
4155int mspace_enable_disable_trace (mspace msp, int enable)
4156{
4157 mstate ms = (mstate)msp;
4158 int was_enabled = 0;
4159
Dave Barached2fe932018-07-19 12:29:45 -04004160 if (use_trace(ms))
Dave Barach6a5adc32018-07-04 10:56:23 -04004161 was_enabled = 1;
4162
4163 if (enable)
4164 enable_trace (ms);
4165 else
4166 disable_trace (ms);
4167
4168 return (was_enabled);
4169}
4170
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004171CLIB_NOSANITIZE_ADDR
Dave Barachd67a4282019-06-15 12:46:13 -04004172int mspace_is_traced (mspace msp)
4173{
4174 mstate ms = (mstate)msp;
4175
4176 if (use_trace(ms))
4177 return 1;
4178 return 0;
4179}
4180
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004181CLIB_NOSANITIZE_ADDR
Dave Barachd67a4282019-06-15 12:46:13 -04004182void* mspace_get_aligned (mspace msp,
David Johnsond9818dd2018-12-14 14:53:41 -05004183 unsigned long n_user_data_bytes,
Dave Barachd67a4282019-06-15 12:46:13 -04004184 unsigned long align,
David Johnsond9818dd2018-12-14 14:53:41 -05004185 unsigned long align_offset) {
Dave Barach6a5adc32018-07-04 10:56:23 -04004186 char *rv;
David Johnsond9818dd2018-12-14 14:53:41 -05004187 unsigned long searchp;
Dave Barach6a5adc32018-07-04 10:56:23 -04004188 unsigned *wwp; /* "where's Waldo" pointer */
4189 mstate ms = (mstate)msp;
4190
4191 /*
Dave Barachd67a4282019-06-15 12:46:13 -04004192 * Allocate space for the "Where's Waldo?" pointer
Dave Barach6a5adc32018-07-04 10:56:23 -04004193 * the base of the dlmalloc object
4194 */
4195 n_user_data_bytes += sizeof(unsigned);
4196
Dave Barachd67a4282019-06-15 12:46:13 -04004197 /*
4198 * Alignment requests less than the size of an mmx vector are ignored
Dave Barach6a5adc32018-07-04 10:56:23 -04004199 */
Florin Corasf5dc9fb2019-04-16 11:27:54 -07004200 if (align < sizeof (uword)) {
Dave Barach6a5adc32018-07-04 10:56:23 -04004201 rv = mspace_malloc (msp, n_user_data_bytes);
4202 if (rv == 0)
4203 return rv;
4204
4205 if (use_trace(ms)) {
4206 mchunkptr p = mem2chunk(rv);
4207 size_t psize = chunksize(p);
Dave Barachd67a4282019-06-15 12:46:13 -04004208
David Johnsond9818dd2018-12-14 14:53:41 -05004209 mheap_get_trace ((unsigned long)rv + sizeof (unsigned), psize);
Dave Barach6a5adc32018-07-04 10:56:23 -04004210 }
4211
4212 wwp = (unsigned *)rv;
4213 *wwp = 0;
4214 rv += sizeof (unsigned);
4215
4216 return rv;
4217 }
4218
4219 /*
4220 * Alignment requests greater than 4K must be at offset zero,
4221 * and must be freed using mspace_free_no_offset - or never freed -
4222 * since the "Where's Waldo?" pointer would waste too much space.
Dave Barachd67a4282019-06-15 12:46:13 -04004223 *
4224 * Waldo is the address of the chunk of memory returned by mspace_malloc,
Dave Barach6a5adc32018-07-04 10:56:23 -04004225 * which we need later to call mspace_free...
4226 */
David Johnsond9818dd2018-12-14 14:53:41 -05004227 if (align > 4<<10 || align_offset == ~0UL) {
Dave Barach6a5adc32018-07-04 10:56:23 -04004228 n_user_data_bytes -= sizeof(unsigned);
4229 assert(align_offset == 0);
4230 rv = internal_memalign(ms, (size_t)align, n_user_data_bytes);
Dave Barachd67a4282019-06-15 12:46:13 -04004231
Dave Barach6a5adc32018-07-04 10:56:23 -04004232 /* Trace the allocation */
4233 if (rv && use_trace(ms)) {
4234 mchunkptr p = mem2chunk(rv);
4235 size_t psize = chunksize(p);
David Johnsond9818dd2018-12-14 14:53:41 -05004236 mheap_get_trace ((unsigned long)rv, psize);
Dave Barach6a5adc32018-07-04 10:56:23 -04004237 }
4238 return rv;
4239 }
4240
4241 align = clib_max (align, MALLOC_ALIGNMENT);
4242 align = max_pow2 (align);
4243
4244 /* Correct align offset to be smaller than alignment. */
4245 align_offset &= (align - 1);
4246
4247 n_user_data_bytes += align;
4248 rv = mspace_malloc (msp, n_user_data_bytes);
4249
4250 if (rv == 0)
4251 return rv;
4252
4253 /* Honor the alignment request */
David Johnsond9818dd2018-12-14 14:53:41 -05004254 searchp = (unsigned long)(rv + sizeof (unsigned));
Dave Barach6a5adc32018-07-04 10:56:23 -04004255
4256#if 0 /* this is the idea... */
4257 while ((searchp + align_offset) % align)
4258 searchp++;
4259#endif
4260
4261 {
David Johnsond9818dd2018-12-14 14:53:41 -05004262 unsigned long where_now, delta;
Dave Barach6a5adc32018-07-04 10:56:23 -04004263
4264 where_now = (searchp + align_offset) % align;
4265 delta = align - where_now;
4266
4267 searchp += delta;
4268 }
4269
4270 wwp = (unsigned *)(searchp - sizeof(unsigned));
David Johnsond9818dd2018-12-14 14:53:41 -05004271 *wwp = (searchp - (((unsigned long) rv) + sizeof (*wwp)));
Dave Barach6a5adc32018-07-04 10:56:23 -04004272 assert (*wwp < align);
4273
4274 if (use_trace(ms)) {
4275 mchunkptr p = mem2chunk(rv);
4276 size_t psize = chunksize(p);
Wei CHEN5e282e92019-04-09 12:38:40 +08004277 mheap_get_trace (searchp, psize);
Dave Barach6a5adc32018-07-04 10:56:23 -04004278 }
4279 return (void *) searchp;
4280}
4281
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004282CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04004283void mspace_put (mspace msp, void *p_arg)
4284{
4285 char *object_header;
4286 unsigned *wwp;
4287 mstate ms = (mstate)msp;
4288
4289 /* Find the object header delta */
4290 wwp = (unsigned *)p_arg;
4291 wwp --;
4292
4293 /* Recover the dlmalloc object pointer */
4294 object_header = (char *)wwp;
4295 object_header -= *wwp;
4296
4297 /* Tracing (if enabled) */
4298 if (use_trace(ms))
4299 {
4300 mchunkptr p = mem2chunk(object_header);
4301 size_t psize = chunksize(p);
4302
David Johnsond9818dd2018-12-14 14:53:41 -05004303 mheap_put_trace ((unsigned long)p_arg, psize);
Dave Barach6a5adc32018-07-04 10:56:23 -04004304 }
4305
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004306#if CLIB_DEBUG > 0 && !defined(CLIB_SANITIZE_ADDR)
Dave Barach1c7bf5d2018-07-31 10:39:30 -04004307 /* Poison the object */
4308 {
4309 size_t psize = mspace_usable_size (object_header);
4310 memset (object_header, 0x13, psize);
4311 }
4312#endif
4313
Dave Barach6a5adc32018-07-04 10:56:23 -04004314 /* And free it... */
4315 mspace_free (msp, object_header);
4316}
4317
4318void mspace_put_no_offset (mspace msp, void *p_arg)
4319{
4320 mstate ms = (mstate)msp;
4321
4322 if (use_trace(ms))
4323 {
4324 mchunkptr p = mem2chunk(p_arg);
4325 size_t psize = chunksize(p);
4326
David Johnsond9818dd2018-12-14 14:53:41 -05004327 mheap_put_trace ((unsigned long)p_arg, psize);
Dave Barach6a5adc32018-07-04 10:56:23 -04004328 }
4329 mspace_free (msp, p_arg);
4330}
4331
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004332CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04004333size_t mspace_usable_size_with_delta (const void *p)
4334{
4335 size_t usable_size;
4336 char *object_header;
4337 unsigned *wwp;
4338
4339 /* Find the object header delta */
4340 wwp = (unsigned *)p;
4341 wwp --;
4342
4343 /* Recover the dlmalloc object pointer */
4344 object_header = (char *)wwp;
4345 object_header -= *wwp;
4346
4347 usable_size = mspace_usable_size (object_header);
4348 /* account for the offset and the size of the offset... */
4349 usable_size -= (*wwp + sizeof (*wwp));
4350 return usable_size;
4351}
4352
4353/*
4354 mspace versions of routines are near-clones of the global
4355 versions. This is not so nice but better than the alternatives.
4356*/
4357
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004358CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04004359void* mspace_malloc(mspace msp, size_t bytes) {
4360 mstate ms = (mstate)msp;
4361 if (!ok_magic(ms)) {
4362 USAGE_ERROR_ACTION(ms,ms);
4363 return 0;
4364 }
4365 if (!PREACTION(ms)) {
4366 void* mem;
4367 size_t nb;
4368 if (bytes <= MAX_SMALL_REQUEST) {
4369 bindex_t idx;
4370 binmap_t smallbits;
4371 nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
4372 idx = small_index(nb);
4373 smallbits = ms->smallmap >> idx;
4374
4375 if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
4376 mchunkptr b, p;
4377 idx += ~smallbits & 1; /* Uses next bin if idx empty */
4378 b = smallbin_at(ms, idx);
4379 p = b->fd;
4380 assert(chunksize(p) == small_index2size(idx));
4381 unlink_first_small_chunk(ms, b, p, idx);
4382 set_inuse_and_pinuse(ms, p, small_index2size(idx));
4383 mem = chunk2mem(p);
4384 check_malloced_chunk(ms, mem, nb);
4385 goto postaction;
4386 }
4387
4388 else if (nb > ms->dvsize) {
4389 if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
4390 mchunkptr b, p, r;
4391 size_t rsize;
4392 bindex_t i;
4393 binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
4394 binmap_t leastbit = least_bit(leftbits);
4395 compute_bit2idx(leastbit, i);
4396 b = smallbin_at(ms, i);
4397 p = b->fd;
4398 assert(chunksize(p) == small_index2size(i));
4399 unlink_first_small_chunk(ms, b, p, i);
4400 rsize = small_index2size(i) - nb;
4401 /* Fit here cannot be remainderless if 4byte sizes */
4402 if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
4403 set_inuse_and_pinuse(ms, p, small_index2size(i));
4404 else {
4405 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4406 r = chunk_plus_offset(p, nb);
4407 set_size_and_pinuse_of_free_chunk(r, rsize);
4408 replace_dv(ms, r, rsize);
4409 }
4410 mem = chunk2mem(p);
4411 check_malloced_chunk(ms, mem, nb);
4412 goto postaction;
4413 }
4414
4415 else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
4416 check_malloced_chunk(ms, mem, nb);
4417 goto postaction;
4418 }
4419 }
4420 }
4421 else if (bytes >= MAX_REQUEST)
4422 nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
4423 else {
4424 nb = pad_request(bytes);
4425 if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
4426 check_malloced_chunk(ms, mem, nb);
4427 goto postaction;
4428 }
4429 }
4430
4431 if (nb <= ms->dvsize) {
4432 size_t rsize = ms->dvsize - nb;
4433 mchunkptr p = ms->dv;
4434 if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
4435 mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
4436 ms->dvsize = rsize;
4437 set_size_and_pinuse_of_free_chunk(r, rsize);
4438 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4439 }
4440 else { /* exhaust dv */
4441 size_t dvs = ms->dvsize;
4442 ms->dvsize = 0;
4443 ms->dv = 0;
4444 set_inuse_and_pinuse(ms, p, dvs);
4445 }
4446 mem = chunk2mem(p);
4447 check_malloced_chunk(ms, mem, nb);
4448 goto postaction;
4449 }
4450
4451 else if (nb < ms->topsize) { /* Split top */
4452 size_t rsize = ms->topsize -= nb;
4453 mchunkptr p = ms->top;
4454 mchunkptr r = ms->top = chunk_plus_offset(p, nb);
4455 r->head = rsize | PINUSE_BIT;
4456 set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
4457 mem = chunk2mem(p);
4458 check_top_chunk(ms, ms->top);
4459 check_malloced_chunk(ms, mem, nb);
4460 goto postaction;
4461 }
4462
4463 mem = sys_alloc(ms, nb);
4464
4465 postaction:
4466 POSTACTION(ms);
4467 return mem;
4468 }
4469
4470 return 0;
4471}
4472
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004473CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04004474void mspace_free(mspace msp, void* mem) {
4475 if (mem != 0) {
4476 mchunkptr p = mem2chunk(mem);
4477#if FOOTERS
4478 mstate fm = get_mstate_for(p);
4479 (void)msp; /* placate people compiling -Wunused */
4480#else /* FOOTERS */
4481 mstate fm = (mstate)msp;
4482#endif /* FOOTERS */
4483 if (!ok_magic(fm)) {
4484 USAGE_ERROR_ACTION(fm, p);
4485 return;
4486 }
4487 if (!PREACTION(fm)) {
4488 check_inuse_chunk(fm, p);
4489 if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
4490 size_t psize = chunksize(p);
4491 mchunkptr next = chunk_plus_offset(p, psize);
4492 if (!pinuse(p)) {
4493 size_t prevsize = p->prev_foot;
4494 if (is_mmapped(p)) {
4495 psize += prevsize + MMAP_FOOT_PAD;
4496 if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
4497 fm->footprint -= psize;
4498 goto postaction;
4499 }
4500 else {
4501 mchunkptr prev = chunk_minus_offset(p, prevsize);
4502 psize += prevsize;
4503 p = prev;
4504 if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
4505 if (p != fm->dv) {
4506 unlink_chunk(fm, p, prevsize);
4507 }
4508 else if ((next->head & INUSE_BITS) == INUSE_BITS) {
4509 fm->dvsize = psize;
4510 set_free_with_pinuse(p, psize, next);
4511 goto postaction;
4512 }
4513 }
4514 else
4515 goto erroraction;
4516 }
4517 }
4518
4519 if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
4520 if (!cinuse(next)) { /* consolidate forward */
4521 if (next == fm->top) {
4522 size_t tsize = fm->topsize += psize;
4523 fm->top = p;
4524 p->head = tsize | PINUSE_BIT;
4525 if (p == fm->dv) {
4526 fm->dv = 0;
4527 fm->dvsize = 0;
4528 }
4529 if (should_trim(fm, tsize))
4530 sys_trim(fm, 0);
4531 goto postaction;
4532 }
4533 else if (next == fm->dv) {
4534 size_t dsize = fm->dvsize += psize;
4535 fm->dv = p;
4536 set_size_and_pinuse_of_free_chunk(p, dsize);
4537 goto postaction;
4538 }
4539 else {
4540 size_t nsize = chunksize(next);
4541 psize += nsize;
4542 unlink_chunk(fm, next, nsize);
4543 set_size_and_pinuse_of_free_chunk(p, psize);
4544 if (p == fm->dv) {
4545 fm->dvsize = psize;
4546 goto postaction;
4547 }
4548 }
4549 }
4550 else
4551 set_free_with_pinuse(p, psize, next);
4552
4553 if (is_small(psize)) {
4554 insert_small_chunk(fm, p, psize);
4555 check_free_chunk(fm, p);
4556 }
4557 else {
4558 tchunkptr tp = (tchunkptr)p;
4559 insert_large_chunk(fm, tp, psize);
4560 check_free_chunk(fm, p);
4561 if (--fm->release_checks == 0)
4562 release_unused_segments(fm);
4563 }
4564 goto postaction;
4565 }
4566 }
4567 erroraction:
4568 USAGE_ERROR_ACTION(fm, p);
4569 postaction:
4570 POSTACTION(fm);
4571 }
4572 }
4573}
4574
4575void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
4576 void* mem;
4577 size_t req = 0;
4578 mstate ms = (mstate)msp;
4579 if (!ok_magic(ms)) {
4580 USAGE_ERROR_ACTION(ms,ms);
4581 return 0;
4582 }
4583 if (n_elements != 0) {
4584 req = n_elements * elem_size;
4585 if (((n_elements | elem_size) & ~(size_t)0xffff) &&
4586 (req / n_elements != elem_size))
4587 req = MAX_SIZE_T; /* force downstream failure on overflow */
4588 }
4589 mem = internal_malloc(ms, req);
4590 if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
4591 memset(mem, 0, req);
4592 return mem;
4593}
4594
4595void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
4596 void* mem = 0;
4597 if (oldmem == 0) {
4598 mem = mspace_malloc(msp, bytes);
4599 }
4600 else if (bytes >= MAX_REQUEST) {
4601 MALLOC_FAILURE_ACTION;
4602 }
4603#ifdef REALLOC_ZERO_BYTES_FREES
4604 else if (bytes == 0) {
4605 mspace_free(msp, oldmem);
4606 }
4607#endif /* REALLOC_ZERO_BYTES_FREES */
4608 else {
4609 size_t nb = request2size(bytes);
4610 mchunkptr oldp = mem2chunk(oldmem);
4611#if ! FOOTERS
4612 mstate m = (mstate)msp;
4613#else /* FOOTERS */
4614 mstate m = get_mstate_for(oldp);
4615 if (!ok_magic(m)) {
4616 USAGE_ERROR_ACTION(m, oldmem);
4617 return 0;
4618 }
4619#endif /* FOOTERS */
4620 if (!PREACTION(m)) {
4621 mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);
4622 POSTACTION(m);
4623 if (newp != 0) {
4624 check_inuse_chunk(m, newp);
4625 mem = chunk2mem(newp);
4626 }
4627 else {
4628 mem = mspace_malloc(m, bytes);
4629 if (mem != 0) {
4630 size_t oc = chunksize(oldp) - overhead_for(oldp);
4631 memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
4632 mspace_free(m, oldmem);
4633 }
4634 }
4635 }
4636 }
4637 return mem;
4638}
4639
4640void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) {
4641 void* mem = 0;
4642 if (oldmem != 0) {
4643 if (bytes >= MAX_REQUEST) {
4644 MALLOC_FAILURE_ACTION;
4645 }
4646 else {
4647 size_t nb = request2size(bytes);
4648 mchunkptr oldp = mem2chunk(oldmem);
4649#if ! FOOTERS
4650 mstate m = (mstate)msp;
4651#else /* FOOTERS */
4652 mstate m = get_mstate_for(oldp);
4653 (void)msp; /* placate people compiling -Wunused */
4654 if (!ok_magic(m)) {
4655 USAGE_ERROR_ACTION(m, oldmem);
4656 return 0;
4657 }
4658#endif /* FOOTERS */
4659 if (!PREACTION(m)) {
4660 mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);
4661 POSTACTION(m);
4662 if (newp == oldp) {
4663 check_inuse_chunk(m, newp);
4664 mem = oldmem;
4665 }
4666 }
4667 }
4668 }
4669 return mem;
4670}
4671
4672void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
4673 mstate ms = (mstate)msp;
4674 if (!ok_magic(ms)) {
4675 USAGE_ERROR_ACTION(ms,ms);
4676 return 0;
4677 }
4678 if (alignment <= MALLOC_ALIGNMENT)
4679 return mspace_malloc(msp, bytes);
4680 return internal_memalign(ms, alignment, bytes);
4681}
4682
4683void** mspace_independent_calloc(mspace msp, size_t n_elements,
4684 size_t elem_size, void* chunks[]) {
4685 size_t sz = elem_size; /* serves as 1-element array */
4686 mstate ms = (mstate)msp;
4687 if (!ok_magic(ms)) {
4688 USAGE_ERROR_ACTION(ms,ms);
4689 return 0;
4690 }
4691 return ialloc(ms, n_elements, &sz, 3, chunks);
4692}
4693
4694void** mspace_independent_comalloc(mspace msp, size_t n_elements,
4695 size_t sizes[], void* chunks[]) {
4696 mstate ms = (mstate)msp;
4697 if (!ok_magic(ms)) {
4698 USAGE_ERROR_ACTION(ms,ms);
4699 return 0;
4700 }
4701 return ialloc(ms, n_elements, sizes, 0, chunks);
4702}
4703
4704size_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) {
4705 return internal_bulk_free((mstate)msp, array, nelem);
4706}
4707
4708#if MALLOC_INSPECT_ALL
4709void mspace_inspect_all(mspace msp,
4710 void(*handler)(void *start,
4711 void *end,
4712 size_t used_bytes,
4713 void* callback_arg),
4714 void* arg) {
4715 mstate ms = (mstate)msp;
4716 if (ok_magic(ms)) {
4717 if (!PREACTION(ms)) {
4718 internal_inspect_all(ms, handler, arg);
4719 POSTACTION(ms);
4720 }
4721 }
4722 else {
4723 USAGE_ERROR_ACTION(ms,ms);
4724 }
4725}
4726#endif /* MALLOC_INSPECT_ALL */
4727
4728int mspace_trim(mspace msp, size_t pad) {
4729 int result = 0;
4730 mstate ms = (mstate)msp;
4731 if (ok_magic(ms)) {
4732 if (!PREACTION(ms)) {
4733 result = sys_trim(ms, pad);
4734 POSTACTION(ms);
4735 }
4736 }
4737 else {
4738 USAGE_ERROR_ACTION(ms,ms);
4739 }
4740 return result;
4741}
4742
4743#if !NO_MALLOC_STATS
4744void mspace_malloc_stats(mspace msp) {
4745 mstate ms = (mstate)msp;
4746 if (ok_magic(ms)) {
4747 internal_malloc_stats(ms);
4748 }
4749 else {
4750 USAGE_ERROR_ACTION(ms,ms);
4751 }
4752}
4753#endif /* NO_MALLOC_STATS */
4754
4755size_t mspace_footprint(mspace msp) {
4756 size_t result = 0;
4757 mstate ms = (mstate)msp;
4758 if (ok_magic(ms)) {
4759 result = ms->footprint;
4760 }
4761 else {
4762 USAGE_ERROR_ACTION(ms,ms);
4763 }
4764 return result;
4765}
4766
4767size_t mspace_max_footprint(mspace msp) {
4768 size_t result = 0;
4769 mstate ms = (mstate)msp;
4770 if (ok_magic(ms)) {
4771 result = ms->max_footprint;
4772 }
4773 else {
4774 USAGE_ERROR_ACTION(ms,ms);
4775 }
4776 return result;
4777}
4778
4779size_t mspace_footprint_limit(mspace msp) {
4780 size_t result = 0;
4781 mstate ms = (mstate)msp;
4782 if (ok_magic(ms)) {
4783 size_t maf = ms->footprint_limit;
4784 result = (maf == 0) ? MAX_SIZE_T : maf;
4785 }
4786 else {
4787 USAGE_ERROR_ACTION(ms,ms);
4788 }
4789 return result;
4790}
4791
4792size_t mspace_set_footprint_limit(mspace msp, size_t bytes) {
4793 size_t result = 0;
4794 mstate ms = (mstate)msp;
4795 if (ok_magic(ms)) {
4796 if (bytes == 0)
4797 result = granularity_align(1); /* Use minimal size */
4798 if (bytes == MAX_SIZE_T)
4799 result = 0; /* disable */
4800 else
4801 result = granularity_align(bytes);
4802 ms->footprint_limit = result;
4803 }
4804 else {
4805 USAGE_ERROR_ACTION(ms,ms);
4806 }
4807 return result;
4808}
4809
4810#if !NO_MALLINFO
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004811CLIB_NOSANITIZE_ADDR
Dave Barachaf7dd5b2018-08-23 17:08:44 -04004812struct dlmallinfo mspace_mallinfo(mspace msp) {
Dave Barach6a5adc32018-07-04 10:56:23 -04004813 mstate ms = (mstate)msp;
4814 if (!ok_magic(ms)) {
4815 USAGE_ERROR_ACTION(ms,ms);
4816 }
4817 return internal_mallinfo(ms);
4818}
4819#endif /* NO_MALLINFO */
4820
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +02004821CLIB_NOSANITIZE_ADDR
Dave Barach6a5adc32018-07-04 10:56:23 -04004822size_t mspace_usable_size(const void* mem) {
4823 if (mem != 0) {
4824 mchunkptr p = mem2chunk(mem);
4825 if (is_inuse(p))
4826 return chunksize(p) - overhead_for(p);
4827 }
4828 return 0;
4829}
4830
4831int mspace_mallopt(int param_number, int value) {
4832 return change_mparam(param_number, value);
4833}
4834
4835#endif /* MSPACES */
4836
4837
4838/* -------------------- Alternative MORECORE functions ------------------- */
4839
4840/*
4841 Guidelines for creating a custom version of MORECORE:
4842
4843 * For best performance, MORECORE should allocate in multiples of pagesize.
4844 * MORECORE may allocate more memory than requested. (Or even less,
4845 but this will usually result in a malloc failure.)
4846 * MORECORE must not allocate memory when given argument zero, but
4847 instead return one past the end address of memory from previous
4848 nonzero call.
4849 * For best performance, consecutive calls to MORECORE with positive
4850 arguments should return increasing addresses, indicating that
4851 space has been contiguously extended.
4852 * Even though consecutive calls to MORECORE need not return contiguous
4853 addresses, it must be OK for malloc'ed chunks to span multiple
4854 regions in those cases where they do happen to be contiguous.
4855 * MORECORE need not handle negative arguments -- it may instead
4856 just return MFAIL when given negative arguments.
4857 Negative arguments are always multiples of pagesize. MORECORE
4858 must not misinterpret negative args as large positive unsigned
4859 args. You can suppress all such calls from even occurring by defining
4860 MORECORE_CANNOT_TRIM,
4861
4862 As an example alternative MORECORE, here is a custom allocator
4863 kindly contributed for pre-OSX macOS. It uses virtually but not
4864 necessarily physically contiguous non-paged memory (locked in,
4865 present and won't get swapped out). You can use it by uncommenting
4866 this section, adding some #includes, and setting up the appropriate
4867 defines above:
4868
4869 #define MORECORE osMoreCore
4870
4871 There is also a shutdown routine that should somehow be called for
4872 cleanup upon program exit.
4873
4874 #define MAX_POOL_ENTRIES 100
4875 #define MINIMUM_MORECORE_SIZE (64 * 1024U)
4876 static int next_os_pool;
4877 void *our_os_pools[MAX_POOL_ENTRIES];
4878
4879 void *osMoreCore(int size)
4880 {
4881 void *ptr = 0;
4882 static void *sbrk_top = 0;
4883
4884 if (size > 0)
4885 {
4886 if (size < MINIMUM_MORECORE_SIZE)
4887 size = MINIMUM_MORECORE_SIZE;
4888 if (CurrentExecutionLevel() == kTaskLevel)
4889 ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
4890 if (ptr == 0)
4891 {
4892 return (void *) MFAIL;
4893 }
4894 // save ptrs so they can be freed during cleanup
4895 our_os_pools[next_os_pool] = ptr;
4896 next_os_pool++;
4897 ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
4898 sbrk_top = (char *) ptr + size;
4899 return ptr;
4900 }
4901 else if (size < 0)
4902 {
4903 // we don't currently support shrink behavior
4904 return (void *) MFAIL;
4905 }
4906 else
4907 {
4908 return sbrk_top;
4909 }
4910 }
4911
4912 // cleanup any allocated memory pools
4913 // called as last thing before shutting down driver
4914
4915 void osCleanupMem(void)
4916 {
4917 void **ptr;
4918
4919 for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
4920 if (*ptr)
4921 {
4922 PoolDeallocate(*ptr);
4923 *ptr = 0;
4924 }
4925 }
4926
4927*/
4928
4929
4930/* -----------------------------------------------------------------------
4931History:
4932 v2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea
4933 * fix bad comparison in dlposix_memalign
4934 * don't reuse adjusted asize in sys_alloc
4935 * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion
4936 * reduce compiler warnings -- thanks to all who reported/suggested these
4937
4938 v2.8.5 Sun May 22 10:26:02 2011 Doug Lea (dl at gee)
4939 * Always perform unlink checks unless INSECURE
4940 * Add posix_memalign.
4941 * Improve realloc to expand in more cases; expose realloc_in_place.
4942 Thanks to Peter Buhr for the suggestion.
4943 * Add footprint_limit, inspect_all, bulk_free. Thanks
4944 to Barry Hayes and others for the suggestions.
4945 * Internal refactorings to avoid calls while holding locks
4946 * Use non-reentrant locks by default. Thanks to Roland McGrath
4947 for the suggestion.
4948 * Small fixes to mspace_destroy, reset_on_error.
4949 * Various configuration extensions/changes. Thanks
4950 to all who contributed these.
4951
4952 V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu)
4953 * Update Creative Commons URL
4954
4955 V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee)
4956 * Use zeros instead of prev foot for is_mmapped
4957 * Add mspace_track_large_chunks; thanks to Jean Brouwers
4958 * Fix set_inuse in internal_realloc; thanks to Jean Brouwers
4959 * Fix insufficient sys_alloc padding when using 16byte alignment
4960 * Fix bad error check in mspace_footprint
4961 * Adaptations for ptmalloc; thanks to Wolfram Gloger.
4962 * Reentrant spin locks; thanks to Earl Chew and others
4963 * Win32 improvements; thanks to Niall Douglas and Earl Chew
4964 * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options
4965 * Extension hook in malloc_state
4966 * Various small adjustments to reduce warnings on some compilers
4967 * Various configuration extensions/changes for more platforms. Thanks
4968 to all who contributed these.
4969
4970 V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee)
4971 * Add max_footprint functions
4972 * Ensure all appropriate literals are size_t
4973 * Fix conditional compilation problem for some #define settings
4974 * Avoid concatenating segments with the one provided
4975 in create_mspace_with_base
4976 * Rename some variables to avoid compiler shadowing warnings
4977 * Use explicit lock initialization.
4978 * Better handling of sbrk interference.
4979 * Simplify and fix segment insertion, trimming and mspace_destroy
4980 * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
4981 * Thanks especially to Dennis Flanagan for help on these.
4982
4983 V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee)
4984 * Fix memalign brace error.
4985
4986 V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee)
4987 * Fix improper #endif nesting in C++
4988 * Add explicit casts needed for C++
4989
4990 V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee)
4991 * Use trees for large bins
4992 * Support mspaces
4993 * Use segments to unify sbrk-based and mmap-based system allocation,
4994 removing need for emulation on most platforms without sbrk.
4995 * Default safety checks
4996 * Optional footer checks. Thanks to William Robertson for the idea.
4997 * Internal code refactoring
4998 * Incorporate suggestions and platform-specific changes.
4999 Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
5000 Aaron Bachmann, Emery Berger, and others.
5001 * Speed up non-fastbin processing enough to remove fastbins.
5002 * Remove useless cfree() to avoid conflicts with other apps.
5003 * Remove internal memcpy, memset. Compilers handle builtins better.
5004 * Remove some options that no one ever used and rename others.
5005
5006 V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
5007 * Fix malloc_state bitmap array misdeclaration
5008
5009 V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee)
5010 * Allow tuning of FIRST_SORTED_BIN_SIZE
5011 * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
5012 * Better detection and support for non-contiguousness of MORECORE.
5013 Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
5014 * Bypass most of malloc if no frees. Thanks To Emery Berger.
5015 * Fix freeing of old top non-contiguous chunk im sysmalloc.
5016 * Raised default trim and map thresholds to 256K.
5017 * Fix mmap-related #defines. Thanks to Lubos Lunak.
5018 * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
5019 * Branch-free bin calculation
5020 * Default trim and mmap thresholds now 256K.
5021
5022 V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee)
5023 * Introduce independent_comalloc and independent_calloc.
5024 Thanks to Michael Pachos for motivation and help.
5025 * Make optional .h file available
5026 * Allow > 2GB requests on 32bit systems.
5027 * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
5028 Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
5029 and Anonymous.
5030 * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
5031 helping test this.)
5032 * memalign: check alignment arg
5033 * realloc: don't try to shift chunks backwards, since this
5034 leads to more fragmentation in some programs and doesn't
5035 seem to help in any others.
5036 * Collect all cases in malloc requiring system memory into sysmalloc
5037 * Use mmap as backup to sbrk
5038 * Place all internal state in malloc_state
5039 * Introduce fastbins (although similar to 2.5.1)
5040 * Many minor tunings and cosmetic improvements
5041 * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
5042 * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
5043 Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
5044 * Include errno.h to support default failure action.
5045
5046 V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
5047 * return null for negative arguments
5048 * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
5049 * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
5050 (e.g. WIN32 platforms)
5051 * Cleanup header file inclusion for WIN32 platforms
5052 * Cleanup code to avoid Microsoft Visual C++ compiler complaints
5053 * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
5054 memory allocation routines
5055 * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
5056 * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
5057 usage of 'assert' in non-WIN32 code
5058 * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
5059 avoid infinite loop
5060 * Always call 'fREe()' rather than 'free()'
5061
5062 V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
5063 * Fixed ordering problem with boundary-stamping
5064
5065 V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
5066 * Added pvalloc, as recommended by H.J. Liu
5067 * Added 64bit pointer support mainly from Wolfram Gloger
5068 * Added anonymously donated WIN32 sbrk emulation
5069 * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
5070 * malloc_extend_top: fix mask error that caused wastage after
5071 foreign sbrks
5072 * Add linux mremap support code from HJ Liu
5073
5074 V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
5075 * Integrated most documentation with the code.
5076 * Add support for mmap, with help from
5077 Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
5078 * Use last_remainder in more cases.
5079 * Pack bins using idea from colin@nyx10.cs.du.edu
Paul Vinciguerraec11b132018-09-24 05:25:00 -07005080 * Use ordered bins instead of best-fit threshold
Dave Barach6a5adc32018-07-04 10:56:23 -04005081 * Eliminate block-local decls to simplify tracing and debugging.
5082 * Support another case of realloc via move into top
Paul Vinciguerraec11b132018-09-24 05:25:00 -07005083 * Fix error occurring when initial sbrk_base not word-aligned.
Dave Barach6a5adc32018-07-04 10:56:23 -04005084 * Rely on page size for units instead of SBRK_UNIT to
5085 avoid surprises about sbrk alignment conventions.
5086 * Add mallinfo, mallopt. Thanks to Raymond Nijssen
5087 (raymond@es.ele.tue.nl) for the suggestion.
5088 * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
5089 * More precautions for cases where other routines call sbrk,
5090 courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
5091 * Added macros etc., allowing use in linux libc from
5092 H.J. Lu (hjl@gnu.ai.mit.edu)
5093 * Inverted this history list
5094
5095 V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
5096 * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
5097 * Removed all preallocation code since under current scheme
5098 the work required to undo bad preallocations exceeds
5099 the work saved in good cases for most test programs.
5100 * No longer use return list or unconsolidated bins since
5101 no scheme using them consistently outperforms those that don't
5102 given above changes.
5103 * Use best fit for very large chunks to prevent some worst-cases.
5104 * Added some support for debugging
5105
5106 V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
5107 * Removed footers when chunks are in use. Thanks to
5108 Paul Wilson (wilson@cs.texas.edu) for the suggestion.
5109
5110 V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
5111 * Added malloc_trim, with help from Wolfram Gloger
5112 (wmglo@Dent.MED.Uni-Muenchen.DE).
5113
5114 V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
5115
5116 V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
5117 * realloc: try to expand in both directions
5118 * malloc: swap order of clean-bin strategy;
5119 * realloc: only conditionally expand backwards
5120 * Try not to scavenge used bins
5121 * Use bin counts as a guide to preallocation
5122 * Occasionally bin return list chunks in first scan
5123 * Add a few optimizations from colin@nyx10.cs.du.edu
5124
5125 V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
5126 * faster bin computation & slightly different binning
5127 * merged all consolidations to one part of malloc proper
5128 (eliminating old malloc_find_space & malloc_clean_bin)
5129 * Scan 2 returns chunks (not just 1)
5130 * Propagate failure in realloc if malloc returns 0
5131 * Add stuff to allow compilation on non-ANSI compilers
5132 from kpv@research.att.com
5133
5134 V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
5135 * removed potential for odd address access in prev_chunk
5136 * removed dependency on getpagesize.h
5137 * misc cosmetics and a bit more internal documentation
5138 * anticosmetics: mangled names in macros to evade debugger strangeness
5139 * tested on sparc, hp-700, dec-mips, rs6000
5140 with gcc & native cc (hp, dec only) allowing
5141 Detlefs & Zorn comparison study (in SIGPLAN Notices.)
5142
5143 Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
5144 * Based loosely on libg++-1.2X malloc. (It retains some of the overall
5145 structure of old version, but most details differ.)
5146
5147*/