diff --git a/porting/linux/user/include/signal.h b/porting/linux/user/include/signal.h index 860b0f70c703d4042fb2f687090decaff613cd8e..1211a6c52da091c2cc3649026fa3d0855ddb0fa6 100644 --- a/porting/linux/user/include/signal.h +++ b/porting/linux/user/include/signal.h @@ -202,6 +202,7 @@ int __libc_current_sigrtmax(void); #define MUSL_SIGNAL_NATIVE_LOCAL (SIGRTMIN + 3) #define MUSL_SIGNAL_JSHEAP (SIGRTMIN + 4) #define MUSL_SIGNAL_JSHEAP_PRIV (SIGRTMIN + 5) +#define MUSL_SIGNAL_MEMCHECK (SIGRTMIN + 9) int kill(pid_t, int); int sigemptyset(sigset_t *); diff --git a/porting/linux/user/src/hook/musl_malloc_dispatch_table.h b/porting/linux/user/src/hook/musl_malloc_dispatch_table.h index 430de744bb50cf996fa1e12699af1796d901fc12..f78ec03bef47a5e01272e1e19e2aa737336289c6 100644 --- a/porting/linux/user/src/hook/musl_malloc_dispatch_table.h +++ b/porting/linux/user/src/hook/musl_malloc_dispatch_table.h @@ -7,7 +7,9 @@ struct musl_libc_globals { volatile atomic_llong current_dispatch_table; volatile atomic_llong so_dispatch_table; + volatile atomic_llong memleak_tracker_so_dispatch_table; struct MallocDispatchType malloc_dispatch_table; + struct MallocDispatchType memleak_tracker_malloc_dispatch_table; }; #endif diff --git a/porting/linux/user/src/hook/musl_preinit.c b/porting/linux/user/src/hook/musl_preinit.c index 5b598d2bc52b4d677cd28dea5ef26f88ef42c1da..ca3f71a826eb9669f8bbe172853fd5dbd1c40f05 100644 --- a/porting/linux/user/src/hook/musl_preinit.c +++ b/porting/linux/user/src/hook/musl_preinit.c @@ -48,6 +48,10 @@ static struct MallocDispatchType __ohos_malloc_hook_init_dispatch = { }; #define MAX_SYM_NAME_SIZE 1000 #define MAX_PROC_NAME_SIZE 256 +#define ADDR_NATIVE_ENABLE (1<<4) +#define ADDR_NATIVE_DISABLE (1<<5) +#define ADDR_NATIVE_SAVE (1<<6) +#define ADDR_NATIVE_CLEAR (1<<7) static char *__malloc_hook_shared_lib = "libnative_hook.z.so"; static char *__malloc_hook_function_prefix = "ohos_malloc_hook"; volatile atomic_llong ohos_malloc_hook_shared_library; @@ -56,20 +60,35 @@ static char *kMemTrackPrefix = "track"; static char *kMemTrackPropertyEnable = "const.hiview.memleak_tracker.enable"; static char *kMemTrackSign = "true"; bool checkLoadMallocMemTrack = false; +unsigned int memLeakTypeContent = 0; +volatile atomic_llong memleak_ever_shared_library_handle; +volatile atomic_llong ohos_malloc_ever_shared_library_handle; void* function_of_shared_lib[LAST_FUNCTION]; +void* function_of_ohos_malloc_shared_lib[LAST_FUNCTION]; +void* function_of_memleak_shared_lib[LAST_FUNCTION]; static enum EnumHookMode __hook_mode = STEP_HOOK_MODE; -static char __memleak_param_value[OHOS_PARAM_MAX_SIZE + 1] = {0}; static void get_native_hook_param(char *buf, unsigned int buf_len) { #ifdef OHOS_ENABLE_PARAMETER const char *key = MUSL_HOOK_PARAM_NAME; unsigned int len = buf_len; - (void)SystemReadParam(kMemTrackPropertyEnable, __memleak_param_value, &len); - if (strncmp(__memleak_param_value, kMemTrackSign, strlen(kMemTrackSign)) == 0) { + (void)SystemReadParam(key, buf, &len); +#else + return; +#endif +} + +static void get_memleak_hook_param() +{ +#ifdef OHOS_ENABLE_PARAMETER + const char *key = kMemTrackPropertyEnable; + unsigned int len = OHOS_PARAM_MAX_SIZE; + char memleak_param_value[OHOS_PARAM_MAX_SIZE + 1] = {0}; + (void)SystemReadParam(key, memleak_param_value, &len); + if (strncmp(memleak_param_value, kMemTrackSign, strlen(kMemTrackSign)) == 0) { checkLoadMallocMemTrack = true; } - (void)SystemReadParam(key, buf, &len); #else return; #endif @@ -267,6 +286,11 @@ static void clear_function_table() { for (size_t i = 0; i < LAST_FUNCTION; i++) { function_of_shared_lib[i] = NULL; + if (__get_memleak_hook_flag()) { + function_of_memleak_shared_lib[i] = NULL; + } else if (__get_global_hook_flag()) { + function_of_ohos_malloc_shared_lib[i] = NULL; + } } } @@ -285,6 +309,11 @@ bool init_malloc_hook_shared_library(void* shared_library_handle, const char* sh char symbol[MAX_SYM_NAME_SIZE]; snprintf(symbol, sizeof(symbol), "%s_%s", prefix, names[i]); function_of_shared_lib[i] = dlsym(shared_library_handle, symbol); + if (__get_memleak_hook_flag()) { + function_of_memleak_shared_lib[i] = function_of_shared_lib[i]; + } else if (__get_global_hook_flag()) { + function_of_ohos_malloc_shared_lib[i] = function_of_shared_lib[i]; + } if (function_of_shared_lib[i] == NULL) { // __musl_log(__MUSL_LOG_ERROR, "%s: %s routine not found in %s\n", getprogname(), symbol, shared_lib); clear_function_table(); @@ -343,14 +372,23 @@ bool finish_install_ohos_malloc_hooks(struct musl_libc_globals* globals, const c return false; } on_start_func_t start_func = (on_start_func_t)(function_of_shared_lib[ON_START_FUNCTION]); - if (!start_func()) { - // __musl_log(__MUSL_LOG_ERROR, "%s: failed to start %s\n", getprogname(), prefix); - clear_function_table(); - return false; + if (__get_global_hook_flag()) { + if (!start_func()) { + // __musl_log(__MUSL_LOG_ERROR, "%s: failed to start %s\n", getprogname(), prefix); + clear_function_table(); + return false; + } + atomic_store_explicit(&__musl_libc_globals.so_dispatch_table, (volatile long long)&globals->malloc_dispatch_table, memory_order_seq_cst); + atomic_store_explicit(&__musl_libc_globals.current_dispatch_table, (volatile long long)&globals->malloc_dispatch_table, memory_order_seq_cst); + } + if (__get_memleak_hook_flag() && checkLoadMallocMemTrack) { + if (!start_func(memLeakTypeContent)) { + clear_function_table(); + return false; + } + atomic_store_explicit(&__musl_libc_globals.memleak_tracker_so_dispatch_table, (volatile long long)&globals->memleak_tracker_malloc_dispatch_table, memory_order_seq_cst); + atomic_store_explicit(&__musl_libc_globals.current_dispatch_table, (volatile long long)&globals->memleak_tracker_malloc_dispatch_table, memory_order_seq_cst); } - atomic_store_explicit(&__musl_libc_globals.so_dispatch_table, (volatile long long)&globals->malloc_dispatch_table, memory_order_seq_cst); - atomic_store_explicit(&__musl_libc_globals.current_dispatch_table, (volatile long long)&globals->malloc_dispatch_table, memory_order_seq_cst); - int ret_value = atexit(malloc_finalize); if (ret_value != 0) { // __musl_log(__MUSL_LOG_ERROR, "failed to set atexit cleanup function: %d\n", ret_value); @@ -372,14 +410,23 @@ static void install_ohos_malloc_hook(struct musl_libc_globals* globals, const ch { volatile void* shared_library_handle = (volatile void *)atomic_load_explicit(&ohos_malloc_hook_shared_library, memory_order_acquire); assert(shared_library_handle == NULL || shared_library_handle == (volatile void*)-1); - shared_library_handle = (volatile void*)load_malloc_hook_shared_library(shared_lib, prefix, &globals->malloc_dispatch_table); + if (__get_memleak_hook_flag()) { + shared_library_handle = (volatile void*)load_malloc_hook_shared_library(shared_lib, prefix, &globals->memleak_tracker_malloc_dispatch_table); + } else if (__get_global_hook_flag()) { + shared_library_handle = (volatile void*)load_malloc_hook_shared_library(shared_lib, prefix, &globals->malloc_dispatch_table); + } if (shared_library_handle == NULL) { // __musl_log(__MUSL_LOG_ERROR, "Can't load shared library '%s'\n", __malloc_hook_shared_lib); return; } - if (finish_install_ohos_malloc_hooks(globals, NULL, __malloc_hook_function_prefix)) { + if (finish_install_ohos_malloc_hooks(globals, NULL, prefix)) { atomic_store_explicit(&ohos_malloc_hook_shared_library, (volatile long long)shared_library_handle, memory_order_seq_cst); + if (strncmp(__malloc_hook_function_prefix, prefix, strlen(prefix)) == 0) { + atomic_store_explicit(&ohos_malloc_ever_shared_library_handle, (volatile long long)shared_library_handle, memory_order_seq_cst); + } else { + atomic_store_explicit(&memleak_ever_shared_library_handle, (volatile long long)shared_library_handle, memory_order_seq_cst); + } } else { // __musl_log(__MUSL_LOG_ERROR, "finish_install_ohos_malloc_hooks failed\n"); dlclose((void *)shared_library_handle); @@ -389,9 +436,13 @@ static void install_ohos_malloc_hook(struct musl_libc_globals* globals, const ch static void* init_ohos_malloc_hook() { - if (checkLoadMallocMemTrack) { - install_ohos_malloc_hook(&__musl_libc_globals, kMemTrackSharedLib, kMemTrackPrefix); - } else { + if (__get_memleak_hook_flag()) { + get_memleak_hook_param(); + if (checkLoadMallocMemTrack) { + install_ohos_malloc_hook(&__musl_libc_globals, kMemTrackSharedLib, kMemTrackPrefix); + } + } + if (__get_global_hook_flag()) { install_ohos_malloc_hook(&__musl_libc_globals, __malloc_hook_shared_lib, __malloc_hook_function_prefix); } return NULL; @@ -418,10 +469,29 @@ static void __set_default_malloc() atomic_store_explicit(&__musl_libc_globals.current_dispatch_table, (volatile const long long)NULL, memory_order_seq_cst); } +static void __restore_hook_function_table() +{ + for (size_t i = 0; i < LAST_FUNCTION; i++) { + if (__get_memleak_hook_flag()) { + function_of_shared_lib[i] = function_of_memleak_shared_lib[i]; + } else if (__get_global_hook_flag()) { + function_of_shared_lib[i] = function_of_ohos_malloc_shared_lib[i]; + } + } +} + static void __install_malloc_hook() { + if (__get_memleak_hook_flag()) { + return; + } atomic_store_explicit(&__hook_enable_hook_flag, (volatile bool)true, memory_order_seq_cst); - + volatile void* ohos_malloc_ever_handle = (volatile void* )atomic_load_explicit(&ohos_malloc_ever_shared_library_handle, memory_order_acquire); + if (ohos_malloc_ever_handle != NULL) { + atomic_store_explicit(&ohos_malloc_hook_shared_library, (volatile long long)ohos_malloc_ever_handle, memory_order_seq_cst); + } else { + atomic_store_explicit(&ohos_malloc_hook_shared_library, (volatile long long)0, memory_order_seq_cst); + } volatile void* shared_library_handle = (volatile void* )atomic_load_explicit(&ohos_malloc_hook_shared_library, memory_order_acquire); if (shared_library_handle == NULL) { MUSL_LOGI("HiProfiler, __install_malloc_hook __hook_mode %{public}d", __hook_mode); @@ -432,17 +502,22 @@ static void __install_malloc_hook() init_ohos_malloc_hook(); } } else if (shared_library_handle != (void*)-1) { + __restore_hook_function_table(); + volatile const struct MallocDispatchType* so_dispatch_value = (volatile const struct MallocDispatchType* )atomic_load_explicit(&__musl_libc_globals.so_dispatch_table, memory_order_acquire); + atomic_store_explicit(&__musl_libc_globals.current_dispatch_table, (volatile long long)so_dispatch_value, memory_order_seq_cst); on_start_func_t start_func = (on_start_func_t)(function_of_shared_lib[ON_START_FUNCTION]); if (start_func && !start_func()) { // __musl_log(__MUSL_LOG_ERROR, "%s: failed to enable malloc\n", getprogname()); } - volatile const struct MallocDispatchType* so_dispatch_value = (volatile const struct MallocDispatchType* )atomic_load_explicit(&__musl_libc_globals.so_dispatch_table, memory_order_acquire); - atomic_store_explicit(&__musl_libc_globals.current_dispatch_table, (volatile long long)so_dispatch_value, memory_order_seq_cst); + } } static void __uninstal_malloc_hook() { + if (__get_memleak_hook_flag()) { + return; + } atomic_store_explicit(&__hook_enable_hook_flag, (volatile bool)false, memory_order_seq_cst); bool flag = __set_hook_flag(false); __set_default_malloc(); @@ -452,6 +527,56 @@ static void __uninstal_malloc_hook() } } +static void __install_memleak_tracker_hook(int32_t sigNum, siginfo_t *info, void *ptr) +{ + if (__get_global_hook_flag()) { + return; + } + atomic_store_explicit(&__memleak_hook_flag, (volatile bool)true, memory_order_seq_cst); + volatile void* memleak_ever_handle = (volatile void* )atomic_load_explicit(&memleak_ever_shared_library_handle, memory_order_acquire); + if (memleak_ever_handle != NULL) { + atomic_store_explicit(&ohos_malloc_hook_shared_library, (volatile long long)memleak_ever_handle, memory_order_seq_cst); + } else { + atomic_store_explicit(&ohos_malloc_hook_shared_library, (volatile long long)0, memory_order_seq_cst); + } + volatile void* shared_library_handle = (volatile void* )atomic_load_explicit(&ohos_malloc_hook_shared_library, memory_order_acquire); + memLeakTypeContent = (unsigned int)(siginfo_t *)((info)->si_addr); + if (shared_library_handle == NULL) { + if (__hook_mode == STEP_HOOK_MODE) { + if (memLeakTypeContent & ADDR_NATIVE_ENABLE) { + atomic_store_explicit(&__musl_libc_globals.current_dispatch_table, (volatile const long long)&__ohos_malloc_hook_init_dispatch, memory_order_seq_cst); + atomic_store_explicit(&ohos_malloc_hook_shared_library, (volatile long long)-1, memory_order_seq_cst); + } + } else { + init_ohos_malloc_hook(); + } + } else if (shared_library_handle != (void*)-1) { + if (checkLoadMallocMemTrack) { + __restore_hook_function_table(); + on_start_func_t start_func = (on_start_func_t)(function_of_shared_lib[ON_START_FUNCTION]); + if (memLeakTypeContent & ADDR_NATIVE_ENABLE) { + volatile const struct MallocDispatchType* memleak_tracker_so_dispatch_value = (volatile const struct MallocDispatchType* )atomic_load_explicit(&__musl_libc_globals.memleak_tracker_so_dispatch_table, memory_order_acquire); + atomic_store_explicit(&__musl_libc_globals.current_dispatch_table, (volatile long long)memleak_tracker_so_dispatch_value, memory_order_seq_cst); + } + if (start_func && !start_func(memLeakTypeContent)) { + // __musl_log(__MUSL_LOG_ERROR, "%s: failed to enable malloc\n", getprogname()); + clear_function_table(); + } + if (memLeakTypeContent & ADDR_NATIVE_ENABLE) { + atomic_store_explicit(&__memleak_hook_flag, (volatile bool)false, memory_order_seq_cst); + bool flag = __set_hook_flag(false); + __set_default_malloc(); + on_end_func_t end_func = (on_end_func_t)(function_of_shared_lib[ON_END_FUNCTION]); + if (end_func) { + end_func(); + } + memLeakTypeContent = 0; + } + } + } +} + + static void __install_malloc_hook_signal_handler() { struct sigaction actionInstallHook = {}; @@ -465,6 +590,15 @@ static void __install_malloc_hook_signal_handler() sigemptyset(&actionDef.sa_mask); sigaddset(&actionDef.sa_mask, MUSL_SIGNAL_HOOK); sigaction(MUSL_SIGNAL_UNHOOK, &actionDef, NULL); + + struct sigaction actionInstallMemleakHook = {}; + actionInstallMemleakHook.sa_handler = NULL; + actionInstallMemleakHook.sa_sigaction = __install_memleak_tracker_hook; + sigemptyset(&actionInstallMemleakHook.sa_mask); + sigaddset(&actionInstallMemleakHook.sa_mask, MUSL_SIGNAL_MEMCHECK); + actionInstallMemleakHook.sa_flags = SA_SIGINFO; + actionInstallMemleakHook.sa_restorer = NULL; + sigaction(MUSL_SIGNAL_MEMCHECK, &actionInstallMemleakHook, NULL); } static void __initialize_malloc() @@ -475,6 +609,7 @@ static void __initialize_malloc() __attribute__((constructor(1))) static void __musl_initialize() { atomic_store_explicit(&__hook_enable_hook_flag, (volatile bool)false, memory_order_seq_cst); + atomic_store_explicit(&__memleak_hook_flag, (volatile bool)false, memory_order_seq_cst); __set_default_malloc(); char hook_process_path[MAX_PROC_NAME_SIZE + 1] = {0}; parse_hook_variable(&__hook_mode, hook_process_path, sizeof(hook_process_path) - 1); diff --git a/porting/linux/user/src/hook/musl_preinit_common.c b/porting/linux/user/src/hook/musl_preinit_common.c index ef3cd14c45136a551983972e15952f0a24134538..936c51d8fe90766d41936f78c7f8748599d2d9c3 100644 --- a/porting/linux/user/src/hook/musl_preinit_common.c +++ b/porting/linux/user/src/hook/musl_preinit_common.c @@ -18,5 +18,6 @@ struct MallocDispatchType __libc_malloc_default_dispatch = { }; volatile atomic_bool __hook_enable_hook_flag; +volatile atomic_bool __memleak_hook_flag; #endif diff --git a/porting/linux/user/src/hook/musl_preinit_common.h b/porting/linux/user/src/hook/musl_preinit_common.h index 83532626e226d8cc8f02e33548b12a9e0b9789c9..6666c97e7c551b804cacb2ea878a6e720889e33d 100644 --- a/porting/linux/user/src/hook/musl_preinit_common.h +++ b/porting/linux/user/src/hook/musl_preinit_common.h @@ -11,6 +11,7 @@ extern struct MallocDispatchType __libc_malloc_default_dispatch; extern volatile atomic_bool __hook_enable_hook_flag; +extern volatile atomic_bool __memleak_hook_flag; extern bool checkLoadMallocMemTrack; enum EnumFunc { @@ -49,6 +50,18 @@ inline bool __get_global_hook_flag() #endif // HOOK_ENABLE } +__attribute__((always_inline)) +inline bool __get_memleak_hook_flag() +{ +#ifdef HOOK_ENABLE + volatile bool memleak_flag = atomic_load_explicit(&__memleak_hook_flag, memory_order_acquire); + return memleak_flag; +#else + return false; +#endif // HOOK_ENABLE +} + + __attribute__((always_inline)) inline bool __get_hook_flag() { @@ -96,7 +109,7 @@ inline volatile const struct MallocDispatchType* get_current_dispatch_table() #ifdef HOOK_ENABLE volatile const struct MallocDispatchType* ret = (struct MallocDispatchType *)atomic_load_explicit(&__musl_libc_globals.current_dispatch_table, memory_order_acquire); if (ret != NULL) { - if (checkLoadMallocMemTrack) { + if (__get_memleak_hook_flag()) { return ret; } if (!__get_global_hook_flag()) {