blob: 3ccaf9b1e7143aa22e50a2b2265dba683e4df1fa [file] [log] [blame]
Mitch Phillipsf3968e82020-01-31 19:57:04 -08001/*
2 * Copyright (C) 2020 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
Mitch Phillipse6997d52020-11-30 15:04:14 -080029#include <alloca.h>
30#include <assert.h>
31#include <ctype.h>
Mitch Phillipsf3968e82020-01-31 19:57:04 -080032#include <stddef.h>
33#include <stdint.h>
34#include <stdio.h>
Mitch Phillipse6997d52020-11-30 15:04:14 -080035#include <stdlib.h>
Mitch Phillipsf3968e82020-01-31 19:57:04 -080036#include <string.h>
37#include <sys/types.h>
38
Mitch Phillipsf3968e82020-01-31 19:57:04 -080039#include "gwp_asan/guarded_pool_allocator.h"
40#include "gwp_asan/options.h"
Mitch Phillipse6997d52020-11-30 15:04:14 -080041#include "gwp_asan_wrappers.h"
Mitch Phillipsf3968e82020-01-31 19:57:04 -080042#include "malloc_common.h"
Mitch Phillipse6997d52020-11-30 15:04:14 -080043#include "platform/bionic/android_unsafe_frame_pointer_chase.h"
Mitch Phillips9634c362022-06-23 11:07:00 -070044#include "platform/bionic/macros.h"
Mitch Phillipse6997d52020-11-30 15:04:14 -080045#include "platform/bionic/malloc.h"
46#include "private/bionic_arc4random.h"
47#include "private/bionic_globals.h"
48#include "private/bionic_malloc_dispatch.h"
49#include "sys/system_properties.h"
50#include "sysprop_helpers.h"
Mitch Phillipsf3968e82020-01-31 19:57:04 -080051
52#ifndef LIBC_STATIC
53#include "bionic/malloc_common_dynamic.h"
54#endif // LIBC_STATIC
55
56static gwp_asan::GuardedPoolAllocator GuardedAlloc;
57static const MallocDispatch* prev_dispatch;
58
Mitch Phillipse6997d52020-11-30 15:04:14 -080059using Action = android_mallopt_gwp_asan_options_t::Action;
Mitch Phillipsf3968e82020-01-31 19:57:04 -080060using Options = gwp_asan::options::Options;
61
Mitch Phillipse6997d52020-11-30 15:04:14 -080062// basename() is a mess, see the manpage. Let's be explicit what handling we
63// want (don't touch my string!).
64extern "C" const char* __gnu_basename(const char* path);
Mitch Phillipsf3968e82020-01-31 19:57:04 -080065
Mitch Phillipse6997d52020-11-30 15:04:14 -080066namespace {
Mitch Phillipsf3968e82020-01-31 19:57:04 -080067
68// ============================================================================
69// Implementation of GWP-ASan malloc wrappers.
70// ============================================================================
71
72void* gwp_asan_calloc(size_t n_elements, size_t elem_size) {
73 if (__predict_false(GuardedAlloc.shouldSample())) {
74 size_t bytes;
75 if (!__builtin_mul_overflow(n_elements, elem_size, &bytes)) {
76 if (void* result = GuardedAlloc.allocate(bytes)) {
77 return result;
78 }
79 }
80 }
81 return prev_dispatch->calloc(n_elements, elem_size);
82}
83
84void gwp_asan_free(void* mem) {
85 if (__predict_false(GuardedAlloc.pointerIsMine(mem))) {
86 GuardedAlloc.deallocate(mem);
87 return;
88 }
89 prev_dispatch->free(mem);
90}
91
92void* gwp_asan_malloc(size_t bytes) {
93 if (__predict_false(GuardedAlloc.shouldSample())) {
94 if (void* result = GuardedAlloc.allocate(bytes)) {
95 return result;
96 }
97 }
98 return prev_dispatch->malloc(bytes);
99}
100
101size_t gwp_asan_malloc_usable_size(const void* mem) {
102 if (__predict_false(GuardedAlloc.pointerIsMine(mem))) {
103 return GuardedAlloc.getSize(mem);
104 }
105 return prev_dispatch->malloc_usable_size(mem);
106}
107
108void* gwp_asan_realloc(void* old_mem, size_t bytes) {
Mitch Phillipsc70311c2022-04-11 13:22:01 -0700109 // GPA::pointerIsMine(p) always returns false where `p == nullptr` (and thus
110 // malloc(bytes) is requested). We always fall back to the backing allocator,
111 // technically missing some coverage, but reducing an extra conditional
112 // branch.
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800113 if (__predict_false(GuardedAlloc.pointerIsMine(old_mem))) {
Mitch Phillipsc70311c2022-04-11 13:22:01 -0700114 if (__predict_false(bytes == 0)) {
115 GuardedAlloc.deallocate(old_mem);
116 return nullptr;
117 }
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800118 void* new_ptr = gwp_asan_malloc(bytes);
Mitch Phillipsc70311c2022-04-11 13:22:01 -0700119 // If malloc() fails, then don't destroy the old memory.
120 if (__predict_false(new_ptr == nullptr)) return nullptr;
121
122 size_t old_size = GuardedAlloc.getSize(old_mem);
123 memcpy(new_ptr, old_mem, (bytes < old_size) ? bytes : old_size);
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800124 GuardedAlloc.deallocate(old_mem);
125 return new_ptr;
126 }
127 return prev_dispatch->realloc(old_mem, bytes);
128}
129
130int gwp_asan_malloc_iterate(uintptr_t base, size_t size,
131 void (*callback)(uintptr_t base, size_t size, void* arg), void* arg) {
132 if (__predict_false(GuardedAlloc.pointerIsMine(reinterpret_cast<void*>(base)))) {
133 // TODO(mitchp): GPA::iterate() returns void, but should return int.
134 // TODO(mitchp): GPA::iterate() should take uintptr_t, not void*.
135 GuardedAlloc.iterate(reinterpret_cast<void*>(base), size, callback, arg);
136 return 0;
137 }
138 return prev_dispatch->malloc_iterate(base, size, callback, arg);
139}
140
141void gwp_asan_malloc_disable() {
142 GuardedAlloc.disable();
143 prev_dispatch->malloc_disable();
144}
145
146void gwp_asan_malloc_enable() {
147 GuardedAlloc.enable();
148 prev_dispatch->malloc_enable();
149}
150
Mitch Phillipse6997d52020-11-30 15:04:14 -0800151const MallocDispatch gwp_asan_dispatch __attribute__((unused)) = {
152 gwp_asan_calloc,
153 gwp_asan_free,
154 Malloc(mallinfo),
155 gwp_asan_malloc,
156 gwp_asan_malloc_usable_size,
157 Malloc(memalign),
158 Malloc(posix_memalign),
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800159#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
Mitch Phillipse6997d52020-11-30 15:04:14 -0800160 Malloc(pvalloc),
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800161#endif
Mitch Phillipse6997d52020-11-30 15:04:14 -0800162 gwp_asan_realloc,
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800163#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
Mitch Phillipse6997d52020-11-30 15:04:14 -0800164 Malloc(valloc),
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800165#endif
Mitch Phillipse6997d52020-11-30 15:04:14 -0800166 gwp_asan_malloc_iterate,
167 gwp_asan_malloc_disable,
168 gwp_asan_malloc_enable,
169 Malloc(mallopt),
170 Malloc(aligned_alloc),
171 Malloc(malloc_info),
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800172};
173
Mitch Phillipse6997d52020-11-30 15:04:14 -0800174bool isPowerOfTwo(uint64_t x) {
175 assert(x != 0);
176 return (x & (x - 1)) == 0;
177}
Mitch Phillips0083b0f2020-02-13 17:37:11 -0800178
Mitch Phillipse6997d52020-11-30 15:04:14 -0800179bool ShouldGwpAsanSampleProcess(unsigned sample_rate) {
180 if (!isPowerOfTwo(sample_rate)) {
181 warning_log(
182 "GWP-ASan process sampling rate of %u is not a power-of-two, and so modulo bias occurs.",
183 sample_rate);
184 }
185
Mitch Phillips0083b0f2020-02-13 17:37:11 -0800186 uint8_t random_number;
187 __libc_safe_arc4random_buf(&random_number, sizeof(random_number));
Mitch Phillipse6997d52020-11-30 15:04:14 -0800188 return random_number % sample_rate == 0;
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800189}
190
Mitch Phillipse6997d52020-11-30 15:04:14 -0800191bool GwpAsanInitialized = false;
192
193// The probability (1 / SampleRate) that an allocation gets chosen to be put
194// into the special GWP-ASan pool.
195using SampleRate_t = typeof(gwp_asan::options::Options::SampleRate);
196constexpr SampleRate_t kDefaultSampleRate = 2500;
197static const char* kSampleRateSystemSysprop = "libc.debug.gwp_asan.sample_rate.system_default";
198static const char* kSampleRateAppSysprop = "libc.debug.gwp_asan.sample_rate.app_default";
199static const char* kSampleRateTargetedSyspropPrefix = "libc.debug.gwp_asan.sample_rate.";
200static const char* kSampleRateEnvVar = "GWP_ASAN_SAMPLE_RATE";
201
202// The probability (1 / ProcessSampling) that a process will be randomly
203// selected for sampling, for system apps and system processes. The process
204// sampling rate should always be a power of two to avoid modulo bias.
205constexpr unsigned kDefaultProcessSampling = 128;
206static const char* kProcessSamplingSystemSysprop =
207 "libc.debug.gwp_asan.process_sampling.system_default";
208static const char* kProcessSamplingAppSysprop = "libc.debug.gwp_asan.process_sampling.app_default";
209static const char* kProcessSamplingTargetedSyspropPrefix = "libc.debug.gwp_asan.process_sampling.";
210static const char* kProcessSamplingEnvVar = "GWP_ASAN_PROCESS_SAMPLING";
211
212// The upper limit of simultaneous allocations supported by GWP-ASan. Any
213// allocations in excess of this limit will be passed to the backing allocator
214// and can't be sampled. This value, if unspecified, will be automatically
215// calculated to keep the same ratio as the default (2500 sampling : 32 allocs).
216// So, if you specify GWP_ASAN_SAMPLE_RATE=1250 (i.e. twice as frequent), we'll
217// automatically calculate that we need double the slots (64).
218using SimultaneousAllocations_t = typeof(gwp_asan::options::Options::MaxSimultaneousAllocations);
219constexpr SimultaneousAllocations_t kDefaultMaxAllocs = 32;
220static const char* kMaxAllocsSystemSysprop = "libc.debug.gwp_asan.max_allocs.system_default";
221static const char* kMaxAllocsAppSysprop = "libc.debug.gwp_asan.max_allocs.app_default";
222static const char* kMaxAllocsTargetedSyspropPrefix = "libc.debug.gwp_asan.max_allocs.";
223static const char* kMaxAllocsEnvVar = "GWP_ASAN_MAX_ALLOCS";
224
Mitch Phillips9634c362022-06-23 11:07:00 -0700225static const char kPersistPrefix[] = "persist.";
226
Mitch Phillipse6997d52020-11-30 15:04:14 -0800227void SetDefaultGwpAsanOptions(Options* options, unsigned* process_sample_rate,
228 const android_mallopt_gwp_asan_options_t& mallopt_options) {
229 options->Enabled = true;
230 options->InstallSignalHandlers = false;
231 options->InstallForkHandlers = true;
232 options->Backtrace = android_unsafe_frame_pointer_chase;
233 options->SampleRate = kDefaultSampleRate;
234 options->MaxSimultaneousAllocations = kDefaultMaxAllocs;
235
236 *process_sample_rate = 1;
237 if (mallopt_options.desire == Action::TURN_ON_WITH_SAMPLING) {
238 *process_sample_rate = kDefaultProcessSampling;
Mitch Phillips2480f492023-01-26 13:59:56 -0800239 } else if (mallopt_options.desire == Action::TURN_ON_FOR_APP_SAMPLED_NON_CRASHING) {
240 *process_sample_rate = kDefaultProcessSampling;
241 options->Recoverable = true;
242 GwpAsanRecoverable = true;
Mitch Phillipse6997d52020-11-30 15:04:14 -0800243 }
244}
245
246bool GetGwpAsanOption(unsigned long long* result,
247 const android_mallopt_gwp_asan_options_t& mallopt_options,
248 const char* system_sysprop, const char* app_sysprop,
249 const char* targeted_sysprop_prefix, const char* env_var,
250 const char* descriptive_name) {
251 const char* basename = "";
252 if (mallopt_options.program_name) basename = __gnu_basename(mallopt_options.program_name);
253
Mitch Phillips9634c362022-06-23 11:07:00 -0700254 constexpr size_t kSyspropMaxLen = 512;
255 char program_specific_sysprop[kSyspropMaxLen] = {};
256 char persist_program_specific_sysprop[kSyspropMaxLen] = {};
257 char persist_default_sysprop[kSyspropMaxLen] = {};
258 const char* sysprop_names[4] = {};
Mitch Phillipse6997d52020-11-30 15:04:14 -0800259 // Tests use a blank program name to specify that system properties should not
260 // be used. Tests still continue to use the environment variable though.
261 if (*basename != '\0') {
Mitch Phillips9634c362022-06-23 11:07:00 -0700262 const char* default_sysprop = system_sysprop;
Mitch Phillipse6997d52020-11-30 15:04:14 -0800263 if (mallopt_options.desire == Action::TURN_ON_FOR_APP) {
Mitch Phillips9634c362022-06-23 11:07:00 -0700264 default_sysprop = app_sysprop;
Mitch Phillipse6997d52020-11-30 15:04:14 -0800265 }
Mitch Phillips9634c362022-06-23 11:07:00 -0700266 async_safe_format_buffer(&program_specific_sysprop[0], kSyspropMaxLen, "%s%s",
267 targeted_sysprop_prefix, basename);
268 async_safe_format_buffer(&persist_program_specific_sysprop[0], kSyspropMaxLen, "%s%s",
269 kPersistPrefix, program_specific_sysprop);
270 async_safe_format_buffer(&persist_default_sysprop[0], kSyspropMaxLen, "%s%s", kPersistPrefix,
271 default_sysprop);
272
273 // In order of precedence, always take the program-specific sysprop (e.g.
274 // '[persist.]libc.debug.gwp_asan.sample_rate.cameraserver') over the
275 // generic sysprop (e.g.
276 // '[persist.]libc.debug.gwp_asan.(system_default|app_default)'). In
277 // addition, always take the non-persistent option over the persistent
278 // option.
279 sysprop_names[0] = program_specific_sysprop;
280 sysprop_names[1] = persist_program_specific_sysprop;
281 sysprop_names[2] = default_sysprop;
282 sysprop_names[3] = persist_default_sysprop;
Mitch Phillipse6997d52020-11-30 15:04:14 -0800283 }
284
285 char settings_buf[PROP_VALUE_MAX];
Mitch Phillips9634c362022-06-23 11:07:00 -0700286 if (!get_config_from_env_or_sysprops(env_var, sysprop_names, arraysize(sysprop_names),
287 settings_buf, PROP_VALUE_MAX)) {
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800288 return false;
289 }
Mitch Phillipse6997d52020-11-30 15:04:14 -0800290
291 char* end;
292 unsigned long long value = strtoull(settings_buf, &end, 10);
293 if (value == ULLONG_MAX || *end != '\0') {
294 warning_log("Invalid GWP-ASan %s: \"%s\". Using default value instead.", descriptive_name,
295 settings_buf);
296 return false;
297 }
298
299 *result = value;
300 return true;
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800301}
302
Mitch Phillipse6997d52020-11-30 15:04:14 -0800303// Initialize the GWP-ASan options structure in *options, taking into account whether someone has
304// asked for specific GWP-ASan settings. The order of priority is:
305// 1. Environment variables.
306// 2. Process-specific system properties.
307// 3. Global system properties.
308// If any of these overrides are found, we return true. Otherwise, use the default values, and
309// return false.
310bool GetGwpAsanOptions(Options* options, unsigned* process_sample_rate,
311 const android_mallopt_gwp_asan_options_t& mallopt_options) {
312 SetDefaultGwpAsanOptions(options, process_sample_rate, mallopt_options);
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800313
Mitch Phillipse6997d52020-11-30 15:04:14 -0800314 bool had_overrides = false;
315
316 unsigned long long buf;
317 if (GetGwpAsanOption(&buf, mallopt_options, kSampleRateSystemSysprop, kSampleRateAppSysprop,
318 kSampleRateTargetedSyspropPrefix, kSampleRateEnvVar, "sample rate")) {
319 options->SampleRate = buf;
320 had_overrides = true;
321 }
322
323 if (GetGwpAsanOption(&buf, mallopt_options, kProcessSamplingSystemSysprop,
324 kProcessSamplingAppSysprop, kProcessSamplingTargetedSyspropPrefix,
325 kProcessSamplingEnvVar, "process sampling rate")) {
326 *process_sample_rate = buf;
327 had_overrides = true;
328 }
329
330 if (GetGwpAsanOption(&buf, mallopt_options, kMaxAllocsSystemSysprop, kMaxAllocsAppSysprop,
331 kMaxAllocsTargetedSyspropPrefix, kMaxAllocsEnvVar,
332 "maximum simultaneous allocations")) {
333 options->MaxSimultaneousAllocations = buf;
334 had_overrides = true;
335 } else if (had_overrides) {
336 // Multiply the number of slots available, such that the ratio between
337 // sampling rate and slots is kept the same as the default. For example, a
338 // sampling rate of 1000 is 2.5x more frequent than default, and so
339 // requires 80 slots (32 * 2.5).
340 float frequency_multiplier = static_cast<float>(options->SampleRate) / kDefaultSampleRate;
341 options->MaxSimultaneousAllocations =
342 /* default */ kDefaultMaxAllocs / frequency_multiplier;
343 }
344 return had_overrides;
345}
346
347bool MaybeInitGwpAsan(libc_globals* globals,
348 const android_mallopt_gwp_asan_options_t& mallopt_options) {
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800349 if (GwpAsanInitialized) {
350 error_log("GWP-ASan was already initialized for this process.");
351 return false;
352 }
353
Mitch Phillipse6997d52020-11-30 15:04:14 -0800354 Options options;
355 unsigned process_sample_rate = kDefaultProcessSampling;
356 if (!GetGwpAsanOptions(&options, &process_sample_rate, mallopt_options) &&
357 mallopt_options.desire == Action::DONT_TURN_ON_UNLESS_OVERRIDDEN) {
358 return false;
359 }
360
361 if (options.SampleRate == 0 || process_sample_rate == 0 ||
362 options.MaxSimultaneousAllocations == 0) {
363 return false;
364 }
365
366 if (!ShouldGwpAsanSampleProcess(process_sample_rate)) {
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800367 return false;
368 }
369
370 // GWP-ASan is compatible with heapprofd/malloc_debug/malloc_hooks iff
371 // GWP-ASan was installed first. If one of these other libraries was already
372 // installed, we don't enable GWP-ASan. These libraries are normally enabled
373 // in libc_init after GWP-ASan, but if the new process is a zygote child and
374 // trying to initialize GWP-ASan through mallopt(), one of these libraries may
375 // be installed. It may be possible to change this in future by modifying the
376 // internal dispatch pointers of these libraries at this point in time, but
377 // given that they're all debug-only, we don't really mind for now.
378 if (GetDefaultDispatchTable() != nullptr) {
379 // Something else is installed.
380 return false;
381 }
382
383 // GWP-ASan's initialization is always called in a single-threaded context, so
384 // we can initialize lock-free.
Mitch Phillipsbba80dc2020-02-11 14:42:14 -0800385 // Set GWP-ASan as the malloc dispatch table.
386 globals->malloc_dispatch_table = gwp_asan_dispatch;
387 atomic_store(&globals->default_dispatch_table, &gwp_asan_dispatch);
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800388
Mitch Phillipsbba80dc2020-02-11 14:42:14 -0800389 // If malloc_limit isn't installed, we can skip the default_dispatch_table
390 // lookup.
391 if (GetDispatchTable() == nullptr) {
392 atomic_store(&globals->current_dispatch_table, &gwp_asan_dispatch);
393 }
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800394
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800395 GwpAsanInitialized = true;
396
Mitch Phillipse6997d52020-11-30 15:04:14 -0800397 prev_dispatch = NativeAllocatorDispatch();
398
399 GuardedAlloc.init(options);
400
401 __libc_shared_globals()->gwp_asan_state = GuardedAlloc.getAllocatorState();
402 __libc_shared_globals()->gwp_asan_metadata = GuardedAlloc.getMetadataRegion();
Mitch Phillipsf3968e82020-01-31 19:57:04 -0800403
404 return true;
405}
Mitch Phillipse6997d52020-11-30 15:04:14 -0800406}; // anonymous namespace
407
408bool MaybeInitGwpAsanFromLibc(libc_globals* globals) {
409 // Never initialize the Zygote here. A Zygote chosen for sampling would also
410 // have all of its children sampled. Instead, the Zygote child will choose
411 // whether it samples or not just after the Zygote forks. Note that the Zygote
412 // changes its name after it's started, at this point it's still called
413 // "app_process" or "app_process64".
414 static const char kAppProcessNamePrefix[] = "app_process";
415 const char* progname = getprogname();
416 if (strncmp(progname, kAppProcessNamePrefix, sizeof(kAppProcessNamePrefix) - 1) == 0)
417 return false;
418
419 android_mallopt_gwp_asan_options_t mallopt_options;
420 mallopt_options.program_name = progname;
421 mallopt_options.desire = Action::TURN_ON_WITH_SAMPLING;
422
423 return MaybeInitGwpAsan(globals, mallopt_options);
424}
Mitch Phillipsc03856c2020-02-13 16:41:14 -0800425
426bool DispatchIsGwpAsan(const MallocDispatch* dispatch) {
427 return dispatch == &gwp_asan_dispatch;
428}
Christopher Ferris8f9713e2021-09-20 17:25:46 -0700429
Mitch Phillipse6997d52020-11-30 15:04:14 -0800430bool EnableGwpAsan(const android_mallopt_gwp_asan_options_t& options) {
Christopher Ferris8f9713e2021-09-20 17:25:46 -0700431 if (GwpAsanInitialized) {
432 return true;
433 }
434
435 bool ret_value;
436 __libc_globals.mutate(
Mitch Phillipse6997d52020-11-30 15:04:14 -0800437 [&](libc_globals* globals) { ret_value = MaybeInitGwpAsan(globals, options); });
Christopher Ferris8f9713e2021-09-20 17:25:46 -0700438 return ret_value;
439}