xref: /netbsd-src/external/bsd/jemalloc/dist/src/jemalloc.c (revision b68c02f57bb10af27f5a72b552f71ce0b9a0e96f)
1 #include <sys/cdefs.h>
2 
3 #ifdef __NetBSD__
4 #include "extern.h"
5 #endif
6 
7 #define JEMALLOC_C_
8 #include "jemalloc/internal/jemalloc_preamble.h"
9 #include "jemalloc/internal/jemalloc_internal_includes.h"
10 
11 #include "jemalloc/internal/assert.h"
12 #include "jemalloc/internal/atomic.h"
13 #include "jemalloc/internal/buf_writer.h"
14 #include "jemalloc/internal/ctl.h"
15 #include "jemalloc/internal/emap.h"
16 #include "jemalloc/internal/extent_dss.h"
17 #include "jemalloc/internal/extent_mmap.h"
18 #include "jemalloc/internal/fxp.h"
19 #include "jemalloc/internal/san.h"
20 #include "jemalloc/internal/hook.h"
21 #include "jemalloc/internal/jemalloc_internal_types.h"
22 #include "jemalloc/internal/log.h"
23 #include "jemalloc/internal/malloc_io.h"
24 #include "jemalloc/internal/mutex.h"
25 #include "jemalloc/internal/nstime.h"
26 #include "jemalloc/internal/rtree.h"
27 #include "jemalloc/internal/safety_check.h"
28 #include "jemalloc/internal/sc.h"
29 #include "jemalloc/internal/spin.h"
30 #include "jemalloc/internal/sz.h"
31 #include "jemalloc/internal/ticker.h"
32 #include "jemalloc/internal/thread_event.h"
33 #include "jemalloc/internal/util.h"
34 
35 #ifdef JEMALLOC_WEAK_NOSTD
36 __weak_alias(mallocx, __je_mallocx)
37 __weak_alias(rallocx, __je_rallocx)
38 __weak_alias(xallocx, __je_xallocx)
39 __weak_alias(sallocx, __je_sallocx)
40 __weak_alias(dallocx, __je_dallocx)
41 __weak_alias(sdallocx, __je_sdallocx)
42 __weak_alias(nallocx, __je_nallocx)
43 
44 __weak_alias(mallctl, __je_mallctl)
45 __weak_alias(mallctlnametomib, __je_mallctlnametomib)
46 __weak_alias(mallctlbymib, __je_mallctlbymib)
47 
48 __weak_alias(malloc_stats_print, __je_malloc_stats_print)
49 __weak_alias(malloc_usable_size, __je_malloc_usable_size)
50 
51 __weak_alias(malloc_message, __je_malloc_message)
52 __weak_alias(malloc_conf, __je_malloc_conf)
53 
54 #endif
55 
56 /******************************************************************************/
57 /* Data. */
58 
59 /* Runtime configuration options. */
60 const char	*je_malloc_conf
61 #ifndef _WIN32
62     JEMALLOC_ATTR(weak)
63 #endif
64     ;
65 /*
66  * The usual rule is that the closer to runtime you are, the higher priority
67  * your configuration settings are (so the jemalloc config options get lower
68  * priority than the per-binary setting, which gets lower priority than the /etc
69  * setting, which gets lower priority than the environment settings).
70  *
71  * But it's a fairly common use case in some testing environments for a user to
72  * be able to control the binary, but nothing else (e.g. a performancy canary
73  * uses the production OS and environment variables, but can run any binary in
74  * those circumstances).  For these use cases, it's handy to have an in-binary
75  * mechanism for overriding environment variable settings, with the idea that if
76  * the results are positive they get promoted to the official settings, and
77  * moved from the binary to the environment variable.
78  *
79  * We don't actually want this to be widespread, so we'll give it a silly name
80  * and not mention it in headers or documentation.
81  */
82 const char	*je_malloc_conf_2_conf_harder
83 #ifndef _WIN32
84     JEMALLOC_ATTR(weak)
85 #endif
86     ;
87 
88 bool	opt_abort =
89 #ifdef JEMALLOC_DEBUG
90     true
91 #else
92     false
93 #endif
94     ;
95 bool	opt_abort_conf =
96 #ifdef JEMALLOC_DEBUG
97     true
98 #else
99     false
100 #endif
101     ;
102 /* Intentionally default off, even with debug builds. */
103 bool	opt_confirm_conf = false;
104 const char	*opt_junk =
105 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
106     "true"
107 #else
108     "false"
109 #endif
110     ;
111 bool	opt_junk_alloc =
112 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
113     true
114 #else
115     false
116 #endif
117     ;
118 bool	opt_junk_free =
119 #if (defined(JEMALLOC_DEBUG) && defined(JEMALLOC_FILL))
120     true
121 #else
122     false
123 #endif
124     ;
125 bool	opt_trust_madvise =
126 #ifdef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS
127     false
128 #else
129     true
130 #endif
131     ;
132 
133 bool opt_cache_oblivious =
134 #ifdef JEMALLOC_CACHE_OBLIVIOUS
135     true
136 #else
137     false
138 #endif
139     ;
140 
141 zero_realloc_action_t opt_zero_realloc_action =
142 #ifdef JEMALLOC_ZERO_REALLOC_DEFAULT_FREE
143     zero_realloc_action_free
144 #else
145     zero_realloc_action_alloc
146 #endif
147     ;
148 
149 atomic_zu_t zero_realloc_count = ATOMIC_INIT(0);
150 
151 const char *zero_realloc_mode_names[] = {
152 	"alloc",
153 	"free",
154 	"abort",
155 };
156 
157 /*
158  * These are the documented values for junk fill debugging facilities -- see the
159  * man page.
160  */
161 static const uint8_t junk_alloc_byte = 0xa5;
162 static const uint8_t junk_free_byte = 0x5a;
163 
164 static void default_junk_alloc(void *ptr, size_t usize) {
165 	memset(ptr, junk_alloc_byte, usize);
166 }
167 
168 static void default_junk_free(void *ptr, size_t usize) {
169 	memset(ptr, junk_free_byte, usize);
170 }
171 
172 void (*junk_alloc_callback)(void *ptr, size_t size) = &default_junk_alloc;
173 void (*junk_free_callback)(void *ptr, size_t size) = &default_junk_free;
174 
175 bool	opt_utrace = false;
176 bool	opt_xmalloc = false;
177 bool	opt_experimental_infallible_new = false;
178 bool	opt_zero = false;
179 unsigned	opt_narenas = 0;
180 fxp_t		opt_narenas_ratio = FXP_INIT_INT(4);
181 
182 unsigned	ncpus;
183 
184 /* Protects arenas initialization. */
185 malloc_mutex_t arenas_lock;
186 
187 /* The global hpa, and whether it's on. */
188 bool opt_hpa = false;
189 hpa_shard_opts_t opt_hpa_opts = HPA_SHARD_OPTS_DEFAULT;
190 sec_opts_t opt_hpa_sec_opts = SEC_OPTS_DEFAULT;
191 
192 /*
193  * Arenas that are used to service external requests.  Not all elements of the
194  * arenas array are necessarily used; arenas are created lazily as needed.
195  *
196  * arenas[0..narenas_auto) are used for automatic multiplexing of threads and
197  * arenas.  arenas[narenas_auto..narenas_total) are only used if the application
198  * takes some action to create them and allocate from them.
199  *
200  * Points to an arena_t.
201  */
202 JEMALLOC_ALIGNED(CACHELINE)
203 atomic_p_t		arenas[MALLOCX_ARENA_LIMIT];
204 static atomic_u_t	narenas_total; /* Use narenas_total_*(). */
205 /* Below three are read-only after initialization. */
206 static arena_t		*a0; /* arenas[0]. */
207 unsigned		narenas_auto;
208 unsigned		manual_arena_base;
209 
210 malloc_init_t malloc_init_state = malloc_init_uninitialized;
211 
212 /* False should be the common case.  Set to true to trigger initialization. */
213 bool			malloc_slow = true;
214 
215 /* When malloc_slow is true, set the corresponding bits for sanity check. */
216 enum {
217 	flag_opt_junk_alloc	= (1U),
218 	flag_opt_junk_free	= (1U << 1),
219 	flag_opt_zero		= (1U << 2),
220 	flag_opt_utrace		= (1U << 3),
221 	flag_opt_xmalloc	= (1U << 4)
222 };
223 static uint8_t	malloc_slow_flags;
224 
225 #ifdef JEMALLOC_THREADED_INIT
226 /* Used to let the initializing thread recursively allocate. */
227 #  define NO_INITIALIZER	((unsigned long)0)
228 #  define INITIALIZER		pthread_self()
229 #  define IS_INITIALIZER	(malloc_initializer == pthread_self())
230 static pthread_t		malloc_initializer = NO_INITIALIZER;
231 #else
232 #  define NO_INITIALIZER	false
233 #  define INITIALIZER		true
234 #  define IS_INITIALIZER	malloc_initializer
235 static bool			malloc_initializer = NO_INITIALIZER;
236 #endif
237 
238 /* Used to avoid initialization races. */
239 #ifdef _WIN32
240 #if _WIN32_WINNT >= 0x0600
241 static malloc_mutex_t	init_lock = SRWLOCK_INIT;
242 #else
243 static malloc_mutex_t	init_lock;
244 static bool init_lock_initialized = false;
245 
246 JEMALLOC_ATTR(constructor)
247 static void WINAPI
248 _init_init_lock(void) {
249 	/*
250 	 * If another constructor in the same binary is using mallctl to e.g.
251 	 * set up extent hooks, it may end up running before this one, and
252 	 * malloc_init_hard will crash trying to lock the uninitialized lock. So
253 	 * we force an initialization of the lock in malloc_init_hard as well.
254 	 * We don't try to care about atomicity of the accessed to the
255 	 * init_lock_initialized boolean, since it really only matters early in
256 	 * the process creation, before any separate thread normally starts
257 	 * doing anything.
258 	 */
259 	if (!init_lock_initialized) {
260 		malloc_mutex_init(&init_lock, "init", WITNESS_RANK_INIT,
261 		    malloc_mutex_rank_exclusive);
262 	}
263 	init_lock_initialized = true;
264 }
265 
266 #ifdef _MSC_VER
267 #  pragma section(".CRT$XCU", read)
268 JEMALLOC_SECTION(".CRT$XCU") JEMALLOC_ATTR(used)
269 static const void (WINAPI *init_init_lock)(void) = _init_init_lock;
270 #endif
271 #endif
272 #else
273 static malloc_mutex_t	init_lock = MALLOC_MUTEX_INITIALIZER;
274 #endif
275 
276 typedef struct {
277 	void	*p;	/* Input pointer (as in realloc(p, s)). */
278 	size_t	s;	/* Request size. */
279 	void	*r;	/* Result pointer. */
280 } malloc_utrace_t;
281 
282 #ifdef JEMALLOC_UTRACE
283 #  define UTRACE(a, b, c) do {						\
284 	if (unlikely(opt_utrace)) {					\
285 		int utrace_serrno = errno;				\
286 		malloc_utrace_t ut;					\
287 		ut.p = (a);						\
288 		ut.s = (b);						\
289 		ut.r = (c);						\
290 		UTRACE_CALL(&ut, sizeof(ut));				\
291 		errno = utrace_serrno;					\
292 	}								\
293 } while (0)
294 #else
295 #  define UTRACE(a, b, c)
296 #endif
297 
298 /* Whether encountered any invalid config options. */
299 static bool had_conf_error = false;
300 
301 /******************************************************************************/
302 /*
303  * Function prototypes for static functions that are referenced prior to
304  * definition.
305  */
306 
307 static bool	malloc_init_hard_a0(void);
308 static bool	malloc_init_hard(void);
309 
310 /******************************************************************************/
311 /*
312  * Begin miscellaneous support functions.
313  */
314 
315 JEMALLOC_ALWAYS_INLINE bool
316 malloc_init_a0(void) {
317 	if (unlikely(malloc_init_state == malloc_init_uninitialized)) {
318 		return malloc_init_hard_a0();
319 	}
320 	return false;
321 }
322 
323 JEMALLOC_ALWAYS_INLINE bool
324 malloc_init(void) {
325 	if (unlikely(!malloc_initialized()) && malloc_init_hard()) {
326 		return true;
327 	}
328 	return false;
329 }
330 
331 /*
332  * The a0*() functions are used instead of i{d,}alloc() in situations that
333  * cannot tolerate TLS variable access.
334  */
335 
336 static void *
337 a0ialloc(size_t size, bool zero, bool is_internal) {
338 	if (unlikely(malloc_init_a0())) {
339 		return NULL;
340 	}
341 
342 	return iallocztm(TSDN_NULL, size, sz_size2index(size), zero, NULL,
343 	    is_internal, arena_get(TSDN_NULL, 0, true), true);
344 }
345 
346 static void
347 a0idalloc(void *ptr, bool is_internal) {
348 	idalloctm(TSDN_NULL, ptr, NULL, NULL, is_internal, true);
349 }
350 
351 void *
352 a0malloc(size_t size) {
353 	return a0ialloc(size, false, true);
354 }
355 
356 void
357 a0dalloc(void *ptr) {
358 	a0idalloc(ptr, true);
359 }
360 
361 /*
362  * FreeBSD's libc uses the bootstrap_*() functions in bootstrap-sensitive
363  * situations that cannot tolerate TLS variable access (TLS allocation and very
364  * early internal data structure initialization).
365  */
366 
367 void *
368 bootstrap_malloc(size_t size) {
369 	if (unlikely(size == 0)) {
370 		size = 1;
371 	}
372 
373 	return a0ialloc(size, false, false);
374 }
375 
376 void *
377 bootstrap_calloc(size_t num, size_t size) {
378 	size_t num_size;
379 
380 	num_size = num * size;
381 	if (unlikely(num_size == 0)) {
382 		assert(num == 0 || size == 0);
383 		num_size = 1;
384 	}
385 
386 	return a0ialloc(num_size, true, false);
387 }
388 
389 void
390 bootstrap_free(void *ptr) {
391 	if (unlikely(ptr == NULL)) {
392 		return;
393 	}
394 
395 	a0idalloc(ptr, false);
396 }
397 
398 void
399 arena_set(unsigned ind, arena_t *arena) {
400 	atomic_store_p(&arenas[ind], arena, ATOMIC_RELEASE);
401 }
402 
403 static void
404 narenas_total_set(unsigned narenas) {
405 	atomic_store_u(&narenas_total, narenas, ATOMIC_RELEASE);
406 }
407 
408 static void
409 narenas_total_inc(void) {
410 	atomic_fetch_add_u(&narenas_total, 1, ATOMIC_RELEASE);
411 }
412 
413 unsigned
414 narenas_total_get(void) {
415 	return atomic_load_u(&narenas_total, ATOMIC_ACQUIRE);
416 }
417 
418 /* Create a new arena and insert it into the arenas array at index ind. */
419 static arena_t *
420 arena_init_locked(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
421 	arena_t *arena;
422 
423 	assert(ind <= narenas_total_get());
424 	if (ind >= MALLOCX_ARENA_LIMIT) {
425 		return NULL;
426 	}
427 	if (ind == narenas_total_get()) {
428 		narenas_total_inc();
429 	}
430 
431 	/*
432 	 * Another thread may have already initialized arenas[ind] if it's an
433 	 * auto arena.
434 	 */
435 	arena = arena_get(tsdn, ind, false);
436 	if (arena != NULL) {
437 		assert(arena_is_auto(arena));
438 		return arena;
439 	}
440 
441 	/* Actually initialize the arena. */
442 	arena = arena_new(tsdn, ind, config);
443 
444 	return arena;
445 }
446 
447 static void
448 arena_new_create_background_thread(tsdn_t *tsdn, unsigned ind) {
449 	if (ind == 0) {
450 		return;
451 	}
452 	/*
453 	 * Avoid creating a new background thread just for the huge arena, which
454 	 * purges eagerly by default.
455 	 */
456 	if (have_background_thread && !arena_is_huge(ind)) {
457 		if (background_thread_create(tsdn_tsd(tsdn), ind)) {
458 			malloc_printf("<jemalloc>: error in background thread "
459 				      "creation for arena %u. Abort.\n", ind);
460 			abort();
461 		}
462 	}
463 }
464 
465 arena_t *
466 arena_init(tsdn_t *tsdn, unsigned ind, const arena_config_t *config) {
467 	arena_t *arena;
468 
469 	malloc_mutex_lock(tsdn, &arenas_lock);
470 	arena = arena_init_locked(tsdn, ind, config);
471 	malloc_mutex_unlock(tsdn, &arenas_lock);
472 
473 	arena_new_create_background_thread(tsdn, ind);
474 
475 	return arena;
476 }
477 
478 static void
479 arena_bind(tsd_t *tsd, unsigned ind, bool internal) {
480 	arena_t *arena = arena_get(tsd_tsdn(tsd), ind, false);
481 	arena_nthreads_inc(arena, internal);
482 
483 	if (internal) {
484 		tsd_iarena_set(tsd, arena);
485 	} else {
486 		tsd_arena_set(tsd, arena);
487 		unsigned shard = atomic_fetch_add_u(&arena->binshard_next, 1,
488 		    ATOMIC_RELAXED);
489 		tsd_binshards_t *bins = tsd_binshardsp_get(tsd);
490 		for (unsigned i = 0; i < SC_NBINS; i++) {
491 			assert(bin_infos[i].n_shards > 0 &&
492 			    bin_infos[i].n_shards <= BIN_SHARDS_MAX);
493 			bins->binshard[i] = shard % bin_infos[i].n_shards;
494 		}
495 	}
496 }
497 
498 void
499 arena_migrate(tsd_t *tsd, arena_t *oldarena, arena_t *newarena) {
500 	assert(oldarena != NULL);
501 	assert(newarena != NULL);
502 
503 	arena_nthreads_dec(oldarena, false);
504 	arena_nthreads_inc(newarena, false);
505 	tsd_arena_set(tsd, newarena);
506 
507 	if (arena_nthreads_get(oldarena, false) == 0) {
508 		/* Purge if the old arena has no associated threads anymore. */
509 		arena_decay(tsd_tsdn(tsd), oldarena,
510 		    /* is_background_thread */ false, /* all */ true);
511 	}
512 }
513 
514 static void
515 arena_unbind(tsd_t *tsd, unsigned ind, bool internal) {
516 	arena_t *arena;
517 
518 	arena = arena_get(tsd_tsdn(tsd), ind, false);
519 	arena_nthreads_dec(arena, internal);
520 
521 	if (internal) {
522 		tsd_iarena_set(tsd, NULL);
523 	} else {
524 		tsd_arena_set(tsd, NULL);
525 	}
526 }
527 
528 /* Slow path, called only by arena_choose(). */
529 arena_t *
530 arena_choose_hard(tsd_t *tsd, bool internal) {
531 	arena_t *ret JEMALLOC_CC_SILENCE_INIT(NULL);
532 
533 	if (have_percpu_arena && PERCPU_ARENA_ENABLED(opt_percpu_arena)) {
534 		unsigned choose = percpu_arena_choose();
535 		ret = arena_get(tsd_tsdn(tsd), choose, true);
536 		assert(ret != NULL);
537 		arena_bind(tsd, arena_ind_get(ret), false);
538 		arena_bind(tsd, arena_ind_get(ret), true);
539 
540 		return ret;
541 	}
542 
543 	if (narenas_auto > 1) {
544 		unsigned i, j, choose[2], first_null;
545 		bool is_new_arena[2];
546 
547 		/*
548 		 * Determine binding for both non-internal and internal
549 		 * allocation.
550 		 *
551 		 *   choose[0]: For application allocation.
552 		 *   choose[1]: For internal metadata allocation.
553 		 */
554 
555 		for (j = 0; j < 2; j++) {
556 			choose[j] = 0;
557 			is_new_arena[j] = false;
558 		}
559 
560 		first_null = narenas_auto;
561 		malloc_mutex_lock(tsd_tsdn(tsd), &arenas_lock);
562 		assert(arena_get(tsd_tsdn(tsd), 0, false) != NULL);
563 		for (i = 1; i < narenas_auto; i++) {
564 			if (arena_get(tsd_tsdn(tsd), i, false) != NULL) {
565 				/*
566 				 * Choose the first arena that has the lowest
567 				 * number of threads assigned to it.
568 				 */
569 				for (j = 0; j < 2; j++) {
570 					if (arena_nthreads_get(arena_get(
571 					    tsd_tsdn(tsd), i, false), !!j) <
572 					    arena_nthreads_get(arena_get(
573 					    tsd_tsdn(tsd), choose[j], false),
574 					    !!j)) {
575 						choose[j] = i;
576 					}
577 				}
578 			} else if (first_null == narenas_auto) {
579 				/*
580 				 * Record the index of the first uninitialized
581 				 * arena, in case all extant arenas are in use.
582 				 *
583 				 * NB: It is possible for there to be
584 				 * discontinuities in terms of initialized
585 				 * versus uninitialized arenas, due to the
586 				 * "thread.arena" mallctl.
587 				 */
588 				first_null = i;
589 			}
590 		}
591 
592 		for (j = 0; j < 2; j++) {
593 			if (arena_nthreads_get(arena_get(tsd_tsdn(tsd),
594 			    choose[j], false), !!j) == 0 || first_null ==
595 			    narenas_auto) {
596 				/*
597 				 * Use an unloaded arena, or the least loaded
598 				 * arena if all arenas are already initialized.
599 				 */
600 				if (!!j == internal) {
601 					ret = arena_get(tsd_tsdn(tsd),
602 					    choose[j], false);
603 				}
604 			} else {
605 				arena_t *arena;
606 
607 				/* Initialize a new arena. */
608 				choose[j] = first_null;
609 				arena = arena_init_locked(tsd_tsdn(tsd),
610 				    choose[j], &arena_config_default);
611 				if (arena == NULL) {
612 					malloc_mutex_unlock(tsd_tsdn(tsd),
613 					    &arenas_lock);
614 					return NULL;
615 				}
616 				is_new_arena[j] = true;
617 				if (!!j == internal) {
618 					ret = arena;
619 				}
620 			}
621 			arena_bind(tsd, choose[j], !!j);
622 		}
623 		malloc_mutex_unlock(tsd_tsdn(tsd), &arenas_lock);
624 
625 		for (j = 0; j < 2; j++) {
626 			if (is_new_arena[j]) {
627 				assert(choose[j] > 0);
628 				arena_new_create_background_thread(
629 				    tsd_tsdn(tsd), choose[j]);
630 			}
631 		}
632 
633 	} else {
634 		ret = arena_get(tsd_tsdn(tsd), 0, false);
635 		arena_bind(tsd, 0, false);
636 		arena_bind(tsd, 0, true);
637 	}
638 
639 	return ret;
640 }
641 
642 void
643 iarena_cleanup(tsd_t *tsd) {
644 	arena_t *iarena;
645 
646 	iarena = tsd_iarena_get(tsd);
647 	if (iarena != NULL) {
648 		arena_unbind(tsd, arena_ind_get(iarena), true);
649 	}
650 }
651 
652 void
653 arena_cleanup(tsd_t *tsd) {
654 	arena_t *arena;
655 
656 	arena = tsd_arena_get(tsd);
657 	if (arena != NULL) {
658 		arena_unbind(tsd, arena_ind_get(arena), false);
659 	}
660 }
661 
662 static void
663 stats_print_atexit(void) {
664 	if (config_stats) {
665 		tsdn_t *tsdn;
666 		unsigned narenas, i;
667 
668 		tsdn = tsdn_fetch();
669 
670 		/*
671 		 * Merge stats from extant threads.  This is racy, since
672 		 * individual threads do not lock when recording tcache stats
673 		 * events.  As a consequence, the final stats may be slightly
674 		 * out of date by the time they are reported, if other threads
675 		 * continue to allocate.
676 		 */
677 		for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
678 			arena_t *arena = arena_get(tsdn, i, false);
679 			if (arena != NULL) {
680 				tcache_slow_t *tcache_slow;
681 
682 				malloc_mutex_lock(tsdn, &arena->tcache_ql_mtx);
683 				ql_foreach(tcache_slow, &arena->tcache_ql,
684 				    link) {
685 					tcache_stats_merge(tsdn,
686 					    tcache_slow->tcache, arena);
687 				}
688 				malloc_mutex_unlock(tsdn,
689 				    &arena->tcache_ql_mtx);
690 			}
691 		}
692 	}
693 	je_malloc_stats_print(NULL, NULL, opt_stats_print_opts);
694 }
695 
696 /*
697  * Ensure that we don't hold any locks upon entry to or exit from allocator
698  * code (in a "broad" sense that doesn't count a reentrant allocation as an
699  * entrance or exit).
700  */
701 JEMALLOC_ALWAYS_INLINE void
702 check_entry_exit_locking(tsdn_t *tsdn) {
703 	if (!config_debug) {
704 		return;
705 	}
706 	if (tsdn_null(tsdn)) {
707 		return;
708 	}
709 	tsd_t *tsd = tsdn_tsd(tsdn);
710 	/*
711 	 * It's possible we hold locks at entry/exit if we're in a nested
712 	 * allocation.
713 	 */
714 	int8_t reentrancy_level = tsd_reentrancy_level_get(tsd);
715 	if (reentrancy_level != 0) {
716 		return;
717 	}
718 	witness_assert_lockless(tsdn_witness_tsdp_get(tsdn));
719 }
720 
721 /*
722  * End miscellaneous support functions.
723  */
724 /******************************************************************************/
725 /*
726  * Begin initialization functions.
727  */
728 
729 static char *
730 jemalloc_secure_getenv(const char *name) {
731 #ifdef JEMALLOC_HAVE_SECURE_GETENV
732 	return secure_getenv(name);
733 #else
734 #  ifdef JEMALLOC_HAVE_ISSETUGID
735 	if (issetugid() != 0) {
736 		return NULL;
737 	}
738 #  endif
739 	return getenv(name);
740 #endif
741 }
742 
743 static unsigned
744 malloc_ncpus(void) {
745 	long result;
746 
747 #ifdef _WIN32
748 	SYSTEM_INFO si;
749 	GetSystemInfo(&si);
750 	result = si.dwNumberOfProcessors;
751 #elif defined(CPU_COUNT)
752 	/*
753 	 * glibc >= 2.6 has the CPU_COUNT macro.
754 	 *
755 	 * glibc's sysconf() uses isspace().  glibc allocates for the first time
756 	 * *before* setting up the isspace tables.  Therefore we need a
757 	 * different method to get the number of CPUs.
758 	 *
759 	 * The getaffinity approach is also preferred when only a subset of CPUs
760 	 * is available, to avoid using more arenas than necessary.
761 	 */
762 	{
763 #  if defined(__FreeBSD__) || defined(__DragonFly__)
764 		cpuset_t set;
765 #  else
766 		cpu_set_t set;
767 #  endif
768 #  if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
769 		sched_getaffinity(0, sizeof(set), &set);
770 #  else
771 		pthread_getaffinity_np(pthread_self(), sizeof(set), &set);
772 #  endif
773 		result = CPU_COUNT(&set);
774 	}
775 #else
776 	result = sysconf(_SC_NPROCESSORS_ONLN);
777 #endif
778 	return ((result == -1) ? 1 : (unsigned)result);
779 }
780 
781 /*
782  * Ensure that number of CPUs is determistinc, i.e. it is the same based on:
783  * - sched_getaffinity()
784  * - _SC_NPROCESSORS_ONLN
785  * - _SC_NPROCESSORS_CONF
786  * Since otherwise tricky things is possible with percpu arenas in use.
787  */
788 static bool
789 malloc_cpu_count_is_deterministic(void)
790 {
791 #ifdef _WIN32
792 	return true;
793 #else
794 	long cpu_onln = sysconf(_SC_NPROCESSORS_ONLN);
795 	long cpu_conf = sysconf(_SC_NPROCESSORS_CONF);
796 	if (cpu_onln != cpu_conf) {
797 		return false;
798 	}
799 #  if defined(CPU_COUNT)
800 #    if defined(__FreeBSD__) || defined(__DragonFly__)
801 	cpuset_t set;
802 #    else
803 	cpu_set_t set;
804 #    endif /* __FreeBSD__ */
805 #    if defined(JEMALLOC_HAVE_SCHED_SETAFFINITY)
806 	sched_getaffinity(0, sizeof(set), &set);
807 #    else /* !JEMALLOC_HAVE_SCHED_SETAFFINITY */
808 	pthread_getaffinity_np(pthread_self(), sizeof(set), &set);
809 #    endif /* JEMALLOC_HAVE_SCHED_SETAFFINITY */
810 	long cpu_affinity = CPU_COUNT(&set);
811 	if (cpu_affinity != cpu_conf) {
812 		return false;
813 	}
814 #  endif /* CPU_COUNT */
815 	return true;
816 #endif
817 }
818 
819 static void
820 init_opt_stats_opts(const char *v, size_t vlen, char *dest) {
821 	size_t opts_len = strlen(dest);
822 	assert(opts_len <= stats_print_tot_num_options);
823 
824 	for (size_t i = 0; i < vlen; i++) {
825 		switch (v[i]) {
826 #define OPTION(o, v, d, s) case o: break;
827 			STATS_PRINT_OPTIONS
828 #undef OPTION
829 		default: continue;
830 		}
831 
832 		if (strchr(dest, v[i]) != NULL) {
833 			/* Ignore repeated. */
834 			continue;
835 		}
836 
837 		dest[opts_len++] = v[i];
838 		dest[opts_len] = '\0';
839 		assert(opts_len <= stats_print_tot_num_options);
840 	}
841 	assert(opts_len == strlen(dest));
842 }
843 
844 /* Reads the next size pair in a multi-sized option. */
845 static bool
846 malloc_conf_multi_sizes_next(const char **slab_size_segment_cur,
847     size_t *vlen_left, size_t *slab_start, size_t *slab_end, size_t *new_size) {
848 	const char *cur = *slab_size_segment_cur;
849 	const char *end;
850 	uintmax_t um;
851 
852 	set_errno(0);
853 
854 	/* First number, then '-' */
855 	um = malloc_strtoumax(cur, &end, 0);
856 	if (get_errno() != 0 || *end != '-') {
857 		return true;
858 	}
859 	*slab_start = (size_t)um;
860 	cur = end + 1;
861 
862 	/* Second number, then ':' */
863 	um = malloc_strtoumax(cur, &end, 0);
864 	if (get_errno() != 0 || *end != ':') {
865 		return true;
866 	}
867 	*slab_end = (size_t)um;
868 	cur = end + 1;
869 
870 	/* Last number */
871 	um = malloc_strtoumax(cur, &end, 0);
872 	if (get_errno() != 0) {
873 		return true;
874 	}
875 	*new_size = (size_t)um;
876 
877 	/* Consume the separator if there is one. */
878 	if (*end == '|') {
879 		end++;
880 	}
881 
882 	*vlen_left -= end - *slab_size_segment_cur;
883 	*slab_size_segment_cur = end;
884 
885 	return false;
886 }
887 
888 static bool
889 malloc_conf_next(char const **opts_p, char const **k_p, size_t *klen_p,
890     char const **v_p, size_t *vlen_p) {
891 	bool accept;
892 	const char *opts = *opts_p;
893 
894 	*k_p = opts;
895 
896 	for (accept = false; !accept;) {
897 		switch (*opts) {
898 		case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
899 		case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
900 		case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
901 		case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
902 		case 'Y': case 'Z':
903 		case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
904 		case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
905 		case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
906 		case 's': case 't': case 'u': case 'v': case 'w': case 'x':
907 		case 'y': case 'z':
908 		case '0': case '1': case '2': case '3': case '4': case '5':
909 		case '6': case '7': case '8': case '9':
910 		case '_':
911 			opts++;
912 			break;
913 		case ':':
914 			opts++;
915 			*klen_p = (uintptr_t)opts - 1 - (uintptr_t)*k_p;
916 			*v_p = opts;
917 			accept = true;
918 			break;
919 		case '\0':
920 			if (opts != *opts_p) {
921 				malloc_write("<jemalloc>: Conf string ends "
922 				    "with key\n");
923 				had_conf_error = true;
924 			}
925 			return true;
926 		default:
927 			malloc_write("<jemalloc>: Malformed conf string\n");
928 			had_conf_error = true;
929 			return true;
930 		}
931 	}
932 
933 	for (accept = false; !accept;) {
934 		switch (*opts) {
935 		case ',':
936 			opts++;
937 			/*
938 			 * Look ahead one character here, because the next time
939 			 * this function is called, it will assume that end of
940 			 * input has been cleanly reached if no input remains,
941 			 * but we have optimistically already consumed the
942 			 * comma if one exists.
943 			 */
944 			if (*opts == '\0') {
945 				malloc_write("<jemalloc>: Conf string ends "
946 				    "with comma\n");
947 				had_conf_error = true;
948 			}
949 			*vlen_p = (uintptr_t)opts - 1 - (uintptr_t)*v_p;
950 			accept = true;
951 			break;
952 		case '\0':
953 			*vlen_p = (uintptr_t)opts - (uintptr_t)*v_p;
954 			accept = true;
955 			break;
956 		default:
957 			opts++;
958 			break;
959 		}
960 	}
961 
962 	*opts_p = opts;
963 	return false;
964 }
965 
966 static void
967 malloc_abort_invalid_conf(void) {
968 	assert(opt_abort_conf);
969 	malloc_printf("<jemalloc>: Abort (abort_conf:true) on invalid conf "
970 	    "value (see above).\n");
971 	abort();
972 }
973 
974 static void
975 malloc_conf_error(const char *msg, const char *k, size_t klen, const char *v,
976     size_t vlen) {
977 	malloc_printf("<jemalloc>: %s: %.*s:%.*s\n", msg, (int)klen, k,
978 	    (int)vlen, v);
979 	/* If abort_conf is set, error out after processing all options. */
980 	const char *experimental = "experimental_";
981 	if (strncmp(k, experimental, strlen(experimental)) == 0) {
982 		/* However, tolerate experimental features. */
983 		return;
984 	}
985 	had_conf_error = true;
986 }
987 
988 static void
989 malloc_slow_flag_init(void) {
990 	/*
991 	 * Combine the runtime options into malloc_slow for fast path.  Called
992 	 * after processing all the options.
993 	 */
994 	malloc_slow_flags |= (opt_junk_alloc ? flag_opt_junk_alloc : 0)
995 	    | (opt_junk_free ? flag_opt_junk_free : 0)
996 	    | (opt_zero ? flag_opt_zero : 0)
997 	    | (opt_utrace ? flag_opt_utrace : 0)
998 	    | (opt_xmalloc ? flag_opt_xmalloc : 0);
999 
1000 	malloc_slow = (malloc_slow_flags != 0);
1001 }
1002 
1003 /* Number of sources for initializing malloc_conf */
1004 #define MALLOC_CONF_NSOURCES 5
1005 
1006 static const char *
1007 obtain_malloc_conf(unsigned which_source, char buf[PATH_MAX + 1]) {
1008 	if (config_debug) {
1009 		static unsigned read_source = 0;
1010 		/*
1011 		 * Each source should only be read once, to minimize # of
1012 		 * syscalls on init.
1013 		 */
1014 		assert(read_source++ == which_source);
1015 	}
1016 	assert(which_source < MALLOC_CONF_NSOURCES);
1017 
1018 	const char *ret;
1019 	switch (which_source) {
1020 	case 0:
1021 		ret = config_malloc_conf;
1022 		break;
1023 	case 1:
1024 		if (je_malloc_conf != NULL) {
1025 			/* Use options that were compiled into the program. */
1026 			ret = je_malloc_conf;
1027 		} else {
1028 			/* No configuration specified. */
1029 			ret = NULL;
1030 		}
1031 		break;
1032 	case 2: {
1033 		ssize_t linklen = 0;
1034 #ifndef _WIN32
1035 		int saved_errno = errno;
1036 		const char *linkname =
1037 #  ifdef JEMALLOC_PREFIX
1038 		    "/etc/"JEMALLOC_PREFIX"malloc.conf"
1039 #  else
1040 		    "/etc/malloc.conf"
1041 #  endif
1042 		    ;
1043 
1044 		/*
1045 		 * Try to use the contents of the "/etc/malloc.conf" symbolic
1046 		 * link's name.
1047 		 */
1048 #ifndef JEMALLOC_READLINKAT
1049 		linklen = readlink(linkname, buf, PATH_MAX);
1050 #else
1051 		linklen = readlinkat(AT_FDCWD, linkname, buf, PATH_MAX);
1052 #endif
1053 		if (linklen == -1) {
1054 			/* No configuration specified. */
1055 			linklen = 0;
1056 			/* Restore errno. */
1057 			set_errno(saved_errno);
1058 		}
1059 #endif
1060 		buf[linklen] = '\0';
1061 		ret = buf;
1062 		break;
1063 	} case 3: {
1064 		const char *envname =
1065 #ifdef JEMALLOC_PREFIX
1066 		    JEMALLOC_CPREFIX"MALLOC_CONF"
1067 #else
1068 		    "MALLOC_CONF"
1069 #endif
1070 		    ;
1071 
1072 		if ((ret = jemalloc_secure_getenv(envname)) != NULL) {
1073 			/*
1074 			 * Do nothing; opts is already initialized to the value
1075 			 * of the MALLOC_CONF environment variable.
1076 			 */
1077 		} else {
1078 			/* No configuration specified. */
1079 			ret = NULL;
1080 		}
1081 		break;
1082 	} case 4: {
1083 		ret = je_malloc_conf_2_conf_harder;
1084 		break;
1085 	} default:
1086 		not_reached();
1087 		ret = NULL;
1088 	}
1089 	return ret;
1090 }
1091 
1092 static void
1093 malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
1094     bool initial_call, const char *opts_cache[MALLOC_CONF_NSOURCES],
1095     char buf[PATH_MAX + 1]) {
1096 	static const char *opts_explain[MALLOC_CONF_NSOURCES] = {
1097 		"string specified via --with-malloc-conf",
1098 		"string pointed to by the global variable malloc_conf",
1099 		"\"name\" of the file referenced by the symbolic link named "
1100 		    "/etc/malloc.conf",
1101 		"value of the environment variable MALLOC_CONF",
1102 		"string pointed to by the global variable "
1103 		    "malloc_conf_2_conf_harder",
1104 	};
1105 	unsigned i;
1106 	const char *opts, *k, *v;
1107 	size_t klen, vlen;
1108 
1109 	for (i = 0; i < MALLOC_CONF_NSOURCES; i++) {
1110 		/* Get runtime configuration. */
1111 		if (initial_call) {
1112 			opts_cache[i] = obtain_malloc_conf(i, buf);
1113 		}
1114 		opts = opts_cache[i];
1115 		if (!initial_call && opt_confirm_conf) {
1116 			malloc_printf(
1117 			    "<jemalloc>: malloc_conf #%u (%s): \"%s\"\n",
1118 			    i + 1, opts_explain[i], opts != NULL ? opts : "");
1119 		}
1120 		if (opts == NULL) {
1121 			continue;
1122 		}
1123 
1124 		while (*opts != '\0' && !malloc_conf_next(&opts, &k, &klen, &v,
1125 		    &vlen)) {
1126 
1127 #define CONF_ERROR(msg, k, klen, v, vlen)				\
1128 			if (!initial_call) {				\
1129 				malloc_conf_error(			\
1130 				    msg, k, klen, v, vlen);		\
1131 				cur_opt_valid = false;			\
1132 			}
1133 #define CONF_CONTINUE	{						\
1134 				if (!initial_call && opt_confirm_conf	\
1135 				    && cur_opt_valid) {			\
1136 					malloc_printf("<jemalloc>: -- "	\
1137 					    "Set conf value: %.*s:%.*s"	\
1138 					    "\n", (int)klen, k,		\
1139 					    (int)vlen, v);		\
1140 				}					\
1141 				continue;				\
1142 			}
1143 #define CONF_MATCH(n)							\
1144 	(sizeof(n)-1 == klen && strncmp(n, k, klen) == 0)
1145 #define CONF_MATCH_VALUE(n)						\
1146 	(sizeof(n)-1 == vlen && strncmp(n, v, vlen) == 0)
1147 #define CONF_HANDLE_BOOL(o, n)						\
1148 			if (CONF_MATCH(n)) {				\
1149 				if (CONF_MATCH_VALUE("true")) {		\
1150 					o = true;			\
1151 				} else if (CONF_MATCH_VALUE("false")) {	\
1152 					o = false;			\
1153 				} else {				\
1154 					CONF_ERROR("Invalid conf value",\
1155 					    k, klen, v, vlen);		\
1156 				}					\
1157 				CONF_CONTINUE;				\
1158 			}
1159       /*
1160        * One of the CONF_MIN macros below expands, in one of the use points,
1161        * to "unsigned integer < 0", which is always false, triggering the
1162        * GCC -Wtype-limits warning, which we disable here and re-enable below.
1163        */
1164       JEMALLOC_DIAGNOSTIC_PUSH
1165       JEMALLOC_DIAGNOSTIC_IGNORE_TYPE_LIMITS
1166 
1167 #define CONF_DONT_CHECK_MIN(um, min)	false
1168 #define CONF_CHECK_MIN(um, min)	((um) < (min))
1169 #define CONF_DONT_CHECK_MAX(um, max)	false
1170 #define CONF_CHECK_MAX(um, max)	((um) > (max))
1171 
1172 #define CONF_VALUE_READ(max_t, result)					\
1173 	      const char *end;						\
1174 	      set_errno(0);						\
1175 	      result = (max_t)malloc_strtoumax(v, &end, 0);
1176 #define CONF_VALUE_READ_FAIL()						\
1177 	      (get_errno() != 0 || (uintptr_t)end - (uintptr_t)v != vlen)
1178 
1179 #define CONF_HANDLE_T(t, max_t, o, n, min, max, check_min, check_max, clip) \
1180 			if (CONF_MATCH(n)) {				\
1181 				max_t mv;				\
1182 				CONF_VALUE_READ(max_t, mv)		\
1183 				if (CONF_VALUE_READ_FAIL()) {		\
1184 					CONF_ERROR("Invalid conf value",\
1185 					    k, klen, v, vlen);		\
1186 				} else if (clip) {			\
1187 					if (check_min(mv, (t)(min))) {	\
1188 						o = (t)(min);		\
1189 					} else if (			\
1190 					    check_max(mv, (t)(max))) {	\
1191 						o = (t)(max);		\
1192 					} else {			\
1193 						o = (t)mv;		\
1194 					}				\
1195 				} else {				\
1196 					if (check_min(mv, (t)(min)) ||	\
1197 					    check_max(mv, (t)(max))) {	\
1198 						CONF_ERROR(		\
1199 						    "Out-of-range "	\
1200 						    "conf value",	\
1201 						    k, klen, v, vlen);	\
1202 					} else {			\
1203 						o = (t)mv;		\
1204 					}				\
1205 				}					\
1206 				CONF_CONTINUE;				\
1207 			}
1208 #define CONF_HANDLE_T_U(t, o, n, min, max, check_min, check_max, clip)	\
1209 	      CONF_HANDLE_T(t, uintmax_t, o, n, min, max, check_min,	\
1210 			    check_max, clip)
1211 #define CONF_HANDLE_T_SIGNED(t, o, n, min, max, check_min, check_max, clip)\
1212 	      CONF_HANDLE_T(t, intmax_t, o, n, min, max, check_min,	\
1213 			    check_max, clip)
1214 
1215 #define CONF_HANDLE_UNSIGNED(o, n, min, max, check_min, check_max,	\
1216     clip)								\
1217 			CONF_HANDLE_T_U(unsigned, o, n, min, max,	\
1218 			    check_min, check_max, clip)
1219 #define CONF_HANDLE_SIZE_T(o, n, min, max, check_min, check_max, clip)	\
1220 			CONF_HANDLE_T_U(size_t, o, n, min, max,		\
1221 			    check_min, check_max, clip)
1222 #define CONF_HANDLE_INT64_T(o, n, min, max, check_min, check_max, clip)	\
1223 			CONF_HANDLE_T_SIGNED(int64_t, o, n, min, max,	\
1224 			    check_min, check_max, clip)
1225 #define CONF_HANDLE_UINT64_T(o, n, min, max, check_min, check_max, clip)\
1226 			CONF_HANDLE_T_U(uint64_t, o, n, min, max,	\
1227 			    check_min, check_max, clip)
1228 #define CONF_HANDLE_SSIZE_T(o, n, min, max)				\
1229 			CONF_HANDLE_T_SIGNED(ssize_t, o, n, min, max,	\
1230 			    CONF_CHECK_MIN, CONF_CHECK_MAX, false)
1231 #define CONF_HANDLE_CHAR_P(o, n, d)					\
1232 			if (CONF_MATCH(n)) {				\
1233 				size_t cpylen = (vlen <=		\
1234 				    sizeof(o)-1) ? vlen :		\
1235 				    sizeof(o)-1;			\
1236 				strncpy(o, v, cpylen);			\
1237 				o[cpylen] = '\0';			\
1238 				CONF_CONTINUE;				\
1239 			}
1240 
1241 			bool cur_opt_valid = true;
1242 
1243 			CONF_HANDLE_BOOL(opt_confirm_conf, "confirm_conf")
1244 			if (initial_call) {
1245 				continue;
1246 			}
1247 
1248 			CONF_HANDLE_BOOL(opt_abort, "abort")
1249 			CONF_HANDLE_BOOL(opt_abort_conf, "abort_conf")
1250 			CONF_HANDLE_BOOL(opt_trust_madvise, "trust_madvise")
1251 			if (strncmp("metadata_thp", k, klen) == 0) {
1252 				int m;
1253 				bool match = false;
1254 				for (m = 0; m < metadata_thp_mode_limit; m++) {
1255 					if (strncmp(metadata_thp_mode_names[m],
1256 					    v, vlen) == 0) {
1257 						opt_metadata_thp = m;
1258 						match = true;
1259 						break;
1260 					}
1261 				}
1262 				if (!match) {
1263 					CONF_ERROR("Invalid conf value",
1264 					    k, klen, v, vlen);
1265 				}
1266 				CONF_CONTINUE;
1267 			}
1268 			CONF_HANDLE_BOOL(opt_retain, "retain")
1269 			if (strncmp("dss", k, klen) == 0) {
1270 				int m;
1271 				bool match = false;
1272 				for (m = 0; m < dss_prec_limit; m++) {
1273 					if (strncmp(dss_prec_names[m], v, vlen)
1274 					    == 0) {
1275 						if (extent_dss_prec_set(m)) {
1276 							CONF_ERROR(
1277 							    "Error setting dss",
1278 							    k, klen, v, vlen);
1279 						} else {
1280 							opt_dss =
1281 							    dss_prec_names[m];
1282 							match = true;
1283 							break;
1284 						}
1285 					}
1286 				}
1287 				if (!match) {
1288 					CONF_ERROR("Invalid conf value",
1289 					    k, klen, v, vlen);
1290 				}
1291 				CONF_CONTINUE;
1292 			}
1293 			if (CONF_MATCH("narenas")) {
1294 				if (CONF_MATCH_VALUE("default")) {
1295 					opt_narenas = 0;
1296 					CONF_CONTINUE;
1297 				} else {
1298 					CONF_HANDLE_UNSIGNED(opt_narenas,
1299 					    "narenas", 1, UINT_MAX,
1300 					    CONF_CHECK_MIN, CONF_DONT_CHECK_MAX,
1301 					    /* clip */ false)
1302 				}
1303 			}
1304 			if (CONF_MATCH("narenas_ratio")) {
1305 				char *end;
1306 				bool err = fxp_parse(&opt_narenas_ratio, v,
1307 				    &end);
1308 				if (err || (size_t)(end - v) != vlen) {
1309 					CONF_ERROR("Invalid conf value",
1310 					    k, klen, v, vlen);
1311 				}
1312 				CONF_CONTINUE;
1313 			}
1314 			if (CONF_MATCH("bin_shards")) {
1315 				const char *bin_shards_segment_cur = v;
1316 				size_t vlen_left = vlen;
1317 				do {
1318 					size_t size_start;
1319 					size_t size_end;
1320 					size_t nshards;
1321 					bool err = malloc_conf_multi_sizes_next(
1322 					    &bin_shards_segment_cur, &vlen_left,
1323 					    &size_start, &size_end, &nshards);
1324 					if (err || bin_update_shard_size(
1325 					    bin_shard_sizes, size_start,
1326 					    size_end, nshards)) {
1327 						CONF_ERROR(
1328 						    "Invalid settings for "
1329 						    "bin_shards", k, klen, v,
1330 						    vlen);
1331 						break;
1332 					}
1333 				} while (vlen_left > 0);
1334 				CONF_CONTINUE;
1335 			}
1336 			CONF_HANDLE_INT64_T(opt_mutex_max_spin,
1337 			    "mutex_max_spin", -1, INT64_MAX, CONF_CHECK_MIN,
1338 			    CONF_DONT_CHECK_MAX, false);
1339 			CONF_HANDLE_SSIZE_T(opt_dirty_decay_ms,
1340 			    "dirty_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
1341 			    QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) :
1342 			    SSIZE_MAX);
1343 			CONF_HANDLE_SSIZE_T(opt_muzzy_decay_ms,
1344 			    "muzzy_decay_ms", -1, NSTIME_SEC_MAX * KQU(1000) <
1345 			    QU(SSIZE_MAX) ? NSTIME_SEC_MAX * KQU(1000) :
1346 			    SSIZE_MAX);
1347 			CONF_HANDLE_BOOL(opt_stats_print, "stats_print")
1348 			if (CONF_MATCH("stats_print_opts")) {
1349 				init_opt_stats_opts(v, vlen,
1350 				    opt_stats_print_opts);
1351 				CONF_CONTINUE;
1352 			}
1353 			CONF_HANDLE_INT64_T(opt_stats_interval,
1354 			    "stats_interval", -1, INT64_MAX,
1355 			    CONF_CHECK_MIN, CONF_DONT_CHECK_MAX, false)
1356 			if (CONF_MATCH("stats_interval_opts")) {
1357 				init_opt_stats_opts(v, vlen,
1358 				    opt_stats_interval_opts);
1359 				CONF_CONTINUE;
1360 			}
1361 			if (config_fill) {
1362 				if (CONF_MATCH("junk")) {
1363 					if (CONF_MATCH_VALUE("true")) {
1364 						opt_junk = "true";
1365 						opt_junk_alloc = opt_junk_free =
1366 						    true;
1367 					} else if (CONF_MATCH_VALUE("false")) {
1368 						opt_junk = "false";
1369 						opt_junk_alloc = opt_junk_free =
1370 						    false;
1371 					} else if (CONF_MATCH_VALUE("alloc")) {
1372 						opt_junk = "alloc";
1373 						opt_junk_alloc = true;
1374 						opt_junk_free = false;
1375 					} else if (CONF_MATCH_VALUE("free")) {
1376 						opt_junk = "free";
1377 						opt_junk_alloc = false;
1378 						opt_junk_free = true;
1379 					} else {
1380 						CONF_ERROR(
1381 						    "Invalid conf value",
1382 						    k, klen, v, vlen);
1383 					}
1384 					CONF_CONTINUE;
1385 				}
1386 				CONF_HANDLE_BOOL(opt_zero, "zero")
1387 			}
1388 			if (config_utrace) {
1389 				CONF_HANDLE_BOOL(opt_utrace, "utrace")
1390 			}
1391 			if (config_xmalloc) {
1392 				CONF_HANDLE_BOOL(opt_xmalloc, "xmalloc")
1393 			}
1394 			if (config_enable_cxx) {
1395 				CONF_HANDLE_BOOL(
1396 				    opt_experimental_infallible_new,
1397 				    "experimental_infallible_new")
1398 			}
1399 
1400 			CONF_HANDLE_BOOL(opt_tcache, "tcache")
1401 			CONF_HANDLE_SIZE_T(opt_tcache_max, "tcache_max",
1402 			    0, TCACHE_MAXCLASS_LIMIT, CONF_DONT_CHECK_MIN,
1403 			    CONF_CHECK_MAX, /* clip */ true)
1404 			if (CONF_MATCH("lg_tcache_max")) {
1405 				size_t m;
1406 				CONF_VALUE_READ(size_t, m)
1407 				if (CONF_VALUE_READ_FAIL()) {
1408 					CONF_ERROR("Invalid conf value",
1409 					    k, klen, v, vlen);
1410 				} else {
1411 					/* clip if necessary */
1412 					if (m > TCACHE_LG_MAXCLASS_LIMIT) {
1413 						m = TCACHE_LG_MAXCLASS_LIMIT;
1414 					}
1415 					opt_tcache_max = (size_t)1 << m;
1416 				}
1417 				CONF_CONTINUE;
1418 			}
1419 			/*
1420 			 * Anyone trying to set a value outside -16 to 16 is
1421 			 * deeply confused.
1422 			 */
1423 			CONF_HANDLE_SSIZE_T(opt_lg_tcache_nslots_mul,
1424 			    "lg_tcache_nslots_mul", -16, 16)
1425 			/* Ditto with values past 2048. */
1426 			CONF_HANDLE_UNSIGNED(opt_tcache_nslots_small_min,
1427 			    "tcache_nslots_small_min", 1, 2048,
1428 			    CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
1429 			CONF_HANDLE_UNSIGNED(opt_tcache_nslots_small_max,
1430 			    "tcache_nslots_small_max", 1, 2048,
1431 			    CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
1432 			CONF_HANDLE_UNSIGNED(opt_tcache_nslots_large,
1433 			    "tcache_nslots_large", 1, 2048,
1434 			    CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
1435 			CONF_HANDLE_SIZE_T(opt_tcache_gc_incr_bytes,
1436 			    "tcache_gc_incr_bytes", 1024, SIZE_T_MAX,
1437 			    CONF_CHECK_MIN, CONF_DONT_CHECK_MAX,
1438 			    /* clip */ true)
1439 			CONF_HANDLE_SIZE_T(opt_tcache_gc_delay_bytes,
1440 			    "tcache_gc_delay_bytes", 0, SIZE_T_MAX,
1441 			    CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX,
1442 			    /* clip */ false)
1443 			CONF_HANDLE_UNSIGNED(opt_lg_tcache_flush_small_div,
1444 			    "lg_tcache_flush_small_div", 1, 16,
1445 			    CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
1446 			CONF_HANDLE_UNSIGNED(opt_lg_tcache_flush_large_div,
1447 			    "lg_tcache_flush_large_div", 1, 16,
1448 			    CONF_CHECK_MIN, CONF_CHECK_MAX, /* clip */ true)
1449 
1450 			/*
1451 			 * The runtime option of oversize_threshold remains
1452 			 * undocumented.  It may be tweaked in the next major
1453 			 * release (6.0).  The default value 8M is rather
1454 			 * conservative / safe.  Tuning it further down may
1455 			 * improve fragmentation a bit more, but may also cause
1456 			 * contention on the huge arena.
1457 			 */
1458 			CONF_HANDLE_SIZE_T(opt_oversize_threshold,
1459 			    "oversize_threshold", 0, SC_LARGE_MAXCLASS,
1460 			    CONF_DONT_CHECK_MIN, CONF_CHECK_MAX, false)
1461 			CONF_HANDLE_SIZE_T(opt_lg_extent_max_active_fit,
1462 			    "lg_extent_max_active_fit", 0,
1463 			    (sizeof(size_t) << 3), CONF_DONT_CHECK_MIN,
1464 			    CONF_CHECK_MAX, false)
1465 
1466 			if (strncmp("percpu_arena", k, klen) == 0) {
1467 				bool match = false;
1468 				for (int m = percpu_arena_mode_names_base; m <
1469 				    percpu_arena_mode_names_limit; m++) {
1470 					if (strncmp(percpu_arena_mode_names[m],
1471 					    v, vlen) == 0) {
1472 						if (!have_percpu_arena) {
1473 							CONF_ERROR(
1474 							    "No getcpu support",
1475 							    k, klen, v, vlen);
1476 						}
1477 						opt_percpu_arena = m;
1478 						match = true;
1479 						break;
1480 					}
1481 				}
1482 				if (!match) {
1483 					CONF_ERROR("Invalid conf value",
1484 					    k, klen, v, vlen);
1485 				}
1486 				CONF_CONTINUE;
1487 			}
1488 			CONF_HANDLE_BOOL(opt_background_thread,
1489 			    "background_thread");
1490 			CONF_HANDLE_SIZE_T(opt_max_background_threads,
1491 					   "max_background_threads", 1,
1492 					   opt_max_background_threads,
1493 					   CONF_CHECK_MIN, CONF_CHECK_MAX,
1494 					   true);
1495 			CONF_HANDLE_BOOL(opt_hpa, "hpa")
1496 			CONF_HANDLE_SIZE_T(opt_hpa_opts.slab_max_alloc,
1497 			    "hpa_slab_max_alloc", PAGE, HUGEPAGE,
1498 			    CONF_CHECK_MIN, CONF_CHECK_MAX, true);
1499 
1500 			/*
1501 			 * Accept either a ratio-based or an exact hugification
1502 			 * threshold.
1503 			 */
1504 			CONF_HANDLE_SIZE_T(opt_hpa_opts.hugification_threshold,
1505 			    "hpa_hugification_threshold", PAGE, HUGEPAGE,
1506 			    CONF_CHECK_MIN, CONF_CHECK_MAX, true);
1507 			if (CONF_MATCH("hpa_hugification_threshold_ratio")) {
1508 				fxp_t ratio;
1509 				char *end;
1510 				bool err = fxp_parse(&ratio, v,
1511 				    &end);
1512 				if (err || (size_t)(end - v) != vlen
1513 				    || ratio > FXP_INIT_INT(1)) {
1514 					CONF_ERROR("Invalid conf value",
1515 					    k, klen, v, vlen);
1516 				} else {
1517 					opt_hpa_opts.hugification_threshold =
1518 					    fxp_mul_frac(HUGEPAGE, ratio);
1519 				}
1520 				CONF_CONTINUE;
1521 			}
1522 
1523 			CONF_HANDLE_UINT64_T(
1524 			    opt_hpa_opts.hugify_delay_ms, "hpa_hugify_delay_ms",
1525 			    0, 0, CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX,
1526 			    false);
1527 
1528 			CONF_HANDLE_UINT64_T(
1529 			    opt_hpa_opts.min_purge_interval_ms,
1530 			    "hpa_min_purge_interval_ms", 0, 0,
1531 			    CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX, false);
1532 
1533 			if (CONF_MATCH("hpa_dirty_mult")) {
1534 				if (CONF_MATCH_VALUE("-1")) {
1535 					opt_hpa_opts.dirty_mult = (fxp_t)-1;
1536 					CONF_CONTINUE;
1537 				}
1538 				fxp_t ratio;
1539 				char *end;
1540 				bool err = fxp_parse(&ratio, v,
1541 				    &end);
1542 				if (err || (size_t)(end - v) != vlen) {
1543 					CONF_ERROR("Invalid conf value",
1544 					    k, klen, v, vlen);
1545 				} else {
1546 					opt_hpa_opts.dirty_mult = ratio;
1547 				}
1548 				CONF_CONTINUE;
1549 			}
1550 
1551 			CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.nshards,
1552 			    "hpa_sec_nshards", 0, 0, CONF_CHECK_MIN,
1553 			    CONF_DONT_CHECK_MAX, true);
1554 			CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.max_alloc,
1555 			    "hpa_sec_max_alloc", PAGE, 0, CONF_CHECK_MIN,
1556 			    CONF_DONT_CHECK_MAX, true);
1557 			CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.max_bytes,
1558 			    "hpa_sec_max_bytes", PAGE, 0, CONF_CHECK_MIN,
1559 			    CONF_DONT_CHECK_MAX, true);
1560 			CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.bytes_after_flush,
1561 			    "hpa_sec_bytes_after_flush", PAGE, 0,
1562 			    CONF_CHECK_MIN, CONF_DONT_CHECK_MAX, true);
1563 			CONF_HANDLE_SIZE_T(opt_hpa_sec_opts.batch_fill_extra,
1564 			    "hpa_sec_batch_fill_extra", 0, HUGEPAGE_PAGES,
1565 			    CONF_CHECK_MIN, CONF_CHECK_MAX, true);
1566 
1567 			if (CONF_MATCH("slab_sizes")) {
1568 				if (CONF_MATCH_VALUE("default")) {
1569 					sc_data_init(sc_data);
1570 					CONF_CONTINUE;
1571 				}
1572 				bool err;
1573 				const char *slab_size_segment_cur = v;
1574 				size_t vlen_left = vlen;
1575 				do {
1576 					size_t slab_start;
1577 					size_t slab_end;
1578 					size_t pgs;
1579 					err = malloc_conf_multi_sizes_next(
1580 					    &slab_size_segment_cur,
1581 					    &vlen_left, &slab_start, &slab_end,
1582 					    &pgs);
1583 					if (!err) {
1584 						sc_data_update_slab_size(
1585 						    sc_data, slab_start,
1586 						    slab_end, (int)pgs);
1587 					} else {
1588 						CONF_ERROR("Invalid settings "
1589 						    "for slab_sizes",
1590 						    k, klen, v, vlen);
1591 					}
1592 				} while (!err && vlen_left > 0);
1593 				CONF_CONTINUE;
1594 			}
1595 			if (config_prof) {
1596 				CONF_HANDLE_BOOL(opt_prof, "prof")
1597 				CONF_HANDLE_CHAR_P(opt_prof_prefix,
1598 				    "prof_prefix", "jeprof")
1599 				CONF_HANDLE_BOOL(opt_prof_active, "prof_active")
1600 				CONF_HANDLE_BOOL(opt_prof_thread_active_init,
1601 				    "prof_thread_active_init")
1602 				CONF_HANDLE_SIZE_T(opt_lg_prof_sample,
1603 				    "lg_prof_sample", 0, (sizeof(uint64_t) << 3)
1604 				    - 1, CONF_DONT_CHECK_MIN, CONF_CHECK_MAX,
1605 				    true)
1606 				CONF_HANDLE_BOOL(opt_prof_accum, "prof_accum")
1607 				CONF_HANDLE_SSIZE_T(opt_lg_prof_interval,
1608 				    "lg_prof_interval", -1,
1609 				    (sizeof(uint64_t) << 3) - 1)
1610 				CONF_HANDLE_BOOL(opt_prof_gdump, "prof_gdump")
1611 				CONF_HANDLE_BOOL(opt_prof_final, "prof_final")
1612 				CONF_HANDLE_BOOL(opt_prof_leak, "prof_leak")
1613 				CONF_HANDLE_BOOL(opt_prof_leak_error,
1614 				    "prof_leak_error")
1615 				CONF_HANDLE_BOOL(opt_prof_log, "prof_log")
1616 				CONF_HANDLE_SSIZE_T(opt_prof_recent_alloc_max,
1617 				    "prof_recent_alloc_max", -1, SSIZE_MAX)
1618 				CONF_HANDLE_BOOL(opt_prof_stats, "prof_stats")
1619 				CONF_HANDLE_BOOL(opt_prof_sys_thread_name,
1620 				    "prof_sys_thread_name")
1621 				if (CONF_MATCH("prof_time_resolution")) {
1622 					if (CONF_MATCH_VALUE("default")) {
1623 						opt_prof_time_res =
1624 						    prof_time_res_default;
1625 					} else if (CONF_MATCH_VALUE("high")) {
1626 						if (!config_high_res_timer) {
1627 							CONF_ERROR(
1628 							    "No high resolution"
1629 							    " timer support",
1630 							    k, klen, v, vlen);
1631 						} else {
1632 							opt_prof_time_res =
1633 							    prof_time_res_high;
1634 						}
1635 					} else {
1636 						CONF_ERROR("Invalid conf value",
1637 						    k, klen, v, vlen);
1638 					}
1639 					CONF_CONTINUE;
1640 				}
1641 				/*
1642 				 * Undocumented.  When set to false, don't
1643 				 * correct for an unbiasing bug in jeprof
1644 				 * attribution.  This can be handy if you want
1645 				 * to get consistent numbers from your binary
1646 				 * across different jemalloc versions, even if
1647 				 * those numbers are incorrect.  The default is
1648 				 * true.
1649 				 */
1650 				CONF_HANDLE_BOOL(opt_prof_unbias, "prof_unbias")
1651 			}
1652 			if (config_log) {
1653 				if (CONF_MATCH("log")) {
1654 					size_t cpylen = (
1655 					    vlen <= sizeof(log_var_names) ?
1656 					    vlen : sizeof(log_var_names) - 1);
1657 					strncpy(log_var_names, v, cpylen);
1658 					log_var_names[cpylen] = '\0';
1659 					CONF_CONTINUE;
1660 				}
1661 			}
1662 			if (CONF_MATCH("thp")) {
1663 				bool match = false;
1664 				for (int m = 0; m < thp_mode_names_limit; m++) {
1665 					if (strncmp(thp_mode_names[m],v, vlen)
1666 					    == 0) {
1667 						if (!have_madvise_huge && !have_memcntl) {
1668 							CONF_ERROR(
1669 							    "No THP support",
1670 							    k, klen, v, vlen);
1671 						}
1672 						opt_thp = m;
1673 						match = true;
1674 						break;
1675 					}
1676 				}
1677 				if (!match) {
1678 					CONF_ERROR("Invalid conf value",
1679 					    k, klen, v, vlen);
1680 				}
1681 				CONF_CONTINUE;
1682 			}
1683 			if (CONF_MATCH("zero_realloc")) {
1684 				if (CONF_MATCH_VALUE("alloc")) {
1685 					opt_zero_realloc_action
1686 					    = zero_realloc_action_alloc;
1687 				} else if (CONF_MATCH_VALUE("free")) {
1688 					opt_zero_realloc_action
1689 					    = zero_realloc_action_free;
1690 				} else if (CONF_MATCH_VALUE("abort")) {
1691 					opt_zero_realloc_action
1692 					    = zero_realloc_action_abort;
1693 				} else {
1694 					CONF_ERROR("Invalid conf value",
1695 					    k, klen, v, vlen);
1696 				}
1697 				CONF_CONTINUE;
1698 			}
1699 			if (config_uaf_detection &&
1700 			    CONF_MATCH("lg_san_uaf_align")) {
1701 				ssize_t a;
1702 				CONF_VALUE_READ(ssize_t, a)
1703 				if (CONF_VALUE_READ_FAIL() || a < -1) {
1704 					CONF_ERROR("Invalid conf value",
1705 					    k, klen, v, vlen);
1706 				}
1707 				if (a == -1) {
1708 					opt_lg_san_uaf_align = -1;
1709 					CONF_CONTINUE;
1710 				}
1711 
1712 				/* clip if necessary */
1713 				ssize_t max_allowed = (sizeof(size_t) << 3) - 1;
1714 				ssize_t min_allowed = LG_PAGE;
1715 				if (a > max_allowed) {
1716 					a = max_allowed;
1717 				} else if (a < min_allowed) {
1718 					a = min_allowed;
1719 				}
1720 
1721 				opt_lg_san_uaf_align = a;
1722 				CONF_CONTINUE;
1723 			}
1724 
1725 			CONF_HANDLE_SIZE_T(opt_san_guard_small,
1726 			    "san_guard_small", 0, SIZE_T_MAX,
1727 			    CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX, false)
1728 			CONF_HANDLE_SIZE_T(opt_san_guard_large,
1729 			    "san_guard_large", 0, SIZE_T_MAX,
1730 			    CONF_DONT_CHECK_MIN, CONF_DONT_CHECK_MAX, false)
1731 
1732 			CONF_ERROR("Invalid conf pair", k, klen, v, vlen);
1733 #undef CONF_ERROR
1734 #undef CONF_CONTINUE
1735 #undef CONF_MATCH
1736 #undef CONF_MATCH_VALUE
1737 #undef CONF_HANDLE_BOOL
1738 #undef CONF_DONT_CHECK_MIN
1739 #undef CONF_CHECK_MIN
1740 #undef CONF_DONT_CHECK_MAX
1741 #undef CONF_CHECK_MAX
1742 #undef CONF_HANDLE_T
1743 #undef CONF_HANDLE_T_U
1744 #undef CONF_HANDLE_T_SIGNED
1745 #undef CONF_HANDLE_UNSIGNED
1746 #undef CONF_HANDLE_SIZE_T
1747 #undef CONF_HANDLE_SSIZE_T
1748 #undef CONF_HANDLE_CHAR_P
1749     /* Re-enable diagnostic "-Wtype-limits" */
1750     JEMALLOC_DIAGNOSTIC_POP
1751 		}
1752 		if (opt_abort_conf && had_conf_error) {
1753 			malloc_abort_invalid_conf();
1754 		}
1755 	}
1756 	atomic_store_b(&log_init_done, true, ATOMIC_RELEASE);
1757 }
1758 
1759 static bool
1760 malloc_conf_init_check_deps(void) {
1761 	if (opt_prof_leak_error && !opt_prof_final) {
1762 		malloc_printf("<jemalloc>: prof_leak_error is set w/o "
1763 		    "prof_final.\n");
1764 		return true;
1765 	}
1766 
1767 	return false;
1768 }
1769 
1770 static void
1771 malloc_conf_init(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS]) {
1772 	const char *opts_cache[MALLOC_CONF_NSOURCES] = {NULL, NULL, NULL, NULL,
1773 		NULL};
1774 	char buf[PATH_MAX + 1];
1775 
1776 	/* The first call only set the confirm_conf option and opts_cache */
1777 	malloc_conf_init_helper(NULL, NULL, true, opts_cache, buf);
1778 	malloc_conf_init_helper(sc_data, bin_shard_sizes, false, opts_cache,
1779 	    NULL);
1780 	if (malloc_conf_init_check_deps()) {
1781 		/* check_deps does warning msg only; abort below if needed. */
1782 		if (opt_abort_conf) {
1783 			malloc_abort_invalid_conf();
1784 		}
1785 	}
1786 }
1787 
1788 #undef MALLOC_CONF_NSOURCES
1789 
1790 static bool
1791 malloc_init_hard_needed(void) {
1792 	if (malloc_initialized() || (IS_INITIALIZER && malloc_init_state ==
1793 	    malloc_init_recursible)) {
1794 		/*
1795 		 * Another thread initialized the allocator before this one
1796 		 * acquired init_lock, or this thread is the initializing
1797 		 * thread, and it is recursively allocating.
1798 		 */
1799 		return false;
1800 	}
1801 #ifdef JEMALLOC_THREADED_INIT
1802 	if (malloc_initializer != NO_INITIALIZER && !IS_INITIALIZER) {
1803 		/* Busy-wait until the initializing thread completes. */
1804 		spin_t spinner = SPIN_INITIALIZER;
1805 		do {
1806 			malloc_mutex_unlock(TSDN_NULL, &init_lock);
1807 			spin_adaptive(&spinner);
1808 			malloc_mutex_lock(TSDN_NULL, &init_lock);
1809 		} while (!malloc_initialized());
1810 		return false;
1811 	}
1812 #endif
1813 	return true;
1814 }
1815 
1816 static bool
1817 malloc_init_hard_a0_locked(void) {
1818 	malloc_initializer = INITIALIZER;
1819 
1820 	JEMALLOC_DIAGNOSTIC_PUSH
1821 	JEMALLOC_DIAGNOSTIC_IGNORE_MISSING_STRUCT_FIELD_INITIALIZERS
1822 	sc_data_t sc_data = {0};
1823 	JEMALLOC_DIAGNOSTIC_POP
1824 
1825 	/*
1826 	 * Ordering here is somewhat tricky; we need sc_boot() first, since that
1827 	 * determines what the size classes will be, and then
1828 	 * malloc_conf_init(), since any slab size tweaking will need to be done
1829 	 * before sz_boot and bin_info_boot, which assume that the values they
1830 	 * read out of sc_data_global are final.
1831 	 */
1832 	sc_boot(&sc_data);
1833 	unsigned bin_shard_sizes[SC_NBINS];
1834 	bin_shard_sizes_boot(bin_shard_sizes);
1835 	/*
1836 	 * prof_boot0 only initializes opt_prof_prefix.  We need to do it before
1837 	 * we parse malloc_conf options, in case malloc_conf parsing overwrites
1838 	 * it.
1839 	 */
1840 	if (config_prof) {
1841 		prof_boot0();
1842 	}
1843 	malloc_conf_init(&sc_data, bin_shard_sizes);
1844 	san_init(opt_lg_san_uaf_align);
1845 	sz_boot(&sc_data, opt_cache_oblivious);
1846 	bin_info_boot(&sc_data, bin_shard_sizes);
1847 
1848 	if (opt_stats_print) {
1849 		/* Print statistics at exit. */
1850 		if (atexit(stats_print_atexit) != 0) {
1851 			malloc_write("<jemalloc>: Error in atexit()\n");
1852 			if (opt_abort) {
1853 				abort();
1854 			}
1855 		}
1856 	}
1857 
1858 	if (stats_boot()) {
1859 		return true;
1860 	}
1861 	if (pages_boot()) {
1862 		return true;
1863 	}
1864 	if (base_boot(TSDN_NULL)) {
1865 		return true;
1866 	}
1867 	/* emap_global is static, hence zeroed. */
1868 	if (emap_init(&arena_emap_global, b0get(), /* zeroed */ true)) {
1869 		return true;
1870 	}
1871 	if (extent_boot()) {
1872 		return true;
1873 	}
1874 	if (ctl_boot()) {
1875 		return true;
1876 	}
1877 	if (config_prof) {
1878 		prof_boot1();
1879 	}
1880 	if (opt_hpa && !hpa_supported()) {
1881 		malloc_printf("<jemalloc>: HPA not supported in the current "
1882 		    "configuration; %s.",
1883 		    opt_abort_conf ? "aborting" : "disabling");
1884 		if (opt_abort_conf) {
1885 			malloc_abort_invalid_conf();
1886 		} else {
1887 			opt_hpa = false;
1888 		}
1889 	}
1890 	if (arena_boot(&sc_data, b0get(), opt_hpa)) {
1891 		return true;
1892 	}
1893 	if (tcache_boot(TSDN_NULL, b0get())) {
1894 		return true;
1895 	}
1896 	if (malloc_mutex_init(&arenas_lock, "arenas", WITNESS_RANK_ARENAS,
1897 	    malloc_mutex_rank_exclusive)) {
1898 		return true;
1899 	}
1900 	hook_boot();
1901 	/*
1902 	 * Create enough scaffolding to allow recursive allocation in
1903 	 * malloc_ncpus().
1904 	 */
1905 	narenas_auto = 1;
1906 	manual_arena_base = narenas_auto + 1;
1907 	memset(arenas, 0, sizeof(arena_t *) * narenas_auto);
1908 	/*
1909 	 * Initialize one arena here.  The rest are lazily created in
1910 	 * arena_choose_hard().
1911 	 */
1912 	if (arena_init(TSDN_NULL, 0, &arena_config_default) == NULL) {
1913 		return true;
1914 	}
1915 	a0 = arena_get(TSDN_NULL, 0, false);
1916 
1917 	if (opt_hpa && !hpa_supported()) {
1918 		malloc_printf("<jemalloc>: HPA not supported in the current "
1919 		    "configuration; %s.",
1920 		    opt_abort_conf ? "aborting" : "disabling");
1921 		if (opt_abort_conf) {
1922 			malloc_abort_invalid_conf();
1923 		} else {
1924 			opt_hpa = false;
1925 		}
1926 	} else if (opt_hpa) {
1927 		hpa_shard_opts_t hpa_shard_opts = opt_hpa_opts;
1928 		hpa_shard_opts.deferral_allowed = background_thread_enabled();
1929 		if (pa_shard_enable_hpa(TSDN_NULL, &a0->pa_shard,
1930 		    &hpa_shard_opts, &opt_hpa_sec_opts)) {
1931 			return true;
1932 		}
1933 	}
1934 
1935 	malloc_init_state = malloc_init_a0_initialized;
1936 
1937 	return false;
1938 }
1939 
1940 static bool
1941 malloc_init_hard_a0(void) {
1942 	bool ret;
1943 
1944 	malloc_mutex_lock(TSDN_NULL, &init_lock);
1945 	ret = malloc_init_hard_a0_locked();
1946 	malloc_mutex_unlock(TSDN_NULL, &init_lock);
1947 	return ret;
1948 }
1949 
1950 /* Initialize data structures which may trigger recursive allocation. */
1951 static bool
1952 malloc_init_hard_recursible(void) {
1953 	malloc_init_state = malloc_init_recursible;
1954 
1955 	ncpus = malloc_ncpus();
1956 	if (opt_percpu_arena != percpu_arena_disabled) {
1957 		bool cpu_count_is_deterministic =
1958 		    malloc_cpu_count_is_deterministic();
1959 		if (!cpu_count_is_deterministic) {
1960 			/*
1961 			 * If # of CPU is not deterministic, and narenas not
1962 			 * specified, disables per cpu arena since it may not
1963 			 * detect CPU IDs properly.
1964 			 */
1965 			if (opt_narenas == 0) {
1966 				opt_percpu_arena = percpu_arena_disabled;
1967 				malloc_write("<jemalloc>: Number of CPUs "
1968 				    "detected is not deterministic. Per-CPU "
1969 				    "arena disabled.\n");
1970 				if (opt_abort_conf) {
1971 					malloc_abort_invalid_conf();
1972 				}
1973 				if (opt_abort) {
1974 					abort();
1975 				}
1976 			}
1977 		}
1978 	}
1979 
1980 #if (defined(JEMALLOC_HAVE_PTHREAD_ATFORK) && !defined(JEMALLOC_MUTEX_INIT_CB) \
1981     && !defined(JEMALLOC_ZONE) && !defined(_WIN32) && \
1982     !defined(__native_client__) && !defined(__NetBSD__))
1983 	/* LinuxThreads' pthread_atfork() allocates. */
1984 	if (pthread_atfork(jemalloc_prefork, jemalloc_postfork_parent,
1985 	    jemalloc_postfork_child) != 0) {
1986 		malloc_write("<jemalloc>: Error in pthread_atfork()\n");
1987 		if (opt_abort) {
1988 			abort();
1989 		}
1990 		return true;
1991 	}
1992 #endif
1993 
1994 	if (background_thread_boot0()) {
1995 		return true;
1996 	}
1997 
1998 	return false;
1999 }
2000 
2001 static unsigned
2002 malloc_narenas_default(void) {
2003 	assert(ncpus > 0);
2004 	/*
2005 	 * For SMP systems, create more than one arena per CPU by
2006 	 * default.
2007 	 */
2008 	if (ncpus > 1) {
2009 		fxp_t fxp_ncpus = FXP_INIT_INT(ncpus);
2010 		fxp_t goal = fxp_mul(fxp_ncpus, opt_narenas_ratio);
2011 		uint32_t int_goal = fxp_round_nearest(goal);
2012 		if (int_goal == 0) {
2013 			return 1;
2014 		}
2015 		return int_goal;
2016 	} else {
2017 		return 1;
2018 	}
2019 }
2020 
2021 static percpu_arena_mode_t
2022 percpu_arena_as_initialized(percpu_arena_mode_t mode) {
2023 	assert(!malloc_initialized());
2024 	assert(mode <= percpu_arena_disabled);
2025 
2026 	if (mode != percpu_arena_disabled) {
2027 		mode += percpu_arena_mode_enabled_base;
2028 	}
2029 
2030 	return mode;
2031 }
2032 
2033 static bool
2034 malloc_init_narenas(void) {
2035 	assert(ncpus > 0);
2036 
2037 	if (opt_percpu_arena != percpu_arena_disabled) {
2038 		if (!have_percpu_arena || malloc_getcpu() < 0) {
2039 			opt_percpu_arena = percpu_arena_disabled;
2040 			malloc_printf("<jemalloc>: perCPU arena getcpu() not "
2041 			    "available. Setting narenas to %u.\n", opt_narenas ?
2042 			    opt_narenas : malloc_narenas_default());
2043 			if (opt_abort) {
2044 				abort();
2045 			}
2046 		} else {
2047 			if (ncpus >= MALLOCX_ARENA_LIMIT) {
2048 				malloc_printf("<jemalloc>: narenas w/ percpu"
2049 				    "arena beyond limit (%d)\n", ncpus);
2050 				if (opt_abort) {
2051 					abort();
2052 				}
2053 				return true;
2054 			}
2055 			/* NB: opt_percpu_arena isn't fully initialized yet. */
2056 			if (percpu_arena_as_initialized(opt_percpu_arena) ==
2057 			    per_phycpu_arena && ncpus % 2 != 0) {
2058 				malloc_printf("<jemalloc>: invalid "
2059 				    "configuration -- per physical CPU arena "
2060 				    "with odd number (%u) of CPUs (no hyper "
2061 				    "threading?).\n", ncpus);
2062 				if (opt_abort)
2063 					abort();
2064 			}
2065 			unsigned n = percpu_arena_ind_limit(
2066 			    percpu_arena_as_initialized(opt_percpu_arena));
2067 			if (opt_narenas < n) {
2068 				/*
2069 				 * If narenas is specified with percpu_arena
2070 				 * enabled, actual narenas is set as the greater
2071 				 * of the two. percpu_arena_choose will be free
2072 				 * to use any of the arenas based on CPU
2073 				 * id. This is conservative (at a small cost)
2074 				 * but ensures correctness.
2075 				 *
2076 				 * If for some reason the ncpus determined at
2077 				 * boot is not the actual number (e.g. because
2078 				 * of affinity setting from numactl), reserving
2079 				 * narenas this way provides a workaround for
2080 				 * percpu_arena.
2081 				 */
2082 				opt_narenas = n;
2083 			}
2084 		}
2085 	}
2086 	if (opt_narenas == 0) {
2087 		opt_narenas = malloc_narenas_default();
2088 	}
2089 	assert(opt_narenas > 0);
2090 
2091 	narenas_auto = opt_narenas;
2092 	/*
2093 	 * Limit the number of arenas to the indexing range of MALLOCX_ARENA().
2094 	 */
2095 	if (narenas_auto >= MALLOCX_ARENA_LIMIT) {
2096 		narenas_auto = MALLOCX_ARENA_LIMIT - 1;
2097 		malloc_printf("<jemalloc>: Reducing narenas to limit (%d)\n",
2098 		    narenas_auto);
2099 	}
2100 	narenas_total_set(narenas_auto);
2101 	if (arena_init_huge()) {
2102 		narenas_total_inc();
2103 	}
2104 	manual_arena_base = narenas_total_get();
2105 
2106 	return false;
2107 }
2108 
2109 static void
2110 malloc_init_percpu(void) {
2111 	opt_percpu_arena = percpu_arena_as_initialized(opt_percpu_arena);
2112 }
2113 
2114 static bool
2115 malloc_init_hard_finish(void) {
2116 	if (malloc_mutex_boot()) {
2117 		return true;
2118 	}
2119 
2120 	malloc_init_state = malloc_init_initialized;
2121 	malloc_slow_flag_init();
2122 
2123 	return false;
2124 }
2125 
2126 static void
2127 malloc_init_hard_cleanup(tsdn_t *tsdn, bool reentrancy_set) {
2128 	malloc_mutex_assert_owner(tsdn, &init_lock);
2129 	malloc_mutex_unlock(tsdn, &init_lock);
2130 	if (reentrancy_set) {
2131 		assert(!tsdn_null(tsdn));
2132 		tsd_t *tsd = tsdn_tsd(tsdn);
2133 		assert(tsd_reentrancy_level_get(tsd) > 0);
2134 		post_reentrancy(tsd);
2135 	}
2136 }
2137 
2138 static bool
2139 malloc_init_hard(void) {
2140 	tsd_t *tsd;
2141 
2142 #if defined(_WIN32) && _WIN32_WINNT < 0x0600
2143 	_init_init_lock();
2144 #endif
2145 	malloc_mutex_lock(TSDN_NULL, &init_lock);
2146 
2147 #define UNLOCK_RETURN(tsdn, ret, reentrancy)		\
2148 	malloc_init_hard_cleanup(tsdn, reentrancy);	\
2149 	return ret;
2150 
2151 	if (!malloc_init_hard_needed()) {
2152 		UNLOCK_RETURN(TSDN_NULL, false, false)
2153 	}
2154 
2155 	if (malloc_init_state != malloc_init_a0_initialized &&
2156 	    malloc_init_hard_a0_locked()) {
2157 		UNLOCK_RETURN(TSDN_NULL, true, false)
2158 	}
2159 
2160 	malloc_mutex_unlock(TSDN_NULL, &init_lock);
2161 	/* Recursive allocation relies on functional tsd. */
2162 	tsd = malloc_tsd_boot0();
2163 	if (tsd == NULL) {
2164 		return true;
2165 	}
2166 	if (malloc_init_hard_recursible()) {
2167 		return true;
2168 	}
2169 
2170 	malloc_mutex_lock(tsd_tsdn(tsd), &init_lock);
2171 	/* Set reentrancy level to 1 during init. */
2172 	pre_reentrancy(tsd, NULL);
2173 	/* Initialize narenas before prof_boot2 (for allocation). */
2174 	if (malloc_init_narenas()
2175 	    || background_thread_boot1(tsd_tsdn(tsd), b0get())) {
2176 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
2177 	}
2178 	if (config_prof && prof_boot2(tsd, b0get())) {
2179 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
2180 	}
2181 
2182 	malloc_init_percpu();
2183 
2184 	if (malloc_init_hard_finish()) {
2185 		UNLOCK_RETURN(tsd_tsdn(tsd), true, true)
2186 	}
2187 	post_reentrancy(tsd);
2188 	malloc_mutex_unlock(tsd_tsdn(tsd), &init_lock);
2189 
2190 	witness_assert_lockless(witness_tsd_tsdn(
2191 	    tsd_witness_tsdp_get_unsafe(tsd)));
2192 	malloc_tsd_boot1();
2193 	/* Update TSD after tsd_boot1. */
2194 	tsd = tsd_fetch();
2195 	if (opt_background_thread) {
2196 		assert(have_background_thread);
2197 		/*
2198 		 * Need to finish init & unlock first before creating background
2199 		 * threads (pthread_create depends on malloc).  ctl_init (which
2200 		 * sets isthreaded) needs to be called without holding any lock.
2201 		 */
2202 		background_thread_ctl_init(tsd_tsdn(tsd));
2203 		if (background_thread_create(tsd, 0)) {
2204 			return true;
2205 		}
2206 	}
2207 #undef UNLOCK_RETURN
2208 	return false;
2209 }
2210 
2211 /*
2212  * End initialization functions.
2213  */
2214 /******************************************************************************/
2215 /*
2216  * Begin allocation-path internal functions and data structures.
2217  */
2218 
2219 /*
2220  * Settings determined by the documented behavior of the allocation functions.
2221  */
2222 typedef struct static_opts_s static_opts_t;
2223 struct static_opts_s {
2224 	/* Whether or not allocation size may overflow. */
2225 	bool may_overflow;
2226 
2227 	/*
2228 	 * Whether or not allocations (with alignment) of size 0 should be
2229 	 * treated as size 1.
2230 	 */
2231 	bool bump_empty_aligned_alloc;
2232 	/*
2233 	 * Whether to assert that allocations are not of size 0 (after any
2234 	 * bumping).
2235 	 */
2236 	bool assert_nonempty_alloc;
2237 
2238 	/*
2239 	 * Whether or not to modify the 'result' argument to malloc in case of
2240 	 * error.
2241 	 */
2242 	bool null_out_result_on_error;
2243 	/* Whether to set errno when we encounter an error condition. */
2244 	bool set_errno_on_error;
2245 
2246 	/*
2247 	 * The minimum valid alignment for functions requesting aligned storage.
2248 	 */
2249 	size_t min_alignment;
2250 
2251 	/* The error string to use if we oom. */
2252 	const char *oom_string;
2253 	/* The error string to use if the passed-in alignment is invalid. */
2254 	const char *invalid_alignment_string;
2255 
2256 	/*
2257 	 * False if we're configured to skip some time-consuming operations.
2258 	 *
2259 	 * This isn't really a malloc "behavior", but it acts as a useful
2260 	 * summary of several other static (or at least, static after program
2261 	 * initialization) options.
2262 	 */
2263 	bool slow;
2264 	/*
2265 	 * Return size.
2266 	 */
2267 	bool usize;
2268 };
2269 
2270 JEMALLOC_ALWAYS_INLINE void
2271 static_opts_init(static_opts_t *static_opts) {
2272 	static_opts->may_overflow = false;
2273 	static_opts->bump_empty_aligned_alloc = false;
2274 	static_opts->assert_nonempty_alloc = false;
2275 	static_opts->null_out_result_on_error = false;
2276 	static_opts->set_errno_on_error = false;
2277 	static_opts->min_alignment = 0;
2278 	static_opts->oom_string = "";
2279 	static_opts->invalid_alignment_string = "";
2280 	static_opts->slow = false;
2281 	static_opts->usize = false;
2282 }
2283 
2284 /*
2285  * These correspond to the macros in jemalloc/jemalloc_macros.h.  Broadly, we
2286  * should have one constant here per magic value there.  Note however that the
2287  * representations need not be related.
2288  */
2289 #define TCACHE_IND_NONE ((unsigned)-1)
2290 #define TCACHE_IND_AUTOMATIC ((unsigned)-2)
2291 #define ARENA_IND_AUTOMATIC ((unsigned)-1)
2292 
2293 typedef struct dynamic_opts_s dynamic_opts_t;
2294 struct dynamic_opts_s {
2295 	void **result;
2296 	size_t usize;
2297 	size_t num_items;
2298 	size_t item_size;
2299 	size_t alignment;
2300 	bool zero;
2301 	unsigned tcache_ind;
2302 	unsigned arena_ind;
2303 };
2304 
2305 JEMALLOC_ALWAYS_INLINE void
2306 dynamic_opts_init(dynamic_opts_t *dynamic_opts) {
2307 	dynamic_opts->result = NULL;
2308 	dynamic_opts->usize = 0;
2309 	dynamic_opts->num_items = 0;
2310 	dynamic_opts->item_size = 0;
2311 	dynamic_opts->alignment = 0;
2312 	dynamic_opts->zero = false;
2313 	dynamic_opts->tcache_ind = TCACHE_IND_AUTOMATIC;
2314 	dynamic_opts->arena_ind = ARENA_IND_AUTOMATIC;
2315 }
2316 
2317 /*
2318  * ind parameter is optional and is only checked and filled if alignment == 0;
2319  * return true if result is out of range.
2320  */
2321 JEMALLOC_ALWAYS_INLINE bool
2322 aligned_usize_get(size_t size, size_t alignment, size_t *usize, szind_t *ind,
2323     bool bump_empty_aligned_alloc) {
2324 	assert(usize != NULL);
2325 	if (alignment == 0) {
2326 		if (ind != NULL) {
2327 			*ind = sz_size2index(size);
2328 			if (unlikely(*ind >= SC_NSIZES)) {
2329 				return true;
2330 			}
2331 			*usize = sz_index2size(*ind);
2332 			assert(*usize > 0 && *usize <= SC_LARGE_MAXCLASS);
2333 			return false;
2334 		}
2335 		*usize = sz_s2u(size);
2336 	} else {
2337 		if (bump_empty_aligned_alloc && unlikely(size == 0)) {
2338 			size = 1;
2339 		}
2340 		*usize = sz_sa2u(size, alignment);
2341 	}
2342 	if (unlikely(*usize == 0 || *usize > SC_LARGE_MAXCLASS)) {
2343 		return true;
2344 	}
2345 	return false;
2346 }
2347 
2348 JEMALLOC_ALWAYS_INLINE bool
2349 zero_get(bool guarantee, bool slow) {
2350 	if (config_fill && slow && unlikely(opt_zero)) {
2351 		return true;
2352 	} else {
2353 		return guarantee;
2354 	}
2355 }
2356 
2357 JEMALLOC_ALWAYS_INLINE tcache_t *
2358 tcache_get_from_ind(tsd_t *tsd, unsigned tcache_ind, bool slow, bool is_alloc) {
2359 	tcache_t *tcache;
2360 	if (tcache_ind == TCACHE_IND_AUTOMATIC) {
2361 		if (likely(!slow)) {
2362 			/* Getting tcache ptr unconditionally. */
2363 			tcache = tsd_tcachep_get(tsd);
2364 			assert(tcache == tcache_get(tsd));
2365 		} else if (is_alloc ||
2366 		    likely(tsd_reentrancy_level_get(tsd) == 0)) {
2367 			tcache = tcache_get(tsd);
2368 		} else {
2369 			tcache = NULL;
2370 		}
2371 	} else {
2372 		/*
2373 		 * Should not specify tcache on deallocation path when being
2374 		 * reentrant.
2375 		 */
2376 		assert(is_alloc || tsd_reentrancy_level_get(tsd) == 0 ||
2377 		    tsd_state_nocleanup(tsd));
2378 		if (tcache_ind == TCACHE_IND_NONE) {
2379 			tcache = NULL;
2380 		} else {
2381 			tcache = tcaches_get(tsd, tcache_ind);
2382 		}
2383 	}
2384 	return tcache;
2385 }
2386 
2387 /* Return true if a manual arena is specified and arena_get() OOMs. */
2388 JEMALLOC_ALWAYS_INLINE bool
2389 arena_get_from_ind(tsd_t *tsd, unsigned arena_ind, arena_t **arena_p) {
2390 	if (arena_ind == ARENA_IND_AUTOMATIC) {
2391 		/*
2392 		 * In case of automatic arena management, we defer arena
2393 		 * computation until as late as we can, hoping to fill the
2394 		 * allocation out of the tcache.
2395 		 */
2396 		*arena_p = NULL;
2397 	} else {
2398 		*arena_p = arena_get(tsd_tsdn(tsd), arena_ind, true);
2399 		if (unlikely(*arena_p == NULL) && arena_ind >= narenas_auto) {
2400 			return true;
2401 		}
2402 	}
2403 	return false;
2404 }
2405 
2406 /* ind is ignored if dopts->alignment > 0. */
2407 JEMALLOC_ALWAYS_INLINE void *
2408 imalloc_no_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd,
2409     size_t size, size_t usize, szind_t ind) {
2410 	/* Fill in the tcache. */
2411 	tcache_t *tcache = tcache_get_from_ind(tsd, dopts->tcache_ind,
2412 	    sopts->slow, /* is_alloc */ true);
2413 
2414 	/* Fill in the arena. */
2415 	arena_t *arena;
2416 	if (arena_get_from_ind(tsd, dopts->arena_ind, &arena)) {
2417 		return NULL;
2418 	}
2419 
2420 	if (unlikely(dopts->alignment != 0)) {
2421 		return ipalloct(tsd_tsdn(tsd), usize, dopts->alignment,
2422 		    dopts->zero, tcache, arena);
2423 	}
2424 
2425 	return iallocztm(tsd_tsdn(tsd), size, ind, dopts->zero, tcache, false,
2426 	    arena, sopts->slow);
2427 }
2428 
2429 JEMALLOC_ALWAYS_INLINE void *
2430 imalloc_sample(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd,
2431     size_t usize, szind_t ind) {
2432 	void *ret;
2433 
2434 	/*
2435 	 * For small allocations, sampling bumps the usize.  If so, we allocate
2436 	 * from the ind_large bucket.
2437 	 */
2438 	szind_t ind_large;
2439 	size_t bumped_usize = usize;
2440 
2441 	dopts->alignment = prof_sample_align(dopts->alignment);
2442 	if (usize <= SC_SMALL_MAXCLASS) {
2443 		assert(((dopts->alignment == 0) ?
2444 		    sz_s2u(SC_LARGE_MINCLASS) :
2445 		    sz_sa2u(SC_LARGE_MINCLASS, dopts->alignment))
2446 			== SC_LARGE_MINCLASS);
2447 		ind_large = sz_size2index(SC_LARGE_MINCLASS);
2448 		bumped_usize = sz_s2u(SC_LARGE_MINCLASS);
2449 		ret = imalloc_no_sample(sopts, dopts, tsd, bumped_usize,
2450 		    bumped_usize, ind_large);
2451 		if (unlikely(ret == NULL)) {
2452 			return NULL;
2453 		}
2454 		arena_prof_promote(tsd_tsdn(tsd), ret, usize);
2455 	} else {
2456 		ret = imalloc_no_sample(sopts, dopts, tsd, usize, usize, ind);
2457 	}
2458 	assert(prof_sample_aligned(ret));
2459 
2460 	return ret;
2461 }
2462 
2463 /*
2464  * Returns true if the allocation will overflow, and false otherwise.  Sets
2465  * *size to the product either way.
2466  */
2467 JEMALLOC_ALWAYS_INLINE bool
2468 compute_size_with_overflow(bool may_overflow, dynamic_opts_t *dopts,
2469     size_t *size) {
2470 	/*
2471 	 * This function is just num_items * item_size, except that we may have
2472 	 * to check for overflow.
2473 	 */
2474 
2475 	if (!may_overflow) {
2476 		assert(dopts->num_items == 1);
2477 		*size = dopts->item_size;
2478 		return false;
2479 	}
2480 
2481 	/* A size_t with its high-half bits all set to 1. */
2482 	static const size_t high_bits = SIZE_T_MAX << (sizeof(size_t) * 8 / 2);
2483 
2484 	*size = dopts->item_size * dopts->num_items;
2485 
2486 	if (unlikely(*size == 0)) {
2487 		return (dopts->num_items != 0 && dopts->item_size != 0);
2488 	}
2489 
2490 	/*
2491 	 * We got a non-zero size, but we don't know if we overflowed to get
2492 	 * there.  To avoid having to do a divide, we'll be clever and note that
2493 	 * if both A and B can be represented in N/2 bits, then their product
2494 	 * can be represented in N bits (without the possibility of overflow).
2495 	 */
2496 	if (likely((high_bits & (dopts->num_items | dopts->item_size)) == 0)) {
2497 		return false;
2498 	}
2499 	if (likely(*size / dopts->item_size == dopts->num_items)) {
2500 		return false;
2501 	}
2502 	return true;
2503 }
2504 
2505 JEMALLOC_ALWAYS_INLINE int
2506 imalloc_body(static_opts_t *sopts, dynamic_opts_t *dopts, tsd_t *tsd) {
2507 	/* Where the actual allocated memory will live. */
2508 	void *allocation = NULL;
2509 	/* Filled in by compute_size_with_overflow below. */
2510 	size_t size = 0;
2511 	/*
2512 	 * The zero initialization for ind is actually dead store, in that its
2513 	 * value is reset before any branch on its value is taken.  Sometimes
2514 	 * though, it's convenient to pass it as arguments before this point.
2515 	 * To avoid undefined behavior then, we initialize it with dummy stores.
2516 	 */
2517 	szind_t ind = 0;
2518 	/* usize will always be properly initialized. */
2519 	size_t usize;
2520 
2521 	/* Reentrancy is only checked on slow path. */
2522 	int8_t reentrancy_level;
2523 
2524 	/* Compute the amount of memory the user wants. */
2525 	if (unlikely(compute_size_with_overflow(sopts->may_overflow, dopts,
2526 	    &size))) {
2527 		goto label_oom;
2528 	}
2529 
2530 	if (unlikely(dopts->alignment < sopts->min_alignment
2531 	    || (dopts->alignment & (dopts->alignment - 1)) != 0)) {
2532 		goto label_invalid_alignment;
2533 	}
2534 
2535 	/* This is the beginning of the "core" algorithm. */
2536 	dopts->zero = zero_get(dopts->zero, sopts->slow);
2537 	if (aligned_usize_get(size, dopts->alignment, &usize, &ind,
2538 	    sopts->bump_empty_aligned_alloc)) {
2539 		goto label_oom;
2540 	}
2541 	dopts->usize = usize;
2542 	/* Validate the user input. */
2543 	if (sopts->assert_nonempty_alloc) {
2544 		assert (size != 0);
2545 	}
2546 
2547 	check_entry_exit_locking(tsd_tsdn(tsd));
2548 
2549 	/*
2550 	 * If we need to handle reentrancy, we can do it out of a
2551 	 * known-initialized arena (i.e. arena 0).
2552 	 */
2553 	reentrancy_level = tsd_reentrancy_level_get(tsd);
2554 	if (sopts->slow && unlikely(reentrancy_level > 0)) {
2555 		/*
2556 		 * We should never specify particular arenas or tcaches from
2557 		 * within our internal allocations.
2558 		 */
2559 		assert(dopts->tcache_ind == TCACHE_IND_AUTOMATIC ||
2560 		    dopts->tcache_ind == TCACHE_IND_NONE);
2561 		assert(dopts->arena_ind == ARENA_IND_AUTOMATIC);
2562 		dopts->tcache_ind = TCACHE_IND_NONE;
2563 		/* We know that arena 0 has already been initialized. */
2564 		dopts->arena_ind = 0;
2565 	}
2566 
2567 	/*
2568 	 * If dopts->alignment > 0, then ind is still 0, but usize was computed
2569 	 * in the previous if statement.  Down the positive alignment path,
2570 	 * imalloc_no_sample and imalloc_sample will ignore ind.
2571 	 */
2572 
2573 	/* If profiling is on, get our profiling context. */
2574 	if (config_prof && opt_prof) {
2575 		bool prof_active = prof_active_get_unlocked();
2576 		bool sample_event = te_prof_sample_event_lookahead(tsd, usize);
2577 		prof_tctx_t *tctx = prof_alloc_prep(tsd, prof_active,
2578 		    sample_event);
2579 
2580 		emap_alloc_ctx_t alloc_ctx;
2581 		if (likely((uintptr_t)tctx == (uintptr_t)1U)) {
2582 			alloc_ctx.slab = (usize <= SC_SMALL_MAXCLASS);
2583 			allocation = imalloc_no_sample(
2584 			    sopts, dopts, tsd, usize, usize, ind);
2585 		} else if ((uintptr_t)tctx > (uintptr_t)1U) {
2586 			allocation = imalloc_sample(
2587 			    sopts, dopts, tsd, usize, ind);
2588 			alloc_ctx.slab = false;
2589 		} else {
2590 			allocation = NULL;
2591 		}
2592 
2593 		if (unlikely(allocation == NULL)) {
2594 			prof_alloc_rollback(tsd, tctx);
2595 			goto label_oom;
2596 		}
2597 		prof_malloc(tsd, allocation, size, usize, &alloc_ctx, tctx);
2598 	} else {
2599 		assert(!opt_prof);
2600 		allocation = imalloc_no_sample(sopts, dopts, tsd, size, usize,
2601 		    ind);
2602 		if (unlikely(allocation == NULL)) {
2603 			goto label_oom;
2604 		}
2605 	}
2606 
2607 	/*
2608 	 * Allocation has been done at this point.  We still have some
2609 	 * post-allocation work to do though.
2610 	 */
2611 
2612 	thread_alloc_event(tsd, usize);
2613 
2614 	assert(dopts->alignment == 0
2615 	    || ((uintptr_t)allocation & (dopts->alignment - 1)) == ZU(0));
2616 
2617 	assert(usize == isalloc(tsd_tsdn(tsd), allocation));
2618 
2619 	if (config_fill && sopts->slow && !dopts->zero
2620 	    && unlikely(opt_junk_alloc)) {
2621 		junk_alloc_callback(allocation, usize);
2622 	}
2623 
2624 	if (sopts->slow) {
2625 		UTRACE(0, size, allocation);
2626 	}
2627 
2628 	/* Success! */
2629 	check_entry_exit_locking(tsd_tsdn(tsd));
2630 	*dopts->result = allocation;
2631 	return 0;
2632 
2633 label_oom:
2634 	if (unlikely(sopts->slow) && config_xmalloc && unlikely(opt_xmalloc)) {
2635 		malloc_write(sopts->oom_string);
2636 		abort();
2637 	}
2638 
2639 	if (sopts->slow) {
2640 		UTRACE(NULL, size, NULL);
2641 	}
2642 
2643 	check_entry_exit_locking(tsd_tsdn(tsd));
2644 
2645 	if (sopts->set_errno_on_error) {
2646 		set_errno(ENOMEM);
2647 	}
2648 
2649 	if (sopts->null_out_result_on_error) {
2650 		*dopts->result = NULL;
2651 	}
2652 
2653 	return ENOMEM;
2654 
2655 	/*
2656 	 * This label is only jumped to by one goto; we move it out of line
2657 	 * anyways to avoid obscuring the non-error paths, and for symmetry with
2658 	 * the oom case.
2659 	 */
2660 label_invalid_alignment:
2661 	if (config_xmalloc && unlikely(opt_xmalloc)) {
2662 		malloc_write(sopts->invalid_alignment_string);
2663 		abort();
2664 	}
2665 
2666 	if (sopts->set_errno_on_error) {
2667 		set_errno(EINVAL);
2668 	}
2669 
2670 	if (sopts->slow) {
2671 		UTRACE(NULL, size, NULL);
2672 	}
2673 
2674 	check_entry_exit_locking(tsd_tsdn(tsd));
2675 
2676 	if (sopts->null_out_result_on_error) {
2677 		*dopts->result = NULL;
2678 	}
2679 
2680 	return EINVAL;
2681 }
2682 
2683 JEMALLOC_ALWAYS_INLINE bool
2684 imalloc_init_check(static_opts_t *sopts, dynamic_opts_t *dopts) {
2685 	if (unlikely(!malloc_initialized()) && unlikely(malloc_init())) {
2686 		if (config_xmalloc && unlikely(opt_xmalloc)) {
2687 			malloc_write(sopts->oom_string);
2688 			abort();
2689 		}
2690 		UTRACE(NULL, dopts->num_items * dopts->item_size, NULL);
2691 		set_errno(ENOMEM);
2692 		*dopts->result = NULL;
2693 
2694 		return false;
2695 	}
2696 
2697 	return true;
2698 }
2699 
2700 /* Returns the errno-style error code of the allocation. */
2701 JEMALLOC_ALWAYS_INLINE int
2702 imalloc(static_opts_t *sopts, dynamic_opts_t *dopts) {
2703 	if (tsd_get_allocates() && !imalloc_init_check(sopts, dopts)) {
2704 		return ENOMEM;
2705 	}
2706 
2707 	/* We always need the tsd.  Let's grab it right away. */
2708 	tsd_t *tsd = tsd_fetch();
2709 	assert(tsd);
2710 	if (likely(tsd_fast(tsd))) {
2711 		/* Fast and common path. */
2712 		tsd_assert_fast(tsd);
2713 		sopts->slow = false;
2714 		return imalloc_body(sopts, dopts, tsd);
2715 	} else {
2716 		if (!tsd_get_allocates() && !imalloc_init_check(sopts, dopts)) {
2717 			return ENOMEM;
2718 		}
2719 
2720 		sopts->slow = true;
2721 		return imalloc_body(sopts, dopts, tsd);
2722 	}
2723 }
2724 
2725 JEMALLOC_NOINLINE
2726 void *
2727 malloc_default(size_t size) {
2728 	void *ret;
2729 	static_opts_t sopts;
2730 	dynamic_opts_t dopts;
2731 
2732 	/*
2733 	 * This variant has logging hook on exit but not on entry.  It's callled
2734 	 * only by je_malloc, below, which emits the entry one for us (and, if
2735 	 * it calls us, does so only via tail call).
2736 	 */
2737 
2738 	static_opts_init(&sopts);
2739 	dynamic_opts_init(&dopts);
2740 
2741 	sopts.null_out_result_on_error = true;
2742 	sopts.set_errno_on_error = true;
2743 	sopts.oom_string = "<jemalloc>: Error in malloc(): out of memory\n";
2744 
2745 	dopts.result = &ret;
2746 	dopts.num_items = 1;
2747 	dopts.item_size = size;
2748 
2749 	imalloc(&sopts, &dopts);
2750 	/*
2751 	 * Note that this branch gets optimized away -- it immediately follows
2752 	 * the check on tsd_fast that sets sopts.slow.
2753 	 */
2754 	if (sopts.slow) {
2755 		uintptr_t args[3] = {size};
2756 		hook_invoke_alloc(hook_alloc_malloc, ret, (uintptr_t)ret, args);
2757 	}
2758 
2759 	LOG("core.malloc.exit", "result: %p", ret);
2760 
2761 	return ret;
2762 }
2763 
2764 /******************************************************************************/
2765 /*
2766  * Begin malloc(3)-compatible functions.
2767  */
2768 
2769 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2770 void JEMALLOC_NOTHROW *
2771 JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1)
2772 je_malloc(size_t size) {
2773 	return imalloc_fastpath(size, &malloc_default);
2774 }
2775 
2776 JEMALLOC_EXPORT int JEMALLOC_NOTHROW
2777 JEMALLOC_ATTR(nonnull(1))
2778 je_posix_memalign(void **memptr, size_t alignment, size_t size) {
2779 	int ret;
2780 	static_opts_t sopts;
2781 	dynamic_opts_t dopts;
2782 
2783 	LOG("core.posix_memalign.entry", "mem ptr: %p, alignment: %zu, "
2784 	    "size: %zu", memptr, alignment, size);
2785 
2786 	static_opts_init(&sopts);
2787 	dynamic_opts_init(&dopts);
2788 
2789 	sopts.bump_empty_aligned_alloc = true;
2790 	sopts.min_alignment = sizeof(void *);
2791 	sopts.oom_string =
2792 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2793 	sopts.invalid_alignment_string =
2794 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2795 
2796 	dopts.result = memptr;
2797 	dopts.num_items = 1;
2798 	dopts.item_size = size;
2799 	dopts.alignment = alignment;
2800 
2801 	ret = imalloc(&sopts, &dopts);
2802 	if (sopts.slow) {
2803 		uintptr_t args[3] = {(uintptr_t)memptr, (uintptr_t)alignment,
2804 			(uintptr_t)size};
2805 		hook_invoke_alloc(hook_alloc_posix_memalign, *memptr,
2806 		    (uintptr_t)ret, args);
2807 	}
2808 
2809 	LOG("core.posix_memalign.exit", "result: %d, alloc ptr: %p", ret,
2810 	    *memptr);
2811 
2812 	return ret;
2813 }
2814 
2815 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2816 void JEMALLOC_NOTHROW *
2817 JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(2)
2818 je_aligned_alloc(size_t alignment, size_t size) {
2819 	void *ret;
2820 
2821 	static_opts_t sopts;
2822 	dynamic_opts_t dopts;
2823 
2824 	LOG("core.aligned_alloc.entry", "alignment: %zu, size: %zu\n",
2825 	    alignment, size);
2826 
2827 	static_opts_init(&sopts);
2828 	dynamic_opts_init(&dopts);
2829 
2830 	sopts.bump_empty_aligned_alloc = true;
2831 	sopts.null_out_result_on_error = true;
2832 	sopts.set_errno_on_error = true;
2833 	sopts.min_alignment = 1;
2834 	sopts.oom_string =
2835 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
2836 	sopts.invalid_alignment_string =
2837 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
2838 
2839 	dopts.result = &ret;
2840 	dopts.num_items = 1;
2841 	dopts.item_size = size;
2842 	dopts.alignment = alignment;
2843 
2844 	imalloc(&sopts, &dopts);
2845 	if (sopts.slow) {
2846 		uintptr_t args[3] = {(uintptr_t)alignment, (uintptr_t)size};
2847 		hook_invoke_alloc(hook_alloc_aligned_alloc, ret,
2848 		    (uintptr_t)ret, args);
2849 	}
2850 
2851 	LOG("core.aligned_alloc.exit", "result: %p", ret);
2852 
2853 	return ret;
2854 }
2855 
2856 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
2857 void JEMALLOC_NOTHROW *
2858 JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2)
2859 je_calloc(size_t num, size_t size) {
2860 	void *ret;
2861 	static_opts_t sopts;
2862 	dynamic_opts_t dopts;
2863 
2864 	LOG("core.calloc.entry", "num: %zu, size: %zu\n", num, size);
2865 
2866 	static_opts_init(&sopts);
2867 	dynamic_opts_init(&dopts);
2868 
2869 	sopts.may_overflow = true;
2870 	sopts.null_out_result_on_error = true;
2871 	sopts.set_errno_on_error = true;
2872 	sopts.oom_string = "<jemalloc>: Error in calloc(): out of memory\n";
2873 
2874 	dopts.result = &ret;
2875 	dopts.num_items = num;
2876 	dopts.item_size = size;
2877 	dopts.zero = true;
2878 
2879 	imalloc(&sopts, &dopts);
2880 	if (sopts.slow) {
2881 		uintptr_t args[3] = {(uintptr_t)num, (uintptr_t)size};
2882 		hook_invoke_alloc(hook_alloc_calloc, ret, (uintptr_t)ret, args);
2883 	}
2884 
2885 	LOG("core.calloc.exit", "result: %p", ret);
2886 
2887 	return ret;
2888 }
2889 
2890 JEMALLOC_ALWAYS_INLINE void
2891 ifree(tsd_t *tsd, void *ptr, tcache_t *tcache, bool slow_path) {
2892 	if (!slow_path) {
2893 		tsd_assert_fast(tsd);
2894 	}
2895 	check_entry_exit_locking(tsd_tsdn(tsd));
2896 	if (tsd_reentrancy_level_get(tsd) != 0) {
2897 		assert(slow_path);
2898 	}
2899 
2900 	assert(ptr != NULL);
2901 	assert(malloc_initialized() || IS_INITIALIZER);
2902 
2903 	emap_alloc_ctx_t alloc_ctx;
2904 	emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
2905 	    &alloc_ctx);
2906 	assert(alloc_ctx.szind != SC_NSIZES);
2907 
2908 	size_t usize = sz_index2size(alloc_ctx.szind);
2909 	if (config_prof && opt_prof) {
2910 		prof_free(tsd, ptr, usize, &alloc_ctx);
2911 	}
2912 
2913 	if (likely(!slow_path)) {
2914 		idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false,
2915 		    false);
2916 	} else {
2917 		if (config_fill && slow_path && opt_junk_free) {
2918 			junk_free_callback(ptr, usize);
2919 		}
2920 		idalloctm(tsd_tsdn(tsd), ptr, tcache, &alloc_ctx, false,
2921 		    true);
2922 	}
2923 	thread_dalloc_event(tsd, usize);
2924 }
2925 
2926 JEMALLOC_ALWAYS_INLINE bool
2927 maybe_check_alloc_ctx(tsd_t *tsd, void *ptr, emap_alloc_ctx_t *alloc_ctx) {
2928 	if (config_opt_size_checks) {
2929 		emap_alloc_ctx_t dbg_ctx;
2930 		emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
2931 		    &dbg_ctx);
2932 		if (alloc_ctx->szind != dbg_ctx.szind) {
2933 			safety_check_fail_sized_dealloc(
2934 			    /* current_dealloc */ true, ptr,
2935 			    /* true_size */ sz_size2index(dbg_ctx.szind),
2936 			    /* input_size */ sz_size2index(alloc_ctx->szind));
2937 			return true;
2938 		}
2939 		if (alloc_ctx->slab != dbg_ctx.slab) {
2940 			safety_check_fail(
2941 			    "Internal heap corruption detected: "
2942 			    "mismatch in slab bit");
2943 			return true;
2944 		}
2945 	}
2946 	return false;
2947 }
2948 
2949 JEMALLOC_ALWAYS_INLINE void
2950 isfree(tsd_t *tsd, void *ptr, size_t usize, tcache_t *tcache, bool slow_path) {
2951 	if (!slow_path) {
2952 		tsd_assert_fast(tsd);
2953 	}
2954 	check_entry_exit_locking(tsd_tsdn(tsd));
2955 	if (tsd_reentrancy_level_get(tsd) != 0) {
2956 		assert(slow_path);
2957 	}
2958 
2959 	assert(ptr != NULL);
2960 	assert(malloc_initialized() || IS_INITIALIZER);
2961 
2962 	emap_alloc_ctx_t alloc_ctx;
2963 	if (!config_prof) {
2964 		alloc_ctx.szind = sz_size2index(usize);
2965 		alloc_ctx.slab = (alloc_ctx.szind < SC_NBINS);
2966 	} else {
2967 		if (likely(!prof_sample_aligned(ptr))) {
2968 			/*
2969 			 * When the ptr is not page aligned, it was not sampled.
2970 			 * usize can be trusted to determine szind and slab.
2971 			 */
2972 			alloc_ctx.szind = sz_size2index(usize);
2973 			alloc_ctx.slab = (alloc_ctx.szind < SC_NBINS);
2974 		} else if (opt_prof) {
2975 			emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global,
2976 			    ptr, &alloc_ctx);
2977 
2978 			if (config_opt_safety_checks) {
2979 				/* Small alloc may have !slab (sampled). */
2980 				if (unlikely(alloc_ctx.szind !=
2981 				    sz_size2index(usize))) {
2982 					safety_check_fail_sized_dealloc(
2983 					    /* current_dealloc */ true, ptr,
2984 					    /* true_size */ sz_index2size(
2985 					    alloc_ctx.szind),
2986 					    /* input_size */ usize);
2987 				}
2988 			}
2989 		} else {
2990 			alloc_ctx.szind = sz_size2index(usize);
2991 			alloc_ctx.slab = (alloc_ctx.szind < SC_NBINS);
2992 		}
2993 	}
2994 	bool fail = maybe_check_alloc_ctx(tsd, ptr, &alloc_ctx);
2995 	if (fail) {
2996 		/*
2997 		 * This is a heap corruption bug.  In real life we'll crash; for
2998 		 * the unit test we just want to avoid breaking anything too
2999 		 * badly to get a test result out.  Let's leak instead of trying
3000 		 * to free.
3001 		 */
3002 		return;
3003 	}
3004 
3005 	if (config_prof && opt_prof) {
3006 		prof_free(tsd, ptr, usize, &alloc_ctx);
3007 	}
3008 	if (likely(!slow_path)) {
3009 		isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, &alloc_ctx,
3010 		    false);
3011 	} else {
3012 		if (config_fill && slow_path && opt_junk_free) {
3013 			junk_free_callback(ptr, usize);
3014 		}
3015 		isdalloct(tsd_tsdn(tsd), ptr, usize, tcache, &alloc_ctx,
3016 		    true);
3017 	}
3018 	thread_dalloc_event(tsd, usize);
3019 }
3020 
3021 static JEMALLOC_NOINLINE
3022 void
3023 free_default(void *ptr) {
3024 	UTRACE(ptr, 0, 0);
3025 	if (likely(ptr != NULL)) {
3026 		/*
3027 		 * We avoid setting up tsd fully (e.g. tcache, arena binding)
3028 		 * based on only free() calls -- other activities trigger the
3029 		 * minimal to full transition.  This is because free() may
3030 		 * happen during thread shutdown after tls deallocation: if a
3031 		 * thread never had any malloc activities until then, a
3032 		 * fully-setup tsd won't be destructed properly.
3033 		 */
3034 		tsd_t *tsd = tsd_fetch_min();
3035 		check_entry_exit_locking(tsd_tsdn(tsd));
3036 
3037 		if (likely(tsd_fast(tsd))) {
3038 			tcache_t *tcache = tcache_get_from_ind(tsd,
3039 			    TCACHE_IND_AUTOMATIC, /* slow */ false,
3040 			    /* is_alloc */ false);
3041 			ifree(tsd, ptr, tcache, /* slow */ false);
3042 		} else {
3043 			tcache_t *tcache = tcache_get_from_ind(tsd,
3044 			    TCACHE_IND_AUTOMATIC, /* slow */ true,
3045 			    /* is_alloc */ false);
3046 			uintptr_t args_raw[3] = {(uintptr_t)ptr};
3047 			hook_invoke_dalloc(hook_dalloc_free, ptr, args_raw);
3048 			ifree(tsd, ptr, tcache, /* slow */ true);
3049 		}
3050 
3051 		check_entry_exit_locking(tsd_tsdn(tsd));
3052 	}
3053 }
3054 
3055 JEMALLOC_ALWAYS_INLINE bool
3056 free_fastpath_nonfast_aligned(void *ptr, bool check_prof) {
3057 	/*
3058 	 * free_fastpath do not handle two uncommon cases: 1) sampled profiled
3059 	 * objects and 2) sampled junk & stash for use-after-free detection.
3060 	 * Both have special alignments which are used to escape the fastpath.
3061 	 *
3062 	 * prof_sample is page-aligned, which covers the UAF check when both
3063 	 * are enabled (the assertion below).  Avoiding redundant checks since
3064 	 * this is on the fastpath -- at most one runtime branch from this.
3065 	 */
3066 	if (config_debug && cache_bin_nonfast_aligned(ptr)) {
3067 		assert(prof_sample_aligned(ptr));
3068 	}
3069 
3070 	if (config_prof && check_prof) {
3071 		/* When prof is enabled, the prof_sample alignment is enough. */
3072 		if (prof_sample_aligned(ptr)) {
3073 			return true;
3074 		} else {
3075 			return false;
3076 		}
3077 	}
3078 
3079 	if (config_uaf_detection) {
3080 		if (cache_bin_nonfast_aligned(ptr)) {
3081 			return true;
3082 		} else {
3083 			return false;
3084 		}
3085 	}
3086 
3087 	return false;
3088 }
3089 
3090 /* Returns whether or not the free attempt was successful. */
3091 JEMALLOC_ALWAYS_INLINE
3092 bool free_fastpath(void *ptr, size_t size, bool size_hint) {
3093 	tsd_t *tsd = tsd_get(false);
3094 	/* The branch gets optimized away unless tsd_get_allocates(). */
3095 	if (unlikely(tsd == NULL)) {
3096 		return false;
3097 	}
3098 	/*
3099 	 *  The tsd_fast() / initialized checks are folded into the branch
3100 	 *  testing (deallocated_after >= threshold) later in this function.
3101 	 *  The threshold will be set to 0 when !tsd_fast.
3102 	 */
3103 	assert(tsd_fast(tsd) ||
3104 	    *tsd_thread_deallocated_next_event_fastp_get_unsafe(tsd) == 0);
3105 
3106 	emap_alloc_ctx_t alloc_ctx;
3107 	if (!size_hint) {
3108 		bool err = emap_alloc_ctx_try_lookup_fast(tsd,
3109 		    &arena_emap_global, ptr, &alloc_ctx);
3110 
3111 		/* Note: profiled objects will have alloc_ctx.slab set */
3112 		if (unlikely(err || !alloc_ctx.slab ||
3113 		    free_fastpath_nonfast_aligned(ptr,
3114 		    /* check_prof */ false))) {
3115 			return false;
3116 		}
3117 		assert(alloc_ctx.szind != SC_NSIZES);
3118 	} else {
3119 		/*
3120 		 * Check for both sizes that are too large, and for sampled /
3121 		 * special aligned objects.  The alignment check will also check
3122 		 * for null ptr.
3123 		 */
3124 		if (unlikely(size > SC_LOOKUP_MAXCLASS ||
3125 		    free_fastpath_nonfast_aligned(ptr,
3126 		    /* check_prof */ true))) {
3127 			return false;
3128 		}
3129 		alloc_ctx.szind = sz_size2index_lookup(size);
3130 		/* Max lookup class must be small. */
3131 		assert(alloc_ctx.szind < SC_NBINS);
3132 		/* This is a dead store, except when opt size checking is on. */
3133 		alloc_ctx.slab = true;
3134 	}
3135 	/*
3136 	 * Currently the fastpath only handles small sizes.  The branch on
3137 	 * SC_LOOKUP_MAXCLASS makes sure of it.  This lets us avoid checking
3138 	 * tcache szind upper limit (i.e. tcache_maxclass) as well.
3139 	 */
3140 	assert(alloc_ctx.slab);
3141 
3142 	uint64_t deallocated, threshold;
3143 	te_free_fastpath_ctx(tsd, &deallocated, &threshold);
3144 
3145 	size_t usize = sz_index2size(alloc_ctx.szind);
3146 	uint64_t deallocated_after = deallocated + usize;
3147 	/*
3148 	 * Check for events and tsd non-nominal (fast_threshold will be set to
3149 	 * 0) in a single branch.  Note that this handles the uninitialized case
3150 	 * as well (TSD init will be triggered on the non-fastpath).  Therefore
3151 	 * anything depends on a functional TSD (e.g. the alloc_ctx sanity check
3152 	 * below) needs to be after this branch.
3153 	 */
3154 	if (unlikely(deallocated_after >= threshold)) {
3155 		return false;
3156 	}
3157 	assert(tsd_fast(tsd));
3158 	bool fail = maybe_check_alloc_ctx(tsd, ptr, &alloc_ctx);
3159 	if (fail) {
3160 		/* See the comment in isfree. */
3161 		return true;
3162 	}
3163 
3164 	tcache_t *tcache = tcache_get_from_ind(tsd, TCACHE_IND_AUTOMATIC,
3165 	    /* slow */ false, /* is_alloc */ false);
3166 	cache_bin_t *bin = &tcache->bins[alloc_ctx.szind];
3167 
3168 	/*
3169 	 * If junking were enabled, this is where we would do it.  It's not
3170 	 * though, since we ensured above that we're on the fast path.  Assert
3171 	 * that to double-check.
3172 	 */
3173 	assert(!opt_junk_free);
3174 
3175 	if (!cache_bin_dalloc_easy(bin, ptr)) {
3176 		return false;
3177 	}
3178 
3179 	*tsd_thread_deallocatedp_get(tsd) = deallocated_after;
3180 
3181 	return true;
3182 }
3183 
3184 JEMALLOC_EXPORT void JEMALLOC_NOTHROW
3185 je_free(void *ptr) {
3186 	LOG("core.free.entry", "ptr: %p", ptr);
3187 
3188 	if (!free_fastpath(ptr, 0, false)) {
3189 		free_default(ptr);
3190 	}
3191 
3192 	LOG("core.free.exit", "");
3193 }
3194 
3195 /*
3196  * End malloc(3)-compatible functions.
3197  */
3198 /******************************************************************************/
3199 /*
3200  * Begin non-standard override functions.
3201  */
3202 
3203 #ifdef JEMALLOC_OVERRIDE_MEMALIGN
3204 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
3205 void JEMALLOC_NOTHROW *
3206 JEMALLOC_ATTR(malloc)
3207 je_memalign(size_t alignment, size_t size) {
3208 	void *ret;
3209 	static_opts_t sopts;
3210 	dynamic_opts_t dopts;
3211 
3212 	LOG("core.memalign.entry", "alignment: %zu, size: %zu\n", alignment,
3213 	    size);
3214 
3215 	static_opts_init(&sopts);
3216 	dynamic_opts_init(&dopts);
3217 
3218 	sopts.min_alignment = 1;
3219 	sopts.oom_string =
3220 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
3221 	sopts.invalid_alignment_string =
3222 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
3223 	sopts.null_out_result_on_error = true;
3224 
3225 	dopts.result = &ret;
3226 	dopts.num_items = 1;
3227 	dopts.item_size = size;
3228 	dopts.alignment = alignment;
3229 
3230 	imalloc(&sopts, &dopts);
3231 	if (sopts.slow) {
3232 		uintptr_t args[3] = {alignment, size};
3233 		hook_invoke_alloc(hook_alloc_memalign, ret, (uintptr_t)ret,
3234 		    args);
3235 	}
3236 
3237 	LOG("core.memalign.exit", "result: %p", ret);
3238 	return ret;
3239 }
3240 #endif
3241 
3242 #ifdef JEMALLOC_OVERRIDE_VALLOC
3243 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
3244 void JEMALLOC_NOTHROW *
3245 JEMALLOC_ATTR(malloc)
3246 je_valloc(size_t size) {
3247 	void *ret;
3248 
3249 	static_opts_t sopts;
3250 	dynamic_opts_t dopts;
3251 
3252 	LOG("core.valloc.entry", "size: %zu\n", size);
3253 
3254 	static_opts_init(&sopts);
3255 	dynamic_opts_init(&dopts);
3256 
3257 	sopts.null_out_result_on_error = true;
3258 	sopts.min_alignment = PAGE;
3259 	sopts.oom_string =
3260 	    "<jemalloc>: Error allocating aligned memory: out of memory\n";
3261 	sopts.invalid_alignment_string =
3262 	    "<jemalloc>: Error allocating aligned memory: invalid alignment\n";
3263 
3264 	dopts.result = &ret;
3265 	dopts.num_items = 1;
3266 	dopts.item_size = size;
3267 	dopts.alignment = PAGE;
3268 
3269 	imalloc(&sopts, &dopts);
3270 	if (sopts.slow) {
3271 		uintptr_t args[3] = {size};
3272 		hook_invoke_alloc(hook_alloc_valloc, ret, (uintptr_t)ret, args);
3273 	}
3274 
3275 	LOG("core.valloc.exit", "result: %p\n", ret);
3276 	return ret;
3277 }
3278 #endif
3279 
3280 #if defined(JEMALLOC_IS_MALLOC) && defined(JEMALLOC_GLIBC_MALLOC_HOOK)
3281 /*
3282  * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
3283  * to inconsistently reference libc's malloc(3)-compatible functions
3284  * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
3285  *
3286  * These definitions interpose hooks in glibc.  The functions are actually
3287  * passed an extra argument for the caller return address, which will be
3288  * ignored.
3289  */
3290 #include <features.h> // defines __GLIBC__ if we are compiling against glibc
3291 
3292 JEMALLOC_EXPORT void (*__free_hook)(void *ptr) = je_free;
3293 JEMALLOC_EXPORT void *(*__malloc_hook)(size_t size) = je_malloc;
3294 JEMALLOC_EXPORT void *(*__realloc_hook)(void *ptr, size_t size) = je_realloc;
3295 #  ifdef JEMALLOC_GLIBC_MEMALIGN_HOOK
3296 JEMALLOC_EXPORT void *(*__memalign_hook)(size_t alignment, size_t size) =
3297     je_memalign;
3298 #  endif
3299 
3300 #  ifdef __GLIBC__
3301 /*
3302  * To enable static linking with glibc, the libc specific malloc interface must
3303  * be implemented also, so none of glibc's malloc.o functions are added to the
3304  * link.
3305  */
3306 #    define ALIAS(je_fn)	__attribute__((alias (#je_fn), used))
3307 /* To force macro expansion of je_ prefix before stringification. */
3308 #    define PREALIAS(je_fn)	ALIAS(je_fn)
3309 #    ifdef JEMALLOC_OVERRIDE___LIBC_CALLOC
3310 void *__libc_calloc(size_t n, size_t size) PREALIAS(je_calloc);
3311 #    endif
3312 #    ifdef JEMALLOC_OVERRIDE___LIBC_FREE
3313 void __libc_free(void* ptr) PREALIAS(je_free);
3314 #    endif
3315 #    ifdef JEMALLOC_OVERRIDE___LIBC_MALLOC
3316 void *__libc_malloc(size_t size) PREALIAS(je_malloc);
3317 #    endif
3318 #    ifdef JEMALLOC_OVERRIDE___LIBC_MEMALIGN
3319 void *__libc_memalign(size_t align, size_t s) PREALIAS(je_memalign);
3320 #    endif
3321 #    ifdef JEMALLOC_OVERRIDE___LIBC_REALLOC
3322 void *__libc_realloc(void* ptr, size_t size) PREALIAS(je_realloc);
3323 #    endif
3324 #    ifdef JEMALLOC_OVERRIDE___LIBC_VALLOC
3325 void *__libc_valloc(size_t size) PREALIAS(je_valloc);
3326 #    endif
3327 #    ifdef JEMALLOC_OVERRIDE___POSIX_MEMALIGN
3328 int __posix_memalign(void** r, size_t a, size_t s) PREALIAS(je_posix_memalign);
3329 #    endif
3330 #    undef PREALIAS
3331 #    undef ALIAS
3332 #  endif
3333 #endif
3334 
3335 /*
3336  * End non-standard override functions.
3337  */
3338 /******************************************************************************/
3339 /*
3340  * Begin non-standard functions.
3341  */
3342 
3343 JEMALLOC_ALWAYS_INLINE unsigned
3344 mallocx_tcache_get(int flags) {
3345 	if (likely((flags & MALLOCX_TCACHE_MASK) == 0)) {
3346 		return TCACHE_IND_AUTOMATIC;
3347 	} else if ((flags & MALLOCX_TCACHE_MASK) == MALLOCX_TCACHE_NONE) {
3348 		return TCACHE_IND_NONE;
3349 	} else {
3350 		return MALLOCX_TCACHE_GET(flags);
3351 	}
3352 }
3353 
3354 JEMALLOC_ALWAYS_INLINE unsigned
3355 mallocx_arena_get(int flags) {
3356 	if (unlikely((flags & MALLOCX_ARENA_MASK) != 0)) {
3357 		return MALLOCX_ARENA_GET(flags);
3358 	} else {
3359 		return ARENA_IND_AUTOMATIC;
3360 	}
3361 }
3362 
3363 #ifdef JEMALLOC_EXPERIMENTAL_SMALLOCX_API
3364 
3365 #define JEMALLOC_SMALLOCX_CONCAT_HELPER(x, y) x ## y
3366 #define JEMALLOC_SMALLOCX_CONCAT_HELPER2(x, y)  \
3367   JEMALLOC_SMALLOCX_CONCAT_HELPER(x, y)
3368 
3369 typedef struct {
3370 	void *ptr;
3371 	size_t size;
3372 } smallocx_return_t;
3373 
3374 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
3375 smallocx_return_t JEMALLOC_NOTHROW
3376 /*
3377  * The attribute JEMALLOC_ATTR(malloc) cannot be used due to:
3378  *  - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86488
3379  */
3380 JEMALLOC_SMALLOCX_CONCAT_HELPER2(je_smallocx_, JEMALLOC_VERSION_GID_IDENT)
3381   (size_t size, int flags) {
3382 	/*
3383 	 * Note: the attribute JEMALLOC_ALLOC_SIZE(1) cannot be
3384 	 * used here because it makes writing beyond the `size`
3385 	 * of the `ptr` undefined behavior, but the objective
3386 	 * of this function is to allow writing beyond `size`
3387 	 * up to `smallocx_return_t::size`.
3388 	 */
3389 	smallocx_return_t ret;
3390 	static_opts_t sopts;
3391 	dynamic_opts_t dopts;
3392 
3393 	LOG("core.smallocx.entry", "size: %zu, flags: %d", size, flags);
3394 
3395 	static_opts_init(&sopts);
3396 	dynamic_opts_init(&dopts);
3397 
3398 	sopts.assert_nonempty_alloc = true;
3399 	sopts.null_out_result_on_error = true;
3400 	sopts.oom_string = "<jemalloc>: Error in mallocx(): out of memory\n";
3401 	sopts.usize = true;
3402 
3403 	dopts.result = &ret.ptr;
3404 	dopts.num_items = 1;
3405 	dopts.item_size = size;
3406 	if (unlikely(flags != 0)) {
3407 		dopts.alignment = MALLOCX_ALIGN_GET(flags);
3408 		dopts.zero = MALLOCX_ZERO_GET(flags);
3409 		dopts.tcache_ind = mallocx_tcache_get(flags);
3410 		dopts.arena_ind = mallocx_arena_get(flags);
3411 	}
3412 
3413 	imalloc(&sopts, &dopts);
3414 	assert(dopts.usize == je_nallocx(size, flags));
3415 	ret.size = dopts.usize;
3416 
3417 	LOG("core.smallocx.exit", "result: %p, size: %zu", ret.ptr, ret.size);
3418 	return ret;
3419 }
3420 #undef JEMALLOC_SMALLOCX_CONCAT_HELPER
3421 #undef JEMALLOC_SMALLOCX_CONCAT_HELPER2
3422 #endif
3423 
3424 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
3425 void JEMALLOC_NOTHROW *
3426 JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1)
3427 je_mallocx(size_t size, int flags) {
3428 	void *ret;
3429 	static_opts_t sopts;
3430 	dynamic_opts_t dopts;
3431 
3432 	LOG("core.mallocx.entry", "size: %zu, flags: %d", size, flags);
3433 
3434 	static_opts_init(&sopts);
3435 	dynamic_opts_init(&dopts);
3436 
3437 	sopts.assert_nonempty_alloc = true;
3438 	sopts.null_out_result_on_error = true;
3439 	sopts.oom_string = "<jemalloc>: Error in mallocx(): out of memory\n";
3440 
3441 	dopts.result = &ret;
3442 	dopts.num_items = 1;
3443 	dopts.item_size = size;
3444 	if (unlikely(flags != 0)) {
3445 		dopts.alignment = MALLOCX_ALIGN_GET(flags);
3446 		dopts.zero = MALLOCX_ZERO_GET(flags);
3447 		dopts.tcache_ind = mallocx_tcache_get(flags);
3448 		dopts.arena_ind = mallocx_arena_get(flags);
3449 	}
3450 
3451 	imalloc(&sopts, &dopts);
3452 	if (sopts.slow) {
3453 		uintptr_t args[3] = {size, flags};
3454 		hook_invoke_alloc(hook_alloc_mallocx, ret, (uintptr_t)ret,
3455 		    args);
3456 	}
3457 
3458 	LOG("core.mallocx.exit", "result: %p", ret);
3459 	return ret;
3460 }
3461 
3462 static void *
3463 irallocx_prof_sample(tsdn_t *tsdn, void *old_ptr, size_t old_usize,
3464     size_t usize, size_t alignment, bool zero, tcache_t *tcache, arena_t *arena,
3465     prof_tctx_t *tctx, hook_ralloc_args_t *hook_args) {
3466 	void *p;
3467 
3468 	if (tctx == NULL) {
3469 		return NULL;
3470 	}
3471 
3472 	alignment = prof_sample_align(alignment);
3473 	if (usize <= SC_SMALL_MAXCLASS) {
3474 		p = iralloct(tsdn, old_ptr, old_usize,
3475 		    SC_LARGE_MINCLASS, alignment, zero, tcache,
3476 		    arena, hook_args);
3477 		if (p == NULL) {
3478 			return NULL;
3479 		}
3480 		arena_prof_promote(tsdn, p, usize);
3481 	} else {
3482 		p = iralloct(tsdn, old_ptr, old_usize, usize, alignment, zero,
3483 		    tcache, arena, hook_args);
3484 	}
3485 	assert(prof_sample_aligned(p));
3486 
3487 	return p;
3488 }
3489 
3490 JEMALLOC_ALWAYS_INLINE void *
3491 irallocx_prof(tsd_t *tsd, void *old_ptr, size_t old_usize, size_t size,
3492     size_t alignment, size_t usize, bool zero, tcache_t *tcache,
3493     arena_t *arena, emap_alloc_ctx_t *alloc_ctx,
3494     hook_ralloc_args_t *hook_args) {
3495 	prof_info_t old_prof_info;
3496 	prof_info_get_and_reset_recent(tsd, old_ptr, alloc_ctx, &old_prof_info);
3497 	bool prof_active = prof_active_get_unlocked();
3498 	bool sample_event = te_prof_sample_event_lookahead(tsd, usize);
3499 	prof_tctx_t *tctx = prof_alloc_prep(tsd, prof_active, sample_event);
3500 	void *p;
3501 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
3502 		p = irallocx_prof_sample(tsd_tsdn(tsd), old_ptr, old_usize,
3503 		    usize, alignment, zero, tcache, arena, tctx, hook_args);
3504 	} else {
3505 		p = iralloct(tsd_tsdn(tsd), old_ptr, old_usize, size, alignment,
3506 		    zero, tcache, arena, hook_args);
3507 	}
3508 	if (unlikely(p == NULL)) {
3509 		prof_alloc_rollback(tsd, tctx);
3510 		return NULL;
3511 	}
3512 	assert(usize == isalloc(tsd_tsdn(tsd), p));
3513 	prof_realloc(tsd, p, size, usize, tctx, prof_active, old_ptr,
3514 	    old_usize, &old_prof_info, sample_event);
3515 
3516 	return p;
3517 }
3518 
3519 static void *
3520 do_rallocx(void *ptr, size_t size, int flags, bool is_realloc) {
3521 	void *p;
3522 	tsd_t *tsd;
3523 	size_t usize;
3524 	size_t old_usize;
3525 	size_t alignment = MALLOCX_ALIGN_GET(flags);
3526 	arena_t *arena;
3527 
3528 	assert(ptr != NULL);
3529 	assert(size != 0);
3530 	assert(malloc_initialized() || IS_INITIALIZER);
3531 	tsd = tsd_fetch();
3532 	check_entry_exit_locking(tsd_tsdn(tsd));
3533 
3534 	bool zero = zero_get(MALLOCX_ZERO_GET(flags), /* slow */ true);
3535 
3536 	unsigned arena_ind = mallocx_arena_get(flags);
3537 	if (arena_get_from_ind(tsd, arena_ind, &arena)) {
3538 		goto label_oom;
3539 	}
3540 
3541 	unsigned tcache_ind = mallocx_tcache_get(flags);
3542 	tcache_t *tcache = tcache_get_from_ind(tsd, tcache_ind,
3543 	    /* slow */ true, /* is_alloc */ true);
3544 
3545 	emap_alloc_ctx_t alloc_ctx;
3546 	emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
3547 	    &alloc_ctx);
3548 	assert(alloc_ctx.szind != SC_NSIZES);
3549 	old_usize = sz_index2size(alloc_ctx.szind);
3550 	assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
3551 	if (aligned_usize_get(size, alignment, &usize, NULL, false)) {
3552 		goto label_oom;
3553 	}
3554 
3555 	hook_ralloc_args_t hook_args = {is_realloc, {(uintptr_t)ptr, size,
3556 		flags, 0}};
3557 	if (config_prof && opt_prof) {
3558 		p = irallocx_prof(tsd, ptr, old_usize, size, alignment, usize,
3559 		    zero, tcache, arena, &alloc_ctx, &hook_args);
3560 		if (unlikely(p == NULL)) {
3561 			goto label_oom;
3562 		}
3563 	} else {
3564 		p = iralloct(tsd_tsdn(tsd), ptr, old_usize, size, alignment,
3565 		    zero, tcache, arena, &hook_args);
3566 		if (unlikely(p == NULL)) {
3567 			goto label_oom;
3568 		}
3569 		assert(usize == isalloc(tsd_tsdn(tsd), p));
3570 	}
3571 	assert(alignment == 0 || ((uintptr_t)p & (alignment - 1)) == ZU(0));
3572 	thread_alloc_event(tsd, usize);
3573 	thread_dalloc_event(tsd, old_usize);
3574 
3575 	UTRACE(ptr, size, p);
3576 	check_entry_exit_locking(tsd_tsdn(tsd));
3577 
3578 	if (config_fill && unlikely(opt_junk_alloc) && usize > old_usize
3579 	    && !zero) {
3580 		size_t excess_len = usize - old_usize;
3581 		void *excess_start = (void *)((uintptr_t)p + old_usize);
3582 		junk_alloc_callback(excess_start, excess_len);
3583 	}
3584 
3585 	return p;
3586 label_oom:
3587 	if (config_xmalloc && unlikely(opt_xmalloc)) {
3588 		malloc_write("<jemalloc>: Error in rallocx(): out of memory\n");
3589 		abort();
3590 	}
3591 	UTRACE(ptr, size, 0);
3592 	check_entry_exit_locking(tsd_tsdn(tsd));
3593 
3594 	return NULL;
3595 }
3596 
3597 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
3598 void JEMALLOC_NOTHROW *
3599 JEMALLOC_ALLOC_SIZE(2)
3600 je_rallocx(void *ptr, size_t size, int flags) {
3601 	LOG("core.rallocx.entry", "ptr: %p, size: %zu, flags: %d", ptr,
3602 	    size, flags);
3603 	void *ret = do_rallocx(ptr, size, flags, false);
3604 	LOG("core.rallocx.exit", "result: %p", ret);
3605 	return ret;
3606 }
3607 
3608 static void *
3609 do_realloc_nonnull_zero(void *ptr) {
3610 	if (config_stats) {
3611 		atomic_fetch_add_zu(&zero_realloc_count, 1, ATOMIC_RELAXED);
3612 	}
3613 	if (opt_zero_realloc_action == zero_realloc_action_alloc) {
3614 		/*
3615 		 * The user might have gotten an alloc setting while expecting a
3616 		 * free setting.  If that's the case, we at least try to
3617 		 * reduce the harm, and turn off the tcache while allocating, so
3618 		 * that we'll get a true first fit.
3619 		 */
3620 		return do_rallocx(ptr, 1, MALLOCX_TCACHE_NONE, true);
3621 	} else if (opt_zero_realloc_action == zero_realloc_action_free) {
3622 		UTRACE(ptr, 0, 0);
3623 		tsd_t *tsd = tsd_fetch();
3624 		check_entry_exit_locking(tsd_tsdn(tsd));
3625 
3626 		tcache_t *tcache = tcache_get_from_ind(tsd,
3627 		    TCACHE_IND_AUTOMATIC, /* slow */ true,
3628 		    /* is_alloc */ false);
3629 		uintptr_t args[3] = {(uintptr_t)ptr, 0};
3630 		hook_invoke_dalloc(hook_dalloc_realloc, ptr, args);
3631 		ifree(tsd, ptr, tcache, true);
3632 
3633 		check_entry_exit_locking(tsd_tsdn(tsd));
3634 		return NULL;
3635 	} else {
3636 		safety_check_fail("Called realloc(non-null-ptr, 0) with "
3637 		    "zero_realloc:abort set\n");
3638 		/* In real code, this will never run; the safety check failure
3639 		 * will call abort.  In the unit test, we just want to bail out
3640 		 * without corrupting internal state that the test needs to
3641 		 * finish.
3642 		 */
3643 		return NULL;
3644 	}
3645 }
3646 
3647 JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
3648 void JEMALLOC_NOTHROW *
3649 JEMALLOC_ALLOC_SIZE(2)
3650 je_realloc(void *ptr, size_t size) {
3651 	LOG("core.realloc.entry", "ptr: %p, size: %zu\n", ptr, size);
3652 
3653 	if (likely(ptr != NULL && size != 0)) {
3654 		void *ret = do_rallocx(ptr, size, 0, true);
3655 		LOG("core.realloc.exit", "result: %p", ret);
3656 		return ret;
3657 	} else if (ptr != NULL && size == 0) {
3658 		void *ret = do_realloc_nonnull_zero(ptr);
3659 		LOG("core.realloc.exit", "result: %p", ret);
3660 		return ret;
3661 	} else {
3662 		/* realloc(NULL, size) is equivalent to malloc(size). */
3663 		void *ret;
3664 
3665 		static_opts_t sopts;
3666 		dynamic_opts_t dopts;
3667 
3668 		static_opts_init(&sopts);
3669 		dynamic_opts_init(&dopts);
3670 
3671 		sopts.null_out_result_on_error = true;
3672 		sopts.set_errno_on_error = true;
3673 		sopts.oom_string =
3674 		    "<jemalloc>: Error in realloc(): out of memory\n";
3675 
3676 		dopts.result = &ret;
3677 		dopts.num_items = 1;
3678 		dopts.item_size = size;
3679 
3680 		imalloc(&sopts, &dopts);
3681 		if (sopts.slow) {
3682 			uintptr_t args[3] = {(uintptr_t)ptr, size};
3683 			hook_invoke_alloc(hook_alloc_realloc, ret,
3684 			    (uintptr_t)ret, args);
3685 		}
3686 		LOG("core.realloc.exit", "result: %p", ret);
3687 		return ret;
3688 	}
3689 }
3690 
3691 JEMALLOC_ALWAYS_INLINE size_t
3692 ixallocx_helper(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size,
3693     size_t extra, size_t alignment, bool zero) {
3694 	size_t newsize;
3695 
3696 	if (ixalloc(tsdn, ptr, old_usize, size, extra, alignment, zero,
3697 	    &newsize)) {
3698 		return old_usize;
3699 	}
3700 
3701 	return newsize;
3702 }
3703 
3704 static size_t
3705 ixallocx_prof_sample(tsdn_t *tsdn, void *ptr, size_t old_usize, size_t size,
3706     size_t extra, size_t alignment, bool zero, prof_tctx_t *tctx) {
3707 	/* Sampled allocation needs to be page aligned. */
3708 	if (tctx == NULL || !prof_sample_aligned(ptr)) {
3709 		return old_usize;
3710 	}
3711 
3712 	return ixallocx_helper(tsdn, ptr, old_usize, size, extra, alignment,
3713 	    zero);
3714 }
3715 
3716 JEMALLOC_ALWAYS_INLINE size_t
3717 ixallocx_prof(tsd_t *tsd, void *ptr, size_t old_usize, size_t size,
3718     size_t extra, size_t alignment, bool zero, emap_alloc_ctx_t *alloc_ctx) {
3719 	/*
3720 	 * old_prof_info is only used for asserting that the profiling info
3721 	 * isn't changed by the ixalloc() call.
3722 	 */
3723 	prof_info_t old_prof_info;
3724 	prof_info_get(tsd, ptr, alloc_ctx, &old_prof_info);
3725 
3726 	/*
3727 	 * usize isn't knowable before ixalloc() returns when extra is non-zero.
3728 	 * Therefore, compute its maximum possible value and use that in
3729 	 * prof_alloc_prep() to decide whether to capture a backtrace.
3730 	 * prof_realloc() will use the actual usize to decide whether to sample.
3731 	 */
3732 	size_t usize_max;
3733 	if (aligned_usize_get(size + extra, alignment, &usize_max, NULL,
3734 	    false)) {
3735 		/*
3736 		 * usize_max is out of range, and chances are that allocation
3737 		 * will fail, but use the maximum possible value and carry on
3738 		 * with prof_alloc_prep(), just in case allocation succeeds.
3739 		 */
3740 		usize_max = SC_LARGE_MAXCLASS;
3741 	}
3742 	bool prof_active = prof_active_get_unlocked();
3743 	bool sample_event = te_prof_sample_event_lookahead(tsd, usize_max);
3744 	prof_tctx_t *tctx = prof_alloc_prep(tsd, prof_active, sample_event);
3745 
3746 	size_t usize;
3747 	if (unlikely((uintptr_t)tctx != (uintptr_t)1U)) {
3748 		usize = ixallocx_prof_sample(tsd_tsdn(tsd), ptr, old_usize,
3749 		    size, extra, alignment, zero, tctx);
3750 	} else {
3751 		usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size,
3752 		    extra, alignment, zero);
3753 	}
3754 
3755 	/*
3756 	 * At this point we can still safely get the original profiling
3757 	 * information associated with the ptr, because (a) the edata_t object
3758 	 * associated with the ptr still lives and (b) the profiling info
3759 	 * fields are not touched.  "(a)" is asserted in the outer je_xallocx()
3760 	 * function, and "(b)" is indirectly verified below by checking that
3761 	 * the alloc_tctx field is unchanged.
3762 	 */
3763 	prof_info_t prof_info;
3764 	if (usize == old_usize) {
3765 		prof_info_get(tsd, ptr, alloc_ctx, &prof_info);
3766 		prof_alloc_rollback(tsd, tctx);
3767 	} else {
3768 		prof_info_get_and_reset_recent(tsd, ptr, alloc_ctx, &prof_info);
3769 		assert(usize <= usize_max);
3770 		sample_event = te_prof_sample_event_lookahead(tsd, usize);
3771 		prof_realloc(tsd, ptr, size, usize, tctx, prof_active, ptr,
3772 		    old_usize, &prof_info, sample_event);
3773 	}
3774 
3775 	assert(old_prof_info.alloc_tctx == prof_info.alloc_tctx);
3776 	return usize;
3777 }
3778 
3779 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
3780 je_xallocx(void *ptr, size_t size, size_t extra, int flags) {
3781 	tsd_t *tsd;
3782 	size_t usize, old_usize;
3783 	size_t alignment = MALLOCX_ALIGN_GET(flags);
3784 	bool zero = zero_get(MALLOCX_ZERO_GET(flags), /* slow */ true);
3785 
3786 	LOG("core.xallocx.entry", "ptr: %p, size: %zu, extra: %zu, "
3787 	    "flags: %d", ptr, size, extra, flags);
3788 
3789 	assert(ptr != NULL);
3790 	assert(size != 0);
3791 	assert(SIZE_T_MAX - size >= extra);
3792 	assert(malloc_initialized() || IS_INITIALIZER);
3793 	tsd = tsd_fetch();
3794 	check_entry_exit_locking(tsd_tsdn(tsd));
3795 
3796 	/*
3797 	 * old_edata is only for verifying that xallocx() keeps the edata_t
3798 	 * object associated with the ptr (though the content of the edata_t
3799 	 * object can be changed).
3800 	 */
3801 	edata_t *old_edata = emap_edata_lookup(tsd_tsdn(tsd),
3802 	    &arena_emap_global, ptr);
3803 
3804 	emap_alloc_ctx_t alloc_ctx;
3805 	emap_alloc_ctx_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr,
3806 	    &alloc_ctx);
3807 	assert(alloc_ctx.szind != SC_NSIZES);
3808 	old_usize = sz_index2size(alloc_ctx.szind);
3809 	assert(old_usize == isalloc(tsd_tsdn(tsd), ptr));
3810 	/*
3811 	 * The API explicitly absolves itself of protecting against (size +
3812 	 * extra) numerical overflow, but we may need to clamp extra to avoid
3813 	 * exceeding SC_LARGE_MAXCLASS.
3814 	 *
3815 	 * Ordinarily, size limit checking is handled deeper down, but here we
3816 	 * have to check as part of (size + extra) clamping, since we need the
3817 	 * clamped value in the above helper functions.
3818 	 */
3819 	if (unlikely(size > SC_LARGE_MAXCLASS)) {
3820 		usize = old_usize;
3821 		goto label_not_resized;
3822 	}
3823 	if (unlikely(SC_LARGE_MAXCLASS - size < extra)) {
3824 		extra = SC_LARGE_MAXCLASS - size;
3825 	}
3826 
3827 	if (config_prof && opt_prof) {
3828 		usize = ixallocx_prof(tsd, ptr, old_usize, size, extra,
3829 		    alignment, zero, &alloc_ctx);
3830 	} else {
3831 		usize = ixallocx_helper(tsd_tsdn(tsd), ptr, old_usize, size,
3832 		    extra, alignment, zero);
3833 	}
3834 
3835 	/*
3836 	 * xallocx() should keep using the same edata_t object (though its
3837 	 * content can be changed).
3838 	 */
3839 	assert(emap_edata_lookup(tsd_tsdn(tsd), &arena_emap_global, ptr)
3840 	    == old_edata);
3841 
3842 	if (unlikely(usize == old_usize)) {
3843 		goto label_not_resized;
3844 	}
3845 	thread_alloc_event(tsd, usize);
3846 	thread_dalloc_event(tsd, old_usize);
3847 
3848 	if (config_fill && unlikely(opt_junk_alloc) && usize > old_usize &&
3849 	    !zero) {
3850 		size_t excess_len = usize - old_usize;
3851 		void *excess_start = (void *)((uintptr_t)ptr + old_usize);
3852 		junk_alloc_callback(excess_start, excess_len);
3853 	}
3854 label_not_resized:
3855 	if (unlikely(!tsd_fast(tsd))) {
3856 		uintptr_t args[4] = {(uintptr_t)ptr, size, extra, flags};
3857 		hook_invoke_expand(hook_expand_xallocx, ptr, old_usize,
3858 		    usize, (uintptr_t)usize, args);
3859 	}
3860 
3861 	UTRACE(ptr, size, ptr);
3862 	check_entry_exit_locking(tsd_tsdn(tsd));
3863 
3864 	LOG("core.xallocx.exit", "result: %zu", usize);
3865 	return usize;
3866 }
3867 
3868 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
3869 JEMALLOC_ATTR(pure)
3870 je_sallocx(const void *ptr, int flags) {
3871 	size_t usize;
3872 	tsdn_t *tsdn;
3873 
3874 	LOG("core.sallocx.entry", "ptr: %p, flags: %d", ptr, flags);
3875 
3876 	assert(malloc_initialized() || IS_INITIALIZER);
3877 	assert(ptr != NULL);
3878 
3879 	tsdn = tsdn_fetch();
3880 	check_entry_exit_locking(tsdn);
3881 
3882 	if (config_debug || force_ivsalloc) {
3883 		usize = ivsalloc(tsdn, ptr);
3884 		assert(force_ivsalloc || usize != 0);
3885 	} else {
3886 		usize = isalloc(tsdn, ptr);
3887 	}
3888 
3889 	check_entry_exit_locking(tsdn);
3890 
3891 	LOG("core.sallocx.exit", "result: %zu", usize);
3892 	return usize;
3893 }
3894 
3895 JEMALLOC_EXPORT void JEMALLOC_NOTHROW
3896 je_dallocx(void *ptr, int flags) {
3897 	LOG("core.dallocx.entry", "ptr: %p, flags: %d", ptr, flags);
3898 
3899 	assert(ptr != NULL);
3900 	assert(malloc_initialized() || IS_INITIALIZER);
3901 
3902 	tsd_t *tsd = tsd_fetch_min();
3903 	bool fast = tsd_fast(tsd);
3904 	check_entry_exit_locking(tsd_tsdn(tsd));
3905 
3906 	unsigned tcache_ind = mallocx_tcache_get(flags);
3907 	tcache_t *tcache = tcache_get_from_ind(tsd, tcache_ind, !fast,
3908 	    /* is_alloc */ false);
3909 
3910 	UTRACE(ptr, 0, 0);
3911 	if (likely(fast)) {
3912 		tsd_assert_fast(tsd);
3913 		ifree(tsd, ptr, tcache, false);
3914 	} else {
3915 		uintptr_t args_raw[3] = {(uintptr_t)ptr, flags};
3916 		hook_invoke_dalloc(hook_dalloc_dallocx, ptr, args_raw);
3917 		ifree(tsd, ptr, tcache, true);
3918 	}
3919 	check_entry_exit_locking(tsd_tsdn(tsd));
3920 
3921 	LOG("core.dallocx.exit", "");
3922 }
3923 
3924 JEMALLOC_ALWAYS_INLINE size_t
3925 inallocx(tsdn_t *tsdn, size_t size, int flags) {
3926 	check_entry_exit_locking(tsdn);
3927 	size_t usize;
3928 	/* In case of out of range, let the user see it rather than fail. */
3929 	aligned_usize_get(size, MALLOCX_ALIGN_GET(flags), &usize, NULL, false);
3930 	check_entry_exit_locking(tsdn);
3931 	return usize;
3932 }
3933 
3934 static JEMALLOC_NOINLINE void
3935 sdallocx_default(void *ptr, size_t size, int flags) {
3936 	assert(ptr != NULL);
3937 	assert(malloc_initialized() || IS_INITIALIZER);
3938 
3939 	tsd_t *tsd = tsd_fetch_min();
3940 	bool fast = tsd_fast(tsd);
3941 	size_t usize = inallocx(tsd_tsdn(tsd), size, flags);
3942 	check_entry_exit_locking(tsd_tsdn(tsd));
3943 
3944 	unsigned tcache_ind = mallocx_tcache_get(flags);
3945 	tcache_t *tcache = tcache_get_from_ind(tsd, tcache_ind, !fast,
3946 	    /* is_alloc */ false);
3947 
3948 	UTRACE(ptr, 0, 0);
3949 	if (likely(fast)) {
3950 		tsd_assert_fast(tsd);
3951 		isfree(tsd, ptr, usize, tcache, false);
3952 	} else {
3953 		uintptr_t args_raw[3] = {(uintptr_t)ptr, size, flags};
3954 		hook_invoke_dalloc(hook_dalloc_sdallocx, ptr, args_raw);
3955 		isfree(tsd, ptr, usize, tcache, true);
3956 	}
3957 	check_entry_exit_locking(tsd_tsdn(tsd));
3958 }
3959 
3960 JEMALLOC_EXPORT void JEMALLOC_NOTHROW
3961 je_sdallocx(void *ptr, size_t size, int flags) {
3962 	LOG("core.sdallocx.entry", "ptr: %p, size: %zu, flags: %d", ptr,
3963 		size, flags);
3964 
3965 	if (flags != 0 || !free_fastpath(ptr, size, true)) {
3966 		sdallocx_default(ptr, size, flags);
3967 	}
3968 
3969 	LOG("core.sdallocx.exit", "");
3970 }
3971 
3972 void JEMALLOC_NOTHROW
3973 je_sdallocx_noflags(void *ptr, size_t size) {
3974 	LOG("core.sdallocx.entry", "ptr: %p, size: %zu, flags: 0", ptr,
3975 		size);
3976 
3977 	if (!free_fastpath(ptr, size, true)) {
3978 		sdallocx_default(ptr, size, 0);
3979 	}
3980 
3981 	LOG("core.sdallocx.exit", "");
3982 }
3983 
3984 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
3985 JEMALLOC_ATTR(pure)
3986 je_nallocx(size_t size, int flags) {
3987 	size_t usize;
3988 	tsdn_t *tsdn;
3989 
3990 	assert(size != 0);
3991 
3992 	if (unlikely(malloc_init())) {
3993 		LOG("core.nallocx.exit", "result: %zu", ZU(0));
3994 		return 0;
3995 	}
3996 
3997 	tsdn = tsdn_fetch();
3998 	check_entry_exit_locking(tsdn);
3999 
4000 	usize = inallocx(tsdn, size, flags);
4001 	if (unlikely(usize > SC_LARGE_MAXCLASS)) {
4002 		LOG("core.nallocx.exit", "result: %zu", ZU(0));
4003 		return 0;
4004 	}
4005 
4006 	check_entry_exit_locking(tsdn);
4007 	LOG("core.nallocx.exit", "result: %zu", usize);
4008 	return usize;
4009 }
4010 
4011 JEMALLOC_EXPORT int JEMALLOC_NOTHROW
4012 je_mallctl(const char *name, void *oldp, size_t *oldlenp, void *newp,
4013     size_t newlen) {
4014 	int ret;
4015 	tsd_t *tsd;
4016 
4017 	LOG("core.mallctl.entry", "name: %s", name);
4018 
4019 	if (unlikely(malloc_init())) {
4020 		LOG("core.mallctl.exit", "result: %d", EAGAIN);
4021 		return EAGAIN;
4022 	}
4023 
4024 	tsd = tsd_fetch();
4025 	check_entry_exit_locking(tsd_tsdn(tsd));
4026 	ret = ctl_byname(tsd, name, oldp, oldlenp, newp, newlen);
4027 	check_entry_exit_locking(tsd_tsdn(tsd));
4028 
4029 	LOG("core.mallctl.exit", "result: %d", ret);
4030 	return ret;
4031 }
4032 
4033 JEMALLOC_EXPORT int JEMALLOC_NOTHROW
4034 je_mallctlnametomib(const char *name, size_t *mibp, size_t *miblenp) {
4035 	int ret;
4036 
4037 	LOG("core.mallctlnametomib.entry", "name: %s", name);
4038 
4039 	if (unlikely(malloc_init())) {
4040 		LOG("core.mallctlnametomib.exit", "result: %d", EAGAIN);
4041 		return EAGAIN;
4042 	}
4043 
4044 	tsd_t *tsd = tsd_fetch();
4045 	check_entry_exit_locking(tsd_tsdn(tsd));
4046 	ret = ctl_nametomib(tsd, name, mibp, miblenp);
4047 	check_entry_exit_locking(tsd_tsdn(tsd));
4048 
4049 	LOG("core.mallctlnametomib.exit", "result: %d", ret);
4050 	return ret;
4051 }
4052 
4053 JEMALLOC_EXPORT int JEMALLOC_NOTHROW
4054 je_mallctlbymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp,
4055   void *newp, size_t newlen) {
4056 	int ret;
4057 	tsd_t *tsd;
4058 
4059 	LOG("core.mallctlbymib.entry", "");
4060 
4061 	if (unlikely(malloc_init())) {
4062 		LOG("core.mallctlbymib.exit", "result: %d", EAGAIN);
4063 		return EAGAIN;
4064 	}
4065 
4066 	tsd = tsd_fetch();
4067 	check_entry_exit_locking(tsd_tsdn(tsd));
4068 	ret = ctl_bymib(tsd, mib, miblen, oldp, oldlenp, newp, newlen);
4069 	check_entry_exit_locking(tsd_tsdn(tsd));
4070 	LOG("core.mallctlbymib.exit", "result: %d", ret);
4071 	return ret;
4072 }
4073 
4074 #define STATS_PRINT_BUFSIZE 65536
4075 JEMALLOC_EXPORT void JEMALLOC_NOTHROW
4076 je_malloc_stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
4077     const char *opts) {
4078 	tsdn_t *tsdn;
4079 
4080 	LOG("core.malloc_stats_print.entry", "");
4081 
4082 	tsdn = tsdn_fetch();
4083 	check_entry_exit_locking(tsdn);
4084 
4085 	if (config_debug) {
4086 		stats_print(write_cb, cbopaque, opts);
4087 	} else {
4088 		buf_writer_t buf_writer;
4089 		buf_writer_init(tsdn, &buf_writer, write_cb, cbopaque, NULL,
4090 		    STATS_PRINT_BUFSIZE);
4091 		stats_print(buf_writer_cb, &buf_writer, opts);
4092 		buf_writer_terminate(tsdn, &buf_writer);
4093 	}
4094 
4095 	check_entry_exit_locking(tsdn);
4096 	LOG("core.malloc_stats_print.exit", "");
4097 }
4098 #undef STATS_PRINT_BUFSIZE
4099 
4100 JEMALLOC_ALWAYS_INLINE size_t
4101 je_malloc_usable_size_impl(JEMALLOC_USABLE_SIZE_CONST void *ptr) {
4102 	assert(malloc_initialized() || IS_INITIALIZER);
4103 
4104 	tsdn_t *tsdn = tsdn_fetch();
4105 	check_entry_exit_locking(tsdn);
4106 
4107 	size_t ret;
4108 	if (unlikely(ptr == NULL)) {
4109 		ret = 0;
4110 	} else {
4111 		if (config_debug || force_ivsalloc) {
4112 			ret = ivsalloc(tsdn, ptr);
4113 			assert(force_ivsalloc || ret != 0);
4114 		} else {
4115 			ret = isalloc(tsdn, ptr);
4116 		}
4117 	}
4118 	check_entry_exit_locking(tsdn);
4119 
4120 	return ret;
4121 }
4122 
4123 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
4124 je_malloc_usable_size(JEMALLOC_USABLE_SIZE_CONST void *ptr) {
4125 	LOG("core.malloc_usable_size.entry", "ptr: %p", ptr);
4126 
4127 	size_t ret = je_malloc_usable_size_impl(ptr);
4128 
4129 	LOG("core.malloc_usable_size.exit", "result: %zu", ret);
4130 	return ret;
4131 }
4132 
4133 #ifdef JEMALLOC_HAVE_MALLOC_SIZE
4134 JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW
4135 je_malloc_size(const void *ptr) {
4136 	LOG("core.malloc_size.entry", "ptr: %p", ptr);
4137 
4138 	size_t ret = je_malloc_usable_size_impl(ptr);
4139 
4140 	LOG("core.malloc_size.exit", "result: %zu", ret);
4141 	return ret;
4142 }
4143 #endif
4144 
4145 static void
4146 batch_alloc_prof_sample_assert(tsd_t *tsd, size_t batch, size_t usize) {
4147 	assert(config_prof && opt_prof);
4148 	bool prof_sample_event = te_prof_sample_event_lookahead(tsd,
4149 	    batch * usize);
4150 	assert(!prof_sample_event);
4151 	size_t surplus;
4152 	prof_sample_event = te_prof_sample_event_lookahead_surplus(tsd,
4153 	    (batch + 1) * usize, &surplus);
4154 	assert(prof_sample_event);
4155 	assert(surplus < usize);
4156 }
4157 
4158 size_t
4159 batch_alloc(void **ptrs, size_t num, size_t size, int flags) {
4160 	LOG("core.batch_alloc.entry",
4161 	    "ptrs: %p, num: %zu, size: %zu, flags: %d", ptrs, num, size, flags);
4162 
4163 	tsd_t *tsd = tsd_fetch();
4164 	check_entry_exit_locking(tsd_tsdn(tsd));
4165 
4166 	size_t filled = 0;
4167 
4168 	if (unlikely(tsd == NULL || tsd_reentrancy_level_get(tsd) > 0)) {
4169 		goto label_done;
4170 	}
4171 
4172 	size_t alignment = MALLOCX_ALIGN_GET(flags);
4173 	size_t usize;
4174 	if (aligned_usize_get(size, alignment, &usize, NULL, false)) {
4175 		goto label_done;
4176 	}
4177 	szind_t ind = sz_size2index(usize);
4178 	bool zero = zero_get(MALLOCX_ZERO_GET(flags), /* slow */ true);
4179 
4180 	/*
4181 	 * The cache bin and arena will be lazily initialized; it's hard to
4182 	 * know in advance whether each of them needs to be initialized.
4183 	 */
4184 	cache_bin_t *bin = NULL;
4185 	arena_t *arena = NULL;
4186 
4187 	size_t nregs = 0;
4188 	if (likely(ind < SC_NBINS)) {
4189 		nregs = bin_infos[ind].nregs;
4190 		assert(nregs > 0);
4191 	}
4192 
4193 	while (filled < num) {
4194 		size_t batch = num - filled;
4195 		size_t surplus = SIZE_MAX; /* Dead store. */
4196 		bool prof_sample_event = config_prof && opt_prof
4197 		    && prof_active_get_unlocked()
4198 		    && te_prof_sample_event_lookahead_surplus(tsd,
4199 		    batch * usize, &surplus);
4200 
4201 		if (prof_sample_event) {
4202 			/*
4203 			 * Adjust so that the batch does not trigger prof
4204 			 * sampling.
4205 			 */
4206 			batch -= surplus / usize + 1;
4207 			batch_alloc_prof_sample_assert(tsd, batch, usize);
4208 		}
4209 
4210 		size_t progress = 0;
4211 
4212 		if (likely(ind < SC_NBINS) && batch >= nregs) {
4213 			if (arena == NULL) {
4214 				unsigned arena_ind = mallocx_arena_get(flags);
4215 				if (arena_get_from_ind(tsd, arena_ind,
4216 				    &arena)) {
4217 					goto label_done;
4218 				}
4219 				if (arena == NULL) {
4220 					arena = arena_choose(tsd, NULL);
4221 				}
4222 				if (unlikely(arena == NULL)) {
4223 					goto label_done;
4224 				}
4225 			}
4226 			size_t arena_batch = batch - batch % nregs;
4227 			size_t n = arena_fill_small_fresh(tsd_tsdn(tsd), arena,
4228 			    ind, ptrs + filled, arena_batch, zero);
4229 			progress += n;
4230 			filled += n;
4231 		}
4232 
4233 		if (likely(ind < nhbins) && progress < batch) {
4234 			if (bin == NULL) {
4235 				unsigned tcache_ind = mallocx_tcache_get(flags);
4236 				tcache_t *tcache = tcache_get_from_ind(tsd,
4237 				    tcache_ind, /* slow */ true,
4238 				    /* is_alloc */ true);
4239 				if (tcache != NULL) {
4240 					bin = &tcache->bins[ind];
4241 				}
4242 			}
4243 			/*
4244 			 * If we don't have a tcache bin, we don't want to
4245 			 * immediately give up, because there's the possibility
4246 			 * that the user explicitly requested to bypass the
4247 			 * tcache, or that the user explicitly turned off the
4248 			 * tcache; in such cases, we go through the slow path,
4249 			 * i.e. the mallocx() call at the end of the while loop.
4250 			 */
4251 			if (bin != NULL) {
4252 				size_t bin_batch = batch - progress;
4253 				/*
4254 				 * n can be less than bin_batch, meaning that
4255 				 * the cache bin does not have enough memory.
4256 				 * In such cases, we rely on the slow path,
4257 				 * i.e. the mallocx() call at the end of the
4258 				 * while loop, to fill in the cache, and in the
4259 				 * next iteration of the while loop, the tcache
4260 				 * will contain a lot of memory, and we can
4261 				 * harvest them here.  Compared to the
4262 				 * alternative approach where we directly go to
4263 				 * the arena bins here, the overhead of our
4264 				 * current approach should usually be minimal,
4265 				 * since we never try to fetch more memory than
4266 				 * what a slab contains via the tcache.  An
4267 				 * additional benefit is that the tcache will
4268 				 * not be empty for the next allocation request.
4269 				 */
4270 				size_t n = cache_bin_alloc_batch(bin, bin_batch,
4271 				    ptrs + filled);
4272 				if (config_stats) {
4273 					bin->tstats.nrequests += n;
4274 				}
4275 				if (zero) {
4276 					for (size_t i = 0; i < n; ++i) {
4277 						memset(ptrs[filled + i], 0,
4278 						    usize);
4279 					}
4280 				}
4281 				if (config_prof && opt_prof
4282 				    && unlikely(ind >= SC_NBINS)) {
4283 					for (size_t i = 0; i < n; ++i) {
4284 						prof_tctx_reset_sampled(tsd,
4285 						    ptrs[filled + i]);
4286 					}
4287 				}
4288 				progress += n;
4289 				filled += n;
4290 			}
4291 		}
4292 
4293 		/*
4294 		 * For thread events other than prof sampling, trigger them as
4295 		 * if there's a single allocation of size (n * usize).  This is
4296 		 * fine because:
4297 		 * (a) these events do not alter the allocation itself, and
4298 		 * (b) it's possible that some event would have been triggered
4299 		 *     multiple times, instead of only once, if the allocations
4300 		 *     were handled individually, but it would do no harm (or
4301 		 *     even be beneficial) to coalesce the triggerings.
4302 		 */
4303 		thread_alloc_event(tsd, progress * usize);
4304 
4305 		if (progress < batch || prof_sample_event) {
4306 			void *p = je_mallocx(size, flags);
4307 			if (p == NULL) { /* OOM */
4308 				break;
4309 			}
4310 			if (progress == batch) {
4311 				assert(prof_sampled(tsd, p));
4312 			}
4313 			ptrs[filled++] = p;
4314 		}
4315 	}
4316 
4317 label_done:
4318 	check_entry_exit_locking(tsd_tsdn(tsd));
4319 	LOG("core.batch_alloc.exit", "result: %zu", filled);
4320 	return filled;
4321 }
4322 
4323 /*
4324  * End non-standard functions.
4325  */
4326 /******************************************************************************/
4327 /*
4328  * The following functions are used by threading libraries for protection of
4329  * malloc during fork().
4330  */
4331 
4332 /*
4333  * If an application creates a thread before doing any allocation in the main
4334  * thread, then calls fork(2) in the main thread followed by memory allocation
4335  * in the child process, a race can occur that results in deadlock within the
4336  * child: the main thread may have forked while the created thread had
4337  * partially initialized the allocator.  Ordinarily jemalloc prevents
4338  * fork/malloc races via the following functions it registers during
4339  * initialization using pthread_atfork(), but of course that does no good if
4340  * the allocator isn't fully initialized at fork time.  The following library
4341  * constructor is a partial solution to this problem.  It may still be possible
4342  * to trigger the deadlock described above, but doing so would involve forking
4343  * via a library constructor that runs before jemalloc's runs.
4344  */
4345 #ifndef JEMALLOC_JET
4346 JEMALLOC_ATTR(constructor)
4347 static void
4348 jemalloc_constructor(void) {
4349 	malloc_init();
4350 }
4351 #endif
4352 
4353 #if !defined(JEMALLOC_MUTEX_INIT_CB) && !defined(__NetBSD__)
4354 void
4355 jemalloc_prefork(void)
4356 #else
4357 JEMALLOC_EXPORT void
4358 _malloc_prefork(void)
4359 #endif
4360 {
4361 	tsd_t *tsd;
4362 	unsigned i, j, narenas;
4363 	arena_t *arena;
4364 
4365 #ifdef JEMALLOC_MUTEX_INIT_CB
4366 	if (!malloc_initialized()) {
4367 		return;
4368 	}
4369 #endif
4370 	assert(malloc_initialized());
4371 
4372 	tsd = tsd_fetch();
4373 
4374 	narenas = narenas_total_get();
4375 
4376 	witness_prefork(tsd_witness_tsdp_get(tsd));
4377 	/* Acquire all mutexes in a safe order. */
4378 	ctl_prefork(tsd_tsdn(tsd));
4379 	tcache_prefork(tsd_tsdn(tsd));
4380 	malloc_mutex_prefork(tsd_tsdn(tsd), &arenas_lock);
4381 	if (have_background_thread) {
4382 		background_thread_prefork0(tsd_tsdn(tsd));
4383 	}
4384 	prof_prefork0(tsd_tsdn(tsd));
4385 	if (have_background_thread) {
4386 		background_thread_prefork1(tsd_tsdn(tsd));
4387 	}
4388 	/* Break arena prefork into stages to preserve lock order. */
4389 	for (i = 0; i < 9; i++) {
4390 		for (j = 0; j < narenas; j++) {
4391 			if ((arena = arena_get(tsd_tsdn(tsd), j, false)) !=
4392 			    NULL) {
4393 				switch (i) {
4394 				case 0:
4395 					arena_prefork0(tsd_tsdn(tsd), arena);
4396 					break;
4397 				case 1:
4398 					arena_prefork1(tsd_tsdn(tsd), arena);
4399 					break;
4400 				case 2:
4401 					arena_prefork2(tsd_tsdn(tsd), arena);
4402 					break;
4403 				case 3:
4404 					arena_prefork3(tsd_tsdn(tsd), arena);
4405 					break;
4406 				case 4:
4407 					arena_prefork4(tsd_tsdn(tsd), arena);
4408 					break;
4409 				case 5:
4410 					arena_prefork5(tsd_tsdn(tsd), arena);
4411 					break;
4412 				case 6:
4413 					arena_prefork6(tsd_tsdn(tsd), arena);
4414 					break;
4415 				case 7:
4416 					arena_prefork7(tsd_tsdn(tsd), arena);
4417 					break;
4418 				case 8:
4419 					arena_prefork8(tsd_tsdn(tsd), arena);
4420 					break;
4421 				default: not_reached();
4422 				}
4423 			}
4424 		}
4425 
4426 	}
4427 	prof_prefork1(tsd_tsdn(tsd));
4428 	stats_prefork(tsd_tsdn(tsd));
4429 	tsd_prefork(tsd);
4430 }
4431 
4432 #if !defined(JEMALLOC_MUTEX_INIT_CB) && !defined(__NetBSD__)
4433 void
4434 jemalloc_postfork_parent(void)
4435 #else
4436 JEMALLOC_EXPORT void
4437 _malloc_postfork(void)
4438 #endif
4439 {
4440 	tsd_t *tsd;
4441 	unsigned i, narenas;
4442 
4443 #ifdef JEMALLOC_MUTEX_INIT_CB
4444 	if (!malloc_initialized()) {
4445 		return;
4446 	}
4447 #endif
4448 	assert(malloc_initialized());
4449 
4450 	tsd = tsd_fetch();
4451 
4452 	tsd_postfork_parent(tsd);
4453 
4454 	witness_postfork_parent(tsd_witness_tsdp_get(tsd));
4455 	/* Release all mutexes, now that fork() has completed. */
4456 	stats_postfork_parent(tsd_tsdn(tsd));
4457 	for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
4458 		arena_t *arena;
4459 
4460 		if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
4461 			arena_postfork_parent(tsd_tsdn(tsd), arena);
4462 		}
4463 	}
4464 	prof_postfork_parent(tsd_tsdn(tsd));
4465 	if (have_background_thread) {
4466 		background_thread_postfork_parent(tsd_tsdn(tsd));
4467 	}
4468 	malloc_mutex_postfork_parent(tsd_tsdn(tsd), &arenas_lock);
4469 	tcache_postfork_parent(tsd_tsdn(tsd));
4470 	ctl_postfork_parent(tsd_tsdn(tsd));
4471 }
4472 
4473 #if !defined(__NetBSD__)
4474 void
4475 jemalloc_postfork_child(void)
4476 #else
4477 JEMALLOC_EXPORT void
4478 _malloc_postfork_child(void)
4479 #endif
4480 {
4481 	tsd_t *tsd;
4482 	unsigned i, narenas;
4483 
4484 	assert(malloc_initialized());
4485 
4486 	tsd = tsd_fetch();
4487 
4488 	tsd_postfork_child(tsd);
4489 
4490 	witness_postfork_child(tsd_witness_tsdp_get(tsd));
4491 	/* Release all mutexes, now that fork() has completed. */
4492 	stats_postfork_child(tsd_tsdn(tsd));
4493 	for (i = 0, narenas = narenas_total_get(); i < narenas; i++) {
4494 		arena_t *arena;
4495 
4496 		if ((arena = arena_get(tsd_tsdn(tsd), i, false)) != NULL) {
4497 			arena_postfork_child(tsd_tsdn(tsd), arena);
4498 		}
4499 	}
4500 	prof_postfork_child(tsd_tsdn(tsd));
4501 	if (have_background_thread) {
4502 		background_thread_postfork_child(tsd_tsdn(tsd));
4503 	}
4504 	malloc_mutex_postfork_child(tsd_tsdn(tsd), &arenas_lock);
4505 	tcache_postfork_child(tsd_tsdn(tsd));
4506 	ctl_postfork_child(tsd_tsdn(tsd));
4507 }
4508 
4509 void (*
4510 je_malloc_message_get(void))(void *, const char *)
4511 {
4512 	return je_malloc_message;
4513 }
4514 
4515 void
4516 je_malloc_message_set(void (*m)(void *, const char *))
4517 {
4518 	je_malloc_message = m;
4519 }
4520 
4521 const char *
4522 je_malloc_conf_get(void)
4523 {
4524 	return je_malloc_conf;
4525 }
4526 
4527 void
4528 je_malloc_conf_set(const char *m)
4529 {
4530 	je_malloc_conf = m;
4531 }
4532 
4533  /******************************************************************************/
4534 
4535 /******************************************************************************/
4536