Clear msghdr flags on successful recvmsg.

.net sets these flags to -1 and then uses their result, especting it to be
zero.

Does not set actual flags (e.g. MSG_TRUNC), but setting to zero is more correct
than what we did before.

PiperOrigin-RevId: 239657951
Change-Id: I89c5f84bc9b94a2cd8ff84e8ecfea09e01142030
This commit is contained in:
Ian Gudger
2019-03-21 13:19:11 -07:00
committed by Shentubot
parent ba937d74f9
commit ba828233b9
2 changed files with 95 additions and 0 deletions
+21
View File
@@ -57,6 +57,10 @@ const nameLenOffset = 8
// to the ControlLen field.
const controlLenOffset = 40
// flagsOffset is the offset form the start of the MessageHeader64 struct
// to the Flags field.
const flagsOffset = 48
// messageHeader64Len is the length of a MessageHeader64 struct.
var messageHeader64Len = uint64(binary.Size(MessageHeader64{}))
@@ -743,6 +747,16 @@ func recvSingleMsg(t *kernel.Task, s socket.Socket, msgPtr usermem.Addr, flags i
return 0, syserror.ConvertIntr(err.ToError(), kernel.ERESTARTSYS)
}
cms.Unix.Release()
if msg.Flags != 0 {
// Copy out the flags to the caller.
//
// TODO: Plumb through actual flags.
if _, err := t.CopyOut(msgPtr+flagsOffset, int32(0)); err != nil {
return 0, err
}
}
return uintptr(n), nil
}
@@ -787,6 +801,13 @@ func recvSingleMsg(t *kernel.Task, s socket.Socket, msgPtr usermem.Addr, flags i
}
}
// Copy out the flags to the caller.
//
// TODO: Plumb through actual flags.
if _, err := t.CopyOut(msgPtr+flagsOffset, int32(0)); err != nil {
return 0, err
}
return uintptr(n), nil
}
+74
View File
@@ -183,6 +183,80 @@ TEST_P(AllSocketPairTest, SendmsgRecvmsg16KB) {
memcmp(sent_data.data(), received_data.data(), sent_data.size()));
}
TEST_P(AllSocketPairTest, RecvmsgMsghdrFlagsNotClearedOnFailure) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
char received_data[10] = {};
struct iovec iov;
iov.iov_base = received_data;
iov.iov_len = sizeof(received_data);
struct msghdr msg = {};
msg.msg_flags = -1;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
ASSERT_THAT(RetryEINTR(recvmsg)(sockets->second_fd(), &msg, MSG_DONTWAIT),
SyscallFailsWithErrno(EAGAIN));
// Check that msghdr flags were not changed.
EXPECT_EQ(msg.msg_flags, -1);
}
TEST_P(AllSocketPairTest, RecvmsgMsghdrFlagsCleared) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
char sent_data[10];
RandomizeBuffer(sent_data, sizeof(sent_data));
ASSERT_THAT(
RetryEINTR(send)(sockets->first_fd(), sent_data, sizeof(sent_data), 0),
SyscallSucceedsWithValue(sizeof(sent_data)));
char received_data[sizeof(sent_data)] = {};
struct iovec iov;
iov.iov_base = received_data;
iov.iov_len = sizeof(received_data);
struct msghdr msg = {};
msg.msg_flags = -1;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
ASSERT_THAT(RetryEINTR(recvmsg)(sockets->second_fd(), &msg, 0),
SyscallSucceedsWithValue(sizeof(sent_data)));
EXPECT_EQ(0, memcmp(received_data, sent_data, sizeof(sent_data)));
// Check that msghdr flags were cleared.
EXPECT_EQ(msg.msg_flags, 0);
}
TEST_P(AllSocketPairTest, RecvmsgPeekMsghdrFlagsCleared) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
char sent_data[10];
RandomizeBuffer(sent_data, sizeof(sent_data));
ASSERT_THAT(
RetryEINTR(send)(sockets->first_fd(), sent_data, sizeof(sent_data), 0),
SyscallSucceedsWithValue(sizeof(sent_data)));
char received_data[sizeof(sent_data)] = {};
struct iovec iov;
iov.iov_base = received_data;
iov.iov_len = sizeof(received_data);
struct msghdr msg = {};
msg.msg_flags = -1;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
ASSERT_THAT(RetryEINTR(recvmsg)(sockets->second_fd(), &msg, MSG_PEEK),
SyscallSucceedsWithValue(sizeof(sent_data)));
EXPECT_EQ(0, memcmp(received_data, sent_data, sizeof(sent_data)));
// Check that msghdr flags were cleared.
EXPECT_EQ(msg.msg_flags, 0);
}
TEST_P(AllSocketPairTest, RecvmmsgInvalidTimeout) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
char buf[10];