blob: 1e0ef142cf5675f9d42a8b324cef811ccf3a2503 [file] [log] [blame]
Christopher Ferris63860cb2015-11-16 17:30:32 -08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29// Contains a thin layer that calls whatever real native allocator
30// has been defined. For the libc shared library, this allows the
31// implementation of a debug malloc that can intercept all of the allocation
32// calls and add special debugging code to attempt to catch allocation
33// errors. All of the debugging code is implemented in a separate shared
34// library that is only loaded when the property "libc.debug.malloc.options"
Christopher Ferris30659fd2019-04-15 19:01:08 -070035// is set to a non-zero value.
Christopher Ferris63860cb2015-11-16 17:30:32 -080036
Christopher Ferrisfa10a3a2019-03-08 10:56:17 -080037#include <errno.h>
Christopher Ferrise4cdbc42019-02-08 17:30:58 -080038#include <stdint.h>
Christopher Ferris6c619a02019-03-01 17:59:51 -080039#include <stdio.h>
Colin Cross869691c2016-01-29 12:48:18 -080040
Christopher Ferris2b0638e2019-09-11 19:05:29 -070041#include <platform/bionic/malloc.h>
Mitch Phillips2210b8d2020-11-25 16:48:54 -080042#include <private/ScopedPthreadMutexLocker.h>
43#include <private/bionic_config.h>
Christopher Ferris0b231992023-10-31 15:09:37 -070044#include <private/bionic_defs.h>
Christopher Ferris63860cb2015-11-16 17:30:32 -080045
Mitch Phillipsf3968e82020-01-31 19:57:04 -080046#include "gwp_asan_wrappers.h"
Peter Collingbourne1e110fb2020-01-09 10:48:22 -080047#include "heap_tagging.h"
Mitch Phillips9cad8422021-01-20 16:03:27 -080048#include "heap_zero_init.h"
Christopher Ferrise4cdbc42019-02-08 17:30:58 -080049#include "malloc_common.h"
Christopher Ferris1fc5ccf2019-02-15 18:06:15 -080050#include "malloc_limit.h"
Mitch Phillips3b21ada2020-01-07 15:47:47 -080051#include "malloc_tagged_pointers.h"
Evgenii Stepanovbe551f52018-08-13 16:46:15 -070052
Christopher Ferrise4cdbc42019-02-08 17:30:58 -080053// =============================================================================
54// Global variables instantations.
55// =============================================================================
Evgenii Stepanovbe551f52018-08-13 16:46:15 -070056
Christopher Ferrise4cdbc42019-02-08 17:30:58 -080057// Malloc hooks globals.
Christopher Ferrisdb478a62018-02-07 18:42:14 -080058void* (*volatile __malloc_hook)(size_t, const void*);
59void* (*volatile __realloc_hook)(void*, size_t, const void*);
60void (*volatile __free_hook)(void*, const void*);
61void* (*volatile __memalign_hook)(size_t, size_t, const void*);
Christopher Ferrise4cdbc42019-02-08 17:30:58 -080062// =============================================================================
Christopher Ferris63860cb2015-11-16 17:30:32 -080063
64// =============================================================================
65// Allocation functions
66// =============================================================================
67extern "C" void* calloc(size_t n_elements, size_t elem_size) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -080068 auto dispatch_table = GetDispatchTable();
69 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -080070 return MaybeTagPointer(dispatch_table->calloc(n_elements, elem_size));
Christopher Ferris63860cb2015-11-16 17:30:32 -080071 }
Elliott Hughesa21f6cc2019-02-25 13:21:04 -080072 void* result = Malloc(calloc)(n_elements, elem_size);
73 if (__predict_false(result == nullptr)) {
74 warning_log("calloc(%zu, %zu) failed: returning null pointer", n_elements, elem_size);
75 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -080076 return MaybeTagPointer(result);
Christopher Ferris63860cb2015-11-16 17:30:32 -080077}
78
79extern "C" void free(void* mem) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -080080 auto dispatch_table = GetDispatchTable();
Mitch Phillips3b21ada2020-01-07 15:47:47 -080081 mem = MaybeUntagAndCheckPointer(mem);
Christopher Ferris62e1e2c2019-02-04 12:26:02 -080082 if (__predict_false(dispatch_table != nullptr)) {
83 dispatch_table->free(mem);
Christopher Ferris63860cb2015-11-16 17:30:32 -080084 } else {
85 Malloc(free)(mem);
86 }
87}
88
89extern "C" struct mallinfo mallinfo() {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -080090 auto dispatch_table = GetDispatchTable();
91 if (__predict_false(dispatch_table != nullptr)) {
92 return dispatch_table->mallinfo();
Christopher Ferris63860cb2015-11-16 17:30:32 -080093 }
94 return Malloc(mallinfo)();
95}
96
Christopher Ferris6c619a02019-03-01 17:59:51 -080097extern "C" int malloc_info(int options, FILE* fp) {
98 auto dispatch_table = GetDispatchTable();
99 if (__predict_false(dispatch_table != nullptr)) {
100 return dispatch_table->malloc_info(options, fp);
101 }
102 return Malloc(malloc_info)(options, fp);
103}
104
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700105extern "C" int mallopt(int param, int value) {
Elliott Hughes446b4dd2021-01-14 13:34:20 -0800106 // Some are handled by libc directly rather than by the allocator.
107 if (param == M_BIONIC_SET_HEAP_TAGGING_LEVEL) {
108 ScopedPthreadMutexLocker locker(&g_heap_tagging_lock);
109 return SetHeapTaggingLevel(static_cast<HeapTaggingLevel>(value));
110 }
Mitch Phillips9cad8422021-01-20 16:03:27 -0800111 if (param == M_BIONIC_ZERO_INIT) {
112 return SetHeapZeroInitialize(value);
Elliott Hughes446b4dd2021-01-14 13:34:20 -0800113 }
Christopher Ferrisb4e560e2023-10-26 17:00:00 -0700114
Elliott Hughes446b4dd2021-01-14 13:34:20 -0800115 // The rest we pass on...
Christopher Ferrisb4e560e2023-10-26 17:00:00 -0700116 int retval;
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800117 auto dispatch_table = GetDispatchTable();
118 if (__predict_false(dispatch_table != nullptr)) {
Christopher Ferrisb4e560e2023-10-26 17:00:00 -0700119 retval = dispatch_table->mallopt(param, value);
120 } else {
121 retval = Malloc(mallopt)(param, value);
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700122 }
Christopher Ferrisb4e560e2023-10-26 17:00:00 -0700123
124 // Track the M_DECAY_TIME mallopt calls.
125 if (param == M_DECAY_TIME && retval == 1) {
126 __libc_globals.mutate([value](libc_globals* globals) {
Chia-hung Duan6abb4062024-04-17 19:08:48 -0700127 if (value <= 0) {
Christopher Ferrisb4e560e2023-10-26 17:00:00 -0700128 atomic_store(&globals->decay_time_enabled, false);
129 } else {
130 atomic_store(&globals->decay_time_enabled, true);
131 }
132 });
133 }
134 return retval;
Christopher Ferrisa1c0d2f2017-05-15 15:50:19 -0700135}
136
Christopher Ferris63860cb2015-11-16 17:30:32 -0800137extern "C" void* malloc(size_t bytes) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800138 auto dispatch_table = GetDispatchTable();
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800139 void *result;
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800140 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800141 result = dispatch_table->malloc(bytes);
142 } else {
143 result = Malloc(malloc)(bytes);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800144 }
Elliott Hughesa21f6cc2019-02-25 13:21:04 -0800145 if (__predict_false(result == nullptr)) {
146 warning_log("malloc(%zu) failed: returning null pointer", bytes);
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800147 return nullptr;
Elliott Hughesa21f6cc2019-02-25 13:21:04 -0800148 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800149 return MaybeTagPointer(result);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800150}
151
152extern "C" size_t malloc_usable_size(const void* mem) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800153 auto dispatch_table = GetDispatchTable();
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800154 mem = MaybeUntagAndCheckPointer(mem);
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800155 if (__predict_false(dispatch_table != nullptr)) {
156 return dispatch_table->malloc_usable_size(mem);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800157 }
158 return Malloc(malloc_usable_size)(mem);
159}
160
161extern "C" void* memalign(size_t alignment, size_t bytes) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800162 auto dispatch_table = GetDispatchTable();
163 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800164 return MaybeTagPointer(dispatch_table->memalign(alignment, bytes));
Christopher Ferris63860cb2015-11-16 17:30:32 -0800165 }
Elliott Hughesa21f6cc2019-02-25 13:21:04 -0800166 void* result = Malloc(memalign)(alignment, bytes);
167 if (__predict_false(result == nullptr)) {
168 warning_log("memalign(%zu, %zu) failed: returning null pointer", alignment, bytes);
169 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800170 return MaybeTagPointer(result);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800171}
172
173extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800174 auto dispatch_table = GetDispatchTable();
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800175 int result;
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800176 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800177 result = dispatch_table->posix_memalign(memptr, alignment, size);
178 } else {
179 result = Malloc(posix_memalign)(memptr, alignment, size);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800180 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800181 if (result == 0) {
182 *memptr = MaybeTagPointer(*memptr);
183 }
184 return result;
Christopher Ferris63860cb2015-11-16 17:30:32 -0800185}
186
Christopher Ferriscae21a92018-02-05 18:14:55 -0800187extern "C" void* aligned_alloc(size_t alignment, size_t size) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800188 auto dispatch_table = GetDispatchTable();
189 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800190 return MaybeTagPointer(dispatch_table->aligned_alloc(alignment, size));
Christopher Ferriscae21a92018-02-05 18:14:55 -0800191 }
Elliott Hughesa21f6cc2019-02-25 13:21:04 -0800192 void* result = Malloc(aligned_alloc)(alignment, size);
193 if (__predict_false(result == nullptr)) {
194 warning_log("aligned_alloc(%zu, %zu) failed: returning null pointer", alignment, size);
195 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800196 return MaybeTagPointer(result);
Christopher Ferriscae21a92018-02-05 18:14:55 -0800197}
198
Elliott Hughes390be502019-04-20 22:18:49 -0700199extern "C" __attribute__((__noinline__)) void* realloc(void* old_mem, size_t bytes) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800200 auto dispatch_table = GetDispatchTable();
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800201 old_mem = MaybeUntagAndCheckPointer(old_mem);
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800202 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800203 return MaybeTagPointer(dispatch_table->realloc(old_mem, bytes));
Christopher Ferris63860cb2015-11-16 17:30:32 -0800204 }
Elliott Hughesa21f6cc2019-02-25 13:21:04 -0800205 void* result = Malloc(realloc)(old_mem, bytes);
206 if (__predict_false(result == nullptr && bytes != 0)) {
207 warning_log("realloc(%p, %zu) failed: returning null pointer", old_mem, bytes);
208 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800209 return MaybeTagPointer(result);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800210}
211
Elliott Hughesb1770852018-09-18 12:52:42 -0700212extern "C" void* reallocarray(void* old_mem, size_t item_count, size_t item_size) {
213 size_t new_size;
214 if (__builtin_mul_overflow(item_count, item_size, &new_size)) {
Elliott Hughesa21f6cc2019-02-25 13:21:04 -0800215 warning_log("reallocaray(%p, %zu, %zu) failed: returning null pointer",
216 old_mem, item_count, item_size);
Elliott Hughesb1770852018-09-18 12:52:42 -0700217 errno = ENOMEM;
218 return nullptr;
219 }
220 return realloc(old_mem, new_size);
221}
222
Christopher Ferris63860cb2015-11-16 17:30:32 -0800223#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
224extern "C" void* pvalloc(size_t bytes) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800225 auto dispatch_table = GetDispatchTable();
226 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800227 return MaybeTagPointer(dispatch_table->pvalloc(bytes));
Christopher Ferris63860cb2015-11-16 17:30:32 -0800228 }
Elliott Hughesa21f6cc2019-02-25 13:21:04 -0800229 void* result = Malloc(pvalloc)(bytes);
230 if (__predict_false(result == nullptr)) {
231 warning_log("pvalloc(%zu) failed: returning null pointer", bytes);
232 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800233 return MaybeTagPointer(result);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800234}
235
236extern "C" void* valloc(size_t bytes) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800237 auto dispatch_table = GetDispatchTable();
238 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800239 return MaybeTagPointer(dispatch_table->valloc(bytes));
Christopher Ferris63860cb2015-11-16 17:30:32 -0800240 }
Elliott Hughesa21f6cc2019-02-25 13:21:04 -0800241 void* result = Malloc(valloc)(bytes);
242 if (__predict_false(result == nullptr)) {
243 warning_log("valloc(%zu) failed: returning null pointer", bytes);
244 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800245 return MaybeTagPointer(result);
Christopher Ferris63860cb2015-11-16 17:30:32 -0800246}
247#endif
Christopher Ferris63860cb2015-11-16 17:30:32 -0800248// =============================================================================
Ryan Savitskiecc37e32018-12-14 15:57:21 +0000249
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800250struct CallbackWrapperArg {
251 void (*callback)(uintptr_t base, size_t size, void* arg);
252 void* arg;
253};
254
255void CallbackWrapper(uintptr_t base, size_t size, void* arg) {
256 CallbackWrapperArg* wrapper_arg = reinterpret_cast<CallbackWrapperArg*>(arg);
257 wrapper_arg->callback(
258 reinterpret_cast<uintptr_t>(MaybeTagPointer(reinterpret_cast<void*>(base))),
259 size, wrapper_arg->arg);
260}
261
Ryan Savitskiecc37e32018-12-14 15:57:21 +0000262// =============================================================================
Colin Cross869691c2016-01-29 12:48:18 -0800263// Exported for use by libmemunreachable.
264// =============================================================================
265
266// Calls callback for every allocation in the anonymous heap mapping
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800267// [base, base+size). Must be called between malloc_disable and malloc_enable.
268// `base` in this can take either a tagged or untagged pointer, but we always
269// provide a tagged pointer to the `base` argument of `callback` if the kernel
270// supports tagged pointers.
Colin Cross869691c2016-01-29 12:48:18 -0800271extern "C" int malloc_iterate(uintptr_t base, size_t size,
272 void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800273 auto dispatch_table = GetDispatchTable();
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800274 // Wrap the malloc_iterate callback we were provided, in order to provide
275 // pointer tagging support.
276 CallbackWrapperArg wrapper_arg;
277 wrapper_arg.callback = callback;
278 wrapper_arg.arg = arg;
279 uintptr_t untagged_base =
280 reinterpret_cast<uintptr_t>(UntagPointer(reinterpret_cast<void*>(base)));
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800281 if (__predict_false(dispatch_table != nullptr)) {
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800282 return dispatch_table->malloc_iterate(
283 untagged_base, size, CallbackWrapper, &wrapper_arg);
Colin Cross869691c2016-01-29 12:48:18 -0800284 }
Mitch Phillips3b21ada2020-01-07 15:47:47 -0800285 return Malloc(malloc_iterate)(
286 untagged_base, size, CallbackWrapper, &wrapper_arg);
Colin Cross869691c2016-01-29 12:48:18 -0800287}
288
289// Disable calls to malloc so malloc_iterate gets a consistent view of
290// allocated memory.
291extern "C" void malloc_disable() {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800292 auto dispatch_table = GetDispatchTable();
293 if (__predict_false(dispatch_table != nullptr)) {
294 return dispatch_table->malloc_disable();
Colin Cross869691c2016-01-29 12:48:18 -0800295 }
296 return Malloc(malloc_disable)();
297}
298
299// Re-enable calls to malloc after a previous call to malloc_disable.
300extern "C" void malloc_enable() {
Christopher Ferris62e1e2c2019-02-04 12:26:02 -0800301 auto dispatch_table = GetDispatchTable();
302 if (__predict_false(dispatch_table != nullptr)) {
303 return dispatch_table->malloc_enable();
Colin Cross869691c2016-01-29 12:48:18 -0800304 }
305 return Malloc(malloc_enable)();
306}
Colin Cross2d4721c2016-02-02 11:57:54 -0800307
Christopher Ferrise4cdbc42019-02-08 17:30:58 -0800308#if defined(LIBC_STATIC)
Colin Cross2d4721c2016-02-02 11:57:54 -0800309extern "C" ssize_t malloc_backtrace(void*, uintptr_t*, size_t) {
310 return 0;
311}
312#endif
Christopher Ferrise4cdbc42019-02-08 17:30:58 -0800313
314#if __has_feature(hwaddress_sanitizer)
315// FIXME: implement these in HWASan allocator.
Christopher Ferris6f517cd2019-11-08 11:28:38 -0800316extern "C" int __sanitizer_malloc_iterate(uintptr_t base __unused, size_t size __unused,
317 void (*callback)(uintptr_t base, size_t size, void* arg)
318 __unused,
319 void* arg __unused) {
Christopher Ferrise4cdbc42019-02-08 17:30:58 -0800320 return 0;
321}
322
323extern "C" void __sanitizer_malloc_disable() {
324}
325
326extern "C" void __sanitizer_malloc_enable() {
327}
Christopher Ferrisfa10a3a2019-03-08 10:56:17 -0800328
329extern "C" int __sanitizer_malloc_info(int, FILE*) {
330 errno = ENOTSUP;
331 return -1;
332}
Christopher Ferrise4cdbc42019-02-08 17:30:58 -0800333#endif
334// =============================================================================
335
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800336static constexpr MallocDispatch __libc_malloc_default_dispatch __attribute__((unused)) = {
337 Malloc(calloc),
338 Malloc(free),
339 Malloc(mallinfo),
340 Malloc(malloc),
341 Malloc(malloc_usable_size),
342 Malloc(memalign),
343 Malloc(posix_memalign),
344#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
345 Malloc(pvalloc),
346#endif
347 Malloc(realloc),
348#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
349 Malloc(valloc),
350#endif
351 Malloc(malloc_iterate),
352 Malloc(malloc_disable),
353 Malloc(malloc_enable),
354 Malloc(mallopt),
355 Malloc(aligned_alloc),
356 Malloc(malloc_info),
357};
358
359const MallocDispatch* NativeAllocatorDispatch() {
360 return &__libc_malloc_default_dispatch;
361}
Christopher Ferris0b231992023-10-31 15:09:37 -0700362
363#if !defined(LIBC_STATIC)
364void MallocInitImpl(libc_globals* globals);
365#endif
366
367// Initializes memory allocation framework.
368// This routine is called from __libc_init routines in libc_init_dynamic.cpp
369// and libc_init_static.cpp.
370__BIONIC_WEAK_FOR_NATIVE_BRIDGE
371__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) {
372#if !defined(LIBC_STATIC)
373 MallocInitImpl(globals);
374#endif
375 const char* value = getenv("MALLOC_USE_APP_DEFAULTS");
376 if (value == nullptr || value[0] == '\0') {
377 return;
378 }
379
380 // Normal apps currently turn off zero init for performance reasons.
381 SetHeapZeroInitialize(false);
382
383 // Do not call mallopt directly since that will try and lock the globals
384 // data structure.
385 int retval;
386 auto dispatch_table = GetDispatchTable();
387 if (__predict_false(dispatch_table != nullptr)) {
388 retval = dispatch_table->mallopt(M_DECAY_TIME, 1);
389 } else {
390 retval = Malloc(mallopt)(M_DECAY_TIME, 1);
391 }
392 if (retval == 1) {
393 globals->decay_time_enabled = true;
394 }
395}