changeset 19946:7ffdbac8e3ae

lib: Avoid assert-crash in istream-concat at close. If stream was seeked to EOF, cur_input=NULL and closing the stream would cause i_stream_concat_skip() to crash. Fixed this by making sure cur_input is never NULL. This also adds a check to not allow seeking past EOF, but this shouldn't happen anyway.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 21 Mar 2016 21:51:49 +0900
parents e8f9cf430e53
children 7b498de3bdba
files src/lib/istream-concat.c
diffstat 1 files changed, 14 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/istream-concat.c	Mon Mar 21 21:46:47 2016 +0900
+++ b/src/lib/istream-concat.c	Mon Mar 21 21:51:49 2016 +0900
@@ -137,10 +137,7 @@
 	ssize_t ret;
 	bool last_stream;
 
-	if (cstream->cur_input == NULL) {
-		stream->istream.stream_errno = EINVAL;
-		return -1;
-	}
+	i_assert(cstream->cur_input != NULL);
 	i_stream_concat_skip(cstream);
 
 	i_assert(stream->pos >= stream->skip + cstream->prev_stream_left);
@@ -274,13 +271,23 @@
 
 	if (find_v_offset(cstream, &v_offset, &cstream->cur_idx) < 0) {
 		/* failed */
-		cstream->cur_input = NULL;
 		stream->istream.stream_errno = EINVAL;
 		return;
 	}
 	cstream->cur_input = cstream->input[cstream->cur_idx];
-	if (cstream->cur_input != NULL)
-		i_stream_seek(cstream->cur_input, v_offset);
+	if (cstream->cur_input == NULL) {
+		/* we allow seeking to EOF, but not past it. */
+		if (v_offset != 0) {
+			io_stream_set_error(&cstream->istream.iostream,
+				"Seeking past EOF by %"PRIuUOFF_T" bytes", v_offset);
+			cstream->istream.istream.stream_errno = EINVAL;
+			return;
+		}
+		i_assert(cstream->cur_idx > 0);
+		cstream->cur_input = cstream->input[cstream->cur_idx-1];
+		v_offset = cstream->input_size[cstream->cur_idx-1];
+	}
+	i_stream_seek(cstream->cur_input, v_offset);
 }
 
 static int