Fix fread returning bad data.

Bug: 19172514
Change-Id: I05016577858a02aca7d14e75e6ec28abc925037c
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 @@
 		 * 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_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);
+}