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