Check for suspicious memory leaks on every dispatch 77/274577/10
authorYoungHun Kim <yh8004.kim@samsung.com>
Tue, 3 May 2022 02:02:28 +0000 (11:02 +0900)
committerYoungHun Kim <yh8004.kim@samsung.com>
Tue, 17 May 2022 04:37:41 +0000 (13:37 +0900)
Change-Id: I60cb4b5bd0059a0e8375c71d03461ba7dfb51d6b

core/include/muse_core_internal.h
packaging/mused.spec
server/include/muse_server_config.h
server/src/muse_server_config.c
server/src/muse_server_module.c

index 40255b2..b82faf9 100644 (file)
@@ -152,6 +152,11 @@ typedef struct muse_channel_info {
        };
 } muse_channel_info_t;
 
+typedef struct ms_trace {
+       int pss;
+       int diff;
+} ms_trace_t;
+
 typedef struct muse_module {
        muse_channel_info_t ch[MUSE_CHANNEL_MAX];
        char recv_msg[MUSE_MSG_MAX_LENGTH + 1];
@@ -163,6 +168,7 @@ typedef struct muse_module {
        intptr_t handle;
        gboolean is_created;
        GMutex dispatch_lock;
+       ms_trace_t t;
 } muse_module_t;
 
 typedef struct muse_recv_data_head {
index 034400b..370861c 100644 (file)
@@ -1,6 +1,6 @@
 Name:       mused
 Summary:    A multimedia daemon
-Version:    0.3.147
+Version:    0.3.148
 Release:    0
 Group:      System/Libraries
 License:    Apache-2.0
index 2ce7d59..b3b5c1c 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #define MUSE_LOG                                                               "muse:logfile"
 #define MUSE_LOCK                                                              "muse:lockfile"
 #define MUSE_CHECK_CPU_MEMORY                                  "muse:check_cpu_memory"
+#define MUSE_MEMORY_LEAK_THRESHOLD                             "muse:memory_leak_threshold"
 #define MUSE_LOG_PERIOD                                                        "muse:log_period"
 #define MUSE_WATCHDOG_MIN_TIMEOUT                              "muse:min_timeout"
 #define MUSE_WATCHDOG_MAX_TIMEOUT                              "muse:max_timeout"
@@ -79,11 +80,14 @@ typedef struct ms_config {
        int host_cnt;
        gboolean check_cpu_memory;
        gboolean log_enabled;
+       int fd;
+       char *logfile;
        char *lockfile;
        int log_period;
        int min_timeout;
        int max_timeout;
        int memory_threshold;
+       int memory_leak_threshold;
        int cpu_threshold;
        gboolean is_watch_external_storage_enabled;
        char *gst_param_str[MUSE_PARAM_MAX];
@@ -106,10 +110,14 @@ char *ms_config_get_gst_param_str(int idx);
 char *ms_config_get_gst_preload_plugins(void);
 char *ms_config_get_path(int idx);
 char *ms_config_get_preloaded_value(int idx);
+char *ms_config_get_logfile(void);
+int ms_config_get_log_fd(void);
 char *ms_config_get_lockfile(void);
 gboolean ms_config_is_log_enabled(void);
 void ms_config_remove_lockfile(void);
 gboolean ms_config_is_check_cpu_memory(void);
+gboolean ms_config_is_memory_leak_detection_enabled(void);
+int ms_config_get_memory_leak_threshold(void);
 int ms_config_get_log_period(void);
 int ms_config_get_min_timeout(void);
 int ms_config_get_max_timeout(void);
index 4da261c..1641c6b 100644 (file)
@@ -55,7 +55,6 @@ static int _ms_config_parser(ms_config_t *conf)
        int host_idx;
        char *hosts = NULL;
        char *host = NULL;
-       char *str = NULL;
        char *ptr = NULL;
        char *key = NULL;
        char gst_param_key[MUSE_MSG_LEN_MAX];
@@ -71,17 +70,14 @@ static int _ms_config_parser(ms_config_t *conf)
                goto out;
        }
 
-       str = _ms_config_get_str(conf->muse_dict, MUSE_LOG, NULL);
-       if (str) {
-               if (strncmp(str, MUSE_USE_LOG, strlen(MUSE_USE_LOG)) == 0)
-                       conf->log_enabled = TRUE;
-               else
-                       conf->log_enabled = FALSE;
-               free(str);
-       } else {
-               LOGE("[%s] get string error", MUSE_LOG);
+       conf->logfile = _ms_config_get_str(conf->muse_dict, MUSE_LOG, NULL);
+       if (conf->logfile)
+               conf->log_enabled = (strncmp(conf->logfile, MUSE_USE_LOG, strlen(MUSE_USE_LOG) == 0));
+       else
                conf->log_enabled = FALSE;
-       }
+
+       muse_core_remove_symlink(conf->logfile);
+       conf->fd = open(conf->logfile, O_CREAT | O_APPEND | O_WRONLY | O_NONBLOCK, 0644);
 
        conf->lockfile = _ms_config_get_str(conf->muse_dict, MUSE_LOCK, NULL);
        if (!conf->lockfile) {
@@ -91,6 +87,8 @@ static int _ms_config_parser(ms_config_t *conf)
 
        conf->check_cpu_memory = (gboolean)_ms_config_get_int(conf->muse_dict, MUSE_CHECK_CPU_MEMORY, TRUE);
 
+       conf->memory_leak_threshold = _ms_config_get_int(conf->muse_dict, MUSE_MEMORY_LEAK_THRESHOLD, 0);
+
        conf->log_period = _ms_config_get_int(conf->muse_dict, MUSE_LOG_PERIOD, DEFAULT_LOG_PERIOD);
 
        conf->min_timeout = _ms_config_get_int(conf->muse_dict, MUSE_WATCHDOG_MIN_TIMEOUT, DEFAULT_WATCHDOG_MIN_TIMEOUT);
@@ -224,6 +222,7 @@ void ms_config_deinit(ms_config_t *conf)
                MUSE_FREE(conf->host[idx]);
        }
 
+       MUSE_FREE(conf->logfile);
        MUSE_FREE(conf->lockfile);
 
        for (idx = 0; idx <= conf->gst_param_cnt; idx++)
@@ -306,6 +305,23 @@ char *ms_config_get_preloaded_value(int idx)
        return value;
 }
 
+char *ms_config_get_logfile(void)
+{
+       ms_config_t *conf = _ms_config_get_instance();
+
+       muse_return_val_if_fail(conf, NULL);
+
+       return conf->logfile;
+}
+
+int ms_config_get_log_fd(void)
+{
+       ms_config_t *conf = _ms_config_get_instance();
+       muse_return_val_if_fail(conf, MUSE_ERR);
+
+       return conf->fd;
+}
+
 char *ms_config_get_lockfile(void)
 {
        ms_config_t *conf = _ms_config_get_instance();
@@ -341,6 +357,22 @@ gboolean ms_config_is_check_cpu_memory(void)
        return conf->check_cpu_memory;
 }
 
+gboolean ms_config_is_memory_leak_detection_enabled(void)
+{
+       ms_config_t *conf = _ms_config_get_instance();
+       muse_return_val_if_fail(conf, FALSE);
+
+       return (conf->memory_leak_threshold != 0);
+}
+
+int ms_config_get_memory_leak_threshold(void)
+{
+       ms_config_t *conf = _ms_config_get_instance();
+       muse_return_val_if_fail(conf, MUSE_ERR);
+
+       return conf->memory_leak_threshold;
+}
+
 int ms_config_get_log_period(void)
 {
        ms_config_t *conf = _ms_config_get_instance();
index 6d3b9b6..d2aa37a 100644 (file)
 #ifdef MUSE_USE_RM_READY
 #include "mm_resource_manager.h"
 #endif
+#include <execinfo.h>
 
 static GMutex dllsym_table_lock;
 
 static gboolean _ms_module_dispatch_timeout_callback(gpointer data);
 static gboolean _ms_module_enable_dispatch_timeout_callback(int cmd, muse_module_h m);
 static void _ms_module_set_loaded_dllsym(int idx, GModule *dllsym, gboolean value);
+static void _ms_module_write_name_time(int fd, int idx);
+static void _ms_module_backtrace(int fd);
+static void _ms_module_check_memory(muse_module_h m);
 
 static gboolean _ms_module_dispatch_timeout_callback(gpointer data)
 {
@@ -83,6 +87,72 @@ static void _ms_module_set_loaded_dllsym(int idx, GModule *dllsym, gboolean valu
        SECURE_LOGD("dll_handle: %p", module->dllsym);
 }
 
+static void _ms_module_write_name_time(int fd, int idx)
+{
+       struct timespec tv;
+       char buf[MUSE_MSG_LEN_MAX] = {0};
+       char time_buf[MUSE_MSG_TIME_LEN] = {0};
+       char *name = ms_config_get_host_name(idx);
+
+       muse_core_get_cur_time(&tv, NULL);
+       muse_core_change_time_format((int)tv.tv_sec, time_buf);
+
+       snprintf(buf, MUSE_MSG_LEN_MAX, "%s %s", name, time_buf);
+
+       write(fd, buf, strlen(buf));
+       write(fd, "\n", 1);
+}
+
+static void _ms_module_backtrace(int fd)
+{
+       void *trace[MUSE_MSG_LEN];
+       Dl_info info;
+       int idx;
+       char *sym_addr = NULL, **s = NULL;
+
+       /* FIXME: Consider the performance and deadlock by non async-signal-safe function */
+       int sz = backtrace(trace, MUSE_MSG_LEN);
+       if (sz <= 0)
+               return;
+
+       s = backtrace_symbols(trace, sz);
+       if (!s)
+               return;
+
+       for (idx = 0; idx < sz; idx++) {
+               sym_addr = g_strstr_len(s[idx], strlen(s[idx]), "[0x");
+
+               memset(&info, 0, sizeof(info));
+
+               write(fd, s[idx], strlen(s[idx]));
+               if (sym_addr && dladdr((const void *)strtoul(sym_addr + 1, NULL, 16), &info) && info.dli_sname)
+                       write(fd, info.dli_sname, strlen(info.dli_sname));
+               write(fd, "\n", 1);
+       }
+
+       free(s);
+}
+
+static void _ms_module_check_memory(muse_module_h m)
+{
+       int fd;
+
+       muse_return_if_fail(ms_get_instance());
+
+       int pss = ms_system_get_memory_usage(ms_get_instance()->pid);
+       int diff = pss - m->t.pss;
+       m->t.pss = pss;
+
+       if (diff > m->t.diff && diff > ms_config_get_memory_leak_threshold()) {
+               m->t.diff = diff;
+               fd = ms_config_get_log_fd();
+               if (fd == MUSE_ERR)
+                       return;
+               _ms_module_write_name_time(fd, m->idx);
+               _ms_module_backtrace(fd);
+       }
+}
+
 GModule *ms_module_open(int idx)
 {
        GModule *dllsym = NULL;
@@ -173,6 +243,9 @@ int ms_module_dispatch(muse_module_h m)
                        if (!rm_success)
                                LOGE("[%s] [%d] Failed to remove %d", ms_config_get_host_name(m->idx), api, id);
                }
+
+               if (ms_config_is_memory_leak_detection_enabled())
+                       _ms_module_check_memory(m);
        } else {
                LOGE("[%s] [%d] error - dispatcher", ms_config_get_host_name(m->idx), api);
                ret = MUSE_ERR;