changeset 3688:1e6af9a000e6 HEAD

mail_cache_delete(): Make sure we don't get to infinite loop if cache records contain a loop.
author Timo Sirainen <tss@iki.fi>
date Fri, 28 Oct 2005 13:52:02 +0300
parents 629ffe1a3874
children 8b68997d6e34
files src/lib-index/mail-cache-transaction.c
diffstat 1 files changed, 35 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-cache-transaction.c	Thu Oct 27 18:57:28 2005 +0300
+++ b/src/lib-index/mail-cache-transaction.c	Fri Oct 28 13:52:02 2005 +0300
@@ -773,9 +773,24 @@
 	return 0;
 }
 
+static int find_offset(array_t *array, uint32_t offset)
+{
+	ARRAY_SET_TYPE(array, uint32_t);
+	const uint32_t *offsets;
+	unsigned int i, count;
+
+	offsets = array_get(array, &count);
+	for (i = 0; i < count; i++) {
+		if (offsets[i] == offset)
+			return TRUE;
+	}
+	return FALSE;
+}
+
 int mail_cache_delete(struct mail_cache *cache, uint32_t offset)
 {
 	const struct mail_cache_record *cache_rec;
+	array_t ARRAY_DEFINE(tmp_offsets, uint32_t);
 
 	i_assert(cache->locked);
 
@@ -789,12 +804,29 @@
 	   the data. also it's actually useful as some index views are still
 	   able to ask cached data from messages that have already been
 	   expunged. */
-	do {
+	t_push();
+	ARRAY_CREATE(&tmp_offsets, pool_datastack_create(), uint32_t, 8);
+	array_append(&tmp_offsets, &offset, 1);
+	for (;;) {
 		cache->hdr_copy.deleted_space += cache_rec->size;
 		if (mail_cache_get_record(cache, cache_rec->prev_offset,
-					  &cache_rec) < 0)
+					  &cache_rec) < 0) {
+			t_pop();
 			return -1;
-	} while (cache_rec != NULL);
+		}
+
+		if (cache_rec == NULL)
+			break;
+
+		if (find_offset(&tmp_offsets, cache_rec->prev_offset)) {
+			mail_cache_set_corrupted(cache,
+						 "record list is circular");
+			t_pop();
+			return -1;
+		}
+		array_append(&tmp_offsets, &cache_rec->prev_offset, 1);
+	}
+	t_pop();
 
 	cache->hdr_modified = TRUE;
 	return 0;