From 7488256f231499910ba90ecbd8243f8f89302fd3 Mon Sep 17 00:00:00 2001 From: Iaroslav Tverdokhlib Date: Tue, 16 Feb 2016 10:21:35 -0800 Subject: [PATCH] Fix wrapvFull for the case when iovec* has size more than 1024 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 | 2 +- folly/test/FileUtilTest.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/folly/detail/FileUtilDetail.h b/folly/detail/FileUtilDetail.h index a10bdda0..50f120ff 100644 --- a/folly/detail/FileUtilDetail.h +++ b/folly/detail/FileUtilDetail.h @@ -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; diff --git a/folly/test/FileUtilTest.cpp b/folly/test/FileUtilTest.cpp index 2ecbb614..adedc522 100644 --- a/folly/test/FileUtilTest.cpp +++ b/folly/test/FileUtilTest.cpp @@ -16,6 +16,7 @@ #include #include +#include #include @@ -179,6 +180,7 @@ TEST_F(FileUtilTest, pread) { class IovecBuffers { public: explicit IovecBuffers(std::initializer_list sizes); + explicit IovecBuffers(std::vector sizes); std::vector 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 sizes) { } } +IovecBuffers::IovecBuffers(std::vector 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 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_) { -- 2.34.1