diff options
-rw-r--r-- | libc/stdio/fread.c | 6 | ||||
-rw-r--r-- | tests/stdio_test.cpp | 38 |
2 files changed, 44 insertions, 0 deletions
diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c index bac8dad..f3f0127 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 890e86e..2ecfc60 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<size_t>(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<size_t>(ftell(fp)); + ASSERT_EQ(22U, fread(buffer, 1, 22, fp)); + ASSERT_EQ(memcmp(file_data+cur_location, buffer, 22), 0); + + fclose(fp); +} |