From cc9ca1051dbf5bd2af1b801de13d43a399521cf9 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 27 Feb 2015 18:22:45 -0800 Subject: [PATCH] Fix fread returning bad data. Bug: 19172514 Change-Id: I05016577858a02aca7d14e75e6ec28abc925037c --- libc/stdio/fread.c | 6 ++++++ tests/stdio_test.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c index bac8dad66..f3f012737 100644 --- a/libc/stdio/fread.c +++ b/libc/stdio/fread.c @@ -102,6 +102,12 @@ fread(void *buf, size_t size, size_t count, FILE *fp) * avoid copying it through the buffer? */ if (total > (size_t) fp->_bf._size) { + /* + * Make sure that fseek doesn't think it can + * reuse the buffer since we are going to read + * directly from the file descriptor. + */ + fp->_flags |= __SMOD; break; } diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp index 890e86edc..2ecfc6072 100644 --- a/tests/stdio_test.cpp +++ b/tests/stdio_test.cpp @@ -965,3 +965,41 @@ TEST(stdio, fwrite_after_fread_slow_path) { TEST(stdio, fwrite_after_fread_fast_path) { test_fwrite_after_fread(64*1024); } + +// http://b/19172514 +TEST(stdio, fread_after_fseek) { + TemporaryFile tf; + + FILE* fp = fopen(tf.filename, "w+"); + ASSERT_TRUE(fp != nullptr); + + char file_data[12288]; + for (size_t i = 0; i < 12288; i++) { + file_data[i] = i; + } + ASSERT_EQ(12288U, fwrite(file_data, 1, 12288, fp)); + fclose(fp); + + fp = fopen(tf.filename, "r"); + ASSERT_TRUE(fp != nullptr); + + char buffer[8192]; + size_t cur_location = 0; + // Small read to populate internal buffer. + ASSERT_EQ(100U, fread(buffer, 1, 100, fp)); + ASSERT_EQ(memcmp(file_data, buffer, 100), 0); + + cur_location = static_cast(ftell(fp)); + // Large read to force reading into the user supplied buffer and bypassing + // the internal buffer. + ASSERT_EQ(8192U, fread(buffer, 1, 8192, fp)); + ASSERT_EQ(memcmp(file_data+cur_location, buffer, 8192), 0); + + // Small backwards seek to verify fseek does not reuse the internal buffer. + ASSERT_EQ(0, fseek(fp, -22, SEEK_CUR)); + cur_location = static_cast(ftell(fp)); + ASSERT_EQ(22U, fread(buffer, 1, 22, fp)); + ASSERT_EQ(memcmp(file_data+cur_location, buffer, 22), 0); + + fclose(fp); +}