[libc] Fix the return value of fread and fwrite.
authorSiva Chandra Reddy <sivachandra@google.com>
Sat, 29 Oct 2022 05:41:17 +0000 (05:41 +0000)
committerSiva Chandra Reddy <sivachandra@google.com>
Sat, 29 Oct 2022 06:10:35 +0000 (06:10 +0000)
They were previously returning the number of bytes read. They should
instead be returning the number of objects read.

libc/src/stdio/fread.cpp
libc/src/stdio/fwrite.cpp
libc/test/src/stdio/fileop_test.cpp

index c6a16e2..779816e 100644 (file)
@@ -16,8 +16,11 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(size_t, fread,
                    (void *__restrict buffer, size_t size, size_t nmemb,
                     ::FILE *stream)) {
+  if (size == 0 || nmemb == 0)
+    return 0;
   return reinterpret_cast<__llvm_libc::File *>(stream)->read(buffer,
-                                                             size * nmemb);
+                                                             size * nmemb) /
+         size;
 }
 
 } // namespace __llvm_libc
index 0ea0611..ffa5558 100644 (file)
@@ -16,8 +16,11 @@ namespace __llvm_libc {
 LLVM_LIBC_FUNCTION(size_t, fwrite,
                    (const void *__restrict buffer, size_t size, size_t nmemb,
                     ::FILE *stream)) {
+  if (size == 0 || nmemb == 0)
+    return 0;
   return reinterpret_cast<__llvm_libc::File *>(stream)->write(buffer,
-                                                              size * nmemb);
+                                                              size * nmemb) /
+         size;
 }
 
 } // namespace __llvm_libc
index 399cc79..6f80163 100644 (file)
@@ -122,3 +122,41 @@ TEST(LlvmLibcFILETest, FFlush) {
 
   ASSERT_EQ(__llvm_libc::fclose(file), 0);
 }
+
+TEST(LlvmLibcFILETest, FOpenFWriteSizeGreaterThanOne) {
+  using MyStruct = struct {
+    char c;
+    unsigned long long i;
+  };
+  constexpr MyStruct WRITE_DATA[] = {{'a', 1}, {'b', 2}, {'c', 3}};
+  constexpr size_t WRITE_NMEMB = sizeof(WRITE_DATA) / sizeof(MyStruct);
+  constexpr char FILENAME[] = "testdata/fread_fwrite.test";
+
+  FILE *file = __llvm_libc::fopen(FILENAME, "w");
+  ASSERT_FALSE(file == nullptr);
+  ASSERT_EQ(size_t(0), __llvm_libc::fwrite(WRITE_DATA, 0, 1, file));
+  ASSERT_EQ(WRITE_NMEMB, __llvm_libc::fwrite(WRITE_DATA, sizeof(MyStruct),
+                                             WRITE_NMEMB, file));
+  EXPECT_EQ(errno, 0);
+  ASSERT_EQ(__llvm_libc::fclose(file), 0);
+
+  file = __llvm_libc::fopen(FILENAME, "r");
+  ASSERT_FALSE(file == nullptr);
+  MyStruct read_data[WRITE_NMEMB];
+  ASSERT_EQ(size_t(0), __llvm_libc::fread(read_data, 0, 1, file));
+  ASSERT_EQ(WRITE_NMEMB,
+            __llvm_libc::fread(read_data, sizeof(MyStruct), WRITE_NMEMB, file));
+  EXPECT_EQ(errno, 0);
+  // Trying to read more should fetch nothing.
+  ASSERT_EQ(size_t(0),
+            __llvm_libc::fread(read_data, sizeof(MyStruct), WRITE_NMEMB, file));
+  EXPECT_EQ(errno, 0);
+  EXPECT_NE(__llvm_libc::feof(file), 0);
+  EXPECT_EQ(__llvm_libc::ferror(file), 0);
+  ASSERT_EQ(__llvm_libc::fclose(file), 0);
+  // Verify that the data which was read is correct.
+  for (size_t i = 0; i < WRITE_NMEMB; ++i) {
+    ASSERT_EQ(read_data[i].c, WRITE_DATA[i].c);
+    ASSERT_EQ(read_data[i].i, WRITE_DATA[i].i);
+  }
+}