[libc-commits] [libc] 412d474 - [libc] Add the MSG_ flags (#194375)

via libc-commits libc-commits at lists.llvm.org
Tue Apr 28 04:25:04 PDT 2026


Author: Pavel Labath
Date: 2026-04-28T13:24:58+02:00
New Revision: 412d474f5e1dc9a931a71cf972c5415e6a025a6f

URL: https://github.com/llvm/llvm-project/commit/412d474f5e1dc9a931a71cf972c5415e6a025a6f
DIFF: https://github.com/llvm/llvm-project/commit/412d474f5e1dc9a931a71cf972c5415e6a025a6f.diff

LOG: [libc] Add the MSG_ flags (#194375)

I've included all of the flags defined on linux, even those not
documented in POSIX (or the manpage). I've also added tests to exercise
the flags, for cases where this can be done with domain sockets.

Added: 
    

Modified: 
    libc/include/llvm-libc-macros/linux/sys-socket-macros.h
    libc/test/src/sys/socket/linux/CMakeLists.txt
    libc/test/src/sys/socket/linux/send_recv_test.cpp
    libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp

Removed: 
    


################################################################################
diff  --git a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
index 0d4460df0196b..1c6ae9f394f63 100644
--- a/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sys-socket-macros.h
@@ -52,6 +52,29 @@
 
 #define SCM_RIGHTS 1
 
+#define MSG_OOB 0x01
+#define MSG_PEEK 0x02
+#define MSG_DONTROUTE 0x04
+#define MSG_CTRUNC 0x08
+#define MSG_PROXY 0x10
+#define MSG_TRUNC 0x20
+#define MSG_DONTWAIT 0x40
+#define MSG_EOR 0x80
+#define MSG_WAITALL 0x100
+#define MSG_FIN 0x200
+#define MSG_SYN 0x400
+#define MSG_CONFIRM 0x800
+#define MSG_RST 0x1000
+#define MSG_ERRQUEUE 0x2000
+#define MSG_NOSIGNAL 0x4000
+#define MSG_MORE 0x8000
+#define MSG_WAITFORONE 0x10000
+#define MSG_BATCH 0x40000
+#define MSG_SOCK_DEVMEM 0x2000000
+#define MSG_ZEROCOPY 0x4000000
+#define MSG_FASTOPEN 0x20000000
+#define MSG_CMSG_CLOEXEC 0x40000000
+
 #define CMSG_ALIGN(len) (((len) + sizeof(size_t) - 1) & ~(sizeof(size_t) - 1))
 #define CMSG_LEN(len) (sizeof(struct cmsghdr) + (len))
 #define CMSG_SPACE(len) (sizeof(struct cmsghdr) + CMSG_ALIGN(len))

diff  --git a/libc/test/src/sys/socket/linux/CMakeLists.txt b/libc/test/src/sys/socket/linux/CMakeLists.txt
index ef88e7e6b9499..378529ca3b71f 100644
--- a/libc/test/src/sys/socket/linux/CMakeLists.txt
+++ b/libc/test/src/sys/socket/linux/CMakeLists.txt
@@ -125,7 +125,7 @@ add_libc_unittest(
   SRCS
     send_recv_test.cpp
   DEPENDS
-    libc.include.sys_socket
+    libc.hdr.sys_socket_macros
     libc.src.errno.errno
     libc.src.sys.socket.socketpair
     libc.src.sys.socket.send
@@ -159,9 +159,11 @@ add_libc_unittest(
   SRCS
     sendmsg_recvmsg_test.cpp
   DEPENDS
-    libc.include.sys_socket
+    libc.hdr.fcntl_macros
+    libc.hdr.sys_socket_macros
     libc.hdr.types.struct_cmsghdr
     libc.src.errno.errno
+    libc.src.fcntl.fcntl
     libc.src.string.memcpy
     libc.src.string.memset
     libc.src.sys.socket.getsockopt

diff  --git a/libc/test/src/sys/socket/linux/send_recv_test.cpp b/libc/test/src/sys/socket/linux/send_recv_test.cpp
index a5a9b29228ece..6210c15810a9c 100644
--- a/libc/test/src/sys/socket/linux/send_recv_test.cpp
+++ b/libc/test/src/sys/socket/linux/send_recv_test.cpp
@@ -6,6 +6,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/sys_socket_macros.h"
 #include "src/sys/socket/recv.h"
 #include "src/sys/socket/send.h"
 #include "src/sys/socket/socketpair.h"
@@ -16,8 +17,6 @@
 #include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
 
-#include <sys/socket.h> // For AF_UNIX and SOCK_DGRAM
-
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 using LlvmLibcSendRecvTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
@@ -46,6 +45,47 @@ TEST_F(LlvmLibcSendRecvTest, SucceedsWithSocketPair) {
   ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
 }
 
+TEST_F(LlvmLibcSendRecvTest, MsgFlagsTest) {
+  int sockpair[2] = {0, 0};
+
+  ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockpair),
+              Succeeds(0));
+
+  char buffer[256] = {};
+
+  // MSG_DONTWAIT on an empty socket returns EAGAIN
+  ASSERT_THAT(
+      LIBC_NAMESPACE::recv(sockpair[1], buffer, sizeof(buffer), MSG_DONTWAIT),
+      Fails<ssize_t>(EAGAIN));
+
+  const char TEST_MESSAGE[] = "this is a long message";
+  const size_t MESSAGE_LEN = sizeof(TEST_MESSAGE);
+
+  ASSERT_THAT(LIBC_NAMESPACE::send(sockpair[0], TEST_MESSAGE, MESSAGE_LEN, 0),
+              Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
+
+  // MSG_PEEK does not remove the message from the socket
+  ASSERT_THAT(
+      LIBC_NAMESPACE::recv(sockpair[1], buffer, sizeof(buffer), MSG_PEEK),
+      Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
+  ASSERT_STREQ(buffer, TEST_MESSAGE);
+
+  // Read the message again, but use a smaller buffer to test MSG_TRUNC. Return
+  // value should be real length.
+  char small_buffer[6] = {};
+  ASSERT_THAT(LIBC_NAMESPACE::recv(sockpair[1], small_buffer,
+                                   sizeof(small_buffer) - 1, MSG_TRUNC),
+              Succeeds(static_cast<ssize_t>(MESSAGE_LEN)));
+  ASSERT_STREQ(small_buffer, "this ");
+
+  // Sending with MSG_NOSIGNAL to a closed socket should fail with EPIPE
+  ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::send(sockpair[0], "x", 1, MSG_NOSIGNAL),
+              Fails<ssize_t>(EPIPE));
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
+}
+
 TEST_F(LlvmLibcSendRecvTest, SendFails) {
   const char TEST_MESSAGE[] = "connection terminated";
   const size_t MESSAGE_LEN = sizeof(TEST_MESSAGE);

diff  --git a/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp b/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
index fc4aa7e91c337..fcc71ab1c3994 100644
--- a/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
+++ b/libc/test/src/sys/socket/linux/sendmsg_recvmsg_test.cpp
@@ -6,8 +6,10 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/fcntl_macros.h"
 #include "hdr/sys_socket_macros.h"
 #include "hdr/types/struct_cmsghdr.h"
+#include "src/fcntl/fcntl.h"
 #include "src/string/memcpy.h"
 #include "src/string/memset.h"
 #include "src/sys/socket/getsockopt.h"
@@ -22,8 +24,6 @@
 #include "test/UnitTest/LibcTest.h"
 #include "test/UnitTest/Test.h"
 
-#include <sys/socket.h> // For AF_UNIX and SOCK_DGRAM
-
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
 using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
 using LlvmLibcSendMsgRecvMsgTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
@@ -201,6 +201,71 @@ TEST_F(LlvmLibcSendMsgRecvMsgTest, SendAndReceiveFileDescriptor) {
   ASSERT_THAT(LIBC_NAMESPACE::close(new_fd), Succeeds(0));
 }
 
+TEST_F(LlvmLibcSendMsgRecvMsgTest, MsgCmsgCloexec) {
+  int sockpair[2] = {0, 0};
+
+  ASSERT_THAT(LIBC_NAMESPACE::socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair),
+              Succeeds(0));
+
+  struct iovec iov;
+  iov.iov_base = reinterpret_cast<void *>(const_cast<char *>("x"));
+  iov.iov_len = 1;
+
+  char control_buf[CMSG_SPACE(sizeof(int))] = {};
+
+  struct msghdr msg;
+  msg.msg_name = nullptr;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_flags = 0;
+  msg.msg_control = control_buf;
+  msg.msg_controllen = CMSG_LEN(sizeof(int));
+
+  struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_RIGHTS;
+  cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+  LIBC_NAMESPACE::memcpy(CMSG_DATA(cmsg), sockpair + 1, sizeof(int));
+
+  ASSERT_THAT(LIBC_NAMESPACE::sendmsg(sockpair[0], &msg, 0),
+              Succeeds(static_cast<ssize_t>(1)));
+
+  char buffer[256];
+
+  iov.iov_base = buffer;
+  iov.iov_len = sizeof(buffer);
+
+  LIBC_NAMESPACE::memset(control_buf, 0, sizeof(control_buf));
+
+  msg.msg_name = nullptr;
+  msg.msg_namelen = 0;
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = control_buf;
+  msg.msg_controllen = sizeof(control_buf);
+  msg.msg_flags = 0;
+
+  // Receive with MSG_CMSG_CLOEXEC
+  ASSERT_THAT(LIBC_NAMESPACE::recvmsg(sockpair[1], &msg, MSG_CMSG_CLOEXEC),
+              Succeeds(static_cast<ssize_t>(1)));
+
+  cmsg = CMSG_FIRSTHDR(&msg);
+  ASSERT_TRUE(cmsg != nullptr);
+
+  int new_fd;
+  LIBC_NAMESPACE::memcpy(&new_fd, CMSG_DATA(cmsg), sizeof(int));
+
+  // Check FD_CLOEXEC
+  int flags = LIBC_NAMESPACE::fcntl(new_fd, F_GETFD);
+  ASSERT_GE(flags, 0);
+  ASSERT_NE(flags & FD_CLOEXEC, 0);
+
+  ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[0]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(sockpair[1]), Succeeds(0));
+  ASSERT_THAT(LIBC_NAMESPACE::close(new_fd), Succeeds(0));
+}
+
 TEST_F(LlvmLibcSendMsgRecvMsgTest, SendFails) {
   const char TEST_MESSAGE[] = "connection terminated";
   const size_t MESSAGE_LEN = sizeof(TEST_MESSAGE);


        


More information about the libc-commits mailing list