Fix wrapvFull for the case when iovec* has size more than 1024
authorIaroslav Tverdokhlib <iaroslav@fb.com>
Tue, 16 Feb 2016 18:21:35 +0000 (10:21 -0800)
committerfacebook-github-bot-0 <folly-bot@fb.com>
Tue, 16 Feb 2016 19:20:26 +0000 (11:20 -0800)
Summary: `folly::wrapvFull` fail if the passed in `iovec*` has more than 1024 (`IOV_MAX`) elements. In particular, it returns -1 with errno 22 [Invalid argument]. The fix is to limit maximum size of iovec* to IOV_MAX that is passed in to `readv/writev/...` in a single iteration of outer loop.

Reviewed By: yfeldblum

Differential Revision: D2935540

fb-gh-sync-id: 6c0a073ac0b59db3d53fb4269b13ddfcc479efb1
shipit-source-id: 6c0a073ac0b59db3d53fb4269b13ddfcc479efb1

folly/detail/FileUtilDetail.h
folly/test/FileUtilTest.cpp

index a10bdda08745389720e211c63f7a30eed6fabc7b..50f120ffb70a62bd432081cb21e20c2928473325 100644 (file)
@@ -76,7 +76,7 @@ ssize_t wrapvFull(F f, int fd, iovec* iov, int count, Offset... offset) {
   ssize_t totalBytes = 0;
   size_t r;
   do {
-    r = f(fd, iov, count, offset...);
+    r = f(fd, iov, std::min(count, IOV_MAX), offset...);
     if (r == (size_t)-1) {
       if (errno == EINTR) {
         continue;
index 2ecbb614aae8a7dc2a520afc23c1a16091a9a500..adedc5226bd810b151f48f04bbe1b86285c41997 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <folly/FileUtil.h>
 #include <folly/detail/FileUtilDetail.h>
+#include <folly/experimental/TestUtil.h>
 
 #include <deque>
 
@@ -179,6 +180,7 @@ TEST_F(FileUtilTest, pread) {
 class IovecBuffers {
  public:
   explicit IovecBuffers(std::initializer_list<size_t> sizes);
+  explicit IovecBuffers(std::vector<size_t> sizes);
 
   std::vector<iovec> iov() const { return iov_; }  // yes, make a copy
   std::string join() const { return folly::join("", buffers_); }
@@ -202,6 +204,19 @@ IovecBuffers::IovecBuffers(std::initializer_list<size_t> sizes) {
   }
 }
 
+IovecBuffers::IovecBuffers(std::vector<size_t> sizes) {
+  iov_.reserve(sizes.size());
+  for (auto s : sizes) {
+    buffers_.push_back(std::string(s, '\0'));
+  }
+  for (auto& b : buffers_) {
+    iovec iov;
+    iov.iov_base = &b[0];
+    iov.iov_len = b.size();
+    iov_.push_back(iov);
+  }
+}
+
 size_t IovecBuffers::size() const {
   size_t s = 0;
   for (auto& b : buffers_) {
@@ -223,6 +238,20 @@ TEST_F(FileUtilTest, readv) {
   }
 }
 
+TEST(FileUtilTest2, wrapv) {
+  TemporaryFile tempFile("file-util-test");
+  std::vector<size_t> sizes;
+  size_t sum = 0;
+  for (int32_t i = 0; i < 1500; ++i) {
+    sizes.push_back(i % 3 + 1);
+    sum += sizes.back();
+  }
+  IovecBuffers buf(sizes);
+  ASSERT_EQ(sum, buf.size());
+  auto iov = buf.iov();
+  EXPECT_EQ(sum, wrapvFull(writev, tempFile.fd(), iov.data(), iov.size()));
+}
+
 #if FOLLY_HAVE_PREADV
 TEST_F(FileUtilTest, preadv) {
   for (auto& p : readers_) {