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