[libc-commits] [libc] [libc] Fix sendfile argument order (PR #223059)

via libc-commits libc-commits at lists.llvm.org
Fri Sep 11 13:54:09 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: Michael Jones (michaelrj-google)

<details>
<summary>Changes</summary>

The previous implementation had the arguments swapped. This PR fixes it
and also adds a test to ensure we don't regress.


---
Full diff: https://github.com/llvm/llvm-project/pull/223059.diff


3 Files Affected:

- (modified) libc/src/sys/sendfile/linux/sendfile.cpp (+4-4) 
- (modified) libc/test/src/sys/sendfile/CMakeLists.txt (+1) 
- (modified) libc/test/src/sys/sendfile/sendfile_test.cpp (+77-1) 


``````````diff
diff --git a/libc/src/sys/sendfile/linux/sendfile.cpp b/libc/src/sys/sendfile/linux/sendfile.cpp
index fffbc97495635..f7321c3eff305 100644
--- a/libc/src/sys/sendfile/linux/sendfile.cpp
+++ b/libc/src/sys/sendfile/linux/sendfile.cpp
@@ -20,13 +20,13 @@ namespace LIBC_NAMESPACE_DECL {
 LLVM_LIBC_FUNCTION(ssize_t, sendfile,
                    (int out_fd, int in_fd, off_t *offset, size_t count)) {
 #ifdef SYS_sendfile
-  ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_sendfile, in_fd,
-                                                      out_fd, offset, count);
+  ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_sendfile, out_fd,
+                                                      in_fd, offset, count);
 #elif defined(SYS_sendfile64)
   // Same as sendfile but can handle large offsets
   static_assert(sizeof(off_t) == 8);
-  ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_sendfile64, in_fd,
-                                                      out_fd, offset, count);
+  ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_sendfile64, out_fd,
+                                                      in_fd, offset, count);
 #else
 #error "sendfile and sendfile64 syscalls not available."
 #endif
