Fix a long-standing memory leak in account prefs.
authorAndrej Kacian <ticho@claws-mail.org>
Sun, 9 Jul 2017 16:27:20 +0000 (18:27 +0200)
committerAndrej Kacian <ticho@claws-mail.org>
Sun, 9 Jul 2017 16:27:20 +0000 (18:27 +0200)
All P_STRING type prefs with non-NULL default values
were being leaked due to overly complicated account
config loading, where we would first initialize
a fresh PrefAccount, then load prefs from config, copying
data between the static tmp_ac_prefs and our dynamically
allocated PrefAccount several times.

Instead of adding another round of data copying from/to
tmp_ac_prefs for purpose of free()ing the P_STRING prefs,
this commit changes prefs_account_read_config() into
prefs_account_new_from_config(), a
Existing accounts are now created with simple:
  ac_prefs = prefs_account_new_from_config(...);
instead of previous:
  ac_prefs = prefs_account_new();
  prefs_account_read_from_config(ac_prefs, ...);

The new function sets up contents of tmp_ac_prefs,
and then its contents are only copied to the newly
allocated PrefsAccount once.

src/account.c
src/prefs_account.c
src/prefs_account.h

index 9625056828cb9d5c9516dedf3cc1bfb5d2d2d1ab..a152ef690ddbda89743722bdf10f19d6abf1e527 100644 (file)
@@ -223,8 +223,7 @@ void account_read_config_all(void)
        /* read config data from file */
        cur_account = NULL;
        for (cur = ac_label_list; cur != NULL; cur = cur->next) {
        /* read config data from file */
        cur_account = NULL;
        for (cur = ac_label_list; cur != NULL; cur = cur->next) {
-               ac_prefs = prefs_account_new();
-               prefs_account_read_config(ac_prefs, (gchar *)cur->data);
+               ac_prefs = prefs_account_new_from_config((gchar *)cur->data);
                account_list = g_list_append(account_list, ac_prefs);
                if (ac_prefs->is_default)
                        cur_account = ac_prefs;
                account_list = g_list_append(account_list, ac_prefs);
                if (ac_prefs->is_default)
                        cur_account = ac_prefs;
index 589d63d1db569211091f52595e720e3cb34aa1b2..513ba6bfa102c2e216ddd343b5dbb72c7e9a41dc 100644 (file)
@@ -3574,20 +3574,31 @@ PrefsAccount *prefs_account_new(void)
        return ac_prefs;
 }
 
        return ac_prefs;
 }
 
-void prefs_account_read_config(PrefsAccount *ac_prefs, const gchar *label)
+PrefsAccount *prefs_account_new_from_config(const gchar *label)
 {
        const gchar *p = label;
        gchar *rcpath;
        gint id;
        gchar **strv, **cur;
        gsize len;
 {
        const gchar *p = label;
        gchar *rcpath;
        gint id;
        gchar **strv, **cur;
        gsize len;
+       PrefsAccount *ac_prefs;
+
+       cm_return_val_if_fail(label != NULL, NULL);
 
 
-       cm_return_if_fail(ac_prefs != NULL);
-       cm_return_if_fail(label != NULL);
+       ac_prefs = g_new0(PrefsAccount, 1);
 
 
+       /* Load default values to tmp_ac_prefs first, ... */
        memset(&tmp_ac_prefs, 0, sizeof(PrefsAccount));
        memset(&tmp_ac_prefs, 0, sizeof(PrefsAccount));
-       tmp_ac_prefs.privacy_prefs = ac_prefs->privacy_prefs;
+       prefs_set_default(basic_param);
+       prefs_set_default(receive_param);
+       prefs_set_default(send_param);
+       prefs_set_default(compose_param);
+       prefs_set_default(templates_param);
+       prefs_set_default(privacy_param);
+       prefs_set_default(ssl_param);
+       prefs_set_default(advanced_param);
 
 
+       /* ... overriding them with values from stored config file. */
        rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL);
        prefs_read_config(basic_param, label, rcpath, NULL);
        prefs_read_config(receive_param, label, rcpath, NULL);
        rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL);
        prefs_read_config(basic_param, label, rcpath, NULL);
        prefs_read_config(receive_param, label, rcpath, NULL);
