From 08baf8e4f38f6e5858b16e954e1841675cecae0c Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 18 Oct 2010 16:51:12 +0100 Subject: [PATCH] ostream-file: Fixed potential crash in write_at() and also fixed attempted optimization. --- src/lib/Makefile.am | 1 + src/lib/ostream-file.c | 12 ++++--- src/lib/test-lib.c | 1 + src/lib/test-lib.h | 1 + src/lib/test-ostream-file.c | 69 +++++++++++++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 5 deletions(-) create mode 100644 src/lib/test-ostream-file.c diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index a0a0700718..0ee3f61fa0 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -237,6 +237,7 @@ test_lib_SOURCES = \ test-llist.c \ test-mempool-alloconly.c \ test-network.c \ + test-ostream-file.c \ test-primes.c \ test-priorityq.c \ test-seq-range-array.c \ diff --git a/src/lib/ostream-file.c b/src/lib/ostream-file.c index d010d1c6a2..d65dbff8cd 100644 --- a/src/lib/ostream-file.c +++ b/src/lib/ostream-file.c @@ -621,7 +621,8 @@ o_stream_file_write_at(struct ostream_private *stream, /* update buffer if the write overlaps it */ used = file_buffer_get_used_size(fstream); - if (fstream->buffer_offset < offset + size && + if (used > 0 && + fstream->buffer_offset < offset + size && fstream->buffer_offset + used > offset) { if (fstream->buffer_offset <= offset) { /* updating from the beginning */ @@ -641,9 +642,11 @@ o_stream_file_write_at(struct ostream_private *stream, of it in one pwrite(). */ } else { /* write only the suffix */ - data = CONST_PTR_OFFSET(data, skip); - size -= skip; - offset += skip; + unsigned int update_count = size - left; + + data = CONST_PTR_OFFSET(data, update_count); + size -= update_count; + offset += update_count; } } else if (skip == 0) { /* everything done */ @@ -651,7 +654,6 @@ o_stream_file_write_at(struct ostream_private *stream, } else { /* still have to write prefix */ size = skip; - } } diff --git a/src/lib/test-lib.c b/src/lib/test-lib.c index f1183e02d1..91b113b658 100644 --- a/src/lib/test-lib.c +++ b/src/lib/test-lib.c @@ -19,6 +19,7 @@ int main(void) test_llist, test_mempool_alloconly, test_network, + test_ostream_file, test_primes, test_priorityq, test_seq_range_array, diff --git a/src/lib/test-lib.h b/src/lib/test-lib.h index 50a880a7a7..43fdc282f1 100644 --- a/src/lib/test-lib.h +++ b/src/lib/test-lib.h @@ -18,6 +18,7 @@ void test_istream_tee(void); void test_llist(void); void test_mempool_alloconly(void); void test_network(void); +void test_ostream_file(void); void test_primes(void); void test_priorityq(void); void test_seq_range_array(void); diff --git a/src/lib/test-ostream-file.c b/src/lib/test-ostream-file.c new file mode 100644 index 0000000000..ead1593032 --- /dev/null +++ b/src/lib/test-ostream-file.c @@ -0,0 +1,69 @@ +/* Copyright (c) 2009-2010 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "str.h" +#include "safe-mkstemp.h" +#include "randgen.h" +#include "ostream.h" + +#include +#include + +#define MAX_BUFSIZE 256 + +static void test_ostream_file_random(void) +{ + struct ostream *output; + string_t *path = t_str_new(128); + char buf[MAX_BUFSIZE*4], buf2[MAX_BUFSIZE*4], randbuf[MAX_BUFSIZE]; + unsigned int i, offset, size; + ssize_t ret; + int fd; + + memset(buf, 0, sizeof(buf)); + fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1); + if (fd == -1) + i_fatal("safe_mkstemp(%s) failed: %m", str_c(path)); + if (unlink(str_c(path)) < 0) + i_fatal("unlink(%s) failed: %m", str_c(path)); + output = o_stream_create_fd(fd, MAX_BUFSIZE, FALSE); + o_stream_cork(output); + + size = (rand() % MAX_BUFSIZE) + 1; + random_fill_weak(randbuf, size); + memcpy(buf, randbuf, size); + o_stream_send(output, buf, size); + + for (i = 0; i < 10; i++) { + offset = rand() % (MAX_BUFSIZE*3); + size = (rand() % MAX_BUFSIZE) + 1; + random_fill_weak(randbuf, size); + memcpy(buf + offset, randbuf, size); + o_stream_pwrite(output, randbuf, size, offset); + if (rand() % 10 == 0) + o_stream_flush(output); + } + + o_stream_flush(output); + o_stream_uncork(output); + ret = pread(fd, buf2, sizeof(buf2), 0); + if (ret < 0) + i_fatal("pread() failed: %m"); + else { + i_assert(ret > 0); + test_assert(memcmp(buf, buf2, ret) == 0); + } + o_stream_unref(&output); + (void)close(fd); +} + +void test_ostream_file(void) +{ + unsigned int i; + + test_begin("ostream pwrite random"); + for (i = 0; i < 100; i++) T_BEGIN { + test_ostream_file_random(); + } T_END; + test_end(); +} -- 2.47.3