diff --git a/libc/test/src/sys/sendfile/CMakeLists.txt b/libc/test/src/sys/sendfile/CMakeLists.txt
index 4fbf436596021..18b792b2333eb 100644
--- a/libc/test/src/sys/sendfile/CMakeLists.txt
+++ b/libc/test/src/sys/sendfile/CMakeLists.txt
@@ -9,6 +9,7 @@ add_libc_test(
   SRCS
     sendfile_test.cpp
   DEPENDS
+    libc.hdr.errno_macros
     libc.hdr.fcntl_macros
     libc.hdr.sys_stat_macros
     libc.src.errno.errno
diff --git a/libc/test/src/sys/sendfile/sendfile_test.cpp b/libc/test/src/sys/sendfile/sendfile_test.cpp
index 7eea3eeca23ef..c018bde5022d1 100644
--- a/libc/test/src/sys/sendfile/sendfile_test.cpp
+++ b/libc/test/src/sys/sendfile/sendfile_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/errno_macros.h"
 #include "hdr/fcntl_macros.h"
 #include "hdr/sys_stat_macros.h"
 #include "src/__support/CPP/string_view.h"
@@ -46,7 +47,7 @@ TEST_F(LlvmLibcSendfileTest, CreateAndTransfer) {
   int out_fd = LIBC_NAMESPACE::open(OUT_FILE, O_CREAT | O_WRONLY, S_IRWXU);
   ASSERT_GT(out_fd, 0);
   ASSERT_ERRNO_SUCCESS();
-  ssize_t size = LIBC_NAMESPACE::sendfile(in_fd, out_fd, nullptr, IN_SIZE);
+  ssize_t size = LIBC_NAMESPACE::sendfile(out_fd, in_fd, nullptr, IN_SIZE);
   ASSERT_EQ(size, IN_SIZE);
   ASSERT_THAT(LIBC_NAMESPACE::close(in_fd), Succeeds(0));
   ASSERT_THAT(LIBC_NAMESPACE::close(out_fd), Succeeds(0));
@@ -61,3 +62,78 @@ TEST_F(LlvmLibcSendfileTest, CreateAndTransfer) {
   ASSERT_THAT(LIBC_NAMESPACE::unlink(IN_FILE), Succeeds(0));
   ASSERT_THAT(LIBC_NAMESPACE::unlink(OUT_FILE), Succeeds(0));
 }
+
+TEST_F(LlvmLibcSendfileTest, WrongDirectionFails) {
+  constexpr const char *IN_FILE = "testdata/sendfile_wrong_in.test";
+  constexpr const char *OUT_FILE = "testdata/sendfile_wrong_out.test";
+  const char IN_DATA[] = "test data";
+  constexpr ssize_t IN_SIZE = ssize_t(sizeof(IN_DATA));
+
+  int in_fd = LIBC_NAMESPACE::open(IN_FILE, O_CREAT | O_WRONLY, S_IRWXU);
+  ASSERT_GT(in_fd, 0);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(LIBC_NAMESPACE::write(in_fd, IN_DATA, IN_SIZE), IN_SIZE);
+  ASSERT_THAT(LIBC_NAMESPACE::close(in_fd), Succeeds(0));
+
+  // in_fd is read-only, out_fd is write-only.
+  in_fd = LIBC_NAMESPACE::open(IN_FILE, O_RDONLY);
+  ASSERT_GT(in_fd, 0);
+  ASSERT_ERRNO_SUCCESS();
+  int out_fd = LIBC_NAMESPACE::open(OUT_FILE, O_CREAT | O_WRONLY, S_IRWXU);
+  ASSERT_GT(out_fd, 0);
+  ASSERT_ERRNO_SUCCESS();
+
+  // Swapping the arguments (passing in_fd as out_fd and out_fd as in_fd) must
+  // fail with EBADF because in_fd cannot be written to and out_fd cannot be
+  // read from.
+  ASSERT_THAT(LIBC_NAMESPACE::sendfile(in_fd, out_fd, nullptr, IN_SIZE),
+              Fails<ssize_t>(EBADF));
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(in_fd), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(out_fd), Succeeds(0));
+
+  ASSERT_THAT(LIBC_NAMESPACE::unlink(IN_FILE), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::unlink(OUT_FILE), Succeeds(0));
+}
+
+TEST_F(LlvmLibcSendfileTest, OffsetTransfer) {
+  constexpr const char *IN_FILE = "testdata/sendfile_offset_in.test";
+  constexpr const char *OUT_FILE = "testdata/sendfile_offset_out.test";
+  const char IN_DATA[] = "sendfile offset test";
+  constexpr ssize_t IN_SIZE = ssize_t(sizeof(IN_DATA));
+  constexpr off_t OFFSET = 9;
+  constexpr ssize_t TRANSFER_SIZE = IN_SIZE - OFFSET;
+
+  int in_fd = LIBC_NAMESPACE::open(IN_FILE, O_CREAT | O_WRONLY, S_IRWXU);
+  ASSERT_GT(in_fd, 0);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(LIBC_NAMESPACE::write(in_fd, IN_DATA, IN_SIZE), IN_SIZE);
+  ASSERT_THAT(LIBC_NAMESPACE::close(in_fd), Succeeds(0));
+
+  in_fd = LIBC_NAMESPACE::open(IN_FILE, O_RDONLY);
+  ASSERT_GT(in_fd, 0);
+  ASSERT_ERRNO_SUCCESS();
+  int out_fd = LIBC_NAMESPACE::open(OUT_FILE, O_CREAT | O_WRONLY, S_IRWXU);
+  ASSERT_GT(out_fd, 0);
+  ASSERT_ERRNO_SUCCESS();
+
+  off_t offset = OFFSET;
+  ssize_t size =
+      LIBC_NAMESPACE::sendfile(out_fd, in_fd, &offset, TRANSFER_SIZE);
+  ASSERT_EQ(size, TRANSFER_SIZE);
+  ASSERT_EQ(offset, off_t(OFFSET + TRANSFER_SIZE));
+  ASSERT_THAT(LIBC_NAMESPACE::close(in_fd), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(out_fd), Succeeds(0));
+
+  out_fd = LIBC_NAMESPACE::open(OUT_FILE, O_RDONLY);
+  ASSERT_GT(out_fd, 0);
+  ASSERT_ERRNO_SUCCESS();
+  char buf[TRANSFER_SIZE];
+  ASSERT_EQ(TRANSFER_SIZE, LIBC_NAMESPACE::read(out_fd, buf, TRANSFER_SIZE));
+  ASSERT_EQ(cpp::string_view(buf, TRANSFER_SIZE),
+            cpp::string_view(IN_DATA + OFFSET, TRANSFER_SIZE));
+  ASSERT_THAT(LIBC_NAMESPACE::close(out_fd), Succeeds(0));
+
+  ASSERT_THAT(LIBC_NAMESPACE::unlink(IN_FILE), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::unlink(OUT_FILE), Succeeds(0));
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/223059


More information about the libc-commits mailing list