Fix wrong resource management 50/181250/7
authorInkyun Kil <inkyun.kil@samsung.com>
Mon, 11 Jun 2018 07:27:24 +0000 (16:27 +0900)
committerInkyun Kil <inkyun.kil@samsung.com>
Thu, 14 Jun 2018 07:28:50 +0000 (16:28 +0900)
If a program is unloaded before GMainContext invoke the 'call_noti_cb',
the program is crashed because the 'call_noti_cb' has deleted.
To prevent it, remove the source from GMainContext at destructor.

Change-Id: I3cdf7e84c055856f58d1797c8444464be585ef0d
Signed-off-by: Inkyun Kil <inkyun.kil@samsung.com>
Signed-off-by: jusung son <jusung07.son@samsung.com>
vconf-compat/vconf.c [changed mode: 0755->0644]

old mode 100755 (executable)
new mode 100644 (file)
index adc7db6..6c38100
@@ -42,6 +42,7 @@
 #define LOG_TAG "VCONF"
 
 static void _restore_noti_cb(gpointer key, gpointer value, gpointer user_data);
+static void _close(void);
 
 static pthread_mutex_t vconf_lock = PTHREAD_MUTEX_INITIALIZER;
 static int _refcnt;
@@ -49,6 +50,7 @@ static struct buxton_client *client;
 static struct buxton_layer *system_layer;
 static struct buxton_layer *memory_layer;
 static GHashTable *noti_tbl;
+static GHashTable *gsource_tbl;
 
 struct noti {
        char *key;
@@ -62,6 +64,11 @@ struct noti_cb {
        bool in_cb;
 };
 
+struct callback_info {
+       keynode_t *key_node;
+       int source_id;           /**< GSource id for call_noti_cb*/
+};
+
 static bool last_result;
 
 static void free_keynode(struct _keynode_t *keynode)
@@ -76,6 +83,28 @@ static void free_keynode(struct _keynode_t *keynode)
        free(keynode);
 }
 
+static void free_callback_info(struct callback_info *cb_info)
+{
+       if (!cb_info)
+               return;
+
+       free_keynode(cb_info->key_node);
+       g_source_remove(cb_info->source_id);
+       free(cb_info);
+}
+
+__attribute__((destructor))
+static void _vconf_finish(void)
+{
+       /* force close */
+       if (_refcnt > 0) {
+               _refcnt = 1;
+               _close();
+       }
+
+       if (gsource_tbl)
+               g_hash_table_remove_all(gsource_tbl);
+}
 
 EXPORT char *vconf_keynode_get_name(keynode_t *keynode)
 {
@@ -369,7 +398,8 @@ static GList *free_copy_list(GList *noti_list, GList *copy_list)
 
 static gboolean call_noti_cb(gpointer data)
 {
-       keynode_t *node = (keynode_t *)data;
+       struct callback_info *cb_info = (struct callback_info *)data;
+       keynode_t *node = cb_info->key_node;
        struct noti *noti;
        GList *l;
        GList *copy;
@@ -393,7 +423,7 @@ static gboolean call_noti_cb(gpointer data)
 
        noti->noti_list = free_copy_list(noti->noti_list, copy);
 
-       free_keynode(node);
+       g_hash_table_remove(gsource_tbl, GINT_TO_POINTER(cb_info->source_id));
 
        return G_SOURCE_REMOVE;
 }
@@ -402,15 +432,32 @@ static void notify_cb(const struct buxton_layer *layer, const char *key,
                const struct buxton_value *val, void *user_data)
 {
        keynode_t *node;
+       struct callback_info *cb_info;
 
        node = calloc(1, sizeof(*node));
-       if (!node)
+       if (!node) {
+               LOGE("Failed to create keynode_t");
                return;
+       }
 
        node->keyname = strdup(key);
        to_vconf_t(val, node);
 
-       g_idle_add_full(G_PRIORITY_HIGH, call_noti_cb, node, NULL);
+       cb_info = calloc(1, sizeof(*cb_info));
+       if (!cb_info) {
+               free_keynode(node);
+               LOGE("Failed to create callback_info_s");
+               return;
+       }
+
+       cb_info->key_node = node;
+       cb_info->source_id = g_idle_add_full(G_PRIORITY_HIGH, call_noti_cb, cb_info, NULL);
+
+       if (gsource_tbl == NULL)
+               gsource_tbl = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                               NULL, (GDestroyNotify)free_callback_info);
+
+       g_hash_table_insert(gsource_tbl, GINT_TO_POINTER(cb_info->source_id), cb_info);
 }
 
 static struct noti_cb *find_noti_cb(struct noti *noti, vconf_callback_fn cb)