Add method to use allocator app defaults. Currently, apps turn off zeroing of memory and enable the decay timer. For shell commands, set these values when the environment variable MALLOC_USE_APP_DEFAULTS is set. This fixes performance differences found between shell spawned command-line tools and native code running in an app. Add a unit test to verify setting after exec. Bug: 302212507 Test: Set the variable to 1 and verified the decay time is enabled. Test: Set the variable to "" and also unset it and verified the decay Test: time is not enabled. Test: Verified that with the variable set, the memory is not zero'd Test: by default. Test: Unit tests pass. Change-Id: I22a47f70f1ce1205c16195532c54b2bf9403e9cd
diff --git a/libc/bionic/libc_init_static.cpp b/libc/bionic/libc_init_static.cpp index cd96375..85e742c 100644 --- a/libc/bionic/libc_init_static.cpp +++ b/libc/bionic/libc_init_static.cpp
@@ -185,6 +185,7 @@ /*load_bias = */ 0); __libc_init_mte_stack(/*stack_top = */ raw_args); __libc_init_scudo(); + __libc_globals.mutate(__libc_init_malloc); __libc_init_profiling_handlers(); __libc_init_fork_handler();
diff --git a/libc/bionic/malloc_common.cpp b/libc/bionic/malloc_common.cpp index 441d884..1e0ef14 100644 --- a/libc/bionic/malloc_common.cpp +++ b/libc/bionic/malloc_common.cpp
@@ -41,6 +41,7 @@ #include <platform/bionic/malloc.h> #include <private/ScopedPthreadMutexLocker.h> #include <private/bionic_config.h> +#include <private/bionic_defs.h> #include "gwp_asan_wrappers.h" #include "heap_tagging.h" @@ -358,3 +359,37 @@ const MallocDispatch* NativeAllocatorDispatch() { return &__libc_malloc_default_dispatch; } + +#if !defined(LIBC_STATIC) +void MallocInitImpl(libc_globals* globals); +#endif + +// Initializes memory allocation framework. +// This routine is called from __libc_init routines in libc_init_dynamic.cpp +// and libc_init_static.cpp. +__BIONIC_WEAK_FOR_NATIVE_BRIDGE +__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) { +#if !defined(LIBC_STATIC) + MallocInitImpl(globals); +#endif + const char* value = getenv("MALLOC_USE_APP_DEFAULTS"); + if (value == nullptr || value[0] == '\0') { + return; + } + + // Normal apps currently turn off zero init for performance reasons. + SetHeapZeroInitialize(false); + + // Do not call mallopt directly since that will try and lock the globals + // data structure. + int retval; + auto dispatch_table = GetDispatchTable(); + if (__predict_false(dispatch_table != nullptr)) { + retval = dispatch_table->mallopt(M_DECAY_TIME, 1); + } else { + retval = Malloc(mallopt)(M_DECAY_TIME, 1); + } + if (retval == 1) { + globals->decay_time_enabled = true; + } +}
diff --git a/libc/bionic/malloc_common_dynamic.cpp b/libc/bionic/malloc_common_dynamic.cpp index 7b6d7d4..e2c6eb1 100644 --- a/libc/bionic/malloc_common_dynamic.cpp +++ b/libc/bionic/malloc_common_dynamic.cpp
@@ -375,7 +375,7 @@ extern "C" size_t __scudo_get_stack_depot_size(); // Initializes memory allocation framework once per process. -static void MallocInitImpl(libc_globals* globals) { +void MallocInitImpl(libc_globals* globals) { char prop[PROP_VALUE_MAX]; char* options = prop; @@ -409,13 +409,6 @@ } } -// Initializes memory allocation framework. -// This routine is called from __libc_init routines in libc_init_dynamic.cpp. -__BIONIC_WEAK_FOR_NATIVE_BRIDGE -__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) { - MallocInitImpl(globals); -} - // ============================================================================= // Functions to support dumping of native heap allocations using malloc debug. // =============================================================================
diff --git a/tests/malloc_test.cpp b/tests/malloc_test.cpp index 8bd8bc6..37c1ef0 100644 --- a/tests/malloc_test.cpp +++ b/tests/malloc_test.cpp
@@ -1779,3 +1779,32 @@ GTEST_SKIP() << "bionic-only test"; #endif } + +TEST(android_mallopt, DISABLED_verify_decay_time_on) { +#if defined(__BIONIC__) + bool value; + EXPECT_TRUE(android_mallopt(M_GET_DECAY_TIME_ENABLED, &value, sizeof(value))); + EXPECT_TRUE(value) << "decay time did not get enabled properly."; +#endif +} + +TEST(android_mallopt, decay_time_set_using_env_variable) { +#if defined(__BIONIC__) + SKIP_WITH_HWASAN << "hwasan does not implement mallopt"; + + bool value; + ASSERT_TRUE(android_mallopt(M_GET_DECAY_TIME_ENABLED, &value, sizeof(value))); + ASSERT_FALSE(value) << "decay time did not get disabled properly."; + + // Verify that setting the environment variable here will be carried into + // fork'd and exec'd processes. + ASSERT_EQ(0, setenv("MALLOC_USE_APP_DEFAULTS", "1", 1)); + ExecTestHelper eth; + eth.SetArgs({testing::internal::GetArgvs()[0].c_str(), "--gtest_also_run_disabled_tests", + "--gtest_filter=android_mallopt.DISABLED_verify_decay_time_on", nullptr}); + eth.Run([&]() { execv(testing::internal::GetArgvs()[0].c_str(), eth.GetArgs()); }, 0, + R"(\[ PASSED \] 1 test)"); +#else + GTEST_SKIP() << "bionic-only test"; +#endif +}