xref: /freebsd/contrib/jemalloc/src/jemalloc.c (revision 0957b409)
1 #define JEMALLOC_C_
2 #include "jemalloc/internal/jemalloc_preamble.h"
3 #include "jemalloc/internal/jemalloc_internal_includes.h"
4 
5 #include "jemalloc/internal/assert.h"
6 #include "jemalloc/internal/atomic.h"
7 #include "jemalloc/internal/ctl.h"
8 #include "jemalloc/internal/extent_dss.h"
9 #include "jemalloc/internal/extent_mmap.h"
10 #include "jemalloc/internal/jemalloc_internal_types.h"
11 #include "jemalloc/internal/log.h"
12 #include "jemalloc/internal/malloc_io.h"
13 #include "jemalloc/internal/mutex.h"
14 #include "jemalloc/internal/rtree.h"
15 #include "jemalloc/internal/size_classes.h"
16 #include "jemalloc/internal/spin.h"
17 #include "jemalloc/internal/sz.h"
18 #include "jemalloc/internal/ticker.h"
19 #include "jemalloc/internal/util.h"
20 
21 /******************************************************************************/
22 /* Data. */
23 
24 /* Work around <http://llvm.org/bugs/show_bug.cgi?id=12623>: */
25 const char	*__malloc_options_1_0 = NULL;
26 __sym_compat(_malloc_options, __malloc_options_1_0, FBSD_1.0);
27 
28 /* Runtime configuration options. */
29 const char	*je_malloc_conf
30 #ifndef _WIN32
31     JEMALLOC_ATTR(weak)
32 #endif
33     ;
34 bool	opt_abort =
35 #ifdef JEMALLOC_DEBUG
36     true
37 #else
38     false
39 #endif
40     ;
41 bool	opt_abort_conf =
42 #ifdef JEMALLOC_DEBUG
43     true
44 #else
45     false
46 #endif
47     ;
48 const char	*opt_junk =
49 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
50     "true"
51 #else
52     "false"
53 #endif
54     ;
55 bool	opt_junk_alloc =
56 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
57     true
58 #else
59     false
60 #endif
61     ;
62 bool	opt_junk_free =
63 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
64     true
65 #else
66     false
67 #endif
68     ;
69 
70 bool	opt_utrace = false;
71 bool	opt_xmalloc = false;
72 bool	opt_zero = false;
73 unsigned	opt_narenas = 0;
74 
75 unsigned	ncpus;
76 
77 /* Protects arenas initialization. */
78 malloc_mutex_t arenas_lock;
79 /*
80  * Arenas that are used to service external requests.  Not all elements of the
81  * arenas array are necessarily used; arenas are created lazily as needed.
82  *
83  * arenas[0..narenas_auto) are used for automatic multiplexing of threads and
84  * arenas.  arenas[narenas_auto..narenas_total) are only used if the application
85  * takes some action to create them and allocate from them.
86  *
87  * Points to an arena_t.
88  */
89 JEMALLOC_ALIGNED(CACHELINE)
90 atomic_p_t		arenas[MALLOCX_ARENA_LIMIT];
91 static atomic_u_t	narenas_total; /* Use narenas_total_*(). */
92 static arena_t		*a0; /* arenas[0]; read-only after initialization. */
93 unsigned		narenas_auto; /* Read-only after initialization. */
94 
95 typedef enum {
96 	malloc_init_uninitialized	= 3,
97 	malloc_init_a0_initialized	= 2,
98 	malloc_init_recursible		= 1,
99 	malloc_init_initialized		= 0 /* Common case --> jnz. */
100 } malloc_init_t;
101 static malloc_init_t	malloc_init_state = malloc_init_uninitialized;
102 
103 /* False should be the common case.  Set to true to trigger initialization. */
104 bool			malloc_slow = true;
105 
106 /* When malloc_slow is true, set the corresponding bits for sanity check. */
107 enum {
108 	flag_opt_junk_alloc	= (1U),
109 	flag_opt_junk_free	= (1U << 1),
110 	flag_opt_zero		= (1U << 2),
111 	flag_opt_utrace		= (1U << 3),
112 	flag_opt_xmalloc	= (1U << 4)
113 };
114 static uint8_t	malloc_slow_flags;
115 
116 #ifdef JEMALLOC_THREADED_INIT
117 /* Used to let the initializing thread recursively allocate. */
118 #  define NO_INITIALIZER	((unsigned long)0)
119 #  define INITIALIZER		pthread_self()
120 #  define IS_INITIALIZER	(malloc_initializer == pthread_self())
121 static pthread_t		malloc_initializer = NO_INITIALIZER;
122 #else
123 #  define NO_INITIALIZER	false
124 #  define INITIALIZER		true
125 #  define IS_INITIALIZER	malloc_initializer
126 static bool			malloc_initializer = NO_INITIALIZER;
127 #endif
128 
129 /* Used to avoid initialization races. */
130 #ifdef _WIN32
131 #if _WIN32_WINNT >= 0x0600
132 static malloc_mutex_t	init_lock = SRWLOCK_INIT;
133 #else
134 static malloc_mutex_t	init_lock;
135 static bool init_lock_initialized = false;
136 
137 JEMALLOC_ATTR(constructor)
138 static void WINAPI
139 _init_init_lock(void) {
140 	/*
141 	 * If another constructor in the same binary is using mallctl to e.g.
142 	 * set up extent hooks, it may end up running before this one, and
143 	 * malloc_init_hard will crash trying to lock the uninitialized lock. So
144 	 * we force an initialization of the lock in malloc_init_hard as well.
145 	 * We don't try to care about atomicity of the accessed to the
146 	 * init_lock_initialized boolean, since it really only matters early in
147 	 * the process creation, before any separate thread normally starts
148 	 * doing anything.
149 	 */
150 	if (!init_lock_initialized) {
151 		malloc_mutex_init(&init_lock, "init", WITNESS_RANK_INIT,
152 		    malloc_mutex_rank_exclusive);
153 	}
154 	init_lock_initialized = true;
155 }
156 
157 #ifdef _MSC_VER
158 #  pragma section(".CRT$XCU", read)
159 JEMALLOC_SECTION(".CRT$XCU") JEMALLOC_ATTR(used)
160 static const void (WINAPI *init_init_lock)(void) = _init_init_lock;
161 #endif
162 #endif
163 #else
164 static malloc_mutex_t	init_lock = MALLOC_MUTEX_INITIALIZER;
165 #endif
166 
167 typedef struct {
168 	void	*p;	/* Input pointer (as in realloc(p, s)). */
169 	size_t	s;	/* Request size. */
170 	void	*r;	/* Result pointer. */
171 } malloc_utrace_t;
172 
173 #ifdef JEMALLOC_UTRACE
174 #  define UTRACE(a, b, c) do {						\
175 	if (unlikely(opt_utrace)) {					\
176 		int utrace_serrno = errno;				\
177 		malloc_utrace_t ut;					\
178 		ut.p = (a);						\
179 		ut.s = (b);						\
180 		ut.r = (c);						\
181 		utrace(&ut, sizeof(ut));				\
182 		errno = utrace_serrno;					\
183 	}								\
184 } while (0)
185 #else
186 #  define UTRACE(a, b, c)
187 #endif
188 
189 /* Whether encountered any invalid config options. */
190 static bool had_conf_error = false;
191 
192 /******************************************************************************/
193 /*
194  * Function prototypes for static functions that are referenced prior to
195  * definition.
196  */
197 
198 static bool	malloc_init_hard_a0(void);
199 static bool	malloc_init_hard(void);
200 
201 /******************************************************************************/
202 /*
203  * Begin miscellaneous support functions.
204  */
205 
206 bool
207 malloc_initialized(void) {
208 	return (malloc_init_state == malloc_init_initialized);
209 }
210 
211 JEMALLOC_ALWAYS_INLINE bool
212 malloc_init_a0(void) {
213 	if (unlikely(malloc_init_state == malloc_init_uninitialized)) {
214 		return malloc_init_hard_a0();
215 	}
216 	return false;
217 }
218 
219 JEMALLOC_ALWAYS_INLINE bool
220 malloc_init(void) {
221 	if (unlikely(!malloc_initialized()) && malloc_init_hard()) {
222 		return true;
223 	}
224 	return false;
225 }
226 
227 /*
228  * The a0*() functions are used instead of i{d,}alloc() in situations that
229  * cannot tolerate TLS variable access.
230  */
231 
232 static void *
233 a0ialloc(size_t size, bool zero, bool is_internal) {
234 	if (unlikely(malloc_init_a0())) {
235 		return NULL;
236 	}
237 
238 	return iallocztm(TSDN_NULL, size, sz_size2index(size), zero, NULL,
239 	    is_internal, arena_get(TSDN_NULL, 0, true), true);
240 }
241 
242 static void
243 a0idalloc(void *ptr, bool is_internal) {
244 	idalloctm(TSDN_NULL, ptr, NULL, NULL, is_internal, true);
245 }
246 
247 void *
248 a0malloc(size_t size) {
249 	return a0ialloc(size, false, true);
250 }
251 
252 void
253 a0dalloc(void *ptr) {
254 	a0idalloc(ptr, true);
255 }
256 
257 /*
258  * FreeBSD's libc uses the bootstrap_*() functions in bootstrap-senstive
259  * situations that cannot tolerate TLS variable access (TLS allocation and very
260  * early internal data structure initialization).
261  */
262 
263 void *
264 bootstrap_malloc(size_t size) {
265 	if (unlikely(size == 0)) {
266 		size = 1;
267 	}
268 
269 	return a0ialloc(size, false, false);
270 }
271 
272 void *
273 bootstrap_calloc(size_t num, size_t size) {
274 	size_t num_size;
275 
276 	num_size = num * size;
277 	if (unlikely(num_size == 0)) {
278 		assert(num == 0 || size == 0);
279 		num_size = 1;
280 	}
281 
282 	return a0ialloc(num_size, true, false);
283 }
284 
285 void
286 bootstrap_free(void *ptr) {
287 	if (unlikely(ptr == NULL)) {
288 		return;
289 	}
290 
291 	a0idalloc(ptr, false);
292 }
293 
294 void
295 arena_set(unsigned ind, arena_t *arena) {
296 	atomic_store_p(&arenas[ind], arena, ATOMIC_RELEASE);
297 }
298 
299 static void
300 narenas_total_set(unsigned narenas) {
301 	atomic_store_u(&narenas_total, narenas, ATOMIC_RELEASE);
302 }
303 
304 static void
305 narenas_total_inc(void) {
306 	atomic_fetch_add_u(&narenas_total, 1, ATOMIC_RELEASE);
307 }
308 
309 unsigned
310 narenas_total_get(void) {
311 	return atomic_load_u(&narenas_total, ATOMIC_ACQUIRE);
312 }
313 
314 /* Create a new arena and insert it into the arenas array at index ind. */
315 static arena_t *
316 arena_init_locked(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
317 	arena_t *arena;
318 
319 	assert(ind <= narenas_total_get());
320 	if (ind >= MALLOCX_ARENA_LIMIT) {
321 		return NULL;
322 	}
323 	if (ind == narenas_total_get()) {
324 		narenas_total_inc();
325 	}
326 
327 	/*
328 	 * Another thread may have already initialized arenas[ind] if it's an
329 	 * auto arena.
330 	 */
331 	arena = arena_get(tsdn, ind, false);
332 	if (arena != NULL) {
333 		assert(ind < narenas_auto);
334 		return arena;
335 	}
336 
337 	/* Actually initialize the arena. */
338 	arena = arena_new(tsdn, ind, extent_hooks);
339 
340 	return arena;
341 }
342 
343 static void
344 arena_new_create_background_thread(tsdn_t *tsdn, unsigned ind) {
345 	if (ind == 0) {
346 		return;
347 	}
348 	if (have_background_thread) {
349 		bool err;
350 		malloc_mutex_lock(tsdn, &background_thread_lock);
351 		err = background_thread_create(tsdn_tsd(tsdn), ind);
352 		malloc_mutex_unlock(tsdn, &background_thread_lock);
353 		if (err) {
354 			malloc_printf("<jemalloc>: error in background thread "
355 				      "creation for arena %u. Abort.\n", ind);
356 			abort();
357 		}
358 	}
359 }
360 
361 arena_t *
362 arena_init(tsdn_t *tsdn, unsigned ind, extent_hooks_t *extent_hooks) {
363 	arena_t *arena;
364 
365 	malloc_mutex_lock(tsdn, &arenas_lock);
366 	arena = arena_init_locked(tsdn, ind, extent_hooks);
367 	malloc_mutex_unlock(tsdn, &arenas_lock);
368 
369 	arena_new_create_background_thread(tsdn, ind);
370 
371 	return arena;
372 }
373 
374 static void
375 arena_bind(tsd_t *tsd, unsigned ind, bool internal) {
376 	arena_t *arena = arena_get(tsd_tsdn(tsd), ind, false);
377 	arena_nthreads_inc(arena, internal);
378 
379 	if (internal) {
380 		tsd_iarena_set(tsd, arena);
381 	} else {
382 		tsd_arena_set(tsd, arena);
383 	}
384 }
385 
386 void
387 arena_migrate(tsd_t *tsd, unsigned oldind, unsigned newind) {
388 	arena_t *oldarena, *newarena;
389 
390 	oldarena = arena_get(tsd_tsdn(tsd), oldind, false);
391 	newarena = arena_get(tsd_tsdn(tsd), newind, false);
392 	arena_nthreads_dec(oldarena, false);
393 	arena_nthreads_inc(newarena, false);
394 	tsd_arena_set(tsd, newarena);
395 }
396 
397 static void
398 arena_unbind(tsd_t *tsd, unsigned ind, bool internal) {
399 	arena_t *arena;
400 
401 	arena = arena_get(tsd_tsdn(tsd), ind, false);
402 	arena_nthreads_dec(arena, internal);
403 
404 	if (internal) {
405 		tsd_iarena_set(tsd, NULL);
406 	} else {
407 		tsd_arena_set(tsd, NULL);
408 	}
409 }
410 
411 arena_tdata_t *
412 arena_tdata_get_hard(tsd_t *tsd, unsigned ind) {
413 	arena_tdata_t *tdata, *arenas_tdata_old;
414 	arena_tdata_t *arenas_tdata = tsd_arenas_tdata_get(tsd);
415 	unsigned narenas_tdata_old, i;
416 	unsigned narenas_tdata = tsd_narenas_tdata_get(tsd);
417 	unsigned narenas_actual = narenas_total_get();
418 
419 	/*
420 	 * Dissociate old tdata array (and set up for deallocation upon return)
421 	 * if it's too small.
422 	 */
423 	if (arenas_tdata != NULL && narenas_tdata < narenas_actual) {
424 		arenas_tdata_old = arenas_tdata;
425 		narenas_tdata_old = narenas_tdata;
426 		arenas_tdata = NULL;
427 		narenas_tdata = 0;
428 		tsd_arenas_tdata_set(tsd, arenas_tdata);
429 		tsd_narenas_tdata_set(tsd, narenas_tdata);
430 	} else {
431 		arenas_tdata_old = NULL;
432 		narenas_tdata_old = 0;
433 	}
434 
435 	/* Allocate tdata array if it's missing. */
436 	if (arenas_tdata == NULL) {
437 		bool *arenas_tdata_bypassp = tsd_arenas_tdata_bypassp_get(tsd);
438 		narenas_tdata = (ind < narenas_actual) ? narenas_actual : ind+1;
439 
440 		if (tsd_nominal(tsd) && !*arenas_tdata_bypassp) {
441 			*arenas_tdata_bypassp = true;
442 			arenas_tdata = (arena_tdata_t *)a0malloc(
443 			    sizeof(arena_tdata_t) * narenas_tdata);
444 			*arenas_tdata_bypassp = false;
445 		}
446 		if (arenas_tdata == NULL) {
447 			tdata = NULL;
448 			goto label_return;
449 		}
450 		assert(tsd_nominal(tsd) && !*arenas_tdata_bypassp);
451 		tsd_arenas_tdata_set(tsd, arenas_tdata);
452 		tsd_narenas_tdata_set(tsd, narenas_tdata);
453 	}
454 
455 	/*
456 	 * Copy to tdata array.  It's possible that the actual number of arenas
457 	 * has increased since narenas_total_get() was called above, but that
458 	 * causes no correctness issues unless two threads concurrently execute
459 	 * the arenas.create mallctl, which we trust mallctl synchronization to
460 	 * prevent.
461 	 */
462 
463 	/* Copy/initialize tickers. */
464 	for (i = 0; i < narenas_actual; i++) {
465 		if (i < narenas_tdata_old) {
466 			ticker_copy(&arenas_tdata[i].decay_ticker,
467 			    &arenas_tdata_old[i].decay_ticker);
468 		} else {
469 			ticker_init(&arenas_tdata[i].decay_ticker,
470 			    DECAY_NTICKS_PER_UPDATE);
471 		}
472 	}
473 	if (narenas_tdata > narenas_actual) {
474 		memset(&arenas_tdata[narenas_actual], 0, sizeof(arena_tdata_t)
475 		    * (narenas_tdata - narenas_actual));
476 	}
477 
478 	/* Read the refreshed tdata array. */
479 	tdata = &arenas_tdata[ind];
480 label_return:
481 	if (arenas_tdata_old != NULL) {
482 		a0dalloc(arenas_tdata_old);
483 	}
484 	return tdata;
485 }
486 
487 /* Slow path, called only by arena_choose(). */
488 arena_t *
489 arena_choose_hard(tsd_t *tsd, bool internal) {
490 	arena_t *ret JEMALLOC_CC_SILENCE_INIT(NULL);
491 
492 	if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
493 		unsigned choose = percpu_arena_choose();
494 		ret = arena_get(tsd_tsdn(tsd), choose, true);
495 		assert(ret != NULL);
496 		arena_bind(tsd, arena_ind_get(ret), false);
497 		arena_bind(tsd, arena_ind_get(ret), true);
498 
499 		return ret;
500 	}
501 
502 	if (narenas_auto > 1) {
503 		unsigned i, j, choose[2], first_null;
504 		bool is_new_arena[2];
505 
506 		/*
507 		 * Determine binding for both non-internal and internal
508 		 * allocation.
509 		 *
510 		 *   choose[0]: For application allocation.
511 		 *   choose[1]: For internal metadata allocation.
512 		 */
513 
514 		for (j = 0; j < 2; j++) {
515 			choose[j] = 0;
516 			is_new_arena[j] = false;
517 		}
518 
519 		first_null = narenas_auto;
520 		malloc_mutex_lock(tsd_tsdn(tsd), &arenas_lock);
521 		assert(arena_get(tsd_tsdn(tsd), 0, false) != NULL);
522 		for (i = 1; i < narenas_auto; i++) {
523 			if (arena_get(tsd_tsdn(tsd), i, false) != NULL) {
524 				/*
525 				 * Choose the first arena that has the lowest
526 				 * number of threads assigned to it.
527 				 */
528 				for (j = 0; j < 2; j++) {
529 					if (arena_nthreads_get(arena_get(
530 					    tsd_tsdn(tsd), i, false), !!j) <
531 					    arena_nthreads_get(arena_get(
532 					    tsd_tsdn(tsd), choose[j], false),
533 					    !!j)) {
534 						choose[j] = i;
535 					}
536 				}
537 			} else if (first_null == narenas_auto) {
538 				/*
539 				 * Record the index of the first uninitialized
540 				 * arena, in case all extant arenas are in use.
541 				 *
542 				 * NB: It is possible for there to be
543 				 * discontinuities in terms of initialized
544 				 * versus uninitialized arenas, due to the
545 				 * "thread.arena" mallctl.
546 				 */
547 				first_null = i;
548 			}
549 		}
550 
551 		for (j = 0; j < 2; j++) {
552 			if (arena_nthreads_get(arena_get(tsd_tsdn(tsd),
553 			    choose[j], false), !!j) == 0 || first_null ==
554 			    narenas_auto) {
555 				/*
556 				 * Use an unloaded arena, or the least loaded
557 				 * arena if all arenas are already initialized.
558 				 */
559 				if (!!j == internal) {
560 					ret = arena_get(tsd_tsdn(tsd),
561 					    choose[j], false);
562 				}
563 			} else {
564 				arena_t *arena;
565 
566 				/* Initialize a new arena. */
567 				choose[j] = first_null;
568 				arena = arena_init_locked(tsd_tsdn(tsd),
569 				    choose[j],
570 				    (extent_hooks_t *)&extent_hooks_default);
571 				if (arena == NULL) {
572 					malloc_mutex_unlock(tsd_tsdn(tsd),
573 					    &arenas_lock);
574 					return NULL;
575 				}
576 				is_new_arena[j] = true;
577 				if (!!j == internal) {
578 					ret = arena;
579 				}
580 			}
581 			arena_bind(tsd, choose[j], !!j);
582 		}
583 		malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock);
584 
585 		for (j = 0; j < 2; j++) {
586 			if (is_new_arena[j]) {
587 				assert(choose[j] > 0);
588 				arena_new_create_background_thread(
589 				    tsd_tsdn(tsd), choose[j]);
590 			}
591 		}
592 
593 	} else {
594 		ret = arena_get(tsd_tsdn(tsd), 0, false);
595 		arena_bind(tsd, 0, false);
596 		arena_bind(tsd, 0, true);
597 	}
598 
599 	return ret;
600 }
601 
602 void
603 iarena_cleanup(tsd_t *tsd) {
604 	arena_t *iarena;
605 
606 	iarena = tsd_iarena_get(tsd);
607 	if (iarena != NULL) {
608 		arena_unbind(tsd, arena_ind_get(iarena), true);
609 	}
610 }
611 
612 void
613 arena_cleanup(tsd_t *tsd) {
614 	arena_t *arena;
615 
616 	arena = tsd_arena_get(tsd);
617 	if (arena != NULL) {
618 		arena_unbind(tsd, arena_ind_get(arena), false);
619 	}
620 }
621 
622 void
623 arenas_tdata_cleanup(tsd_t *tsd) {
624 	arena_tdata_t *arenas_tdata;
625 
626 	/* Prevent tsd->arenas_tdata from being (re)created. */
627 	*tsd_arenas_tdata_bypassp_get(tsd) = true;
628 
629 	arenas_tdata = tsd_arenas_tdata_get(tsd);
630 	if (arenas_tdata != NULL) {
631 		tsd_arenas_tdata_set(tsd, NULL);
632 		a0dalloc(arenas_tdata);
633 	}
634 }
635 
636 static void
637 stats_print_atexit(void) {
638 	if (config_stats) {
639 		tsdn_t *tsdn;
640 		unsigned narenas, i;
641 
642 		tsdn = tsdn_fetch();
643 
644 		/*
645 		 * Merge stats from extant threads.  This is racy, since
646 		 * individual threads do not lock when recording tcache stats
647 		 * events.  As a consequence, the final stats may be slightly
648 		 * out of date by the time they are reported, if other threads
649 		 * continue to allocate.
650 		 */
651 		for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
652 			arena_t *arena = arena_get(tsdn, i, false);
653 			if (arena != NULL) {
654 				tcache_t *tcache;
655 
656 				malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx);
657 				ql_foreach(tcache, &arena->tcache_ql, link) {
658 					tcache_stats_merge(tsdn, tcache, arena);
659 				}
660 				malloc_mutex_unlock(tsdn,
661 				    &arena->tcache_ql_mtx);
662 			}
663 		}
664 	}
665 	je_malloc_stats_print(NULL, NULL, opt_stats_print_opts);
666 }
667 
668 /*
669  * Ensure that we don't hold any locks upon entry to or exit from allocator
670  * code (in a "broad" sense that doesn't count a reentrant allocation as an
671  * entrance or exit).
672  */
673 JEMALLOC_ALWAYS_INLINE void
674 check_entry_exit_locking(tsdn_t *tsdn) {
675 	if (!config_debug) {
676 		return;
677 	}
678 	if (tsdn_null(tsdn)) {
679 		return;
680 	}
681 	tsd_t *tsd = tsdn_tsd(tsdn);
682 	/*
683 	 * It's possible we hold locks at entry/exit if we're in a nested
684 	 * allocation.
685 	 */
686 	int8_t reentrancy_level = tsd_reentrancy_level_get(tsd);
687 	if (reentrancy_level != 0) {
688 		return;
689 	}
690 	witness_assert_lockless(tsdn_witness_tsdp_get(tsdn));
691 }
692 
693 /*
694  * End miscellaneous support functions.
695  */
696 /******************************************************************************/
697 /*
698  * Begin initialization functions.
699  */
700 
701 static char *
702 jemalloc_secure_getenv(const char *name) {
703 #ifdef JEMALLOC_HAVE_SECURE_GETENV
704 	return secure_getenv(name);
705 #else
706 #  ifdef JEMALLOC_HAVE_ISSETUGID
707 	if (issetugid() != 0) {
708 		return NULL;
709 	}
710 #  endif
711 	return getenv(name);
712 #endif
713 }
714 
715 static unsigned
716 malloc_ncpus(void) {
717 	long result;
718 
719 #ifdef _WIN32
720 	SYSTEM_INFO si;
721 	GetSystemInfo(&si);
722 	result = si.dwNumberOfProcessors;
723 #elif defined(JEMALLOC_GLIBC_MALLOC_HOOK) && defined(CPU_COUNT)
724 	/*
725 	 * glibc >= 2.6 has the CPU_COUNT macro.
726 	 *
727 	 * glibc's sysconf() uses isspace().  glibc allocates for the first time
728 	 * *before* setting up the isspace tables.  Therefore we need a
729 	 * different method to get the number of CPUs.
730 	 */
731 	{
732 		cpu_set_t set;
733 
734 		pthread_getaffinity_np(pthread_self(), sizeof(set), &set);
735 		result = CPU_COUNT(&set);
736 	}
737 #else
738 	result = sysconf(_SC_NPROCESSORS_ONLN);
739 #endif
740 	return ((result == -1) ? 1 : (unsigned)result);
741 }
742 
743 static void
744 init_opt_stats_print_opts(const char *v, size_t vlen) {
745 	size_t opts_len = strlen(opt_stats_print_opts);
746 	assert(opts_len <= stats_print_tot_num_options);
747 
748 	for (size_t i = 0; i < vlen; i++) {
749 		switch (v[i]) {
750 #define OPTION(o, v, d, s) case o: break;
751 			STATS_PRINT_OPTIONS
752 #undef OPTION
753 		default: continue;
754 		}
755 
756 		if (strchr(opt_stats_print_opts, v[i]) != NULL) {
757 			/* Ignore repeated. */
758 			continue;
759 		}
760 
761 		opt_stats_print_opts[opts_len++] = v[i];
762 		opt_stats_print_opts[opts_len] = '\0';
763 		assert(opts_len <= stats_print_tot_num_options);
764 	}
765 	assert(opts_len == strlen(opt_stats_print_opts));
766 }
767 
768 static bool
769 malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p,
770     char const **v_p, size_t *vlen_p) {
771 	bool accept;
772 	const char *opts = *opts_p;
773 
774 	*k_p = opts;
775 
776 	for (accept = false; !accept;) {
777 		switch (*opts) {
778 		case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
779 		case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
780 		case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
781 		case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
782 		case 'Y': case 'Z':
783 		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
784 		case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
785 		case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
786 		case 's': case 't': case 'u': case 'v': case 'w': case 'x':
787 		case 'y': case 'z':
788 		case '0': case '1': case '2': case '3': case '4': case '5':
789 		case '6': case '7': case '8': case '9':
790 		case '_':
791 			opts++;
792 			break;
793 		case ':':
794 			opts++;
795 			*klen_p = (uintptr_t)opts - 1 - (uintptr_t)*k_p;
796 			*v_p = opts;
797 			accept = true;
798 			break;
799 		case '\0':
800 			if (opts != *opts_p) {
801 				malloc_write("<jemalloc>: Conf string ends "
802 				    "with key\n");
803 			}
804 			return true;
805 		default:
806 			malloc_write("<jemalloc>: Malformed conf string\n");
807 			return true;
808 		}
809 	}
810 
811 	for (accept = false; !accept;) {
812 		switch (*opts) {
813 		case ',':
814 			opts++;
815 			/*
816 			 * Look ahead one character here, because the next time
817 			 * this function is called, it will assume that end of
818 			 * input has been cleanly reached if no input remains,
819 			 * but we have optimistically already consumed the
820 			 * comma if one exists.
821 			 */
822 			if (*opts == '\0') {
823 				malloc_write("<jemalloc>: Conf string ends "
824 				    "with comma\n");
825 			}
826 			*vlen_p = (uintptr_t)opts - 1 - (uintptr_t)*v_p;
827 			accept = true;
828 			break;
829 		case '\0':
830 			*vlen_p = (uintptr_t)opts - (uintptr_t)*v_p;
831 			accept = true;
832 			break;
833 		default:
834 			opts++;
835 			break;
836 		}
837 	}
838 
839 	*opts_p = opts;
840 	return false;
841 }
842 
843 static void
844 malloc_abort_invalid_conf(void) {
845 	assert(opt_abort_conf);
846 	malloc_printf("<jemalloc>: Abort (abort_conf:true) on invalid conf "
847 	    "value (see above).\n");
848 	abort();
849 }
850 
851 static void
852 malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v,
853     size_t vlen) {
854 	malloc_printf("<jemalloc>: %s: %.*s:%.*s\n", msg, (int)klen, k,
855 	    (int)vlen, v);
856 	/* If abort_conf is set, error out after processing all options. */
857 	had_conf_error = true;
858 }
859 
860 static void
861 malloc_slow_flag_init(void) {
862 	/*
863 	 * Combine the runtime options into malloc_slow for fast path.  Called
864 	 * after processing all the options.
865 	 */
866 	malloc_slow_flags |= (opt_junk_alloc ? flag_opt_junk_alloc : 0)
867 	    | (opt_junk_free ? flag_opt_junk_free : 0)
868 	    | (opt_zero ? flag_opt_zero : 0)
869 	    | (opt_utrace ? flag_opt_utrace : 0)
870 	    | (opt_xmalloc ? flag_opt_xmalloc : 0);
871 
872 	malloc_slow = (malloc_slow_flags != 0);
873 }
874 
875 static void
876 malloc_conf_init(void) {
877 	unsigned i;
878 	char buf[PATH_MAX + 1];
879 	const char *opts, *k, *v;
880 	size_t klen, vlen;
881 
882 	for (i = 0; i < 4; i++) {
883 		/* Get runtime configuration. */
884 		switch (i) {
885 		case 0:
886 			opts = config_malloc_conf;
887 			break;
888 		case 1:
889 			if (je_malloc_conf != NULL) {
890 				/*
891 				 * Use options that were compiled into the
892 				 * program.
893 				 */
894 				opts = je_malloc_conf;
895 			} else {
896 				/* No configuration specified. */
897 				buf[0] = '\0';
898 				opts = buf;
899 			}
900 			break;
901 		case 2: {
902 			ssize_t linklen = 0;
903 #ifndef _WIN32
904 			int saved_errno = errno;
905 			const char *linkname =
906 #  ifdef JEMALLOC_PREFIX
907 			    "/etc/"JEMALLOC_PREFIX"malloc.conf"
908 #  else
909 			    "/etc/malloc.conf"
910 #  endif
911 			    ;
912 
913 			/*
914 			 * Try to use the contents of the "/etc/malloc.conf"
915 			 * symbolic link's name.
916 			 */
917 			linklen = readlink(linkname, buf, sizeof(buf) - 1);
918 			if (linklen == -1) {
919 				/* No configuration specified. */
920 				linklen = 0;
921 				/* Restore errno. */
922 				set_errno(saved_errno);
923 			}
924 #endif
925 			buf[linklen] = '\0';
926 			opts = buf;
927 			break;
928 		} case 3: {
929 			const char *envname =
930 #ifdef JEMALLOC_PREFIX
931 			    JEMALLOC_CPREFIX"MALLOC_CONF"
932 #else
933 			    "MALLOC_CONF"
934 #endif
935 			    ;
936 
937 			if ((opts = jemalloc_secure_getenv(envname)) != NULL) {
938 				/*
939 				 * Do nothing; opts is already initialized to
940 				 * the value of the MALLOC_CONF environment
941 				 * variable.
942 				 */
943 			} else {
944 				/* No configuration specified. */
945 				buf[0] = '\0';
946 				opts = buf;
947 			}
948 			break;
949 		} default:
950 			not_reached();
951 			buf[0] = '\0';
952 			opts = buf;
953 		}
954 
955 		while (*opts != '\0' && !malloc_conf_next(&opts, &k, &klen, &v,
956 		    &vlen)) {
957 #define CONF_MATCH(n)							\
958 	(sizeof(n)-1 == klen && strncmp(n, k, klen) == 0)
959 #define CONF_MATCH_VALUE(n)						\
960 	(sizeof(n)-1 == vlen && strncmp(n, v, vlen) == 0)
961 #define CONF_HANDLE_BOOL(o, n)						\
962 			if (CONF_MATCH(n)) {				\
963 				if (CONF_MATCH_VALUE("true")) {		\
964 					o = true;			\
965 				} else if (CONF_MATCH_VALUE("false")) {	\
966 					o = false;			\
967 				} else {				\
968 					malloc_conf_error(		\
969 					    "Invalid conf value",	\
970 					    k, klen, v, vlen);		\
971 				}					\
972 				continue;				\
973 			}
974 #define CONF_MIN_no(um, min)	false
975 #define CONF_MIN_yes(um, min)	((um) < (min))
976 #define CONF_MAX_no(um, max)	false
977 #define CONF_MAX_yes(um, max)	((um) > (max))
978 #define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip)	\
979 			if (CONF_MATCH(n)) {				\
980 				uintmax_t um;				\
981 				char *end;				\
982 									\
983 				set_errno(0);				\
984 				um = malloc_strtoumax(v, &end, 0);	\
985 				if (get_errno() != 0 || (uintptr_t)end -\
986 				    (uintptr_t)v != vlen) {		\
987 					malloc_conf_error(		\
988 					    "Invalid conf value",	\
989 					    k, klen, v, vlen);		\
990 				} else if (clip) {			\
991 					if (CONF_MIN_##check_min(um,	\
992 					    (t)(min))) {		\
993 						o = (t)(min);		\
994 					} else if (			\
995 					    CONF_MAX_##check_max(um,	\
996 					    (t)(max))) {		\
997 						o = (t)(max);		\
998 					} else {			\
999 						o = (t)um;		\
1000 					}				\
1001 				} else {				\
1002 					if (CONF_MIN_##check_min(um,	\
1003 					    (t)(min)) ||		\
1004 					    CONF_MAX_##check_max(um,	\
1005 					    (t)(max))) {		\
1006 						malloc_conf_error(	\
1007 						    "Out-of-range "	\
1008 						    "conf value",	\
1009 						    k, klen, v, vlen);	\
1010 					} else {			\
1011 						o = (t)um;		\
1012 					}				\
1013 				}					\
1014 				continue;				\
1015 			}
1016 #define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max,	\
1017     clip)								\
1018 			CONF_HANDLE_T_U(unsigned, o, n, min, max,	\
1019 			    check_min, check_max, clip)
1020 #define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip)	\
1021 			CONF_HANDLE_T_U(size_t, o, n, min, max,		\
1022 			    check_min, check_max, clip)
1023 #define CONF_HANDLE_SSIZE_T(o, n, min, max)				\
1024 			if (CONF_MATCH(n)) {				\
1025 				long l;					\
1026 				char *end;				\
1027 									\
1028 				set_errno(0);				\
1029 				l = strtol(v, &end, 0);			\
1030 				if (get_errno() != 0 || (uintptr_t)end -\
1031 				    (uintptr_t)v != vlen) {		\
1032 					malloc_conf_error(		\
1033 					    "Invalid conf value",	\
1034 					    k, klen, v, vlen);		\
1035 				} else if (l < (ssize_t)(min) || l >	\
1036 				    (ssize_t)(max)) {			\
1037 					malloc_conf_error(		\
1038 					    "Out-of-range conf value",	\
1039 					    k, klen, v, vlen);		\
1040 				} else {				\
1041 					o = l;				\
1042 				}					\
1043 				continue;				\
1044 			}
1045 #define CONF_HANDLE_CHAR_P(o, n, d)					\
1046 			if (CONF_MATCH(n)) {				\
1047 				size_t cpylen = (vlen <=		\
1048 				    sizeof(o)-1) ? vlen :		\
1049 				    sizeof(o)-1;			\
1050 				strncpy(o, v, cpylen);			\
1051 				o[cpylen] = '\0';			\
1052 				continue;				\
1053 			}
1054 
1055 			CONF_HANDLE_BOOL(opt_abort, "abort")
1056 			CONF_HANDLE_BOOL(opt_abort_conf, "abort_conf")
1057 			if (strncmp("metadata_thp", k, klen) == 0) {
1058 				int i;
1059 				bool match = false;
1060 				for (i = 0; i < metadata_thp_mode_limit; i++) {
1061 					if (strncmp(metadata_thp_mode_names[i],
1062 					    v, vlen) == 0) {
1063 						opt_metadata_thp = i;
1064 						match = true;
1065 						break;
1066 					}
1067 				}
1068 				if (!match) {
1069 					malloc_conf_error("Invalid conf value",
1070 					    k, klen, v, vlen);
1071 				}
1072 				continue;
1073 			}
1074 			CONF_HANDLE_BOOL(opt_retain, "retain")
1075 			if (strncmp("dss", k, klen) == 0) {
1076 				int i;
1077 				bool match = false;
1078 				for (i = 0; i < dss_prec_limit; i++) {
1079 					if (strncmp(dss_prec_names[i], v, vlen)
1080 					    == 0) {
1081 						if (extent_dss_prec_set(i)) {
1082 							malloc_conf_error(
1083 							    "Error setting dss",
1084 							    k, klen, v, vlen);
1085 						} else {
1086 							opt_dss =
1087 							    dss_prec_names[i];
1088 							match = true;
1089 							break;
1090 						}
1091 					}
1092 				}
1093 				if (!match) {
1094 					malloc_conf_error("Invalid conf value",
1095 					    k, klen, v, vlen);
1096 				}
1097 				continue;
1098 			}
1099 			CONF_HANDLE_UNSIGNED(opt_narenas, "narenas", 1,
1100 			    UINT_MAX, yes, no, false)
1101 			CONF_HANDLE_SSIZE_T(opt_dirty_decay_ms,
1102 			    "dirty_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
1103 			    QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) :
1104 			    SSIZE_MAX);
1105 			CONF_HANDLE_SSIZE_T(opt_muzzy_decay_ms,
1106 			    "muzzy_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
1107 			    QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) :
1108 			    SSIZE_MAX);
1109 			CONF_HANDLE_BOOL(opt_stats_print, "stats_print")
1110 			if (CONF_MATCH("stats_print_opts")) {
1111 				init_opt_stats_print_opts(v, vlen);
1112 				continue;
1113 			}
1114 			if (config_fill) {
1115 				if (CONF_MATCH("junk")) {
1116 					if (CONF_MATCH_VALUE("true")) {
1117 						opt_junk = "true";
1118 						opt_junk_alloc = opt_junk_free =
1119 						    true;
1120 					} else if (CONF_MATCH_VALUE("false")) {
1121 						opt_junk = "false";
1122 						opt_junk_alloc = opt_junk_free =
1123 						    false;
1124 					} else if (CONF_MATCH_VALUE("alloc")) {
1125 						opt_junk = "alloc";
1126 						opt_junk_alloc = true;
1127 						opt_junk_free = false;
1128 					} else if (CONF_MATCH_VALUE("free")) {
1129 						opt_junk = "free";
1130 						opt_junk_alloc = false;
1131 						opt_junk_free = true;
1132 					} else {
1133 						malloc_conf_error(
1134 						    "Invalid conf value", k,
1135 						    klen, v, vlen);
1136 					}
1137 					continue;
1138 				}
1139 				CONF_HANDLE_BOOL(opt_zero, "zero")
1140 			}
1141 			if (config_utrace) {
1142 				CONF_HANDLE_BOOL(opt_utrace, "utrace")
1143 			}
1144 			if (config_xmalloc) {
1145 				CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc")
1146 			}
1147 			CONF_HANDLE_BOOL(opt_tcache, "tcache")
1148 			CONF_HANDLE_SIZE_T(opt_lg_extent_max_active_fit,
1149 			    "lg_extent_max_active_fit", 0,
1150 			    (sizeof(size_t) << 3), yes, yes, false)
1151 			CONF_HANDLE_SSIZE_T(opt_lg_tcache_max, "lg_tcache_max",
1152 			    -1, (sizeof(size_t) << 3) - 1)
1153 			if (strncmp("percpu_arena", k, klen) == 0) {
1154 				bool match = false;
1155 				for (int i = percpu_arena_mode_names_base; i <
1156 				    percpu_arena_mode_names_limit; i++) {
1157 					if (strncmp(percpu_arena_mode_names[i],
1158 					    v, vlen) == 0) {
1159 						if (!have_percpu_arena) {
1160 							malloc_conf_error(
1161 							    "No getcpu support",
1162 							    k, klen, v, vlen);
1163 						}
1164 						opt_percpu_arena = i;
1165 						match = true;
1166 						break;
1167 					}
1168 				}
1169 				if (!match) {
1170 					malloc_conf_error("Invalid conf value",
1171 					    k, klen, v, vlen);
1172 				}
1173 				continue;
1174 			}
1175 			CONF_HANDLE_BOOL(opt_background_thread,
1176 			    "background_thread");
1177 			CONF_HANDLE_SIZE_T(opt_max_background_threads,
1178 					   "max_background_threads", 1,
1179 					   opt_max_background_threads, yes, yes,
1180 					   true);
1181 			if (config_prof) {
1182 				CONF_HANDLE_BOOL(opt_prof, "prof")
1183 				CONF_HANDLE_CHAR_P(opt_prof_prefix,
1184 				    "prof_prefix", "jeprof")
1185 				CONF_HANDLE_BOOL(opt_prof_active, "prof_active")
1186 				CONF_HANDLE_BOOL(opt_prof_thread_active_init,
1187 				    "prof_thread_active_init")
1188 				CONF_HANDLE_SIZE_T(opt_lg_prof_sample,
1189 				    "lg_prof_sample", 0, (sizeof(uint64_t) << 3)
1190 				    - 1, no, yes, true)
1191 				CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum")
1192 				CONF_HANDLE_SSIZE_T(opt_lg_prof_interval,
1193 				    "lg_prof_interval", -1,
1194 				    (sizeof(uint64_t) << 3) - 1)
1195 				CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump")
1196 				CONF_HANDLE_BOOL(opt_prof_final, "prof_final")
1197 				CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak")
1198 			}
1199 			if (config_log) {
1200 				if (CONF_MATCH("log")) {
1201 					size_t cpylen = (
1202 					    vlen <= sizeof(log_var_names) ?
1203 					    vlen : sizeof(log_var_names) - 1);
1204 					strncpy(log_var_names, v, cpylen);
1205 					log_var_names[cpylen] = '\0';
1206 					continue;
1207 				}
1208 			}
1209 			if (CONF_MATCH("thp")) {
1210 				bool match = false;
1211 				for (int i = 0; i < thp_mode_names_limit; i++) {
1212 					if (strncmp(thp_mode_names[i],v, vlen)
1213 					    == 0) {
1214 						if (!have_madvise_huge) {
1215 							malloc_conf_error(
1216 							    "No THP support",
1217 							    k, klen, v, vlen);
1218 						}
1219 						opt_thp = i;
1220 						match = true;
1221 						break;
1222 					}
1223 				}
1224 				if (!match) {
1225 					malloc_conf_error("Invalid conf value",
1226 					    k, klen, v, vlen);
1227 				}
1228 				continue;
1229 			}
1230 			malloc_conf_error("Invalid conf pair", k, klen, v,
1231 			    vlen);
1232 #undef CONF_MATCH
1233 #undef CONF_MATCH_VALUE
1234 #undef CONF_HANDLE_BOOL
1235 #undef CONF_MIN_no
1236 #undef CONF_MIN_yes
1237 #undef CONF_MAX_no
1238 #undef CONF_MAX_yes
1239 #undef CONF_HANDLE_T_U
1240 #undef CONF_HANDLE_UNSIGNED
1241 #undef CONF_HANDLE_SIZE_T
1242 #undef CONF_HANDLE_SSIZE_T
1243 #undef CONF_HANDLE_CHAR_P
1244 		}
1245 		if (opt_abort_conf && had_conf_error) {
1246 			malloc_abort_invalid_conf();
1247 		}
1248 	}
1249 	atomic_store_b(&log_init_done, true, ATOMIC_RELEASE);
1250 }
1251 
1252 static bool
1253 malloc_init_hard_needed(void) {
1254 	if (malloc_initialized() || (IS_INITIALIZER && malloc_init_state ==
1255 	    malloc_init_recursible)) {
1256 		/*
1257 		 * Another thread initialized the allocator before this one
1258 		 * acquired init_lock, or this thread is the initializing
1259 		 * thread, and it is recursively allocating.
1260 		 */
1261 		return false;
1262 	}
1263 #ifdef JEMALLOC_THREADED_INIT
1264 	if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) {
1265 		/* Busy-wait until the initializing thread completes. */
1266 		spin_t spinner = SPIN_INITIALIZER;
1267 		do {
1268 			malloc_mutex_unlock(TSDN_NULL, &init_lock);
1269 			spin_adaptive(&spinner);
1270 			malloc_mutex_lock(TSDN_NULL, &init_lock);
1271 		} while (!malloc_initialized());
1272 		return false;
1273 	}
1274 #endif
1275 	return true;
1276 }
1277 
1278 static bool
1279 malloc_init_hard_a0_locked() {
1280 	malloc_initializer = INITIALIZER;
1281 
1282 	if (config_prof) {
1283 		prof_boot0();
1284 	}
1285 	malloc_conf_init();
1286 	if (opt_stats_print) {
1287 		/* Print statistics at exit. */
1288 		if (atexit(stats_print_atexit) != 0) {
1289 			malloc_write("<jemalloc>: Error in atexit()\n");
1290 			if (opt_abort) {
1291 				abort();
1292 			}
1293 		}
1294 	}
1295 	if (pages_boot()) {
1296 		return true;
1297 	}
1298 	if (base_boot(TSDN_NULL)) {
1299 		return true;
1300 	}
1301 	if (extent_boot()) {
1302 		return true;
1303 	}
1304 	if (ctl_boot()) {
1305 		return true;
1306 	}
1307 	if (config_prof) {
1308 		prof_boot1();
1309 	}
1310 	arena_boot();
1311 	if (tcache_boot(TSDN_NULL)) {
1312 		return true;
1313 	}
1314 	if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS,
1315 	    malloc_mutex_rank_exclusive)) {
1316 		return true;
1317 	}
1318 	/*
1319 	 * Create enough scaffolding to allow recursive allocation in
1320 	 * malloc_ncpus().
1321 	 */
1322 	narenas_auto = 1;
1323 	memset(arenas, 0, sizeof(arena_t *) * narenas_auto);
1324 	/*
1325 	 * Initialize one arena here.  The rest are lazily created in
1326 	 * arena_choose_hard().
1327 	 */
1328 	if (arena_init(TSDN_NULL, 0, (extent_hooks_t *)&extent_hooks_default)
1329 	    == NULL) {
1330 		return true;
1331 	}
1332 	a0 = arena_get(TSDN_NULL, 0, false);
1333 	malloc_init_state = malloc_init_a0_initialized;
1334 
1335 	return false;
1336 }
1337 
1338 static bool
1339 malloc_init_hard_a0(void) {
1340 	bool ret;
1341 
1342 	malloc_mutex_lock(TSDN_NULL, &init_lock);
1343 	ret = malloc_init_hard_a0_locked();
1344 	malloc_mutex_unlock(TSDN_NULL, &init_lock);
1345 	return ret;
1346 }
1347 
1348 /* Initialize data structures which may trigger recursive allocation. */
1349 static bool
1350 malloc_init_hard_recursible(void) {
1351 	malloc_init_state = malloc_init_recursible;
1352 
1353 	ncpus = malloc_ncpus();
1354 
1355 #if (defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \
1356     && !defined(JEMALLOC_ZONE) && !defined(_WIN32) && \
1357     !defined(__native_client__))
1358 	/* LinuxThreads' pthread_atfork() allocates. */
1359 	if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
1360 	    jemalloc_postfork_child) != 0) {
1361 		malloc_write("<jemalloc>: Error in pthread_atfork()\n");
1362 		if (opt_abort) {
1363 			abort();
1364 		}
1365 		return true;
1366 	}
1367 #endif
1368 
1369 	if (background_thread_boot0()) {
1370 		return true;
1371 	}
1372 
1373 	return false;
1374 }
1375 
1376 static unsigned
1377 malloc_narenas_default(void) {
1378 	assert(ncpus > 0);
1379 	/*
1380 	 * For SMP systems, create more than one arena per CPU by
1381 	 * default.
1382 	 */
1383 	if (ncpus > 1) {
1384 		return ncpus << 2;
1385 	} else {
1386 		return 1;
1387 	}
1388 }
1389 
1390 static percpu_arena_mode_t
1391 percpu_arena_as_initialized(percpu_arena_mode_t mode) {
1392 	assert(!malloc_initialized());
1393 	assert(mode <= percpu_arena_disabled);
1394 
1395 	if (mode != percpu_arena_disabled) {
1396 		mode += percpu_arena_mode_enabled_base;
1397 	}
1398 
1399 	return mode;
1400 }
1401 
1402 static bool
1403 malloc_init_narenas(void) {
1404 	assert(ncpus > 0);
1405 
1406 	if (opt_percpu_arena != percpu_arena_disabled) {
1407 		if (!have_percpu_arena || malloc_getcpu() < 0) {
1408 			opt_percpu_arena = percpu_arena_disabled;
1409 			malloc_printf("<jemalloc>: perCPU arena getcpu() not "
1410 			    "available. Setting narenas to %u.\n", opt_narenas ?
1411 			    opt_narenas : malloc_narenas_default());
1412 			if (opt_abort) {
1413 				abort();
1414 			}
1415 		} else {
1416 			if (ncpus >= MALLOCX_ARENA_LIMIT) {
1417 				malloc_printf("<jemalloc>: narenas w/ percpu"
1418 				    "arena beyond limit (%d)\n", ncpus);
1419 				if (opt_abort) {
1420 					abort();
1421 				}
1422 				return true;
1423 			}
1424 			/* NB: opt_percpu_arena isn't fully initialized yet. */
1425 			if (percpu_arena_as_initialized(opt_percpu_arena) ==
1426 			    per_phycpu_arena && ncpus % 2 != 0) {
1427 				malloc_printf("<jemalloc>: invalid "
1428 				    "configuration -- per physical CPU arena "
1429 				    "with odd number (%u) of CPUs (no hyper "
1430 				    "threading?).\n", ncpus);
1431 				if (opt_abort)
1432 					abort();
1433 			}
1434 			unsigned n = percpu_arena_ind_limit(
1435 			    percpu_arena_as_initialized(opt_percpu_arena));
1436 			if (opt_narenas < n) {
1437 				/*
1438 				 * If narenas is specified with percpu_arena
1439 				 * enabled, actual narenas is set as the greater
1440 				 * of the two. percpu_arena_choose will be free
1441 				 * to use any of the arenas based on CPU
1442 				 * id. This is conservative (at a small cost)
1443 				 * but ensures correctness.
1444 				 *
1445 				 * If for some reason the ncpus determined at
1446 				 * boot is not the actual number (e.g. because
1447 				 * of affinity setting from numactl), reserving
1448 				 * narenas this way provides a workaround for
1449 				 * percpu_arena.
1450 				 */
1451 				opt_narenas = n;
1452 			}
1453 		}
1454 	}
1455 	if (opt_narenas == 0) {
1456 		opt_narenas = malloc_narenas_default();
1457 	}
1458 	assert(opt_narenas > 0);
1459 
1460 	narenas_auto = opt_narenas;
1461 	/*
1462 	 * Limit the number of arenas to the indexing range of MALLOCX_ARENA().
1463 	 */
1464 	if (narenas_auto >= MALLOCX_ARENA_LIMIT) {
1465 		narenas_auto = MALLOCX_ARENA_LIMIT - 1;
1466 		malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n",
1467 		    narenas_auto);
1468 	}
1469 	narenas_total_set(narenas_auto);
1470 
1471 	return false;
1472 }
1473 
1474 static void
1475 malloc_init_percpu(void) {
1476 	opt_percpu_arena = percpu_arena_as_initialized(opt_percpu_arena);
1477 }
1478 
1479 static bool
1480 malloc_init_hard_finish(void) {
1481 	if (malloc_mutex_boot()) {
1482 		return true;
1483 	}
1484 
1485 	malloc_init_state = malloc_init_initialized;
1486 	malloc_slow_flag_init();
1487 
1488 	return false;
1489 }
1490 
1491 static void
1492 malloc_init_hard_cleanup(tsdn_t *tsdn, bool reentrancy_set) {
1493 	malloc_mutex_assert_owner(tsdn, &init_lock);
1494 	malloc_mutex_unlock(tsdn, &init_lock);
1495 	if (reentrancy_set) {
1496 		assert(!tsdn_null(tsdn));
1497 		tsd_t *tsd = tsdn_tsd(tsdn);
1498 		assert(tsd_reentrancy_level_get(tsd) > 0);
1499 		post_reentrancy(tsd);
1500 	}
1501 }
1502 
1503 static bool
1504 malloc_init_hard(void) {
1505 	tsd_t *tsd;
1506 
1507 #if defined(_WIN32) && _WIN32_WINNT < 0x0600
1508 	_init_init_lock();
1509 #endif
1510 	malloc_mutex_lock(TSDN_NULL, &init_lock);
1511 
1512 #define UNLOCK_RETURN(tsdn, ret, reentrancy)		\
1513 	malloc_init_hard_cleanup(tsdn, reentrancy);	\
1514 	return ret;
1515 
1516 	if (!malloc_init_hard_needed()) {
1517 		UNLOCK_RETURN(TSDN_NULL, false, false)
1518 	}
1519 
1520 	if (malloc_init_state != malloc_init_a0_initialized &&
1521 	    malloc_init_hard_a0_locked()) {
1522 		UNLOCK_RETURN(TSDN_NULL, true, false)
1523 	}
1524 
1525 	malloc_mutex_unlock(TSDN_NULL, &init_lock);
1526 	/* Recursive allocation relies on functional tsd. */
1527 	tsd = malloc_tsd_boot0();
1528 	if (tsd == NULL) {
1529 		return true;
1530 	}
1531 	if (malloc_init_hard_recursible()) {
1532 		return true;
1533 	}
1534 
1535 	malloc_mutex_lock(tsd_tsdn(tsd), &init_lock);
1536 	/* Set reentrancy level to 1 during init. */
1537 	pre_reentrancy(tsd, NULL);
1538 	/* Initialize narenas before prof_boot2 (for allocation). */
1539 	if (malloc_init_narenas() || background_thread_boot1(tsd_tsdn(tsd))) {
1540 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
1541 	}
1542 	if (config_prof && prof_boot2(tsd)) {
1543 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
1544 	}
1545 
1546 	malloc_init_percpu();
1547 
1548 	if (malloc_init_hard_finish()) {
1549 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
1550 	}
1551 	post_reentrancy(tsd);
1552 	malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock);
1553 
1554 	witness_assert_lockless(witness_tsd_tsdn(
1555 	    tsd_witness_tsdp_get_unsafe(tsd)));
1556 	malloc_tsd_boot1();
1557 	/* Update TSD after tsd_boot1. */
1558 	tsd = tsd_fetch();
1559 	if (opt_background_thread) {
1560 		assert(have_background_thread);
1561 		/*
1562 		 * Need to finish init & unlock first before creating background
1563 		 * threads (pthread_create depends on malloc).  ctl_init (which
1564 		 * sets isthreaded) needs to be called without holding any lock.
1565 		 */
1566 		background_thread_ctl_init(tsd_tsdn(tsd));
1567 
1568 		malloc_mutex_lock(tsd_tsdn(tsd), &background_thread_lock);
1569 		bool err = background_thread_create(tsd, 0);
1570 		malloc_mutex_unlock(tsd_tsdn(tsd), &background_thread_lock);
1571 		if (err) {
1572 			return true;
1573 		}
1574 	}
1575 #undef UNLOCK_RETURN
1576 	return false;
1577 }
1578 
1579 /*
1580  * End initialization functions.
1581  */
1582 /******************************************************************************/
1583 /*
1584  * Begin allocation-path internal functions and data structures.
1585  */
1586 
1587 /*
1588  * Settings determined by the documented behavior of the allocation functions.
1589  */
1590 typedef struct static_opts_s static_opts_t;
1591 struct static_opts_s {
1592 	/* Whether or not allocation size may overflow. */
1593 	bool may_overflow;
1594 	/* Whether or not allocations of size 0 should be treated as size 1. */
1595 	bool bump_empty_alloc;
1596 	/*
1597 	 * Whether to assert that allocations are not of size 0 (after any
1598 	 * bumping).
1599 	 */
1600 	bool assert_nonempty_alloc;
1601 
1602 	/*
1603 	 * Whether or not to modify the 'result' argument to malloc in case of
1604 	 * error.
1605 	 */
1606 	bool null_out_result_on_error;
1607 	/* Whether to set errno when we encounter an error condition. */
1608 	bool set_errno_on_error;
1609 
1610 	/*
1611 	 * The minimum valid alignment for functions requesting aligned storage.
1612 	 */
1613 	size_t min_alignment;
1614 
1615 	/* The error string to use if we oom. */
1616 	const char *oom_string;
1617 	/* The error string to use if the passed-in alignment is invalid. */
1618 	const char *invalid_alignment_string;
1619 
1620 	/*
1621 	 * False if we're configured to skip some time-consuming operations.
1622 	 *
1623 	 * This isn't really a malloc "behavior", but it acts as a useful
1624 	 * summary of several other static (or at least, static after program
1625 	 * initialization) options.
1626 	 */
1627 	bool slow;
1628 };
1629 
1630 JEMALLOC_ALWAYS_INLINE void
1631 static_opts_init(static_opts_t *static_opts) {
1632 	static_opts->may_overflow = false;
1633 	static_opts->bump_empty_alloc = false;
1634 	static_opts->assert_nonempty_alloc = false;
1635 	static_opts->null_out_result_on_error = false;
1636 	static_opts->set_errno_on_error = false;
1637 	static_opts->min_alignment = 0;
1638 	static_opts->oom_string = "";
1639 	static_opts->invalid_alignment_string = "";
1640 	static_opts->slow = false;
1641 }
1642 
1643 /*
1644  * These correspond to the macros in jemalloc/jemalloc_macros.h.  Broadly, we
1645  * should have one constant here per magic value there.  Note however that the
1646  * representations need not be related.
1647  */
1648 #define TCACHE_IND_NONE ((unsigned)-1)
1649 #define TCACHE_IND_AUTOMATIC ((unsigned)-2)
1650 #define ARENA_IND_AUTOMATIC ((unsigned)-1)
1651 
1652 typedef struct dynamic_opts_s dynamic_opts_t;
1653 struct dynamic_opts_s {
1654 	void **result;
1655 	size_t num_items;
1656 	size_t item_size;
1657 	size_t alignment;
1658 	bool zero;
1659 	unsigned tcache_ind;
1660 	unsigned arena_ind;
1661 };
1662 
1663 JEMALLOC_ALWAYS_INLINE void
1664 dynamic_opts_init(dynamic_opts_t *dynamic_opts) {
1665 	dynamic_opts->result = NULL;
1666 	dynamic_opts->num_items = 0;
1667 	dynamic_opts->item_size = 0;
1668 	dynamic_opts->alignment = 0;
1669 	dynamic_opts->zero = false;
1670 	dynamic_opts->tcache_ind = TCACHE_IND_AUTOMATIC;
1671 	dynamic_opts->arena_ind = ARENA_IND_AUTOMATIC;
1672 }
1673 
1674 /* ind is ignored if dopts->alignment > 0. */
1675 JEMALLOC_ALWAYS_INLINE void *
1676 imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd,
1677     size_t size, size_t usize, szind_t ind) {
1678 	tcache_t *tcache;
1679 	arena_t *arena;
1680 
1681 	/* Fill in the tcache. */
1682 	if (dopts->tcache_ind == TCACHE_IND_AUTOMATIC) {
1683 		if (likely(!sopts->slow)) {
1684 			/* Getting tcache ptr unconditionally. */
1685 			tcache = tsd_tcachep_get(tsd);
1686 			assert(tcache == tcache_get(tsd));
1687 		} else {
1688 			tcache = tcache_get(tsd);
1689 		}
1690 	} else if (dopts->tcache_ind == TCACHE_IND_NONE) {
1691 		tcache = NULL;
1692 	} else {
1693 		tcache = tcaches_get(tsd, dopts->tcache_ind);
1694 	}
1695 
1696 	/* Fill in the arena. */
1697 	if (dopts->arena_ind == ARENA_IND_AUTOMATIC) {
1698 		/*
1699 		 * In case of automatic arena management, we defer arena
1700 		 * computation until as late as we can, hoping to fill the
1701 		 * allocation out of the tcache.
1702 		 */
1703 		arena = NULL;
1704 	} else {
1705 		arena = arena_get(tsd_tsdn(tsd), dopts->arena_ind, true);
1706 	}
1707 
1708 	if (unlikely(dopts->alignment != 0)) {
1709 		return ipalloct(tsd_tsdn(tsd), usize, dopts->alignment,
1710 		    dopts->zero, tcache, arena);
1711 	}
1712 
1713 	return iallocztm(tsd_tsdn(tsd), size, ind, dopts->zero, tcache, false,
1714 	    arena, sopts->slow);
1715 }
1716 
1717 JEMALLOC_ALWAYS_INLINE void *
1718 imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd,
1719     size_t usize, szind_t ind) {
1720 	void *ret;
1721 
1722 	/*
1723 	 * For small allocations, sampling bumps the usize.  If so, we allocate
1724 	 * from the ind_large bucket.
1725 	 */
1726 	szind_t ind_large;
1727 	size_t bumped_usize = usize;
1728 
1729 	if (usize <= SMALL_MAXCLASS) {
1730 		assert(((dopts->alignment == 0) ? sz_s2u(LARGE_MINCLASS) :
1731 		    sz_sa2u(LARGE_MINCLASS, dopts->alignment))
1732 		    == LARGE_MINCLASS);
1733 		ind_large = sz_size2index(LARGE_MINCLASS);
1734 		bumped_usize = sz_s2u(LARGE_MINCLASS);
1735 		ret = imalloc_no_sample(sopts, dopts, tsd, bumped_usize,
1736 		    bumped_usize, ind_large);
1737 		if (unlikely(ret == NULL)) {
1738 			return NULL;
1739 		}
1740 		arena_prof_promote(tsd_tsdn(tsd), ret, usize);
1741 	} else {
1742 		ret = imalloc_no_sample(sopts, dopts, tsd, usize, usize, ind);
1743 	}
1744 
1745 	return ret;
1746 }
1747 
1748 /*
1749  * Returns true if the allocation will overflow, and false otherwise.  Sets
1750  * *size to the product either way.
1751  */
1752 JEMALLOC_ALWAYS_INLINE bool
1753 compute_size_with_overflow(bool may_overflow, dynamic_opts_t *dopts,
1754     size_t *size) {
1755 	/*
1756 	 * This function is just num_items * item_size, except that we may have
1757 	 * to check for overflow.
1758 	 */
1759 
1760 	if (!may_overflow) {
1761 		assert(dopts->num_items == 1);
1762 		*size = dopts->item_size;
1763 		return false;
1764 	}
1765 
1766 	/* A size_t with its high-half bits all set to 1. */
1767 	static const size_t high_bits = SIZE_T_MAX << (sizeof(size_t) * 8 / 2);
1768 
1769 	*size = dopts->item_size * dopts->num_items;
1770 
1771 	if (unlikely(*size == 0)) {
1772 		return (dopts->num_items != 0 && dopts->item_size != 0);
1773 	}
1774 
1775 	/*
1776 	 * We got a non-zero size, but we don't know if we overflowed to get
1777 	 * there.  To avoid having to do a divide, we'll be clever and note that
1778 	 * if both A and B can be represented in N/2 bits, then their product
1779 	 * can be represented in N bits (without the possibility of overflow).
1780 	 */
1781 	if (likely((high_bits & (dopts->num_items | dopts->item_size)) == 0)) {
1782 		return false;
1783 	}
1784 	if (likely(*size / dopts->item_size == dopts->num_items)) {
1785 		return false;
1786 	}
1787 	return true;
1788 }
1789 
1790 JEMALLOC_ALWAYS_INLINE int
1791 imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) {
1792 	/* Where the actual allocated memory will live. */
1793 	void *allocation = NULL;
1794 	/* Filled in by compute_size_with_overflow below. */
1795 	size_t size = 0;
1796 	/*
1797 	 * For unaligned allocations, we need only ind.  For aligned
1798 	 * allocations, or in case of stats or profiling we need usize.
1799 	 *
1800 	 * These are actually dead stores, in that their values are reset before
1801 	 * any branch on their value is taken.  Sometimes though, it's
1802 	 * convenient to pass them as arguments before this point.  To avoid
1803 	 * undefined behavior then, we initialize them with dummy stores.
1804 	 */
1805 	szind_t ind = 0;
1806 	size_t usize = 0;
1807 
1808 	/* Reentrancy is only checked on slow path. */
1809 	int8_t reentrancy_level;
1810 
1811 	/* Compute the amount of memory the user wants. */
1812 	if (unlikely(compute_size_with_overflow(sopts->may_overflow, dopts,
1813 	    &size))) {
1814 		goto label_oom;
1815 	}
1816 
1817 	/* Validate the user input. */
1818 	if (sopts->bump_empty_alloc) {
1819 		if (unlikely(size == 0)) {
1820 			size = 1;
1821 		}
1822 	}
1823 
1824 	if (sopts->assert_nonempty_alloc) {
1825 		assert (size != 0);
1826 	}
1827 
1828 	if (unlikely(dopts->alignment < sopts->min_alignment
1829 	    || (dopts->alignment & (dopts->alignment - 1)) != 0)) {
1830 		goto label_invalid_alignment;
1831 	}
1832 
1833 	/* This is the beginning of the "core" algorithm. */
1834 
1835 	if (dopts->alignment == 0) {
1836 		ind = sz_size2index(size);
1837 		if (unlikely(ind >= NSIZES)) {
1838 			goto label_oom;
1839 		}
1840 		if (config_stats || (config_prof && opt_prof)) {
1841 			usize = sz_index2size(ind);
1842 			assert(usize > 0 && usize <= LARGE_MAXCLASS);
1843 		}
1844 	} else {
1845 		usize = sz_sa2u(size, dopts->alignment);
1846 		if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
1847 			goto label_oom;
1848 		}
1849 	}
1850 
1851 	check_entry_exit_locking(tsd_tsdn(tsd));
1852 
1853 	/*
1854 	 * If we need to handle reentrancy, we can do it out of a
1855 	 * known-initialized arena (i.e. arena 0).
1856 	 */
1857 	reentrancy_level = tsd_reentrancy_level_get(tsd);
1858 	if (sopts->slow && unlikely(reentrancy_level > 0)) {
1859 		/*
1860 		 * We should never specify particular arenas or tcaches from
1861 		 * within our internal allocations.
1862 		 */
1863 		assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC ||
1864 		    dopts->tcache_ind == TCACHE_IND_NONE);
1865 		assert(dopts->arena_ind == ARENA_IND_AUTOMATIC);
1866 		dopts->tcache_ind = TCACHE_IND_NONE;
1867 		/* We know that arena 0 has already been initialized. */
1868 		dopts->arena_ind = 0;
1869 	}
1870 
1871 	/* If profiling is on, get our profiling context. */
1872 	if (config_prof && opt_prof) {
1873 		/*
1874 		 * Note that if we're going down this path, usize must have been
1875 		 * initialized in the previous if statement.
1876 		 */
1877 		prof_tctx_t *tctx = prof_alloc_prep(
1878 		    tsd, usize, prof_active_get_unlocked(), true);
1879 
1880 		alloc_ctx_t alloc_ctx;
1881 		if (likely((uintptr_t)tctx == (uintptr_t)1U)) {
1882 			alloc_ctx.slab = (usize <= SMALL_MAXCLASS);
1883 			allocation = imalloc_no_sample(
1884 			    sopts, dopts, tsd, usize, usize, ind);
1885 		} else if ((uintptr_t)tctx > (uintptr_t)1U) {
1886 			/*
1887 			 * Note that ind might still be 0 here.  This is fine;
1888 			 * imalloc_sample ignores ind if dopts->alignment > 0.
1889 			 */
1890 			allocation = imalloc_sample(
1891 			    sopts, dopts, tsd, usize, ind);
1892 			alloc_ctx.slab = false;
1893 		} else {
1894 			allocation = NULL;
1895 		}
1896 
1897 		if (unlikely(allocation == NULL)) {
1898 			prof_alloc_rollback(tsd, tctx, true);
1899 			goto label_oom;
1900 		}
1901 		prof_malloc(tsd_tsdn(tsd), allocation, usize, &alloc_ctx, tctx);
1902 	} else {
1903 		/*
1904 		 * If dopts->alignment > 0, then ind is still 0, but usize was
1905 		 * computed in the previous if statement.  Down the positive
1906 		 * alignment path, imalloc_no_sample ignores ind and size
1907 		 * (relying only on usize).
1908 		 */
1909 		allocation = imalloc_no_sample(sopts, dopts, tsd, size, usize,
1910 		    ind);
1911 		if (unlikely(allocation == NULL)) {
1912 			goto label_oom;
1913 		}
1914 	}
1915 
1916 	/*
1917 	 * Allocation has been done at this point.  We still have some
1918 	 * post-allocation work to do though.
1919 	 */
1920 	assert(dopts->alignment == 0
1921 	    || ((uintptr_t)allocation & (dopts->alignment - 1)) == ZU(0));
1922 
1923 	if (config_stats) {
1924 		assert(usize == isalloc(tsd_tsdn(tsd), allocation));
1925 		*tsd_thread_allocatedp_get(tsd) += usize;
1926 	}
1927 
1928 	if (sopts->slow) {
1929 		UTRACE(0, size, allocation);
1930 	}
1931 
1932 	/* Success! */
1933 	check_entry_exit_locking(tsd_tsdn(tsd));
1934 	*dopts->result = allocation;
1935 	return 0;
1936 
1937 label_oom:
1938 	if (unlikely(sopts->slow) && config_xmalloc && unlikely(opt_xmalloc)) {
1939 		malloc_write(sopts->oom_string);
1940 		abort();
1941 	}
1942 
1943 	if (sopts->slow) {
1944 		UTRACE(NULL, size, NULL);
1945 	}
1946 
1947 	check_entry_exit_locking(tsd_tsdn(tsd));
1948 
1949 	if (sopts->set_errno_on_error) {
1950 		set_errno(ENOMEM);
1951 	}
1952 
1953 	if (sopts->null_out_result_on_error) {
1954 		*dopts->result = NULL;
1955 	}
1956 
1957 	return ENOMEM;
1958 
1959 	/*
1960 	 * This label is only jumped to by one goto; we move it out of line
1961 	 * anyways to avoid obscuring the non-error paths, and for symmetry with
1962 	 * the oom case.
1963 	 */
1964 label_invalid_alignment:
1965 	if (config_xmalloc && unlikely(opt_xmalloc)) {
1966 		malloc_write(sopts->invalid_alignment_string);
1967 		abort();
1968 	}
1969 
1970 	if (sopts->set_errno_on_error) {
1971 		set_errno(EINVAL);
1972 	}
1973 
1974 	if (sopts->slow) {
1975 		UTRACE(NULL, size, NULL);
1976 	}
1977 
1978 	check_entry_exit_locking(tsd_tsdn(tsd));
1979 
1980 	if (sopts->null_out_result_on_error) {
1981 		*dopts->result = NULL;
1982 	}
1983 
1984 	return EINVAL;
1985 }
1986 
1987 /* Returns the errno-style error code of the allocation. */
1988 JEMALLOC_ALWAYS_INLINE int
1989 imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) {
1990 	if (unlikely(!malloc_initialized()) && unlikely(malloc_init())) {
1991 		if (config_xmalloc && unlikely(opt_xmalloc)) {
1992 			malloc_write(sopts->oom_string);
1993 			abort();
1994 		}
1995 		UTRACE(NULL, dopts->num_items * dopts->item_size, NULL);
1996 		set_errno(ENOMEM);
1997 		*dopts->result = NULL;
1998 
1999 		return ENOMEM;
2000 	}
2001 
2002 	/* We always need the tsd.  Let's grab it right away. */
2003 	tsd_t *tsd = tsd_fetch();
2004 	assert(tsd);
2005 	if (likely(tsd_fast(tsd))) {
2006 		/* Fast and common path. */
2007 		tsd_assert_fast(tsd);
2008 		sopts->slow = false;
2009 		return imalloc_body(sopts, dopts, tsd);
2010 	} else {
2011 		sopts->slow = true;
2012 		return imalloc_body(sopts, dopts, tsd);
2013 	}
2014 }
2015 /******************************************************************************/
2016 /*
2017  * Begin malloc(3)-compatible functions.
2018  */
2019 
2020 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2021 void JEMALLOC_NOTHROW *
2022 JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1)
2023 je_malloc(size_t size) {
2024 	void *ret;
2025 	static_opts_t sopts;
2026 	dynamic_opts_t dopts;
2027 
2028 	LOG("core.malloc.entry", "size: %zu", size);
2029 
2030 	static_opts_init(&sopts);
2031 	dynamic_opts_init(&dopts);
2032 
2033 	sopts.bump_empty_alloc = true;
2034 	sopts.null_out_result_on_error = true;
2035 	sopts.set_errno_on_error = true;
2036 	sopts.oom_string = "<jemalloc>: Error in malloc(): out of memory\n";
2037 
2038 	dopts.result = &ret;
2039 	dopts.num_items = 1;
2040 	dopts.item_size = size;
2041 
2042 	imalloc(&sopts, &dopts);
2043 
2044 	LOG("core.malloc.exit", "result: %p", ret);
2045 
2046 	return ret;
2047 }
2048 
2049 JEMALLOC_EXPORT int JEMALLOC_NOTHROW
2050 JEMALLOC_ATTR(nonnull(1))
2051 je_posix_memalign(void **memptr, size_t alignment, size_t size) {
2052 	int ret;
2053 	static_opts_t sopts;
2054 	dynamic_opts_t dopts;
2055 
2056 	LOG("core.posix_memalign.entry", "mem ptr: %p, alignment: %zu, "
2057 	    "size: %zu", memptr, alignment, size);
2058 
2059 	static_opts_init(&sopts);
2060 	dynamic_opts_init(&dopts);
2061 
2062 	sopts.bump_empty_alloc = true;
2063 	sopts.min_alignment = sizeof(void *);
2064 	sopts.oom_string =
2065 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2066 	sopts.invalid_alignment_string =
2067 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2068 
2069 	dopts.result = memptr;
2070 	dopts.num_items = 1;
2071 	dopts.item_size = size;
2072 	dopts.alignment = alignment;
2073 
2074 	ret = imalloc(&sopts, &dopts);
2075 
2076 	LOG("core.posix_memalign.exit", "result: %d, alloc ptr: %p", ret,
2077 	    *memptr);
2078 
2079 	return ret;
2080 }
2081 
2082 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2083 void JEMALLOC_NOTHROW *
2084 JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(2)
2085 je_aligned_alloc(size_t alignment, size_t size) {
2086 	void *ret;
2087 
2088 	static_opts_t sopts;
2089 	dynamic_opts_t dopts;
2090 
2091 	LOG("core.aligned_alloc.entry", "alignment: %zu, size: %zu\n",
2092 	    alignment, size);
2093 
2094 	static_opts_init(&sopts);
2095 	dynamic_opts_init(&dopts);
2096 
2097 	sopts.bump_empty_alloc = true;
2098 	sopts.null_out_result_on_error = true;
2099 	sopts.set_errno_on_error = true;
2100 	sopts.min_alignment = 1;
2101 	sopts.oom_string =
2102 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2103 	sopts.invalid_alignment_string =
2104 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2105 
2106 	dopts.result = &ret;
2107 	dopts.num_items = 1;
2108 	dopts.item_size = size;
2109 	dopts.alignment = alignment;
2110 
2111 	imalloc(&sopts, &dopts);
2112 
2113 	LOG("core.aligned_alloc.exit", "result: %p", ret);
2114 
2115 	return ret;
2116 }
2117 
2118 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2119 void JEMALLOC_NOTHROW *
2120 JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2)
2121 je_calloc(size_t num, size_t size) {
2122 	void *ret;
2123 	static_opts_t sopts;
2124 	dynamic_opts_t dopts;
2125 
2126 	LOG("core.calloc.entry", "num: %zu, size: %zu\n", num, size);
2127 
2128 	static_opts_init(&sopts);
2129 	dynamic_opts_init(&dopts);
2130 
2131 	sopts.may_overflow = true;
2132 	sopts.bump_empty_alloc = true;
2133 	sopts.null_out_result_on_error = true;
2134 	sopts.set_errno_on_error = true;
2135 	sopts.oom_string = "<jemalloc>: Error in calloc(): out of memory\n";
2136 
2137 	dopts.result = &ret;
2138 	dopts.num_items = num;
2139 	dopts.item_size = size;
2140 	dopts.zero = true;
2141 
2142 	imalloc(&sopts, &dopts);
2143 
2144 	LOG("core.calloc.exit", "result: %p", ret);
2145 
2146 	return ret;
2147 }
2148 
2149 static void *
2150 irealloc_prof_sample(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
2151     prof_tctx_t *tctx) {
2152 	void *p;
2153 
2154 	if (tctx == NULL) {
2155 		return NULL;
2156 	}
2157 	if (usize <= SMALL_MAXCLASS) {
2158 		p = iralloc(tsd, old_ptr, old_usize, LARGE_MINCLASS, 0, false);
2159 		if (p == NULL) {
2160 			return NULL;
2161 		}
2162 		arena_prof_promote(tsd_tsdn(tsd), p, usize);
2163 	} else {
2164 		p = iralloc(tsd, old_ptr, old_usize, usize, 0, false);
2165 	}
2166 
2167 	return p;
2168 }
2169 
2170 JEMALLOC_ALWAYS_INLINE void *
2171 irealloc_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t usize,
2172    alloc_ctx_t *alloc_ctx) {
2173 	void *p;
2174 	bool prof_active;
2175 	prof_tctx_t *old_tctx, *tctx;
2176 
2177 	prof_active = prof_active_get_unlocked();
2178 	old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr, alloc_ctx);
2179 	tctx = prof_alloc_prep(tsd, usize, prof_active, true);
2180 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
2181 		p = irealloc_prof_sample(tsd, old_ptr, old_usize, usize, tctx);
2182 	} else {
2183 		p = iralloc(tsd, old_ptr, old_usize, usize, 0, false);
2184 	}
2185 	if (unlikely(p == NULL)) {
2186 		prof_alloc_rollback(tsd, tctx, true);
2187 		return NULL;
2188 	}
2189 	prof_realloc(tsd, p, usize, tctx, prof_active, true, old_ptr, old_usize,
2190 	    old_tctx);
2191 
2192 	return p;
2193 }
2194 
2195 JEMALLOC_ALWAYS_INLINE void
2196 ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) {
2197 	if (!slow_path) {
2198 		tsd_assert_fast(tsd);
2199 	}
2200 	check_entry_exit_locking(tsd_tsdn(tsd));
2201 	if (tsd_reentrancy_level_get(tsd) != 0) {
2202 		assert(slow_path);
2203 	}
2204 
2205 	assert(ptr != NULL);
2206 	assert(malloc_initialized() || IS_INITIALIZER);
2207 
2208 	alloc_ctx_t alloc_ctx;
2209 	rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2210 	rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2211 	    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2212 	assert(alloc_ctx.szind != NSIZES);
2213 
2214 	size_t usize;
2215 	if (config_prof && opt_prof) {
2216 		usize = sz_index2size(alloc_ctx.szind);
2217 		prof_free(tsd, ptr, usize, &alloc_ctx);
2218 	} else if (config_stats) {
2219 		usize = sz_index2size(alloc_ctx.szind);
2220 	}
2221 	if (config_stats) {
2222 		*tsd_thread_deallocatedp_get(tsd) += usize;
2223 	}
2224 
2225 	if (likely(!slow_path)) {
2226 		idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false,
2227 		    false);
2228 	} else {
2229 		idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false,
2230 		    true);
2231 	}
2232 }
2233 
2234 JEMALLOC_ALWAYS_INLINE void
2235 isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) {
2236 	if (!slow_path) {
2237 		tsd_assert_fast(tsd);
2238 	}
2239 	check_entry_exit_locking(tsd_tsdn(tsd));
2240 	if (tsd_reentrancy_level_get(tsd) != 0) {
2241 		assert(slow_path);
2242 	}
2243 
2244 	assert(ptr != NULL);
2245 	assert(malloc_initialized() || IS_INITIALIZER);
2246 
2247 	alloc_ctx_t alloc_ctx, *ctx;
2248 	if (!config_cache_oblivious && ((uintptr_t)ptr & PAGE_MASK) != 0) {
2249 		/*
2250 		 * When cache_oblivious is disabled and ptr is not page aligned,
2251 		 * the allocation was not sampled -- usize can be used to
2252 		 * determine szind directly.
2253 		 */
2254 		alloc_ctx.szind = sz_size2index(usize);
2255 		alloc_ctx.slab = true;
2256 		ctx = &alloc_ctx;
2257 		if (config_debug) {
2258 			alloc_ctx_t dbg_ctx;
2259 			rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2260 			rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree,
2261 			    rtree_ctx, (uintptr_t)ptr, true, &dbg_ctx.szind,
2262 			    &dbg_ctx.slab);
2263 			assert(dbg_ctx.szind == alloc_ctx.szind);
2264 			assert(dbg_ctx.slab == alloc_ctx.slab);
2265 		}
2266 	} else if (config_prof && opt_prof) {
2267 		rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2268 		rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2269 		    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2270 		assert(alloc_ctx.szind == sz_size2index(usize));
2271 		ctx = &alloc_ctx;
2272 	} else {
2273 		ctx = NULL;
2274 	}
2275 
2276 	if (config_prof && opt_prof) {
2277 		prof_free(tsd, ptr, usize, ctx);
2278 	}
2279 	if (config_stats) {
2280 		*tsd_thread_deallocatedp_get(tsd) += usize;
2281 	}
2282 
2283 	if (likely(!slow_path)) {
2284 		isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, ctx, false);
2285 	} else {
2286 		isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, ctx, true);
2287 	}
2288 }
2289 
2290 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2291 void JEMALLOC_NOTHROW *
2292 JEMALLOC_ALLOC_SIZE(2)
2293 je_realloc(void *ptr, size_t size) {
2294 	void *ret;
2295 	tsdn_t *tsdn JEMALLOC_CC_SILENCE_INIT(NULL);
2296 	size_t usize JEMALLOC_CC_SILENCE_INIT(0);
2297 	size_t old_usize = 0;
2298 
2299 	LOG("core.realloc.entry", "ptr: %p, size: %zu\n", ptr, size);
2300 
2301 	if (unlikely(size == 0)) {
2302 		if (ptr != NULL) {
2303 			/* realloc(ptr, 0) is equivalent to free(ptr). */
2304 			UTRACE(ptr, 0, 0);
2305 			tcache_t *tcache;
2306 			tsd_t *tsd = tsd_fetch();
2307 			if (tsd_reentrancy_level_get(tsd) == 0) {
2308 				tcache = tcache_get(tsd);
2309 			} else {
2310 				tcache = NULL;
2311 			}
2312 			ifree(tsd, ptr, tcache, true);
2313 
2314 			LOG("core.realloc.exit", "result: %p", NULL);
2315 			return NULL;
2316 		}
2317 		size = 1;
2318 	}
2319 
2320 	if (likely(ptr != NULL)) {
2321 		assert(malloc_initialized() || IS_INITIALIZER);
2322 		tsd_t *tsd = tsd_fetch();
2323 
2324 		check_entry_exit_locking(tsd_tsdn(tsd));
2325 
2326 		alloc_ctx_t alloc_ctx;
2327 		rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2328 		rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2329 		    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2330 		assert(alloc_ctx.szind != NSIZES);
2331 		old_usize = sz_index2size(alloc_ctx.szind);
2332 		assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
2333 		if (config_prof && opt_prof) {
2334 			usize = sz_s2u(size);
2335 			ret = unlikely(usize == 0 || usize > LARGE_MAXCLASS) ?
2336 			    NULL : irealloc_prof(tsd, ptr, old_usize, usize,
2337 			    &alloc_ctx);
2338 		} else {
2339 			if (config_stats) {
2340 				usize = sz_s2u(size);
2341 			}
2342 			ret = iralloc(tsd, ptr, old_usize, size, 0, false);
2343 		}
2344 		tsdn = tsd_tsdn(tsd);
2345 	} else {
2346 		/* realloc(NULL, size) is equivalent to malloc(size). */
2347 		void *ret = je_malloc(size);
2348 		LOG("core.realloc.exit", "result: %p", ret);
2349 		return ret;
2350 	}
2351 
2352 	if (unlikely(ret == NULL)) {
2353 		if (config_xmalloc && unlikely(opt_xmalloc)) {
2354 			malloc_write("<jemalloc>: Error in realloc(): "
2355 			    "out of memory\n");
2356 			abort();
2357 		}
2358 		set_errno(ENOMEM);
2359 	}
2360 	if (config_stats && likely(ret != NULL)) {
2361 		tsd_t *tsd;
2362 
2363 		assert(usize == isalloc(tsdn, ret));
2364 		tsd = tsdn_tsd(tsdn);
2365 		*tsd_thread_allocatedp_get(tsd) += usize;
2366 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
2367 	}
2368 	UTRACE(ptr, size, ret);
2369 	check_entry_exit_locking(tsdn);
2370 
2371 	LOG("core.realloc.exit", "result: %p", ret);
2372 	return ret;
2373 }
2374 
2375 JEMALLOC_EXPORT void JEMALLOC_NOTHROW
2376 je_free(void *ptr) {
2377 	LOG("core.free.entry", "ptr: %p", ptr);
2378 
2379 	UTRACE(ptr, 0, 0);
2380 	if (likely(ptr != NULL)) {
2381 		/*
2382 		 * We avoid setting up tsd fully (e.g. tcache, arena binding)
2383 		 * based on only free() calls -- other activities trigger the
2384 		 * minimal to full transition.  This is because free() may
2385 		 * happen during thread shutdown after tls deallocation: if a
2386 		 * thread never had any malloc activities until then, a
2387 		 * fully-setup tsd won't be destructed properly.
2388 		 */
2389 		tsd_t *tsd = tsd_fetch_min();
2390 		check_entry_exit_locking(tsd_tsdn(tsd));
2391 
2392 		tcache_t *tcache;
2393 		if (likely(tsd_fast(tsd))) {
2394 			tsd_assert_fast(tsd);
2395 			/* Unconditionally get tcache ptr on fast path. */
2396 			tcache = tsd_tcachep_get(tsd);
2397 			ifree(tsd, ptr, tcache, false);
2398 		} else {
2399 			if (likely(tsd_reentrancy_level_get(tsd) == 0)) {
2400 				tcache = tcache_get(tsd);
2401 			} else {
2402 				tcache = NULL;
2403 			}
2404 			ifree(tsd, ptr, tcache, true);
2405 		}
2406 		check_entry_exit_locking(tsd_tsdn(tsd));
2407 	}
2408 	LOG("core.free.exit", "");
2409 }
2410 
2411 /*
2412  * End malloc(3)-compatible functions.
2413  */
2414 /******************************************************************************/
2415 /*
2416  * Begin non-standard override functions.
2417  */
2418 
2419 #ifdef JEMALLOC_OVERRIDE_MEMALIGN
2420 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2421 void JEMALLOC_NOTHROW *
2422 JEMALLOC_ATTR(malloc)
2423 je_memalign(size_t alignment, size_t size) {
2424 	void *ret;
2425 	static_opts_t sopts;
2426 	dynamic_opts_t dopts;
2427 
2428 	LOG("core.memalign.entry", "alignment: %zu, size: %zu\n", alignment,
2429 	    size);
2430 
2431 	static_opts_init(&sopts);
2432 	dynamic_opts_init(&dopts);
2433 
2434 	sopts.bump_empty_alloc = true;
2435 	sopts.min_alignment = 1;
2436 	sopts.oom_string =
2437 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2438 	sopts.invalid_alignment_string =
2439 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2440 	sopts.null_out_result_on_error = true;
2441 
2442 	dopts.result = &ret;
2443 	dopts.num_items = 1;
2444 	dopts.item_size = size;
2445 	dopts.alignment = alignment;
2446 
2447 	imalloc(&sopts, &dopts);
2448 
2449 	LOG("core.memalign.exit", "result: %p", ret);
2450 	return ret;
2451 }
2452 #endif
2453 
2454 #ifdef JEMALLOC_OVERRIDE_VALLOC
2455 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2456 void JEMALLOC_NOTHROW *
2457 JEMALLOC_ATTR(malloc)
2458 je_valloc(size_t size) {
2459 	void *ret;
2460 
2461 	static_opts_t sopts;
2462 	dynamic_opts_t dopts;
2463 
2464 	LOG("core.valloc.entry", "size: %zu\n", size);
2465 
2466 	static_opts_init(&sopts);
2467 	dynamic_opts_init(&dopts);
2468 
2469 	sopts.bump_empty_alloc = true;
2470 	sopts.null_out_result_on_error = true;
2471 	sopts.min_alignment = PAGE;
2472 	sopts.oom_string =
2473 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2474 	sopts.invalid_alignment_string =
2475 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2476 
2477 	dopts.result = &ret;
2478 	dopts.num_items = 1;
2479 	dopts.item_size = size;
2480 	dopts.alignment = PAGE;
2481 
2482 	imalloc(&sopts, &dopts);
2483 
2484 	LOG("core.valloc.exit", "result: %p\n", ret);
2485 	return ret;
2486 }
2487 #endif
2488 
2489 #if defined(JEMALLOC_IS_MALLOC) && defined(JEMALLOC_GLIBC_MALLOC_HOOK)
2490 /*
2491  * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
2492  * to inconsistently reference libc's malloc(3)-compatible functions
2493  * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
2494  *
2495  * These definitions interpose hooks in glibc.  The functions are actually
2496  * passed an extra argument for the caller return address, which will be
2497  * ignored.
2498  */
2499 JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free;
2500 JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc;
2501 JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc;
2502 #  ifdef JEMALLOC_GLIBC_MEMALIGN_HOOK
2503 JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) =
2504     je_memalign;
2505 #  endif
2506 
2507 #  ifdef CPU_COUNT
2508 /*
2509  * To enable static linking with glibc, the libc specific malloc interface must
2510  * be implemented also, so none of glibc's malloc.o functions are added to the
2511  * link.
2512  */
2513 #    define ALIAS(je_fn)	__attribute__((alias (#je_fn), used))
2514 /* To force macro expansion of je_ prefix before stringification. */
2515 #    define PREALIAS(je_fn)	ALIAS(je_fn)
2516 #    ifdef JEMALLOC_OVERRIDE___LIBC_CALLOC
2517 void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc);
2518 #    endif
2519 #    ifdef JEMALLOC_OVERRIDE___LIBC_FREE
2520 void __libc_free(void* ptr) PREALIAS(je_free);
2521 #    endif
2522 #    ifdef JEMALLOC_OVERRIDE___LIBC_MALLOC
2523 void *__libc_malloc(size_t size) PREALIAS(je_malloc);
2524 #    endif
2525 #    ifdef JEMALLOC_OVERRIDE___LIBC_MEMALIGN
2526 void *__libc_memalign(size_t align, size_t s) PREALIAS(je_memalign);
2527 #    endif
2528 #    ifdef JEMALLOC_OVERRIDE___LIBC_REALLOC
2529 void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc);
2530 #    endif
2531 #    ifdef JEMALLOC_OVERRIDE___LIBC_VALLOC
2532 void *__libc_valloc(size_t size) PREALIAS(je_valloc);
2533 #    endif
2534 #    ifdef JEMALLOC_OVERRIDE___POSIX_MEMALIGN
2535 int __posix_memalign(void** r, size_t a, size_t s) PREALIAS(je_posix_memalign);
2536 #    endif
2537 #    undef PREALIAS
2538 #    undef ALIAS
2539 #  endif
2540 #endif
2541 
2542 /*
2543  * End non-standard override functions.
2544  */
2545 /******************************************************************************/
2546 /*
2547  * Begin non-standard functions.
2548  */
2549 
2550 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2551 void JEMALLOC_NOTHROW *
2552 JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1)
2553 je_mallocx(size_t size, int flags) {
2554 	void *ret;
2555 	static_opts_t sopts;
2556 	dynamic_opts_t dopts;
2557 
2558 	LOG("core.mallocx.entry", "size: %zu, flags: %d", size, flags);
2559 
2560 	static_opts_init(&sopts);
2561 	dynamic_opts_init(&dopts);
2562 
2563 	sopts.assert_nonempty_alloc = true;
2564 	sopts.null_out_result_on_error = true;
2565 	sopts.oom_string = "<jemalloc>: Error in mallocx(): out of memory\n";
2566 
2567 	dopts.result = &ret;
2568 	dopts.num_items = 1;
2569 	dopts.item_size = size;
2570 	if (unlikely(flags != 0)) {
2571 		if ((flags & MALLOCX_LG_ALIGN_MASK) != 0) {
2572 			dopts.alignment = MALLOCX_ALIGN_GET_SPECIFIED(flags);
2573 		}
2574 
2575 		dopts.zero = MALLOCX_ZERO_GET(flags);
2576 
2577 		if ((flags & MALLOCX_TCACHE_MASK) != 0) {
2578 			if ((flags & MALLOCX_TCACHE_MASK)
2579 			    == MALLOCX_TCACHE_NONE) {
2580 				dopts.tcache_ind = TCACHE_IND_NONE;
2581 			} else {
2582 				dopts.tcache_ind = MALLOCX_TCACHE_GET(flags);
2583 			}
2584 		} else {
2585 			dopts.tcache_ind = TCACHE_IND_AUTOMATIC;
2586 		}
2587 
2588 		if ((flags & MALLOCX_ARENA_MASK) != 0)
2589 			dopts.arena_ind = MALLOCX_ARENA_GET(flags);
2590 	}
2591 
2592 	imalloc(&sopts, &dopts);
2593 
2594 	LOG("core.mallocx.exit", "result: %p", ret);
2595 	return ret;
2596 }
2597 
2598 static void *
2599 irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize,
2600     size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena,
2601     prof_tctx_t *tctx) {
2602 	void *p;
2603 
2604 	if (tctx == NULL) {
2605 		return NULL;
2606 	}
2607 	if (usize <= SMALL_MAXCLASS) {
2608 		p = iralloct(tsdn, old_ptr, old_usize, LARGE_MINCLASS,
2609 		    alignment, zero, tcache, arena);
2610 		if (p == NULL) {
2611 			return NULL;
2612 		}
2613 		arena_prof_promote(tsdn, p, usize);
2614 	} else {
2615 		p = iralloct(tsdn, old_ptr, old_usize, usize, alignment, zero,
2616 		    tcache, arena);
2617 	}
2618 
2619 	return p;
2620 }
2621 
2622 JEMALLOC_ALWAYS_INLINE void *
2623 irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
2624     size_t alignment, size_t *usize, bool zero, tcache_t *tcache,
2625     arena_t *arena, alloc_ctx_t *alloc_ctx) {
2626 	void *p;
2627 	bool prof_active;
2628 	prof_tctx_t *old_tctx, *tctx;
2629 
2630 	prof_active = prof_active_get_unlocked();
2631 	old_tctx = prof_tctx_get(tsd_tsdn(tsd), old_ptr, alloc_ctx);
2632 	tctx = prof_alloc_prep(tsd, *usize, prof_active, false);
2633 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
2634 		p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize,
2635 		    *usize, alignment, zero, tcache, arena, tctx);
2636 	} else {
2637 		p = iralloct(tsd_tsdn(tsd), old_ptr, old_usize, size, alignment,
2638 		    zero, tcache, arena);
2639 	}
2640 	if (unlikely(p == NULL)) {
2641 		prof_alloc_rollback(tsd, tctx, false);
2642 		return NULL;
2643 	}
2644 
2645 	if (p == old_ptr && alignment != 0) {
2646 		/*
2647 		 * The allocation did not move, so it is possible that the size
2648 		 * class is smaller than would guarantee the requested
2649 		 * alignment, and that the alignment constraint was
2650 		 * serendipitously satisfied.  Additionally, old_usize may not
2651 		 * be the same as the current usize because of in-place large
2652 		 * reallocation.  Therefore, query the actual value of usize.
2653 		 */
2654 		*usize = isalloc(tsd_tsdn(tsd), p);
2655 	}
2656 	prof_realloc(tsd, p, *usize, tctx, prof_active, false, old_ptr,
2657 	    old_usize, old_tctx);
2658 
2659 	return p;
2660 }
2661 
2662 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2663 void JEMALLOC_NOTHROW *
2664 JEMALLOC_ALLOC_SIZE(2)
2665 je_rallocx(void *ptr, size_t size, int flags) {
2666 	void *p;
2667 	tsd_t *tsd;
2668 	size_t usize;
2669 	size_t old_usize;
2670 	size_t alignment = MALLOCX_ALIGN_GET(flags);
2671 	bool zero = flags & MALLOCX_ZERO;
2672 	arena_t *arena;
2673 	tcache_t *tcache;
2674 
2675 	LOG("core.rallocx.entry", "ptr: %p, size: %zu, flags: %d", ptr,
2676 	    size, flags);
2677 
2678 
2679 	assert(ptr != NULL);
2680 	assert(size != 0);
2681 	assert(malloc_initialized() || IS_INITIALIZER);
2682 	tsd = tsd_fetch();
2683 	check_entry_exit_locking(tsd_tsdn(tsd));
2684 
2685 	if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) {
2686 		unsigned arena_ind = MALLOCX_ARENA_GET(flags);
2687 		arena = arena_get(tsd_tsdn(tsd), arena_ind, true);
2688 		if (unlikely(arena == NULL)) {
2689 			goto label_oom;
2690 		}
2691 	} else {
2692 		arena = NULL;
2693 	}
2694 
2695 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
2696 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) {
2697 			tcache = NULL;
2698 		} else {
2699 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
2700 		}
2701 	} else {
2702 		tcache = tcache_get(tsd);
2703 	}
2704 
2705 	alloc_ctx_t alloc_ctx;
2706 	rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2707 	rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2708 	    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2709 	assert(alloc_ctx.szind != NSIZES);
2710 	old_usize = sz_index2size(alloc_ctx.szind);
2711 	assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
2712 	if (config_prof && opt_prof) {
2713 		usize = (alignment == 0) ?
2714 		    sz_s2u(size) : sz_sa2u(size, alignment);
2715 		if (unlikely(usize == 0 || usize > LARGE_MAXCLASS)) {
2716 			goto label_oom;
2717 		}
2718 		p = irallocx_prof(tsd, ptr, old_usize, size, alignment, &usize,
2719 		    zero, tcache, arena, &alloc_ctx);
2720 		if (unlikely(p == NULL)) {
2721 			goto label_oom;
2722 		}
2723 	} else {
2724 		p = iralloct(tsd_tsdn(tsd), ptr, old_usize, size, alignment,
2725 		    zero, tcache, arena);
2726 		if (unlikely(p == NULL)) {
2727 			goto label_oom;
2728 		}
2729 		if (config_stats) {
2730 			usize = isalloc(tsd_tsdn(tsd), p);
2731 		}
2732 	}
2733 	assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0));
2734 
2735 	if (config_stats) {
2736 		*tsd_thread_allocatedp_get(tsd) += usize;
2737 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
2738 	}
2739 	UTRACE(ptr, size, p);
2740 	check_entry_exit_locking(tsd_tsdn(tsd));
2741 
2742 	LOG("core.rallocx.exit", "result: %p", p);
2743 	return p;
2744 label_oom:
2745 	if (config_xmalloc && unlikely(opt_xmalloc)) {
2746 		malloc_write("<jemalloc>: Error in rallocx(): out of memory\n");
2747 		abort();
2748 	}
2749 	UTRACE(ptr, size, 0);
2750 	check_entry_exit_locking(tsd_tsdn(tsd));
2751 
2752 	LOG("core.rallocx.exit", "result: %p", NULL);
2753 	return NULL;
2754 }
2755 
2756 JEMALLOC_ALWAYS_INLINE size_t
2757 ixallocx_helper(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size,
2758     size_t extra, size_t alignment, bool zero) {
2759 	size_t usize;
2760 
2761 	if (ixalloc(tsdn, ptr, old_usize, size, extra, alignment, zero)) {
2762 		return old_usize;
2763 	}
2764 	usize = isalloc(tsdn, ptr);
2765 
2766 	return usize;
2767 }
2768 
2769 static size_t
2770 ixallocx_prof_sample(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size,
2771     size_t extra, size_t alignment, bool zero, prof_tctx_t *tctx) {
2772 	size_t usize;
2773 
2774 	if (tctx == NULL) {
2775 		return old_usize;
2776 	}
2777 	usize = ixallocx_helper(tsdn, ptr, old_usize, size, extra, alignment,
2778 	    zero);
2779 
2780 	return usize;
2781 }
2782 
2783 JEMALLOC_ALWAYS_INLINE size_t
2784 ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size,
2785     size_t extra, size_t alignment, bool zero, alloc_ctx_t *alloc_ctx) {
2786 	size_t usize_max, usize;
2787 	bool prof_active;
2788 	prof_tctx_t *old_tctx, *tctx;
2789 
2790 	prof_active = prof_active_get_unlocked();
2791 	old_tctx = prof_tctx_get(tsd_tsdn(tsd), ptr, alloc_ctx);
2792 	/*
2793 	 * usize isn't knowable before ixalloc() returns when extra is non-zero.
2794 	 * Therefore, compute its maximum possible value and use that in
2795 	 * prof_alloc_prep() to decide whether to capture a backtrace.
2796 	 * prof_realloc() will use the actual usize to decide whether to sample.
2797 	 */
2798 	if (alignment == 0) {
2799 		usize_max = sz_s2u(size+extra);
2800 		assert(usize_max > 0 && usize_max <= LARGE_MAXCLASS);
2801 	} else {
2802 		usize_max = sz_sa2u(size+extra, alignment);
2803 		if (unlikely(usize_max == 0 || usize_max > LARGE_MAXCLASS)) {
2804 			/*
2805 			 * usize_max is out of range, and chances are that
2806 			 * allocation will fail, but use the maximum possible
2807 			 * value and carry on with prof_alloc_prep(), just in
2808 			 * case allocation succeeds.
2809 			 */
2810 			usize_max = LARGE_MAXCLASS;
2811 		}
2812 	}
2813 	tctx = prof_alloc_prep(tsd, usize_max, prof_active, false);
2814 
2815 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
2816 		usize = ixallocx_prof_sample(tsd_tsdn(tsd), ptr, old_usize,
2817 		    size, extra, alignment, zero, tctx);
2818 	} else {
2819 		usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size,
2820 		    extra, alignment, zero);
2821 	}
2822 	if (usize == old_usize) {
2823 		prof_alloc_rollback(tsd, tctx, false);
2824 		return usize;
2825 	}
2826 	prof_realloc(tsd, ptr, usize, tctx, prof_active, false, ptr, old_usize,
2827 	    old_tctx);
2828 
2829 	return usize;
2830 }
2831 
2832 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
2833 je_xallocx(void *ptr, size_t size, size_t extra, int flags) {
2834 	tsd_t *tsd;
2835 	size_t usize, old_usize;
2836 	size_t alignment = MALLOCX_ALIGN_GET(flags);
2837 	bool zero = flags & MALLOCX_ZERO;
2838 
2839 	LOG("core.xallocx.entry", "ptr: %p, size: %zu, extra: %zu, "
2840 	    "flags: %d", ptr, size, extra, flags);
2841 
2842 	assert(ptr != NULL);
2843 	assert(size != 0);
2844 	assert(SIZE_T_MAX - size >= extra);
2845 	assert(malloc_initialized() || IS_INITIALIZER);
2846 	tsd = tsd_fetch();
2847 	check_entry_exit_locking(tsd_tsdn(tsd));
2848 
2849 	alloc_ctx_t alloc_ctx;
2850 	rtree_ctx_t *rtree_ctx = tsd_rtree_ctx(tsd);
2851 	rtree_szind_slab_read(tsd_tsdn(tsd), &extents_rtree, rtree_ctx,
2852 	    (uintptr_t)ptr, true, &alloc_ctx.szind, &alloc_ctx.slab);
2853 	assert(alloc_ctx.szind != NSIZES);
2854 	old_usize = sz_index2size(alloc_ctx.szind);
2855 	assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
2856 	/*
2857 	 * The API explicitly absolves itself of protecting against (size +
2858 	 * extra) numerical overflow, but we may need to clamp extra to avoid
2859 	 * exceeding LARGE_MAXCLASS.
2860 	 *
2861 	 * Ordinarily, size limit checking is handled deeper down, but here we
2862 	 * have to check as part of (size + extra) clamping, since we need the
2863 	 * clamped value in the above helper functions.
2864 	 */
2865 	if (unlikely(size > LARGE_MAXCLASS)) {
2866 		usize = old_usize;
2867 		goto label_not_resized;
2868 	}
2869 	if (unlikely(LARGE_MAXCLASS - size < extra)) {
2870 		extra = LARGE_MAXCLASS - size;
2871 	}
2872 
2873 	if (config_prof && opt_prof) {
2874 		usize = ixallocx_prof(tsd, ptr, old_usize, size, extra,
2875 		    alignment, zero, &alloc_ctx);
2876 	} else {
2877 		usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size,
2878 		    extra, alignment, zero);
2879 	}
2880 	if (unlikely(usize == old_usize)) {
2881 		goto label_not_resized;
2882 	}
2883 
2884 	if (config_stats) {
2885 		*tsd_thread_allocatedp_get(tsd) += usize;
2886 		*tsd_thread_deallocatedp_get(tsd) += old_usize;
2887 	}
2888 label_not_resized:
2889 	UTRACE(ptr, size, ptr);
2890 	check_entry_exit_locking(tsd_tsdn(tsd));
2891 
2892 	LOG("core.xallocx.exit", "result: %zu", usize);
2893 	return usize;
2894 }
2895 
2896 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
2897 JEMALLOC_ATTR(pure)
2898 je_sallocx(const void *ptr, UNUSED int flags) {
2899 	size_t usize;
2900 	tsdn_t *tsdn;
2901 
2902 	LOG("core.sallocx.entry", "ptr: %p, flags: %d", ptr, flags);
2903 
2904 	assert(malloc_initialized() || IS_INITIALIZER);
2905 	assert(ptr != NULL);
2906 
2907 	tsdn = tsdn_fetch();
2908 	check_entry_exit_locking(tsdn);
2909 
2910 	if (config_debug || force_ivsalloc) {
2911 		usize = ivsalloc(tsdn, ptr);
2912 		assert(force_ivsalloc || usize != 0);
2913 	} else {
2914 		usize = isalloc(tsdn, ptr);
2915 	}
2916 
2917 	check_entry_exit_locking(tsdn);
2918 
2919 	LOG("core.sallocx.exit", "result: %zu", usize);
2920 	return usize;
2921 }
2922 
2923 JEMALLOC_EXPORT void JEMALLOC_NOTHROW
2924 je_dallocx(void *ptr, int flags) {
2925 	LOG("core.dallocx.entry", "ptr: %p, flags: %d", ptr, flags);
2926 
2927 	assert(ptr != NULL);
2928 	assert(malloc_initialized() || IS_INITIALIZER);
2929 
2930 	tsd_t *tsd = tsd_fetch();
2931 	bool fast = tsd_fast(tsd);
2932 	check_entry_exit_locking(tsd_tsdn(tsd));
2933 
2934 	tcache_t *tcache;
2935 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
2936 		/* Not allowed to be reentrant and specify a custom tcache. */
2937 		assert(tsd_reentrancy_level_get(tsd) == 0);
2938 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) {
2939 			tcache = NULL;
2940 		} else {
2941 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
2942 		}
2943 	} else {
2944 		if (likely(fast)) {
2945 			tcache = tsd_tcachep_get(tsd);
2946 			assert(tcache == tcache_get(tsd));
2947 		} else {
2948 			if (likely(tsd_reentrancy_level_get(tsd) == 0)) {
2949 				tcache = tcache_get(tsd);
2950 			}  else {
2951 				tcache = NULL;
2952 			}
2953 		}
2954 	}
2955 
2956 	UTRACE(ptr, 0, 0);
2957 	if (likely(fast)) {
2958 		tsd_assert_fast(tsd);
2959 		ifree(tsd, ptr, tcache, false);
2960 	} else {
2961 		ifree(tsd, ptr, tcache, true);
2962 	}
2963 	check_entry_exit_locking(tsd_tsdn(tsd));
2964 
2965 	LOG("core.dallocx.exit", "");
2966 }
2967 
2968 JEMALLOC_ALWAYS_INLINE size_t
2969 inallocx(tsdn_t *tsdn, size_t size, int flags) {
2970 	check_entry_exit_locking(tsdn);
2971 
2972 	size_t usize;
2973 	if (likely((flags & MALLOCX_LG_ALIGN_MASK) == 0)) {
2974 		usize = sz_s2u(size);
2975 	} else {
2976 		usize = sz_sa2u(size, MALLOCX_ALIGN_GET_SPECIFIED(flags));
2977 	}
2978 	check_entry_exit_locking(tsdn);
2979 	return usize;
2980 }
2981 
2982 JEMALLOC_EXPORT void JEMALLOC_NOTHROW
2983 je_sdallocx(void *ptr, size_t size, int flags) {
2984 	assert(ptr != NULL);
2985 	assert(malloc_initialized() || IS_INITIALIZER);
2986 
2987 	LOG("core.sdallocx.entry", "ptr: %p, size: %zu, flags: %d", ptr,
2988 	    size, flags);
2989 
2990 	tsd_t *tsd = tsd_fetch();
2991 	bool fast = tsd_fast(tsd);
2992 	size_t usize = inallocx(tsd_tsdn(tsd), size, flags);
2993 	assert(usize == isalloc(tsd_tsdn(tsd), ptr));
2994 	check_entry_exit_locking(tsd_tsdn(tsd));
2995 
2996 	tcache_t *tcache;
2997 	if (unlikely((flags & MALLOCX_TCACHE_MASK) != 0)) {
2998 		/* Not allowed to be reentrant and specify a custom tcache. */
2999 		assert(tsd_reentrancy_level_get(tsd) == 0);
3000 		if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) {
3001 			tcache = NULL;
3002 		} else {
3003 			tcache = tcaches_get(tsd, MALLOCX_TCACHE_GET(flags));
3004 		}
3005 	} else {
3006 		if (likely(fast)) {
3007 			tcache = tsd_tcachep_get(tsd);
3008 			assert(tcache == tcache_get(tsd));
3009 		} else {
3010 			if (likely(tsd_reentrancy_level_get(tsd) == 0)) {
3011 				tcache = tcache_get(tsd);
3012 			} else {
3013 				tcache = NULL;
3014 			}
3015 		}
3016 	}
3017 
3018 	UTRACE(ptr, 0, 0);
3019 	if (likely(fast)) {
3020 		tsd_assert_fast(tsd);
3021 		isfree(tsd, ptr, usize, tcache, false);
3022 	} else {
3023 		isfree(tsd, ptr, usize, tcache, true);
3024 	}
3025 	check_entry_exit_locking(tsd_tsdn(tsd));
3026 
3027 	LOG("core.sdallocx.exit", "");
3028 }
3029 
3030 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
3031 JEMALLOC_ATTR(pure)
3032 je_nallocx(size_t size, int flags) {
3033 	size_t usize;
3034 	tsdn_t *tsdn;
3035 
3036 	assert(size != 0);
3037 
3038 	if (unlikely(malloc_init())) {
3039 		LOG("core.nallocx.exit", "result: %zu", ZU(0));
3040 		return 0;
3041 	}
3042 
3043 	tsdn = tsdn_fetch();
3044 	check_entry_exit_locking(tsdn);
3045 
3046 	usize = inallocx(tsdn, size, flags);
3047 	if (unlikely(usize > LARGE_MAXCLASS)) {
3048 		LOG("core.nallocx.exit", "result: %zu", ZU(0));
3049 		return 0;
3050 	}
3051 
3052 	check_entry_exit_locking(tsdn);
3053 	LOG("core.nallocx.exit", "result: %zu", usize);
3054 	return usize;
3055 }
3056 
3057 JEMALLOC_EXPORT int JEMALLOC_NOTHROW
3058 je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
3059     size_t newlen) {
3060 	int ret;
3061 	tsd_t *tsd;
3062 
3063 	LOG("core.mallctl.entry", "name: %s", name);
3064 
3065 	if (unlikely(malloc_init())) {
3066 		LOG("core.mallctl.exit", "result: %d", EAGAIN);
3067 		return EAGAIN;
3068 	}
3069 
3070 	tsd = tsd_fetch();
3071 	check_entry_exit_locking(tsd_tsdn(tsd));
3072 	ret = ctl_byname(tsd, name, oldp, oldlenp, newp, newlen);
3073 	check_entry_exit_locking(tsd_tsdn(tsd));
3074 
3075 	LOG("core.mallctl.exit", "result: %d", ret);
3076 	return ret;
3077 }
3078 
3079 JEMALLOC_EXPORT int JEMALLOC_NOTHROW
3080 je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) {
3081 	int ret;
3082 
3083 	LOG("core.mallctlnametomib.entry", "name: %s", name);
3084 
3085 	if (unlikely(malloc_init())) {
3086 		LOG("core.mallctlnametomib.exit", "result: %d", EAGAIN);
3087 		return EAGAIN;
3088 	}
3089 
3090 	tsd_t *tsd = tsd_fetch();
3091 	check_entry_exit_locking(tsd_tsdn(tsd));
3092 	ret = ctl_nametomib(tsd, name, mibp, miblenp);
3093 	check_entry_exit_locking(tsd_tsdn(tsd));
3094 
3095 	LOG("core.mallctlnametomib.exit", "result: %d", ret);
3096 	return ret;
3097 }
3098 
3099 JEMALLOC_EXPORT int JEMALLOC_NOTHROW
3100 je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
3101   void *newp, size_t newlen) {
3102 	int ret;
3103 	tsd_t *tsd;
3104 
3105 	LOG("core.mallctlbymib.entry", "");
3106 
3107 	if (unlikely(malloc_init())) {
3108 		LOG("core.mallctlbymib.exit", "result: %d", EAGAIN);
3109 		return EAGAIN;
3110 	}
3111 
3112 	tsd = tsd_fetch();
3113 	check_entry_exit_locking(tsd_tsdn(tsd));
3114 	ret = ctl_bymib(tsd, mib, miblen, oldp, oldlenp, newp, newlen);
3115 	check_entry_exit_locking(tsd_tsdn(tsd));
3116 	LOG("core.mallctlbymib.exit", "result: %d", ret);
3117 	return ret;
3118 }
3119 
3120 JEMALLOC_EXPORT void JEMALLOC_NOTHROW
3121 je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
3122     const char *opts) {
3123 	tsdn_t *tsdn;
3124 
3125 	LOG("core.malloc_stats_print.entry", "");
3126 
3127 	tsdn = tsdn_fetch();
3128 	check_entry_exit_locking(tsdn);
3129 	stats_print(write_cb, cbopaque, opts);
3130 	check_entry_exit_locking(tsdn);
3131 	LOG("core.malloc_stats_print.exit", "");
3132 }
3133 
3134 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
3135 je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) {
3136 	size_t ret;
3137 	tsdn_t *tsdn;
3138 
3139 	LOG("core.malloc_usable_size.entry", "ptr: %p", ptr);
3140 
3141 	assert(malloc_initialized() || IS_INITIALIZER);
3142 
3143 	tsdn = tsdn_fetch();
3144 	check_entry_exit_locking(tsdn);
3145 
3146 	if (unlikely(ptr == NULL)) {
3147 		ret = 0;
3148 	} else {
3149 		if (config_debug || force_ivsalloc) {
3150 			ret = ivsalloc(tsdn, ptr);
3151 			assert(force_ivsalloc || ret != 0);
3152 		} else {
3153 			ret = isalloc(tsdn, ptr);
3154 		}
3155 	}
3156 
3157 	check_entry_exit_locking(tsdn);
3158 	LOG("core.malloc_usable_size.exit", "result: %zu", ret);
3159 	return ret;
3160 }
3161 
3162 /*
3163  * End non-standard functions.
3164  */
3165 /******************************************************************************/
3166 /*
3167  * Begin compatibility functions.
3168  */
3169 
3170 #define	ALLOCM_LG_ALIGN(la)	(la)
3171 #define	ALLOCM_ALIGN(a)		(ffsl(a)-1)
3172 #define	ALLOCM_ZERO		((int)0x40)
3173 #define	ALLOCM_NO_MOVE		((int)0x80)
3174 
3175 #define	ALLOCM_SUCCESS		0
3176 #define	ALLOCM_ERR_OOM		1
3177 #define	ALLOCM_ERR_NOT_MOVED	2
3178 
3179 int
3180 je_allocm(void **ptr, size_t *rsize, size_t size, int flags) {
3181 	assert(ptr != NULL);
3182 
3183 	void *p = je_mallocx(size, flags);
3184 	if (p == NULL) {
3185 		return (ALLOCM_ERR_OOM);
3186 	}
3187 	if (rsize != NULL) {
3188 		*rsize = isalloc(tsdn_fetch(), p);
3189 	}
3190 	*ptr = p;
3191 	return ALLOCM_SUCCESS;
3192 }
3193 
3194 int
3195 je_rallocm(void **ptr, size_t *rsize, size_t size, size_t extra, int flags) {
3196 	assert(ptr != NULL);
3197 	assert(*ptr != NULL);
3198 	assert(size != 0);
3199 	assert(SIZE_T_MAX - size >= extra);
3200 
3201 	int ret;
3202 	bool no_move = flags & ALLOCM_NO_MOVE;
3203 
3204 	if (no_move) {
3205 		size_t usize = je_xallocx(*ptr, size, extra, flags);
3206 		ret = (usize >= size) ? ALLOCM_SUCCESS : ALLOCM_ERR_NOT_MOVED;
3207 		if (rsize != NULL) {
3208 			*rsize = usize;
3209 		}
3210 	} else {
3211 		void *p = je_rallocx(*ptr, size+extra, flags);
3212 		if (p != NULL) {
3213 			*ptr = p;
3214 			ret = ALLOCM_SUCCESS;
3215 		} else {
3216 			ret = ALLOCM_ERR_OOM;
3217 		}
3218 		if (rsize != NULL) {
3219 			*rsize = isalloc(tsdn_fetch(), *ptr);
3220 		}
3221 	}
3222 	return ret;
3223 }
3224 
3225 int
3226 je_sallocm(const void *ptr, size_t *rsize, int flags) {
3227 	assert(rsize != NULL);
3228 	*rsize = je_sallocx(ptr, flags);
3229 	return ALLOCM_SUCCESS;
3230 }
3231 
3232 int
3233 je_dallocm(void *ptr, int flags) {
3234 	je_dallocx(ptr, flags);
3235 	return ALLOCM_SUCCESS;
3236 }
3237 
3238 int
3239 je_nallocm(size_t *rsize, size_t size, int flags) {
3240 	size_t usize = je_nallocx(size, flags);
3241 	if (usize == 0) {
3242 		return ALLOCM_ERR_OOM;
3243 	}
3244 	if (rsize != NULL) {
3245 		*rsize = usize;
3246 	}
3247 	return ALLOCM_SUCCESS;
3248 }
3249 
3250 #undef ALLOCM_LG_ALIGN
3251 #undef ALLOCM_ALIGN
3252 #undef ALLOCM_ZERO
3253 #undef ALLOCM_NO_MOVE
3254 
3255 #undef ALLOCM_SUCCESS
3256 #undef ALLOCM_ERR_OOM
3257 #undef ALLOCM_ERR_NOT_MOVED
3258 
3259 /*
3260  * End compatibility functions.
3261  */
3262 /******************************************************************************/
3263 /*
3264  * The following functions are used by threading libraries for protection of
3265  * malloc during fork().
3266  */
3267 
3268 /*
3269  * If an application creates a thread before doing any allocation in the main
3270  * thread, then calls fork(2) in the main thread followed by memory allocation
3271  * in the child process, a race can occur that results in deadlock within the
3272  * child: the main thread may have forked while the created thread had
3273  * partially initialized the allocator.  Ordinarily jemalloc prevents
3274  * fork/malloc races via the following functions it registers during
3275  * initialization using pthread_atfork(), but of course that does no good if
3276  * the allocator isn't fully initialized at fork time.  The following library
3277  * constructor is a partial solution to this problem.  It may still be possible
3278  * to trigger the deadlock described above, but doing so would involve forking
3279  * via a library constructor that runs before jemalloc's runs.
3280  */
3281 #ifndef JEMALLOC_JET
3282 JEMALLOC_ATTR(constructor)
3283 static void
3284 jemalloc_constructor(void) {
3285 	malloc_init();
3286 }
3287 #endif
3288 
3289 #ifndef JEMALLOC_MUTEX_INIT_CB
3290 void
3291 jemalloc_prefork(void)
3292 #else
3293 JEMALLOC_EXPORT void
3294 _malloc_prefork(void)
3295 #endif
3296 {
3297 	tsd_t *tsd;
3298 	unsigned i, j, narenas;
3299 	arena_t *arena;
3300 
3301 #ifdef JEMALLOC_MUTEX_INIT_CB
3302 	if (!malloc_initialized()) {
3303 		return;
3304 	}
3305 #endif
3306 	assert(malloc_initialized());
3307 
3308 	tsd = tsd_fetch();
3309 
3310 	narenas = narenas_total_get();
3311 
3312 	witness_prefork(tsd_witness_tsdp_get(tsd));
3313 	/* Acquire all mutexes in a safe order. */
3314 	ctl_prefork(tsd_tsdn(tsd));
3315 	tcache_prefork(tsd_tsdn(tsd));
3316 	malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock);
3317 	if (have_background_thread) {
3318 		background_thread_prefork0(tsd_tsdn(tsd));
3319 	}
3320 	prof_prefork0(tsd_tsdn(tsd));
3321 	if (have_background_thread) {
3322 		background_thread_prefork1(tsd_tsdn(tsd));
3323 	}
3324 	/* Break arena prefork into stages to preserve lock order. */
3325 	for (i = 0; i < 8; i++) {
3326 		for (j = 0; j < narenas; j++) {
3327 			if ((arena = arena_get(tsd_tsdn(tsd), j, false)) !=
3328 			    NULL) {
3329 				switch (i) {
3330 				case 0:
3331 					arena_prefork0(tsd_tsdn(tsd), arena);
3332 					break;
3333 				case 1:
3334 					arena_prefork1(tsd_tsdn(tsd), arena);
3335 					break;
3336 				case 2:
3337 					arena_prefork2(tsd_tsdn(tsd), arena);
3338 					break;
3339 				case 3:
3340 					arena_prefork3(tsd_tsdn(tsd), arena);
3341 					break;
3342 				case 4:
3343 					arena_prefork4(tsd_tsdn(tsd), arena);
3344 					break;
3345 				case 5:
3346 					arena_prefork5(tsd_tsdn(tsd), arena);
3347 					break;
3348 				case 6:
3349 					arena_prefork6(tsd_tsdn(tsd), arena);
3350 					break;
3351 				case 7:
3352 					arena_prefork7(tsd_tsdn(tsd), arena);
3353 					break;
3354 				default: not_reached();
3355 				}
3356 			}
3357 		}
3358 	}
3359 	prof_prefork1(tsd_tsdn(tsd));
3360 }
3361 
3362 #ifndef JEMALLOC_MUTEX_INIT_CB
3363 void
3364 jemalloc_postfork_parent(void)
3365 #else
3366 JEMALLOC_EXPORT void
3367 _malloc_postfork(void)
3368 #endif
3369 {
3370 	tsd_t *tsd;
3371 	unsigned i, narenas;
3372 
3373 #ifdef JEMALLOC_MUTEX_INIT_CB
3374 	if (!malloc_initialized()) {
3375 		return;
3376 	}
3377 #endif
3378 	assert(malloc_initialized());
3379 
3380 	tsd = tsd_fetch();
3381 
3382 	witness_postfork_parent(tsd_witness_tsdp_get(tsd));
3383 	/* Release all mutexes, now that fork() has completed. */
3384 	for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
3385 		arena_t *arena;
3386 
3387 		if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
3388 			arena_postfork_parent(tsd_tsdn(tsd), arena);
3389 		}
3390 	}
3391 	prof_postfork_parent(tsd_tsdn(tsd));
3392 	if (have_background_thread) {
3393 		background_thread_postfork_parent(tsd_tsdn(tsd));
3394 	}
3395 	malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock);
3396 	tcache_postfork_parent(tsd_tsdn(tsd));
3397 	ctl_postfork_parent(tsd_tsdn(tsd));
3398 }
3399 
3400 void
3401 jemalloc_postfork_child(void) {
3402 	tsd_t *tsd;
3403 	unsigned i, narenas;
3404 
3405 	assert(malloc_initialized());
3406 
3407 	tsd = tsd_fetch();
3408 
3409 	witness_postfork_child(tsd_witness_tsdp_get(tsd));
3410 	/* Release all mutexes, now that fork() has completed. */
3411 	for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
3412 		arena_t *arena;
3413 
3414 		if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
3415 			arena_postfork_child(tsd_tsdn(tsd), arena);
3416 		}
3417 	}
3418 	prof_postfork_child(tsd_tsdn(tsd));
3419 	if (have_background_thread) {
3420 		background_thread_postfork_child(tsd_tsdn(tsd));
3421 	}
3422 	malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock);
3423 	tcache_postfork_child(tsd_tsdn(tsd));
3424 	ctl_postfork_child(tsd_tsdn(tsd));
3425 }
3426 
3427 void
3428 _malloc_first_thread(void)
3429 {
3430 
3431 	(void)malloc_mutex_first_thread();
3432 }
3433 
3434 /******************************************************************************/
3435