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