From: Hwankyu Jhun Date: Fri, 24 Feb 2017 03:38:11 +0000 (+0900) Subject: Fix double free issue X-Git-Tag: accepted/tizen/common/20170227.043107~1 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fappfw%2Fapp-core.git;a=commitdiff_plain;h=a9d23c4a35fee6276bebffa77d7eba3aa53f02a2 Fix double free issue When destroying the hash table, the application has crashed by the language list. Some nodes of the list are released when the language is found in the __append_langs function. If the node is released, we should replace the value of the hash table. Change-Id: I926d52850b2ac596d777bbc05ed2f947855f9041 Signed-off-by: Hwankyu Jhun --- diff --git a/src/appcore-i18n.c b/src/appcore-i18n.c index 1003ea8..572bdd8 100644 --- a/src/appcore-i18n.c +++ b/src/appcore-i18n.c @@ -33,24 +33,78 @@ #include "appcore-internal.h" +struct lang_info_s { + char *parent; + GList *list; +}; + static int _set; static char locale_dir[PATH_MAX]; -static void __free_children_langs(gpointer data) +static void __destroy_lang_info(gpointer data) { - GList *list = (GList *)data; + struct lang_info_s *info = (struct lang_info_s *)data; - if (list == NULL) + if (info == NULL) return; - g_list_free_full(list, (GDestroyNotify)free); + if (info->list) + g_list_free_full(info->list, free); + if (info->parent) + free(info->parent); + free(info); +} + +static struct lang_info_s *__create_lang_info(const char *lang) +{ + struct lang_info_s *info; + + info = calloc(1, sizeof(struct lang_info_s)); + if (info == NULL) { + _ERR("Out of memory"); + return NULL; + } + + info->parent = strdup(lang); + if (info->parent == NULL) { + _ERR("Out of memory"); + free(info); + return NULL; + } + + return info; } static gint __compare_langs(gconstpointer a, gconstpointer b) { + if (!a || !b) + return -1; + return strcmp(a, b); } +static char *__get_string_before(const char *str, const char *delim) +{ + char *new_str; + char *dup_str; + char *token; + + dup_str = strdup(str); + if (dup_str == NULL) + return NULL; + + token = strtok(dup_str, delim); + if (token == NULL) { + free(dup_str); + return NULL; + } + + new_str = strdup(token); + free(dup_str); + + return new_str; +} + static GHashTable *__get_lang_table(void) { GHashTable *table; @@ -59,15 +113,14 @@ static GHashTable *__get_lang_table(void) char buf[PATH_MAX]; struct stat stat_buf; int ret; - char *dup_lang; - char *token; - GList *list; + char *parent_lang; + struct lang_info_s *info; if (locale_dir[0] == 0 || locale_dir[0] == '\0') return NULL; table = g_hash_table_new_full(g_str_hash, g_str_equal, - free, __free_children_langs); + NULL, __destroy_lang_info); if (table == NULL) { _ERR("Out of memory"); return NULL; @@ -89,128 +142,84 @@ static GHashTable *__get_lang_table(void) if (ret != 0 || !S_ISDIR(stat_buf.st_mode)) continue; - dup_lang = strdup(dentry->d_name); - if (dup_lang == NULL) { + parent_lang = __get_string_before(dentry->d_name, "_"); + if (parent_lang == NULL) { _ERR("Out of memory"); break; } - token = strtok(dup_lang, "_"); - if (token == NULL) { - free(dup_lang); - continue; - } - - list = (GList *)g_hash_table_lookup(table, token); - if (list == NULL) { - list = g_list_append(list, strdup(dentry->d_name)); - g_hash_table_insert(table, strdup(token), list); - } else { - list = g_list_append(list, strdup(dentry->d_name)); + info = g_hash_table_lookup(table, parent_lang); + if (info == NULL) { + info = __create_lang_info(parent_lang); + if (info == NULL) { + free(parent_lang); + break; + } + g_hash_table_insert(table, info->parent, info); } - free(dup_lang); + info->list = g_list_append(info->list, strdup(dentry->d_name)); + free(parent_lang); } closedir(dp); return table; } -static char *__get_string_before(const char *str, const char *delim) -{ - char *new_str; - char *dup_str; - char *token; - - dup_str = strdup(str); - if (dup_str == NULL) - return NULL; - - token = strtok(dup_str, delim); - if (token == NULL) { - free(dup_str); - return NULL; - } - - new_str = strdup(token); - free(dup_str); - - return new_str; -} - static GList *__append_langs(const char *lang, GList *list, GHashTable *table) { - GList *child_list; - GList *child_iter; + struct lang_info_s *info; GList *found; - char *child_lang; - char *parent_lang; + char *parent_lang = NULL; char *extract_lang; - char *tmp; if (lang == NULL) return list; - found = g_list_find_custom(g_list_first(list), lang, - __compare_langs); - if (found) { - tmp = (char *)found->data; - list = g_list_remove(list, tmp); - list = g_list_append(list, tmp); - return list; - } - extract_lang = __get_string_before(lang, "."); if (extract_lang == NULL) return list; - parent_lang = __get_string_before(extract_lang, "_"); - if (parent_lang == NULL) { - free(extract_lang); - return list; + found = g_list_find_custom(list, extract_lang, __compare_langs); + if (found) { + list = g_list_remove_link(list, found); + list = g_list_concat(list, found); + goto end; } - child_list = g_hash_table_lookup(table, parent_lang); - if (child_list == NULL) { - free(parent_lang); - free(extract_lang); - return list; - } + parent_lang = __get_string_before(extract_lang, "_"); + if (parent_lang == NULL) + goto end; + + info = g_hash_table_lookup(table, parent_lang); + if (info == NULL) + goto end; - found = g_list_find_custom(g_list_first(child_list), - extract_lang, __compare_langs); + found = g_list_find_custom(info->list, extract_lang, __compare_langs); if (found) { - tmp = (char *)found->data; - child_list = g_list_remove(child_list, tmp); - list = g_list_append(list, tmp); - free(parent_lang); - free(extract_lang); - return list; + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); + goto end; } - free(extract_lang); - found = g_list_find_custom(g_list_first(child_list), - parent_lang, __compare_langs); + found = g_list_find_custom(info->list, parent_lang, __compare_langs); if (found) { - tmp = (char *)found->data; - child_list = g_list_remove(child_list, tmp); - list = g_list_append(list, tmp); - free(parent_lang); - return list; + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); + goto end; } - free(parent_lang); - - child_iter = g_list_first(child_list); - while (child_iter) { - child_lang = (char *)child_iter->data; - child_iter = g_list_next(child_iter); - if (child_lang) { - list = g_list_append(list, strdup(child_lang)); - child_list = g_list_remove(child_list, child_lang); - free(child_lang); - break; - } + + found = g_list_first(info->list); + if (found) { + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); } +end: + if (extract_lang) + free(extract_lang); + if (parent_lang) + free(parent_lang); + return list; } @@ -243,8 +252,7 @@ static GList *__append_default_langs(GList *list) GList *found; for (i = 0; i < (sizeof(langs) / sizeof(langs[0])); i++) { - found = g_list_find_custom(g_list_first(list), langs[i], - __compare_langs); + found = g_list_find_custom(list, langs[i], __compare_langs); if (found == NULL) list = g_list_append(list, strdup(langs[i])); } diff --git a/src/base/appcore_base.c b/src/base/appcore_base.c index 7a15b33..305c065 100644 --- a/src/base/appcore_base.c +++ b/src/base/appcore_base.c @@ -60,6 +60,11 @@ typedef struct _appcore_base_event_node { void *data; } appcore_base_event_node; +struct lang_info_s { + char *parent; + GList *list; +}; + static appcore_base_context __context; static GList *__events; static GDBusConnection *__bus; @@ -117,21 +122,70 @@ static void __on_low_battery(keynode_t *key, void *data) __invoke_callback(key, APPCORE_BASE_EVENT_LOW_BATTERY); } -static void __free_children_langs(gpointer data) +static void __destroy_lang_info(gpointer data) { - GList *list = (GList *)data; + struct lang_info_s *info = (struct lang_info_s *)data; - if (list == NULL) + if (info == NULL) return; - g_list_free_full(list, (GDestroyNotify)free); + if (info->list) + g_list_free_full(info->list, free); + if (info->parent) + free(info->parent); + free(info); +} + +static struct lang_info_s *__create_lang_info(const char *lang) +{ + struct lang_info_s *info; + + info = calloc(1, sizeof(struct lang_info_s)); + if (info == NULL) { + _ERR("Out of memory"); + return NULL; + } + + info->parent = strdup(lang); + if (info->parent == NULL) { + _ERR("Out of memory"); + free(info); + return NULL; + } + + return info; } static gint __compare_langs(gconstpointer a, gconstpointer b) { + if (!a || !b) + return -1; + return strcmp(a, b); } +static char *__get_string_before(const char *str, const char *delim) +{ + char *new_str; + char *dup_str; + char *token; + + dup_str = strdup(str); + if (dup_str == NULL) + return NULL; + + token = strtok(dup_str, delim); + if (token == NULL) { + free(dup_str); + return NULL; + } + + new_str = strdup(token); + free(dup_str); + + return new_str; +} + static GHashTable *__get_lang_table(void) { GHashTable *table; @@ -140,15 +194,14 @@ static GHashTable *__get_lang_table(void) char buf[PATH_MAX]; struct stat stat_buf; int ret; - char *dup_lang; - char *token; - GList *list; + char *parent_lang; + struct lang_info_s *info; if (__locale_dir == NULL || __locale_dir[0] == '\0') return NULL; table = g_hash_table_new_full(g_str_hash, g_str_equal, - free, __free_children_langs); + NULL, __destroy_lang_info); if (table == NULL) { _ERR("Out of memory"); return NULL; @@ -171,128 +224,84 @@ static GHashTable *__get_lang_table(void) if (ret != 0 || !S_ISDIR(stat_buf.st_mode)) continue; - dup_lang = strdup(dentry->d_name); - if (dup_lang == NULL) { + parent_lang = __get_string_before(dentry->d_name, "_"); + if (parent_lang == NULL) { _ERR("Out of memory"); break; } - token = strtok(dup_lang, "_"); - if (token == NULL) { - free(dup_lang); - continue; - } - - list = (GList *)g_hash_table_lookup(table, token); - if (list == NULL) { - list = g_list_append(list, strdup(dentry->d_name)); - g_hash_table_insert(table, strdup(token), list); - } else { - list = g_list_append(list, strdup(dentry->d_name)); + info = g_hash_table_lookup(table, parent_lang); + if (info == NULL) { + info = __create_lang_info(parent_lang); + if (info == NULL) { + free(parent_lang); + break; + } + g_hash_table_insert(table, info->parent, info); } - free(dup_lang); + info->list = g_list_append(info->list, strdup(dentry->d_name)); + free(parent_lang); } closedir(dp); return table; } -static char *__get_string_before(const char *str, const char *delim) -{ - char *new_str; - char *dup_str; - char *token; - - dup_str = strdup(str); - if (dup_str == NULL) - return NULL; - - token = strtok(dup_str, delim); - if (token == NULL) { - free(dup_str); - return NULL; - } - - new_str = strdup(token); - free(dup_str); - - return new_str; -} - static GList *__append_langs(const char *lang, GList *list, GHashTable *table) { - GList *child_list; - GList *child_iter; + struct lang_info_s *info; GList *found; - char *child_lang; - char *parent_lang; + char *parent_lang = NULL; char *extract_lang; - char *tmp; if (lang == NULL) return list; - found = g_list_find_custom(g_list_first(list), lang, - __compare_langs); - if (found) { - tmp = (char *)found->data; - list = g_list_remove(list, tmp); - list = g_list_append(list, tmp); - return list; - } - extract_lang = __get_string_before(lang, "."); if (extract_lang == NULL) return list; - parent_lang = __get_string_before(extract_lang, "_"); - if (parent_lang == NULL) { - free(extract_lang); - return list; + found = g_list_find_custom(list, extract_lang, __compare_langs); + if (found) { + list = g_list_remove_link(list, found); + list = g_list_concat(list, found); + goto end; } - child_list = g_hash_table_lookup(table, parent_lang); - if (child_list == NULL) { - free(parent_lang); - free(extract_lang); - return list; - } + parent_lang = __get_string_before(extract_lang, "_"); + if (parent_lang == NULL) + goto end; + + info = g_hash_table_lookup(table, parent_lang); + if (info == NULL) + goto end; - found = g_list_find_custom(g_list_first(child_list), - extract_lang, __compare_langs); + found = g_list_find_custom(info->list, extract_lang, __compare_langs); if (found) { - tmp = (char *)found->data; - child_list = g_list_remove(child_list, tmp); - list = g_list_append(list, tmp); - free(parent_lang); - free(extract_lang); - return list; + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); + goto end; } - free(extract_lang); - found = g_list_find_custom(g_list_first(child_list), - parent_lang, __compare_langs); + found = g_list_find_custom(info->list, parent_lang, __compare_langs); if (found) { - tmp = (char *)found->data; - child_list = g_list_remove(child_list, tmp); - list = g_list_append(list, tmp); - free(parent_lang); - return list; + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); + goto end; } - free(parent_lang); - - child_iter = g_list_first(child_list); - while (child_iter) { - child_lang = (char *)child_iter->data; - child_iter = g_list_next(child_iter); - if (child_lang) { - list = g_list_append(list, strdup(child_lang)); - child_list = g_list_remove(child_list, child_lang); - free(child_lang); - break; - } + + found = g_list_first(info->list); + if (found) { + info->list = g_list_remove_link(info->list, found); + list = g_list_concat(list, found); } +end: + if (extract_lang) + free(extract_lang); + if (parent_lang) + free(parent_lang); + return list; } @@ -325,8 +334,7 @@ static GList *__append_default_langs(GList *list) GList *found; for (i = 0; i < (sizeof(langs) / sizeof(langs[0])); i++) { - found = g_list_find_custom(g_list_first(list), langs[i], - __compare_langs); + found = g_list_find_custom(list, langs[i], __compare_langs); if (found == NULL) list = g_list_append(list, strdup(langs[i])); }