• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *   http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifdef USE_GWP_ASAN
17 #define _GNU_SOURCE
18 
19 #include <fcntl.h>
20 #include <unistd.h>
21 #include <string.h>
22 #include <sys/random.h>
23 
24 #include "gwp_asan.h"
25 
26 #include "musl_log.h"
27 #include "musl_malloc.h"
28 #include "pthread.h"
29 #include "pthread_impl.h"
30 
31 #ifdef OHOS_ENABLE_PARAMETER
32 #include "sys_param.h"
33 #endif
34 
35 #define MAX_SIMULTANEOUS_ALLOCATIONS 32
36 #define SAMPLE_RATE 2500
37 #define GWP_ASAN_NAME_LEN 256
38 #define GWP_ASAN_PREDICT_TRUE(exp) __builtin_expect((exp) != 0, 1)
39 #define GWP_ASAN_PREDICT_FALSE(exp) __builtin_expect((exp) != 0, 0)
40 #define GWP_ASAN_LOGD(...) // change it to MUSL_LOGD to get gwp_asan debug log.
41 #define GWP_ASAN_NO_ADDRESS __attribute__((no_sanitize("address", "hwaddress")))
42 
43 #if defined(__aarch64__)
44 #define REG_AARCH64_X29 29
get_pc(ucontext_t * context)45 static size_t get_pc(ucontext_t *context)
46 {
47     return context->uc_mcontext.pc;
48 }
49 
get_frame_pointer(ucontext_t * context)50 static size_t get_frame_pointer(ucontext_t *context)
51 {
52     return context->uc_mcontext.regs[REG_AARCH64_X29];
53 }
54 #else
get_pc(ucontext_t * context)55 static size_t get_pc(ucontext_t *context)
56 {
57     GWP_ASAN_LOGD("[gwp_asan] Unsupported platform");
58     return 0;
59 }
60 
get_frame_pointer(ucontext_t * context)61 static size_t get_frame_pointer(ucontext_t *context)
62 {
63     GWP_ASAN_LOGD("[gwp_asan] Unsupported platform");
64     return 0;
65 }
66 #endif
67 
68 static bool gwp_asan_initialized = false;
69 static uint8_t process_sample_rate = 128;
70 static uint8_t force_sample_alloctor = 0;
71 static uint8_t previous_random_value = 0;
72 
73 #ifndef _GNU_SOURCE
74 typedef struct {
75     const char *dli_fname;
76     void *dli_fbase;
77     const char *dli_sname;
78     void *dli_saddr;
79 } Dl_info;
80 #endif
81 
82 // C interfaces of gwp_asan provided by LLVM side.
83 extern void init_gwp_asan(void *init_options);
84 extern void* gwp_asan_malloc(size_t bytes);
85 extern void gwp_asan_free(void *mem);
86 extern bool gwp_asan_should_sample();
87 extern bool gwp_asan_pointer_is_mine(void *mem);
88 extern bool gwp_asan_has_free_mem();
89 extern size_t gwp_asan_get_size(void *mem);
90 extern void gwp_asan_disable();
91 extern void gwp_asan_enable();
92 extern void gwp_asan_iterate(void *base, size_t size,
93                                   void (*callback)(void* base, size_t size, void *arg), void *arg);
94 
95 
96 extern int dladdr(const void *addr, Dl_info *info);
97 
get_process_short_name(char * buf,size_t length)98 static char *get_process_short_name(char *buf, size_t length)
99 {
100     char *app = NULL;
101     int fd = open("/proc/self/cmdline", O_RDONLY);
102     if (fd != -1) {
103         ssize_t ret = read(fd, buf, length - 1);
104         if (ret != -1) {
105             buf[ret] = 0;
106             app = strrchr(buf, '/');
107             if (app) {
108                 app++;
109             } else {
110                 app = buf;
111             }
112             char *app_end = strchr(app, ':');
113             if (app_end) {
114                 *app_end = 0;
115             }
116         }
117         close(fd);
118     }
119     return app;
120 }
121 
is_gwp_asan_disable()122 bool is_gwp_asan_disable()
123 {
124     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.disable.all";
125     static CachedHandle para_handler = NULL;
126     if (para_handler == NULL) {
127         para_handler = CachedParameterCreate(para_name, "false");
128     }
129     const char *para_value = CachedParameterGet(para_handler);
130     if (para_value != NULL && strcmp(para_value, "true") == 0) {
131         return true;
132     }
133     return false;
134 }
135 
force_sample_process_by_env()136 bool force_sample_process_by_env()
137 {
138     char buf[GWP_ASAN_NAME_LEN];
139     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
140     if (!path) {
141         return false;
142     }
143     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.enable.app.";
144     strcat(para_name, path);
145     static CachedHandle app_enable_handle = NULL;
146     if (app_enable_handle == NULL) {
147         app_enable_handle = CachedParameterCreate(para_name, "false");
148     }
149     const char *param_value = CachedParameterGet(app_enable_handle);
150     if (param_value != NULL) {
151         if (strcmp(param_value, "true") == 0) {
152             return true;
153         }
154     }
155     return false;
156 }
157 
force_sample_alloctor_by_env()158 bool force_sample_alloctor_by_env()
159 {
160     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.sample.all";
161     static CachedHandle para_handler = NULL;
162     if (para_handler == NULL) {
163         para_handler = CachedParameterCreate(para_name, "false");
164     }
165     const char *para_value = CachedParameterGet(para_handler);
166     if (para_value != NULL && strcmp(para_value, "true") == 0) {
167         force_sample_alloctor = 1;
168         return true;
169     }
170     return false;
171 }
172 
should_sample_process()173 bool should_sample_process()
174 {
175 #ifdef OHOS_ENABLE_PARAMETER
176     if (force_sample_process_by_env()) {
177         return true;
178     }
179 #endif
180 
181     uint8_t random_value;
182     // If getting a random number using a non-blocking fails, the random value is incremented.
183     if (getrandom(&random_value, sizeof(random_value), GRND_RANDOM | GRND_NONBLOCK) == -1) {
184         random_value = previous_random_value + 1;
185         previous_random_value = random_value;
186     }
187 
188     return (random_value % process_sample_rate) == 0 ? true : false;
189 }
190 
191 #define ASAN_LOG_LIB "libasan_logger.z.so"
192 static void (*WriteSanitizerLog)(char*, size_t, char*);
193 static void* handle = NULL;
194 static bool try_load_asan_logger = false;
195 static pthread_mutex_t gwpasan_mutex = PTHREAD_MUTEX_INITIALIZER;
196 
gwp_asan_printf(const char * fmt,...)197 void gwp_asan_printf(const char *fmt, ...)
198 {
199     char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.log.path";
200     static CachedHandle para_handler = NULL;
201     if (para_handler == NULL) {
202         para_handler = CachedParameterCreate(para_name, "default");
203     }
204     const char *para_value = CachedParameterGet(para_handler);
205     if (strcmp(para_value, "file") == 0) {
206         char process_short_name[GWP_ASAN_NAME_LEN];
207         char *path = get_process_short_name(process_short_name, GWP_ASAN_NAME_LEN);
208         if (!path) {
209             MUSL_LOGE("[gwp_asan]: get_process_short_name failed!");
210             return;
211         }
212         char log_path[GWP_ASAN_NAME_LEN];
213         snprintf(log_path, GWP_ASAN_NAME_LEN, "%s%s.%s.%d.log", GWP_ASAN_LOG_DIR, GWP_ASAN_LOG_TAG, path, getpid());
214         FILE *fp = fopen(log_path, "a+");
215         if (!fp) {
216             MUSL_LOGE("[gwp_asan]: %{public}s fopen %{public}s failed!", path, log_path);
217             return;
218         } else {
219             MUSL_LOGE("[gwp_asan]: %{public}s fopen %{public}s succeed.", path, log_path);
220         }
221         va_list ap;
222         va_start(ap, fmt);
223         int result = vfprintf(fp, fmt, ap);
224         va_end(ap);
225         fclose(fp);
226         if (result < 0) {
227             MUSL_LOGE("[gwp_asan] %{public}s write log failed!\n", path);
228         }
229         return;
230     }
231     if (strcmp(para_value, "default") == 0) {
232         va_list ap;
233         va_start(ap, fmt);
234         char log_buffer[PATH_MAX];
235         int result = vsnprintf(log_buffer, PATH_MAX, fmt, ap);
236         va_end(ap);
237         if (result < 0) {
238             MUSL_LOGE("[gwp_asan] write log failed!\n");
239         }
240         if (WriteSanitizerLog != NULL) {
241             WriteSanitizerLog(log_buffer, strlen(log_buffer), "faultlogger");
242             return;
243 	}
244         if (try_load_asan_logger) {
245             return;
246         }
247         pthread_mutex_lock(&gwpasan_mutex);
248         if (WriteSanitizerLog != NULL) {
249             WriteSanitizerLog(log_buffer, strlen(log_buffer), "faultlogger");
250             pthread_mutex_unlock(&gwpasan_mutex);
251             return;
252         }
253         if (!try_load_asan_logger && handle == NULL) {
254             handle = dlopen(ASAN_LOG_LIB, RTLD_LAZY);
255 	    if (handle == NULL) {
256                 pthread_mutex_unlock(&gwpasan_mutex);
257                 return;
258             }
259             try_load_asan_logger = true;
260             *(void**)(&WriteSanitizerLog) = dlsym(handle, "WriteSanitizerLog");
261             if (WriteSanitizerLog != NULL) {
262                 WriteSanitizerLog(log_buffer, strlen(log_buffer), "faultlogger");
263             }
264         }
265         pthread_mutex_unlock(&gwpasan_mutex);
266         return;
267     }
268     if (strcmp(para_value, "stdout") == 0) {
269         va_list ap;
270         va_start(ap, fmt);
271         int result = vfprintf(stdout, fmt, ap);
272         va_end(ap);
273         if (result < 0) {
274             MUSL_LOGE("[gwp_asan] write log failed!\n");
275         }
276         return;
277     }
278 }
279 
gwp_asan_printf_backtrace(uintptr_t * trace_buffer,size_t trace_length,printf_t gwp_asan_printf)280 void gwp_asan_printf_backtrace(uintptr_t *trace_buffer, size_t trace_length, printf_t gwp_asan_printf)
281 {
282     if (trace_length == 0) {
283         gwp_asan_printf("It dosen't see any stack trace!\n");
284     }
285     for (size_t i = 0; i < trace_length; i++) {
286         if (trace_buffer[i]) {
287             Dl_info info;
288             if (dladdr(trace_buffer[i], &info)) {
289                 size_t offset = trace_buffer[i] - (uintptr_t)info.dli_fbase;
290                 gwp_asan_printf("  #%zu %p (%s+%p)\n", i, trace_buffer[i], info.dli_fname, offset);
291             } else {
292                 gwp_asan_printf("  #%zu %p\n", i, trace_buffer[i]);
293             }
294         }
295     }
296     gwp_asan_printf("\n");
297 }
298 
299 // Strip pc because pc may have been protected by pac(Pointer Authentication) when build with "-mbranch-protection".
strip_pac_pc(size_t ptr)300 size_t strip_pac_pc(size_t ptr)
301 {
302 #if defined(MUSL_AARCH64_ARCH)
303     register size_t x30 __asm__("x30") = ptr;
304     // "xpaclri" is a NOP on pre armv8.3-a arch.
305     __asm__ volatile("xpaclri" : "+r"(x30));
306     return x30;
307 #else
308     return ptr;
309 #endif
310 }
311 
312 /* This function is used for gwp_asan to record the call stack when allocate and deallocate.
313  * So we implemented a fast unwind function by using fp.
314  * The unwind process may stop because the value of fp is incorrect(fp was not saved on the stack due to optimization)
315  * We can build library with "-fno-omit-frame-pointer" to get a more accurate call stack.
316  * The basic unwind principle is as follows:
317  * Stack: func1->func2->func3
318  * --------------------| [Low Adress]
319  * |   fp      |       |-------->|
320  * |   lr      | func3 |         |
321  * |   ......  |       |         |
322  * --------------------|<--------|
323  * |   fp      |       |-------->|
324  * |   lr      | func2 |         |
325  * |   ......  |       |         |
326  * --------------------|         |
327  * |   fp      |       |<--------|
328  * |   lr      | func1 |
329  * |   ......  |       |
330  * --------------------| [High Address]
331  */
run_unwind(size_t * frame_buf,size_t num_frames,size_t max_record_stack,size_t current_frame_addr)332 GWP_ASAN_NO_ADDRESS size_t run_unwind(size_t *frame_buf,
333                                       size_t num_frames,
334                                       size_t max_record_stack,
335                                       size_t current_frame_addr)
336 {
337     size_t stack_end = (size_t)(__pthread_self()->stack);
338     size_t prev_fp = 0;
339     size_t prev_lr = 0;
340     while (true) {
341         unwind_info *frame = (unwind_info*)(current_frame_addr);
342         GWP_ASAN_LOGD("[gwp_asan] unwind info:%{public}d cur:%{public}p, end:%{public}p fp:%{public}p lr:%{public}p \n",
343                       num_frames, current_frame_addr, stack_end, frame->fp, frame->lr);
344         size_t stripped_lr = strip_pac_pc(frame->lr);
345         if (!stripped_lr) {
346             break;
347         }
348         if (num_frames < max_record_stack) {
349             frame_buf[num_frames] = stripped_lr - 4;
350         }
351         ++num_frames;
352         if (frame->fp == prev_fp || frame->lr == prev_lr || frame->fp < current_frame_addr + sizeof(unwind_info) ||
353             frame->fp >= stack_end || frame->fp % sizeof(void*) != 0) {
354             break;
355         }
356         prev_fp = frame->fp;
357         prev_lr = frame->lr;
358         current_frame_addr = frame->fp;
359     }
360 
361     return num_frames;
362 }
363 
libc_gwp_asan_unwind_fast(size_t * frame_buf,size_t max_record_stack)364 GWP_ASAN_NO_ADDRESS size_t libc_gwp_asan_unwind_fast(size_t *frame_buf, size_t max_record_stack)
365 {
366     size_t current_frame_addr = __builtin_frame_address(0);
367     size_t num_frames = 0;
368 
369     return run_unwind(frame_buf, num_frames, max_record_stack, current_frame_addr);
370 }
371 
372 // Get fault address from sigchain in signal handler
libc_gwp_asan_unwind_segv(size_t * frame_buf,size_t max_record_stack,void * signal_context)373 GWP_ASAN_NO_ADDRESS size_t libc_gwp_asan_unwind_segv(size_t *frame_buf, size_t max_record_stack, void *signal_context)
374 {
375     ucontext_t *context = (ucontext_t *)signal_context;
376     size_t current_frame_addr = get_frame_pointer(context);
377     size_t pc = get_pc(context);
378     size_t num_frames = 0;
379 
380     if (current_frame_addr && pc) {
381         frame_buf[num_frames] = strip_pac_pc(pc);
382         ++num_frames;
383     }
384     return run_unwind(frame_buf, num_frames, max_record_stack, current_frame_addr);
385 }
386 
may_init_gwp_asan(bool force_init)387 bool may_init_gwp_asan(bool force_init)
388 {
389     GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan enter force_init:%{public}d.\n", force_init);
390     if (gwp_asan_initialized) {
391         GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because gwp_asan_initialized is true.\n");
392         return false;
393     }
394 #ifdef OHOS_ENABLE_PARAMETER
395     // Turn off gwp_asan.
396     if (GWP_ASAN_PREDICT_FALSE(is_gwp_asan_disable())) {
397         GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because gwp_asan is disable by env.\n");
398         return false;
399     }
400 #endif
401 
402     if (!force_init && !should_sample_process()) {
403         GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because sample not hit.\n");
404         return false;
405     }
406 
407 #ifdef OHOS_ENABLE_PARAMETER
408     // All memory allocations use gwp_asan.
409     force_sample_alloctor_by_env();
410 #endif
411 
412     gwp_asan_option gwp_asan_option = {
413         .enable = true,
414         .install_fork_handlers = true,
415         .install_signal_handlers = true,
416         .max_simultaneous_allocations = MAX_SIMULTANEOUS_ALLOCATIONS,
417         .sample_rate = SAMPLE_RATE,
418         .backtrace = libc_gwp_asan_unwind_fast,
419         .gwp_asan_printf = gwp_asan_printf,
420         .printf_backtrace = gwp_asan_printf_backtrace,
421         .segv_backtrace = libc_gwp_asan_unwind_segv,
422     };
423 
424     char buf[GWP_ASAN_NAME_LEN];
425     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
426     if (!path) {
427         return false;
428     }
429 
430     MUSL_LOGE("[gwp_asan]: %{public}d %{public}s gwp_asan initializing.\n", getpid(), path);
431     init_gwp_asan((void*)&gwp_asan_option);
432     gwp_asan_initialized = true;
433     MUSL_LOGE("[gwp_asan]: %{public}d %{public}s gwp_asan initialized.\n", getpid(), path);
434     return true;
435 }
init_gwp_asan_by_libc(bool force_init)436 bool init_gwp_asan_by_libc(bool force_init)
437 {
438     char buf[GWP_ASAN_NAME_LEN];
439     char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
440     if (!path) {
441         return false;
442     }
443     // We don't sample appspawn, and the chaild process decides whether to sample or not.
444     if (strcmp(path, "appspawn") == 0 || strcmp(path, "sh") == 0) {
445         return false;
446     }
447     return may_init_gwp_asan(force_init);
448 }
449 
get_platform_gwp_asan_tls_slot()450 void* get_platform_gwp_asan_tls_slot()
451 {
452     return (void*)(&(__pthread_self()->gwp_asan_tls));
453 }
454 
libc_gwp_asan_malloc(size_t bytes)455 void* libc_gwp_asan_malloc(size_t bytes)
456 {
457     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
458         return MuslFunc(malloc)(bytes);
459     }
460     void *res = NULL;
461     if (GWP_ASAN_PREDICT_FALSE(force_sample_alloctor || gwp_asan_should_sample())) {
462         res = gwp_asan_malloc(bytes);
463         if (res != NULL) {
464             return res;
465         }
466     }
467     return MuslFunc(malloc)(bytes);
468 }
469 
libc_gwp_asan_calloc(size_t nmemb,size_t size)470 void* libc_gwp_asan_calloc(size_t nmemb, size_t size)
471 {
472     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
473         return MuslFunc(calloc)(nmemb, size);
474     }
475 
476     if (GWP_ASAN_PREDICT_FALSE(force_sample_alloctor || gwp_asan_should_sample())) {
477         size_t total_bytes;
478         void* result = NULL;
479         if (!__builtin_mul_overflow(nmemb, size, &total_bytes)) {
480             GWP_ASAN_LOGD("[gwp_asan]: call gwp_asan_malloc nmemb:%{public}d size:%{public}d.\n", nmemb, size);
481             result = gwp_asan_malloc(total_bytes);
482             if (result != NULL) {
483                 return result;
484             }
485         }
486     }
487 
488     return MuslFunc(calloc)(nmemb, size);
489 }
490 
libc_gwp_asan_realloc(void * ptr,size_t size)491 void* libc_gwp_asan_realloc(void *ptr, size_t size)
492 {
493     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
494         return MuslFunc(realloc)(ptr, size);
495     }
496 
497     if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(ptr))) {
498         GWP_ASAN_LOGD("[gwp_asan]: call gwp_asan_malloc ptr:%{public}p size:%{public}d.\n", ptr, size);
499         if (GWP_ASAN_PREDICT_FALSE(size == 0)) {
500             gwp_asan_free(ptr);
501             return NULL;
502         }
503 
504         void* new_addr = gwp_asan_malloc(size);
505         if (new_addr != NULL) {
506             size_t old_size = gwp_asan_get_size(ptr);
507             memcpy(new_addr, ptr, (size < old_size) ? size : old_size);
508             gwp_asan_free(ptr);
509             return new_addr;
510         } else {
511             // Use the default allocator if gwp malloc failed.
512             void* addr_of_default_allocator = MuslFunc(malloc)(size);
513             if (addr_of_default_allocator != NULL) {
514                 size_t old_size = gwp_asan_get_size(ptr);
515                 memcpy(addr_of_default_allocator, ptr, (size < old_size) ? size : old_size);
516                 gwp_asan_free(ptr);
517                 return addr_of_default_allocator;
518             } else {
519                 return NULL;
520             }
521         }
522     }
523     return MuslFunc(realloc)(ptr, size);
524 }
525 
libc_gwp_asan_free(void * addr)526 void libc_gwp_asan_free(void *addr)
527 {
528     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
529         return MuslFunc(free)(addr);
530     }
531     if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(addr))) {
532         return gwp_asan_free(addr);
533     }
534     return MuslFunc(free)(addr);
535 }
536 
libc_gwp_asan_malloc_usable_size(void * addr)537 size_t libc_gwp_asan_malloc_usable_size(void *addr)
538 {
539     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
540         return MuslMalloc(malloc_usable_size)(addr);
541     }
542     if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(addr))) {
543         return gwp_asan_get_size(addr);
544     }
545     return MuslMalloc(malloc_usable_size)(addr);
546 }
547 
libc_gwp_asan_malloc_iterate(void * base,size_t size,void (* callback)(uintptr_t base,size_t size,void * arg),void * arg)548 void libc_gwp_asan_malloc_iterate(void *base, size_t size,
549                              void (*callback)(uintptr_t base, size_t size, void *arg), void *arg)
550 {
551     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
552         return;
553     }
554     if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(base))) {
555         return gwp_asan_iterate(base, size, callback, arg);
556     }
557     return;
558 }
559 
libc_gwp_asan_malloc_disable()560 void libc_gwp_asan_malloc_disable()
561 {
562     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
563         return;
564     }
565 
566     return gwp_asan_disable();
567 }
568 
libc_gwp_asan_malloc_enable()569 void libc_gwp_asan_malloc_enable()
570 {
571     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
572         return;
573     }
574 
575     return gwp_asan_enable();
576 }
577 
libc_gwp_asan_has_free_mem()578 bool libc_gwp_asan_has_free_mem()
579 {
580     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
581         return false;
582     }
583     gwp_asan_disable();
584     int res = gwp_asan_has_free_mem();
585     gwp_asan_enable();
586     return res;
587 }
libc_gwp_asan_ptr_is_mine(void * addr)588 bool libc_gwp_asan_ptr_is_mine(void *addr)
589 {
590     if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
591         return false;
592     }
593 
594     return gwp_asan_pointer_is_mine(addr);
595 }
596 #else
597 #include <stdbool.h>
598 
599 // Used for appspawn.
may_init_gwp_asan(bool force_init)600 bool may_init_gwp_asan(bool force_init)
601 {
602     return false;
603 }
604 #endif
605