Fix use after free
[claws.git] / src / msgcache.c
index d73df46a2eae8e2c9bec11d9a18b54878875da2b..82480ed9c10b7d02babd720098ac9633860599e9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2009 Hiroyuki Yamamoto & The Claws Mail Team
+ * Copyright (C) 1999-2012 Hiroyuki Yamamoto & The Claws Mail Team
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -19,6 +19,7 @@
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
+#include "claws-features.h"
 #endif
 
 #include "defs.h"
@@ -177,7 +178,6 @@ void msgcache_remove_msg(MsgCache *cache, guint msgnum)
        MsgInfo *msginfo;
 
        cm_return_if_fail(cache != NULL);
-       cm_return_if_fail(msgnum > 0);
 
        msginfo = (MsgInfo *) g_hash_table_lookup(cache->msgnum_table, &msgnum);
        if(!msginfo)
@@ -187,10 +187,12 @@ void msgcache_remove_msg(MsgCache *cache, guint msgnum)
        if(msginfo->msgid)
                g_hash_table_remove(cache->msgid_table, msginfo->msgid);
        g_hash_table_remove(cache->msgnum_table, &msginfo->msgnum);
+
+       msginfo->folder->cache_dirty = TRUE;
+
        procmsg_msginfo_free(msginfo);
        cache->last_access = time(NULL);
 
-       msginfo->folder->cache_dirty = TRUE;
 
        debug_print("Cache size: %d messages, %u bytes\n", g_hash_table_size(cache->msgnum_table), cache->memusage);
 }
@@ -714,12 +716,6 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
                        if(msginfo->msgid)
                                g_hash_table_insert(cache->msgid_table, msginfo->msgid, msginfo);
                }
-
-#ifdef G_OS_WIN32
-               UnmapViewOfFile((void*) cache_data);
-#else
-               munmap(cache_data, map_len);
-#endif
        } else {
                while (fread(&num, sizeof(num), 1, fp) == 1) {
                        if (swapping)
@@ -772,8 +768,14 @@ MsgCache *msgcache_read_cache(FolderItem *item, const gchar *cache_file)
                }
        }
 bail_err:
+       if (cache_data != NULL && cache_data != MAP_FAILED) {
+#ifdef G_OS_WIN32
+               UnmapViewOfFile((void*) cache_data);
+#else
+               munmap(cache_data, map_len);
+#endif
+       }
        fclose(fp);
-
        if (conv != NULL) {
                if (conv->free != NULL)
                        conv->free(conv);
@@ -803,7 +805,7 @@ void msgcache_read_mark(MsgCache *cache, const gchar *mark_file)
        gint map_len = -1;
        char *cache_data = NULL;
        struct stat st;
-       gboolean error;
+       gboolean error = FALSE;
 
        swapping = TRUE;
 
@@ -859,16 +861,14 @@ void msgcache_read_mark(MsgCache *cache, const gchar *mark_file)
                                msginfo->flags.perm_flags = perm_flags;
                        }
                }
-#ifdef G_OS_WIN32
-               UnmapViewOfFile((void*) cache_data);
-#else
-               munmap(cache_data, map_len);
-#endif
        } else {
                while (fread(&num, sizeof(num), 1, fp) == 1) {
                        if (swapping)
                                num = bswap_32(num);
-                       if (fread(&perm_flags, sizeof(perm_flags), 1, fp) != 1) break;
+                       if (fread(&perm_flags, sizeof(perm_flags), 1, fp) != 1) {
+                               error = TRUE;
+                               break;
+                       }
                        if (swapping)
                                perm_flags = bswap_32(perm_flags);
                        msginfo = g_hash_table_lookup(cache->msgnum_table, &num);
@@ -878,7 +878,17 @@ void msgcache_read_mark(MsgCache *cache, const gchar *mark_file)
                }       
        }
 bail_err:
+       if (cache_data != NULL && cache_data != MAP_FAILED) {
+#ifdef G_OS_WIN32
+               UnmapViewOfFile((void*) cache_data);
+#else
+               munmap(cache_data, map_len);
+#endif
+       }
        fclose(fp);
+       if (error) {
+               debug_print("error reading cache mark from %s\n", mark_file);
+       }
 }
 
 void msgcache_read_tags(MsgCache *cache, const gchar *tags_file)
@@ -955,11 +965,6 @@ void msgcache_read_tags(MsgCache *cache, const gchar *tags_file)
                                msginfo->tags = g_slist_reverse(msginfo->tags);
                        }
                }
-#ifdef G_OS_WIN32
-               UnmapViewOfFile((void*) cache_data);
-#else
-               munmap(cache_data, map_len);
-#endif
        } else {
                while (fread(&num, sizeof(num), 1, fp) == 1) {
                        gint id = -1;
@@ -985,7 +990,17 @@ void msgcache_read_tags(MsgCache *cache, const gchar *tags_file)
                }
        }
 bail_err:
+       if (cache_data != NULL && cache_data != MAP_FAILED) {
+#ifdef G_OS_WIN32
+               UnmapViewOfFile((void*) cache_data);
+#else
+               munmap(cache_data, map_len);
+#endif
+       }
        fclose(fp);
+       if (error) {
+               debug_print("error reading cache tags from %s\n", tags_file);
+       }
 }
 
 static int msgcache_write_cache(MsgInfo *msginfo, FILE *fp)
@@ -1127,7 +1142,8 @@ gint msgcache_write(const gchar *cache_file, const gchar *mark_file, const gchar
 
        if (w_err != 0) {
                g_warning("failed to write charset\n");
-               fclose(write_fps.cache_fp);
+               if (write_fps.cache_fp)
+                       fclose(write_fps.cache_fp);
                claws_unlink(new_cache);
                g_free(new_cache);
                g_free(new_mark);
@@ -1139,7 +1155,8 @@ gint msgcache_write(const gchar *cache_file, const gchar *mark_file, const gchar
                write_fps.mark_fp = msgcache_open_data_file(new_mark, MARK_VERSION,
                        DATA_WRITE, NULL, 0);
                if (write_fps.mark_fp == NULL) {
-                       fclose(write_fps.cache_fp);
+                       if (write_fps.cache_fp)
+                               fclose(write_fps.cache_fp);
                        claws_unlink(new_cache);
                        g_free(new_cache);
                        g_free(new_mark);
@@ -1154,8 +1171,10 @@ gint msgcache_write(const gchar *cache_file, const gchar *mark_file, const gchar
                write_fps.tags_fp = msgcache_open_data_file(new_tags, TAGS_VERSION,
                        DATA_WRITE, NULL, 0);
                if (write_fps.tags_fp == NULL) {
-                       fclose(write_fps.cache_fp);
-                       fclose(write_fps.mark_fp);
+                       if (write_fps.cache_fp)
+                               fclose(write_fps.cache_fp);
+                       if (write_fps.mark_fp)
+                               fclose(write_fps.mark_fp);
                        claws_unlink(new_cache);
                        claws_unlink(new_mark);
                        g_free(new_cache);