]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
ostream-file: Fixed potential crash in write_at() and also fixed attempted optimization.
authorTimo Sirainen <tss@iki.fi>
Mon, 18 Oct 2010 15:51:12 +0000 (16:51 +0100)
committerTimo Sirainen <tss@iki.fi>
Mon, 18 Oct 2010 15:51:12 +0000 (16:51 +0100)
src/lib/Makefile.am
src/lib/ostream-file.c
src/lib/test-lib.c
src/lib/test-lib.h
src/lib/test-ostream-file.c [new file with mode: 0644]

index a0a07007181107686013b85346b3288a844a594a..0ee3f61fa07e967a9a113339e7ac43251a68e01f 100644 (file)
@@ -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 \
index d010d1c6a20b4b477742b1b890cc66639344de35..d65dbff8cd8a991df3fb05d568fccb00bd5d2b93 100644 (file)
@@ -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;
-
                }
        }
 
index f1183e02d19f2f7a71412548bfc73ecdb7f404f2..91b113b658360e50dc8cd22899298d40fc6e741b 100644 (file)
@@ -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,
index 50a880a7a7d67bab4feee34004e9c722c9b2ce79..43fdc282f184d41d73e76dafef568ab0f5363ec8 100644 (file)
@@ -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 (file)
index 0000000..ead1593
--- /dev/null
@@ -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 <stdlib.h>
+#include <unistd.h>
+
+#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();
+}