From 23c502c6ef08d83e8ed68f90ed75138e14a3a246 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Wed, 10 Apr 2013 16:50:34 +0300 Subject: [PATCH] lib-index: Assert-crashfix on some rare situations. mail_index_modseq_get_next_log_offset() might have returned e.g. (seq=4, offset=40) to point to the beginning of a next file. The view itself could still have been pointing to seq=3 end of file. Now calling mail_transaction_log_view_set() with these two positions (that are basically the same) should result in an empty view instead of assert crash. --- src/lib-index/mail-transaction-log-view.c | 34 ++++++++++++++--------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/lib-index/mail-transaction-log-view.c b/src/lib-index/mail-transaction-log-view.c index 60f594e4d8..852fe08446 100644 --- a/src/lib-index/mail-transaction-log-view.c +++ b/src/lib-index/mail-transaction-log-view.c @@ -63,14 +63,12 @@ int mail_transaction_log_view_set(struct mail_transaction_log_view *view, uint32_t max_file_seq, uoff_t max_file_offset, bool *reset_r) { - struct mail_transaction_log_file *file, *const *files, *tail; + struct mail_transaction_log_file *file, *const *files; uoff_t start_offset, end_offset; unsigned int i; uint32_t seq; int ret; - i_assert(min_file_seq <= max_file_seq); - *reset_r = FALSE; if (view->log == NULL) { @@ -79,28 +77,35 @@ int mail_transaction_log_view_set(struct mail_transaction_log_view *view, return -1; } - tail = view->log->files; if (min_file_seq == 0) { /* index file doesn't exist yet. this transaction log should start from the beginning */ - if (tail->hdr.prev_file_seq != 0) { + if (view->log->files->hdr.prev_file_seq != 0) { /* but it doesn't */ return 0; } - min_file_seq = tail->hdr.file_seq; + min_file_seq = view->log->files->hdr.file_seq; min_file_offset = 0; if (max_file_seq == 0) { max_file_seq = min_file_seq; max_file_offset = min_file_offset; } - } + } - if (min_file_seq == tail->hdr.prev_file_seq && - min_file_offset == tail->hdr.prev_file_offset) { - /* we can skip this */ - min_file_seq = tail->hdr.file_seq; + for (file = view->log->files; file != NULL; file = file->next) { + if (file->hdr.prev_file_seq == min_file_seq) + break; + } + if (file != NULL && min_file_offset == file->hdr.prev_file_offset) { + /* we can skip to the next file. we've delayed checking for + min_file_seq <= max_file_seq until now, because it's not + really an error to specify the same position twice (even if + in "wrong" order) */ + i_assert(min_file_seq <= max_file_seq || + file->hdr.file_seq <= max_file_seq); + min_file_seq = file->hdr.file_seq; min_file_offset = 0; if (min_file_seq > max_file_seq) { @@ -108,6 +113,8 @@ int mail_transaction_log_view_set(struct mail_transaction_log_view *view, max_file_seq = min_file_seq; max_file_offset = min_file_offset; } + } else { + i_assert(min_file_seq <= max_file_seq); } if (min_file_seq == max_file_seq && min_file_offset > max_file_offset) { @@ -119,12 +126,13 @@ int mail_transaction_log_view_set(struct mail_transaction_log_view *view, return -1; } - if (min_file_offset > 0 && min_file_offset < tail->hdr.hdr_size) { + if (min_file_offset > 0 && file != NULL && + min_file_offset < file->hdr.hdr_size) { /* log file offset is probably corrupted in the index file. */ mail_transaction_log_view_set_corrupted(view, "file_seq=%u, min_file_offset (%"PRIuUOFF_T ") < hdr_size (%u)", - min_file_seq, min_file_offset, tail->hdr.hdr_size); + min_file_seq, min_file_offset, file->hdr.hdr_size); return -1; } -- 2.47.3