From 322bd12ecb14da27bcd024361cee565f2f0a443b Mon Sep 17 00:00:00 2001 From: Inkyun Kil Date: Mon, 11 Jun 2018 16:27:24 +0900 Subject: [PATCH] Fix wrong resource management 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 Signed-off-by: jusung son --- vconf-compat/vconf.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 51 insertions(+), 4 deletions(-) mode change 100755 => 100644 vconf-compat/vconf.c diff --git a/vconf-compat/vconf.c b/vconf-compat/vconf.c old mode 100755 new mode 100644 index adc7db6..6c38100 --- a/vconf-compat/vconf.c +++ b/vconf-compat/vconf.c @@ -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) -- 2.7.4