@@ -3600,11 +3611,14 @@ void prefs_account_read_config(PrefsAccount *ac_prefs, const gchar *label)
        g_free(rcpath);
 
        *ac_prefs = tmp_ac_prefs;
        g_free(rcpath);
 
        *ac_prefs = tmp_ac_prefs;
+
        while (*p && !g_ascii_isdigit(*p)) p++;
        id = atoi(p);
        if (id < 0) g_warning("wrong account id: %d", id);
        ac_prefs->account_id = id;
 
        while (*p && !g_ascii_isdigit(*p)) p++;
        id = atoi(p);
        if (id < 0) g_warning("wrong account id: %d", id);
        ac_prefs->account_id = id;
 
+       /* Now parse privacy_prefs. */
+       ac_prefs->privacy_prefs = g_hash_table_new(g_str_hash, g_str_equal);
        if (privacy_prefs != NULL) {
                strv = g_strsplit(privacy_prefs, ",", 0);
                for (cur = strv; *cur != NULL; cur++) {
        if (privacy_prefs != NULL) {
                strv = g_strsplit(privacy_prefs, ",", 0);
                for (cur = strv; *cur != NULL; cur++) {
@@ -3627,6 +3641,8 @@ void prefs_account_read_config(PrefsAccount *ac_prefs, const gchar *label)
                privacy_prefs = NULL;
        }
 
                privacy_prefs = NULL;
        }
 
+       /* For older configurations, move stored passwords into the
+        * password store. */
        gboolean passwords_migrated = FALSE;
 
        if (ac_prefs->passwd != NULL && strlen(ac_prefs->passwd) > 1) {
        gboolean passwords_migrated = FALSE;
 
        if (ac_prefs->passwd != NULL && strlen(ac_prefs->passwd) > 1) {
@@ -3652,14 +3668,16 @@ void prefs_account_read_config(PrefsAccount *ac_prefs, const gchar *label)
                passwords_migrated = TRUE;
        }
 
                passwords_migrated = TRUE;
        }
 
-       /* Write out password store to file immediately after their move
-        * from accountrc there. */
+       /* Write out password store to file immediately, to prevent
+        * their loss. */
        if (passwords_migrated)
                passwd_store_write_config();
 
        ac_prefs->receive_in_progress = FALSE;
 
        prefs_custom_header_read_config(ac_prefs);
        if (passwords_migrated)
                passwd_store_write_config();
 
        ac_prefs->receive_in_progress = FALSE;
 
        prefs_custom_header_read_config(ac_prefs);
+
+       return ac_prefs;
 }
 
 static void create_privacy_prefs(gpointer key, gpointer _value, gpointer user_data)
 }
 
 static void create_privacy_prefs(gpointer key, gpointer _value, gpointer user_data)
index 83f6efad74a2027ba9a625f90d46b4495d106878..fd4dc1a61820b12cf164c31c6d5652be71d21cb0 100644 (file)
@@ -211,10 +211,9 @@ struct _PrefsAccount
 
 void prefs_account_init                        (void);
 
 
 void prefs_account_init                        (void);
 
-PrefsAccount *prefs_account_new                (void);
+PrefsAccount *prefs_account_new                        (void);
+PrefsAccount *prefs_account_new_from_config    (const gchar    *label);
 
 
-void prefs_account_read_config         (PrefsAccount   *ac_prefs,
-                                        const gchar    *label);
 void prefs_account_write_config_all    (GList          *account_list);
 
 void prefs_account_free                        (PrefsAccount   *ac_prefs);
 void prefs_account_write_config_all    (GList          *account_list);
 
 void prefs_account_free                        (PrefsAccount   *ac_prefs);