1570af302Sopenharmony_ci/**
2570af302Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3570af302Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4570af302Sopenharmony_ci * you may not use this file except in compliance with the License.
5570af302Sopenharmony_ci * You may obtain a copy of the License at
6570af302Sopenharmony_ci *
7570af302Sopenharmony_ci *   http://www.apache.org/licenses/LICENSE-2.0
8570af302Sopenharmony_ci *
9570af302Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10570af302Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11570af302Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12570af302Sopenharmony_ci * See the License for the specific language governing permissions and
13570af302Sopenharmony_ci * limitations under the License.
14570af302Sopenharmony_ci */
15570af302Sopenharmony_ci
16570af302Sopenharmony_ci#ifdef USE_GWP_ASAN
17570af302Sopenharmony_ci
18570af302Sopenharmony_ci#include <fcntl.h>
19570af302Sopenharmony_ci#include <unistd.h>
20570af302Sopenharmony_ci#include <string.h>
21570af302Sopenharmony_ci#include <sys/random.h>
22570af302Sopenharmony_ci
23570af302Sopenharmony_ci#include "gwp_asan.h"
24570af302Sopenharmony_ci
25570af302Sopenharmony_ci#include "musl_log.h"
26570af302Sopenharmony_ci#include "musl_malloc.h"
27570af302Sopenharmony_ci#include "pthread.h"
28570af302Sopenharmony_ci#include "pthread_impl.h"
29570af302Sopenharmony_ci
30570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER
31570af302Sopenharmony_ci#include "sys_param.h"
32570af302Sopenharmony_ci#endif
33570af302Sopenharmony_ci
34570af302Sopenharmony_ci#define MAX_SIMULTANEOUS_ALLOCATIONS 32
35570af302Sopenharmony_ci#define SAMPLE_RATE 2500
36570af302Sopenharmony_ci#define GWP_ASAN_NAME_LEN 256
37570af302Sopenharmony_ci#define GWP_ASAN_PREDICT_TRUE(exp) __builtin_expect((exp) != 0, 1)
38570af302Sopenharmony_ci#define GWP_ASAN_PREDICT_FALSE(exp) __builtin_expect((exp) != 0, 0)
39570af302Sopenharmony_ci#define GWP_ASAN_LOGD(...) // change it to MUSL_LOGD to get gwp_asan debug log.
40570af302Sopenharmony_ci#define GWP_ASAN_NO_ADDRESS __attribute__((no_sanitize("address", "hwaddress")))
41570af302Sopenharmony_ci
42570af302Sopenharmony_cistatic bool gwp_asan_initialized = false;
43570af302Sopenharmony_cistatic uint8_t process_sample_rate = 128;
44570af302Sopenharmony_cistatic uint8_t force_sample_alloctor = 0;
45570af302Sopenharmony_cistatic uint8_t previous_random_value = 0;
46570af302Sopenharmony_ci
47570af302Sopenharmony_citypedef struct {
48570af302Sopenharmony_ci    const char *dli_fname;
49570af302Sopenharmony_ci    void *dli_fbase;
50570af302Sopenharmony_ci    const char *dli_sname;
51570af302Sopenharmony_ci    void *dli_saddr;
52570af302Sopenharmony_ci} Dl_info;
53570af302Sopenharmony_ci
54570af302Sopenharmony_ci// C interfaces of gwp_asan provided by LLVM side.
55570af302Sopenharmony_ciextern void init_gwp_asan(void *init_options);
56570af302Sopenharmony_ciextern void* gwp_asan_malloc(size_t bytes);
57570af302Sopenharmony_ciextern void gwp_asan_free(void *mem);
58570af302Sopenharmony_ciextern bool gwp_asan_should_sample();
59570af302Sopenharmony_ciextern bool gwp_asan_pointer_is_mine(void *mem);
60570af302Sopenharmony_ciextern bool gwp_asan_has_free_mem();
61570af302Sopenharmony_ciextern size_t gwp_asan_get_size(void *mem);
62570af302Sopenharmony_ciextern void gwp_asan_disable();
63570af302Sopenharmony_ciextern void gwp_asan_enable();
64570af302Sopenharmony_ciextern void gwp_asan_iterate(void *base, size_t size,
65570af302Sopenharmony_ci                                  void (*callback)(void* base, size_t size, void *arg), void *arg);
66570af302Sopenharmony_ci
67570af302Sopenharmony_ci
68570af302Sopenharmony_ciextern int dladdr(const void *addr, Dl_info *info);
69570af302Sopenharmony_ci
70570af302Sopenharmony_cistatic char *get_process_short_name(char *buf, size_t length)
71570af302Sopenharmony_ci{
72570af302Sopenharmony_ci    char *app = NULL;
73570af302Sopenharmony_ci    int fd = open("/proc/self/cmdline", O_RDONLY);
74570af302Sopenharmony_ci    if (fd != -1) {
75570af302Sopenharmony_ci        ssize_t ret = read(fd, buf, length - 1);
76570af302Sopenharmony_ci        if (ret != -1) {
77570af302Sopenharmony_ci            buf[ret] = 0;
78570af302Sopenharmony_ci            app = strrchr(buf, '/');
79570af302Sopenharmony_ci            if (app) {
80570af302Sopenharmony_ci                app++;
81570af302Sopenharmony_ci            } else {
82570af302Sopenharmony_ci                app = buf;
83570af302Sopenharmony_ci            }
84570af302Sopenharmony_ci            char *app_end = strchr(app, ':');
85570af302Sopenharmony_ci            if (app_end) {
86570af302Sopenharmony_ci                *app_end = 0;
87570af302Sopenharmony_ci            }
88570af302Sopenharmony_ci        }
89570af302Sopenharmony_ci        close(fd);
90570af302Sopenharmony_ci    }
91570af302Sopenharmony_ci    return app;
92570af302Sopenharmony_ci}
93570af302Sopenharmony_ci
94570af302Sopenharmony_cibool is_gwp_asan_disable()
95570af302Sopenharmony_ci{
96570af302Sopenharmony_ci    char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.disable.all";
97570af302Sopenharmony_ci    static CachedHandle para_handler = NULL;
98570af302Sopenharmony_ci    if (para_handler == NULL) {
99570af302Sopenharmony_ci        para_handler = CachedParameterCreate(para_name, "false");
100570af302Sopenharmony_ci    }
101570af302Sopenharmony_ci    char *para_value = CachedParameterGet(para_handler);
102570af302Sopenharmony_ci    if (para_value != NULL && strcmp(para_value, "true") == 0) {
103570af302Sopenharmony_ci        return true;
104570af302Sopenharmony_ci    }
105570af302Sopenharmony_ci    return false;
106570af302Sopenharmony_ci}
107570af302Sopenharmony_ci
108570af302Sopenharmony_cibool force_sample_process_by_env()
109570af302Sopenharmony_ci{
110570af302Sopenharmony_ci    char buf[GWP_ASAN_NAME_LEN];
111570af302Sopenharmony_ci    char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
112570af302Sopenharmony_ci    if (!path) {
113570af302Sopenharmony_ci        return false;
114570af302Sopenharmony_ci    }
115570af302Sopenharmony_ci    char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.enable.app.";
116570af302Sopenharmony_ci    strcat(para_name, path);
117570af302Sopenharmony_ci    static CachedHandle app_enable_handle = NULL;
118570af302Sopenharmony_ci    if (app_enable_handle == NULL) {
119570af302Sopenharmony_ci        app_enable_handle = CachedParameterCreate(para_name, "false");
120570af302Sopenharmony_ci    }
121570af302Sopenharmony_ci    char *param_value = CachedParameterGet(app_enable_handle);
122570af302Sopenharmony_ci    if (param_value != NULL) {
123570af302Sopenharmony_ci        if (strcmp(param_value, "true") == 0) {
124570af302Sopenharmony_ci            return true;
125570af302Sopenharmony_ci        }
126570af302Sopenharmony_ci    }
127570af302Sopenharmony_ci    return false;
128570af302Sopenharmony_ci}
129570af302Sopenharmony_ci
130570af302Sopenharmony_cibool force_sample_alloctor_by_env()
131570af302Sopenharmony_ci{
132570af302Sopenharmony_ci    char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.sample.all";
133570af302Sopenharmony_ci    static CachedHandle para_handler = NULL;
134570af302Sopenharmony_ci    if (para_handler == NULL) {
135570af302Sopenharmony_ci        para_handler = CachedParameterCreate(para_name, "false");
136570af302Sopenharmony_ci    }
137570af302Sopenharmony_ci    char *para_value = CachedParameterGet(para_handler);
138570af302Sopenharmony_ci    if (para_value != NULL && strcmp(para_value, "true") == 0) {
139570af302Sopenharmony_ci        force_sample_alloctor = 1;
140570af302Sopenharmony_ci        return true;
141570af302Sopenharmony_ci    }
142570af302Sopenharmony_ci    return false;
143570af302Sopenharmony_ci}
144570af302Sopenharmony_ci
145570af302Sopenharmony_cibool should_sample_process()
146570af302Sopenharmony_ci{
147570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER
148570af302Sopenharmony_ci    if (force_sample_process_by_env()) {
149570af302Sopenharmony_ci        return true;
150570af302Sopenharmony_ci    }
151570af302Sopenharmony_ci#endif
152570af302Sopenharmony_ci
153570af302Sopenharmony_ci    uint8_t random_value;
154570af302Sopenharmony_ci    // If getting a random number using a non-blocking fails, the random value is incremented.
155570af302Sopenharmony_ci    if (getrandom(&random_value, sizeof(random_value), GRND_RANDOM | GRND_NONBLOCK) == -1) {
156570af302Sopenharmony_ci        random_value = previous_random_value + 1;
157570af302Sopenharmony_ci        previous_random_value = random_value;
158570af302Sopenharmony_ci    }
159570af302Sopenharmony_ci
160570af302Sopenharmony_ci    return (random_value % process_sample_rate) == 0 ? true : false;
161570af302Sopenharmony_ci}
162570af302Sopenharmony_ci
163570af302Sopenharmony_ci#define ASAN_LOG_LIB "libasan_logger.z.so"
164570af302Sopenharmony_cistatic void (*WriteGwpAsanLog)(char*, size_t);
165570af302Sopenharmony_cistatic void* handle = NULL;
166570af302Sopenharmony_cistatic bool try_load_asan_logger = false;
167570af302Sopenharmony_cistatic pthread_mutex_t gwpasan_mutex = PTHREAD_MUTEX_INITIALIZER;
168570af302Sopenharmony_ci
169570af302Sopenharmony_civoid gwp_asan_printf(const char *fmt, ...)
170570af302Sopenharmony_ci{
171570af302Sopenharmony_ci    char para_name[GWP_ASAN_NAME_LEN] = "gwp_asan.log.path";
172570af302Sopenharmony_ci    static CachedHandle para_handler = NULL;
173570af302Sopenharmony_ci    if (para_handler == NULL) {
174570af302Sopenharmony_ci        para_handler = CachedParameterCreate(para_name, "file");
175570af302Sopenharmony_ci    }
176570af302Sopenharmony_ci    char *para_value = CachedParameterGet(para_handler);
177570af302Sopenharmony_ci    if (strcmp(para_value, "file") == 0) {
178570af302Sopenharmony_ci        char process_short_name[GWP_ASAN_NAME_LEN];
179570af302Sopenharmony_ci        char *path = get_process_short_name(process_short_name, GWP_ASAN_NAME_LEN);
180570af302Sopenharmony_ci        if (!path) {
181570af302Sopenharmony_ci            MUSL_LOGE("[gwp_asan]: get_process_short_name failed!");
182570af302Sopenharmony_ci            return;
183570af302Sopenharmony_ci        }
184570af302Sopenharmony_ci        char log_path[GWP_ASAN_NAME_LEN];
185570af302Sopenharmony_ci        snprintf(log_path, GWP_ASAN_NAME_LEN, "%s%s.%s.%d.log", GWP_ASAN_LOG_DIR, GWP_ASAN_LOG_TAG, path, getpid());
186570af302Sopenharmony_ci        FILE *fp = fopen(log_path, "a+");
187570af302Sopenharmony_ci        if (!fp) {
188570af302Sopenharmony_ci            MUSL_LOGE("[gwp_asan]: %{public}s fopen %{public}s failed!", path, log_path);
189570af302Sopenharmony_ci            return;
190570af302Sopenharmony_ci        } else {
191570af302Sopenharmony_ci            MUSL_LOGE("[gwp_asan]: %{public}s fopen %{public}s succeed.", path, log_path);
192570af302Sopenharmony_ci        }
193570af302Sopenharmony_ci        va_list ap;
194570af302Sopenharmony_ci        va_start(ap, fmt);
195570af302Sopenharmony_ci        int result = vfprintf(fp, fmt, ap);
196570af302Sopenharmony_ci        va_end(ap);
197570af302Sopenharmony_ci        fclose(fp);
198570af302Sopenharmony_ci        if (result < 0) {
199570af302Sopenharmony_ci            MUSL_LOGE("[gwp_asan] %{public}s write log failed!\n", path);
200570af302Sopenharmony_ci        }
201570af302Sopenharmony_ci        return;
202570af302Sopenharmony_ci    }
203570af302Sopenharmony_ci    if (strcmp(para_value, "default") == 0) {
204570af302Sopenharmony_ci        va_list ap;
205570af302Sopenharmony_ci        va_start(ap, fmt);
206570af302Sopenharmony_ci        char log_buffer[PATH_MAX];
207570af302Sopenharmony_ci        int result = vsnprintf(log_buffer, PATH_MAX, fmt, ap);
208570af302Sopenharmony_ci        va_end(ap);
209570af302Sopenharmony_ci        if (result < 0) {
210570af302Sopenharmony_ci            MUSL_LOGE("[gwp_asan] write log failed!\n");
211570af302Sopenharmony_ci        }
212570af302Sopenharmony_ci        if (WriteGwpAsanLog != NULL) {
213570af302Sopenharmony_ci            WriteGwpAsanLog(log_buffer, strlen(log_buffer));
214570af302Sopenharmony_ci            return;
215570af302Sopenharmony_ci	}
216570af302Sopenharmony_ci        if (try_load_asan_logger) {
217570af302Sopenharmony_ci            return;
218570af302Sopenharmony_ci        }
219570af302Sopenharmony_ci        pthread_mutex_lock(&gwpasan_mutex);
220570af302Sopenharmony_ci        if (WriteGwpAsanLog != NULL) {
221570af302Sopenharmony_ci            WriteGwpAsanLog(log_buffer, strlen(log_buffer));
222570af302Sopenharmony_ci            pthread_mutex_unlock(&gwpasan_mutex);
223570af302Sopenharmony_ci            return;
224570af302Sopenharmony_ci        }
225570af302Sopenharmony_ci        if (!try_load_asan_logger && handle == NULL) {
226570af302Sopenharmony_ci            try_load_asan_logger = true;
227570af302Sopenharmony_ci            handle = dlopen(ASAN_LOG_LIB, RTLD_LAZY);
228570af302Sopenharmony_ci	    if (handle == NULL) {
229570af302Sopenharmony_ci                pthread_mutex_unlock(&gwpasan_mutex);
230570af302Sopenharmony_ci                return;
231570af302Sopenharmony_ci            }
232570af302Sopenharmony_ci            *(void**)(&WriteGwpAsanLog) = dlsym(handle, "WriteGwpAsanLog");
233570af302Sopenharmony_ci            if (WriteGwpAsanLog != NULL) {
234570af302Sopenharmony_ci                WriteGwpAsanLog(log_buffer, strlen(log_buffer));
235570af302Sopenharmony_ci            }
236570af302Sopenharmony_ci        }
237570af302Sopenharmony_ci        pthread_mutex_unlock(&gwpasan_mutex);
238570af302Sopenharmony_ci        return;
239570af302Sopenharmony_ci    }
240570af302Sopenharmony_ci    if (strcmp(para_value, "stdout") == 0) {
241570af302Sopenharmony_ci        va_list ap;
242570af302Sopenharmony_ci        va_start(ap, fmt);
243570af302Sopenharmony_ci        int result = vfprintf(stdout, fmt, ap);
244570af302Sopenharmony_ci        va_end(ap);
245570af302Sopenharmony_ci        if (result < 0) {
246570af302Sopenharmony_ci            MUSL_LOGE("[gwp_asan] write log failed!\n");
247570af302Sopenharmony_ci        }
248570af302Sopenharmony_ci        return;
249570af302Sopenharmony_ci    }
250570af302Sopenharmony_ci}
251570af302Sopenharmony_ci
252570af302Sopenharmony_civoid gwp_asan_printf_backtrace(uintptr_t *trace_buffer, size_t trace_length, printf_t gwp_asan_printf)
253570af302Sopenharmony_ci{
254570af302Sopenharmony_ci    if (trace_length == 0) {
255570af302Sopenharmony_ci        gwp_asan_printf("It dosen't see any stack trace!\n");
256570af302Sopenharmony_ci    }
257570af302Sopenharmony_ci    for (size_t i = 0; i < trace_length; i++) {
258570af302Sopenharmony_ci        if (trace_buffer[i]) {
259570af302Sopenharmony_ci            Dl_info info;
260570af302Sopenharmony_ci            if (dladdr(trace_buffer[i], &info)) {
261570af302Sopenharmony_ci                size_t offset = trace_buffer[i] - (uintptr_t)info.dli_fbase;
262570af302Sopenharmony_ci                gwp_asan_printf("  #%zu %p (%s+%p)\n", i, trace_buffer[i], info.dli_fname, offset);
263570af302Sopenharmony_ci            } else {
264570af302Sopenharmony_ci                gwp_asan_printf("  #%zu %p\n", i, trace_buffer[i]);
265570af302Sopenharmony_ci            }
266570af302Sopenharmony_ci        }
267570af302Sopenharmony_ci    }
268570af302Sopenharmony_ci    gwp_asan_printf("\n");
269570af302Sopenharmony_ci}
270570af302Sopenharmony_ci
271570af302Sopenharmony_ci// Strip pc because pc may have been protected by pac(Pointer Authentication) when build with "-mbranch-protection".
272570af302Sopenharmony_cisize_t strip_pac_pc(size_t ptr)
273570af302Sopenharmony_ci{
274570af302Sopenharmony_ci#if defined(MUSL_AARCH64_ARCH)
275570af302Sopenharmony_ci    register size_t x30 __asm__("x30") = ptr;
276570af302Sopenharmony_ci    // "xpaclri" is a NOP on pre armv8.3-a arch.
277570af302Sopenharmony_ci    __asm__ volatile("xpaclri" : "+r"(x30));
278570af302Sopenharmony_ci    return x30;
279570af302Sopenharmony_ci#else
280570af302Sopenharmony_ci    return ptr;
281570af302Sopenharmony_ci#endif
282570af302Sopenharmony_ci}
283570af302Sopenharmony_ci
284570af302Sopenharmony_ci/* This function is used for gwp_asan to record the call stack when allocate and deallocate.
285570af302Sopenharmony_ci * So we implemented a fast unwind function by using fp.
286570af302Sopenharmony_ci * The unwind process may stop because the value of fp is incorrect(fp was not saved on the stack due to optimization)
287570af302Sopenharmony_ci * We can build library with "-fno-omit-frame-pointer" to get a more accurate call stack.
288570af302Sopenharmony_ci * The basic unwind principle is as follows:
289570af302Sopenharmony_ci * Stack: func1->func2->func3
290570af302Sopenharmony_ci * --------------------| [Low Adress]
291570af302Sopenharmony_ci * |   fp      |       |-------->|
292570af302Sopenharmony_ci * |   lr      | func3 |         |
293570af302Sopenharmony_ci * |   ......  |       |         |
294570af302Sopenharmony_ci * --------------------|<--------|
295570af302Sopenharmony_ci * |   fp      |       |-------->|
296570af302Sopenharmony_ci * |   lr      | func2 |         |
297570af302Sopenharmony_ci * |   ......  |       |         |
298570af302Sopenharmony_ci * --------------------|         |
299570af302Sopenharmony_ci * |   fp      |       |<--------|
300570af302Sopenharmony_ci * |   lr      | func1 |
301570af302Sopenharmony_ci * |   ......  |       |
302570af302Sopenharmony_ci * --------------------| [High Address]
303570af302Sopenharmony_ci */
304570af302Sopenharmony_ciGWP_ASAN_NO_ADDRESS size_t libc_gwp_asan_unwind_fast(size_t *frame_buf, size_t max_record_stack,
305570af302Sopenharmony_ci                                                     __attribute__((unused)) void *signal_context)
306570af302Sopenharmony_ci{
307570af302Sopenharmony_ci    size_t current_frame_addr = __builtin_frame_address(0);
308570af302Sopenharmony_ci    size_t stack_end = (size_t)(__pthread_self()->stack);
309570af302Sopenharmony_ci    size_t num_frames = 0;
310570af302Sopenharmony_ci    size_t prev_fp = 0;
311570af302Sopenharmony_ci    size_t prev_lr = 0;
312570af302Sopenharmony_ci    while (true) {
313570af302Sopenharmony_ci        unwind_info *frame = (unwind_info*)(current_frame_addr);
314570af302Sopenharmony_ci        GWP_ASAN_LOGD("[gwp_asan] unwind info:%{public}d cur:%{public}p, end:%{public}p fp:%{public}p lr:%{public}p \n",
315570af302Sopenharmony_ci                      num_frames, current_frame_addr, stack_end, frame->fp, frame->lr);
316570af302Sopenharmony_ci        if (!frame->lr) {
317570af302Sopenharmony_ci            break;
318570af302Sopenharmony_ci        }
319570af302Sopenharmony_ci        if (num_frames < max_record_stack) {
320570af302Sopenharmony_ci            frame_buf[num_frames] = strip_pac_pc(frame->lr) - 4;
321570af302Sopenharmony_ci        }
322570af302Sopenharmony_ci        ++num_frames;
323570af302Sopenharmony_ci        if (frame->fp == prev_fp || frame->lr == prev_lr || frame->fp < current_frame_addr + sizeof(unwind_info) ||
324570af302Sopenharmony_ci            frame->fp >= stack_end || frame->fp % sizeof(void*) != 0) {
325570af302Sopenharmony_ci            break;
326570af302Sopenharmony_ci        }
327570af302Sopenharmony_ci        prev_fp = frame->fp;
328570af302Sopenharmony_ci        prev_lr = frame->lr;
329570af302Sopenharmony_ci        current_frame_addr = frame->fp;
330570af302Sopenharmony_ci    }
331570af302Sopenharmony_ci
332570af302Sopenharmony_ci    return num_frames;
333570af302Sopenharmony_ci}
334570af302Sopenharmony_ci
335570af302Sopenharmony_cibool may_init_gwp_asan(bool force_init)
336570af302Sopenharmony_ci{
337570af302Sopenharmony_ci    GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan enter force_init:%{public}d.\n", force_init);
338570af302Sopenharmony_ci    if (gwp_asan_initialized) {
339570af302Sopenharmony_ci        GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because gwp_asan_initialized is true.\n");
340570af302Sopenharmony_ci        return false;
341570af302Sopenharmony_ci    }
342570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER
343570af302Sopenharmony_ci    // Turn off gwp_asan.
344570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_FALSE(is_gwp_asan_disable())) {
345570af302Sopenharmony_ci        GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because gwp_asan is disable by env.\n");
346570af302Sopenharmony_ci        return false;
347570af302Sopenharmony_ci    }
348570af302Sopenharmony_ci#endif
349570af302Sopenharmony_ci
350570af302Sopenharmony_ci    if (!force_init && !should_sample_process()) {
351570af302Sopenharmony_ci        GWP_ASAN_LOGD("[gwp_asan]: may_init_gwp_asan return because sample not hit.\n");
352570af302Sopenharmony_ci        return false;
353570af302Sopenharmony_ci    }
354570af302Sopenharmony_ci
355570af302Sopenharmony_ci#ifdef OHOS_ENABLE_PARAMETER
356570af302Sopenharmony_ci    // All memory allocations use gwp_asan.
357570af302Sopenharmony_ci    force_sample_alloctor_by_env();
358570af302Sopenharmony_ci#endif
359570af302Sopenharmony_ci
360570af302Sopenharmony_ci    gwp_asan_option gwp_asan_option = {
361570af302Sopenharmony_ci        .enable = true,
362570af302Sopenharmony_ci        .install_fork_handlers = true,
363570af302Sopenharmony_ci        .install_signal_handlers = true,
364570af302Sopenharmony_ci        .max_simultaneous_allocations = MAX_SIMULTANEOUS_ALLOCATIONS,
365570af302Sopenharmony_ci        .sample_rate = SAMPLE_RATE,
366570af302Sopenharmony_ci        .backtrace = libc_gwp_asan_unwind_fast,
367570af302Sopenharmony_ci        .gwp_asan_printf = gwp_asan_printf,
368570af302Sopenharmony_ci        .printf_backtrace = gwp_asan_printf_backtrace,
369570af302Sopenharmony_ci        .segv_backtrace = libc_gwp_asan_unwind_fast,
370570af302Sopenharmony_ci    };
371570af302Sopenharmony_ci
372570af302Sopenharmony_ci    char buf[GWP_ASAN_NAME_LEN];
373570af302Sopenharmony_ci    char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
374570af302Sopenharmony_ci    if (!path) {
375570af302Sopenharmony_ci        return false;
376570af302Sopenharmony_ci    }
377570af302Sopenharmony_ci
378570af302Sopenharmony_ci    MUSL_LOGE("[gwp_asan]: %{public}d %{public}s gwp_asan initializing.\n", getpid(), path);
379570af302Sopenharmony_ci    init_gwp_asan((void*)&gwp_asan_option);
380570af302Sopenharmony_ci    gwp_asan_initialized = true;
381570af302Sopenharmony_ci    MUSL_LOGE("[gwp_asan]: %{public}d %{public}s gwp_asan initialized.\n", getpid(), path);
382570af302Sopenharmony_ci    return true;
383570af302Sopenharmony_ci}
384570af302Sopenharmony_cibool init_gwp_asan_by_libc(bool force_init)
385570af302Sopenharmony_ci{
386570af302Sopenharmony_ci    char buf[GWP_ASAN_NAME_LEN];
387570af302Sopenharmony_ci    char *path = get_process_short_name(buf, GWP_ASAN_NAME_LEN);
388570af302Sopenharmony_ci    if (!path) {
389570af302Sopenharmony_ci        return false;
390570af302Sopenharmony_ci    }
391570af302Sopenharmony_ci    // We don't sample appspawn, and the chaild process decides whether to sample or not.
392570af302Sopenharmony_ci    if (strcmp(path, "appspawn") == 0 || strcmp(path, "sh") == 0) {
393570af302Sopenharmony_ci        return false;
394570af302Sopenharmony_ci    }
395570af302Sopenharmony_ci    return may_init_gwp_asan(force_init);
396570af302Sopenharmony_ci}
397570af302Sopenharmony_ci
398570af302Sopenharmony_civoid* get_platform_gwp_asan_tls_slot()
399570af302Sopenharmony_ci{
400570af302Sopenharmony_ci    return (void*)(&(__pthread_self()->gwp_asan_tls));
401570af302Sopenharmony_ci}
402570af302Sopenharmony_ci
403570af302Sopenharmony_civoid* libc_gwp_asan_malloc(size_t bytes)
404570af302Sopenharmony_ci{
405570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
406570af302Sopenharmony_ci        return MuslFunc(malloc)(bytes);
407570af302Sopenharmony_ci    }
408570af302Sopenharmony_ci    void *res = NULL;
409570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_FALSE(force_sample_alloctor || gwp_asan_should_sample())) {
410570af302Sopenharmony_ci        res = gwp_asan_malloc(bytes);
411570af302Sopenharmony_ci        if (res != NULL) {
412570af302Sopenharmony_ci            return res;
413570af302Sopenharmony_ci        }
414570af302Sopenharmony_ci    }
415570af302Sopenharmony_ci    return MuslFunc(malloc)(bytes);
416570af302Sopenharmony_ci}
417570af302Sopenharmony_ci
418570af302Sopenharmony_civoid* libc_gwp_asan_calloc(size_t nmemb, size_t size)
419570af302Sopenharmony_ci{
420570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
421570af302Sopenharmony_ci        return MuslFunc(calloc)(nmemb, size);
422570af302Sopenharmony_ci    }
423570af302Sopenharmony_ci
424570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_FALSE(force_sample_alloctor || gwp_asan_should_sample())) {
425570af302Sopenharmony_ci        size_t total_bytes;
426570af302Sopenharmony_ci        void* result = NULL;
427570af302Sopenharmony_ci        if (!__builtin_mul_overflow(nmemb, size, &total_bytes)) {
428570af302Sopenharmony_ci            GWP_ASAN_LOGD("[gwp_asan]: call gwp_asan_malloc nmemb:%{public}d size:%{public}d.\n", nmemb, size);
429570af302Sopenharmony_ci            result = gwp_asan_malloc(total_bytes);
430570af302Sopenharmony_ci            if (result != NULL) {
431570af302Sopenharmony_ci                return result;
432570af302Sopenharmony_ci            }
433570af302Sopenharmony_ci        }
434570af302Sopenharmony_ci    }
435570af302Sopenharmony_ci
436570af302Sopenharmony_ci    return MuslFunc(calloc)(nmemb, size);
437570af302Sopenharmony_ci}
438570af302Sopenharmony_ci
439570af302Sopenharmony_civoid* libc_gwp_asan_realloc(void *ptr, size_t size)
440570af302Sopenharmony_ci{
441570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
442570af302Sopenharmony_ci        return MuslFunc(realloc)(ptr, size);
443570af302Sopenharmony_ci    }
444570af302Sopenharmony_ci
445570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(ptr))) {
446570af302Sopenharmony_ci        GWP_ASAN_LOGD("[gwp_asan]: call gwp_asan_malloc ptr:%{public}p size:%{public}d.\n", ptr, size);
447570af302Sopenharmony_ci        if (GWP_ASAN_PREDICT_FALSE(size == 0)) {
448570af302Sopenharmony_ci            gwp_asan_free(ptr);
449570af302Sopenharmony_ci            return NULL;
450570af302Sopenharmony_ci        }
451570af302Sopenharmony_ci
452570af302Sopenharmony_ci        void* new_addr = gwp_asan_malloc(size);
453570af302Sopenharmony_ci        if (new_addr != NULL) {
454570af302Sopenharmony_ci            size_t old_size = gwp_asan_get_size(ptr);
455570af302Sopenharmony_ci            memcpy(new_addr, ptr, (size < old_size) ? size : old_size);
456570af302Sopenharmony_ci            gwp_asan_free(ptr);
457570af302Sopenharmony_ci            return new_addr;
458570af302Sopenharmony_ci        } else {
459570af302Sopenharmony_ci            // Use the default allocator if gwp malloc failed.
460570af302Sopenharmony_ci            void* addr_of_default_allocator = MuslFunc(malloc)(size);
461570af302Sopenharmony_ci            if (addr_of_default_allocator != NULL) {
462570af302Sopenharmony_ci                size_t old_size = gwp_asan_get_size(ptr);
463570af302Sopenharmony_ci                memcpy(addr_of_default_allocator, ptr, (size < old_size) ? size : old_size);
464570af302Sopenharmony_ci                gwp_asan_free(ptr);
465570af302Sopenharmony_ci                return addr_of_default_allocator;
466570af302Sopenharmony_ci            } else {
467570af302Sopenharmony_ci                return NULL;
468570af302Sopenharmony_ci            }
469570af302Sopenharmony_ci        }
470570af302Sopenharmony_ci    }
471570af302Sopenharmony_ci    return MuslFunc(realloc)(ptr, size);
472570af302Sopenharmony_ci}
473570af302Sopenharmony_ci
474570af302Sopenharmony_civoid libc_gwp_asan_free(void *addr)
475570af302Sopenharmony_ci{
476570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
477570af302Sopenharmony_ci        return MuslFunc(free)(addr);
478570af302Sopenharmony_ci    }
479570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(addr))) {
480570af302Sopenharmony_ci        return gwp_asan_free(addr);
481570af302Sopenharmony_ci    }
482570af302Sopenharmony_ci    return MuslFunc(free)(addr);
483570af302Sopenharmony_ci}
484570af302Sopenharmony_ci
485570af302Sopenharmony_cisize_t libc_gwp_asan_malloc_usable_size(void *addr)
486570af302Sopenharmony_ci{
487570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
488570af302Sopenharmony_ci        return MuslMalloc(malloc_usable_size)(addr);
489570af302Sopenharmony_ci    }
490570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(addr))) {
491570af302Sopenharmony_ci        return gwp_asan_get_size(addr);
492570af302Sopenharmony_ci    }
493570af302Sopenharmony_ci    return MuslMalloc(malloc_usable_size)(addr);
494570af302Sopenharmony_ci}
495570af302Sopenharmony_ci
496570af302Sopenharmony_civoid libc_gwp_asan_malloc_iterate(void *base, size_t size,
497570af302Sopenharmony_ci                             void (*callback)(uintptr_t base, size_t size, void *arg), void *arg)
498570af302Sopenharmony_ci{
499570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
500570af302Sopenharmony_ci        return;
501570af302Sopenharmony_ci    }
502570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_FALSE(gwp_asan_pointer_is_mine(base))) {
503570af302Sopenharmony_ci        return gwp_asan_iterate(base, size, callback, arg);
504570af302Sopenharmony_ci    }
505570af302Sopenharmony_ci    return;
506570af302Sopenharmony_ci}
507570af302Sopenharmony_ci
508570af302Sopenharmony_civoid libc_gwp_asan_malloc_disable()
509570af302Sopenharmony_ci{
510570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
511570af302Sopenharmony_ci        return;
512570af302Sopenharmony_ci    }
513570af302Sopenharmony_ci
514570af302Sopenharmony_ci    return gwp_asan_disable();
515570af302Sopenharmony_ci}
516570af302Sopenharmony_ci
517570af302Sopenharmony_civoid libc_gwp_asan_malloc_enable()
518570af302Sopenharmony_ci{
519570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
520570af302Sopenharmony_ci        return;
521570af302Sopenharmony_ci    }
522570af302Sopenharmony_ci
523570af302Sopenharmony_ci    return gwp_asan_enable();
524570af302Sopenharmony_ci}
525570af302Sopenharmony_ci
526570af302Sopenharmony_cibool libc_gwp_asan_has_free_mem()
527570af302Sopenharmony_ci{
528570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
529570af302Sopenharmony_ci        return false;
530570af302Sopenharmony_ci    }
531570af302Sopenharmony_ci    gwp_asan_disable();
532570af302Sopenharmony_ci    int res = gwp_asan_has_free_mem();
533570af302Sopenharmony_ci    gwp_asan_enable();
534570af302Sopenharmony_ci    return res;
535570af302Sopenharmony_ci}
536570af302Sopenharmony_cibool libc_gwp_asan_ptr_is_mine(void *addr)
537570af302Sopenharmony_ci{
538570af302Sopenharmony_ci    if (GWP_ASAN_PREDICT_TRUE(!gwp_asan_initialized)) {
539570af302Sopenharmony_ci        return false;
540570af302Sopenharmony_ci    }
541570af302Sopenharmony_ci
542570af302Sopenharmony_ci    return gwp_asan_pointer_is_mine(addr);
543570af302Sopenharmony_ci}
544570af302Sopenharmony_ci#else
545570af302Sopenharmony_ci#include <stdbool.h>
546570af302Sopenharmony_ci
547570af302Sopenharmony_ci// Used for appspawn.
548570af302Sopenharmony_cibool may_init_gwp_asan(bool force_init)
549570af302Sopenharmony_ci{
550570af302Sopenharmony_ci    return false;
551570af302Sopenharmony_ci}
552570af302Sopenharmony_ci#endif
553