Index: lib/msan/tests/CMakeLists.txt =================================================================== --- lib/msan/tests/CMakeLists.txt +++ lib/msan/tests/CMakeLists.txt @@ -35,6 +35,7 @@ -Wno-zero-length-array -Wno-uninitialized -Werror=sign-compare + -Wno-gnu-zero-variadic-macro-arguments ) set(MSAN_UNITTEST_INSTRUMENTED_CFLAGS ${MSAN_UNITTEST_COMMON_CFLAGS} Index: lib/msan/tests/msan_test.cc =================================================================== --- lib/msan/tests/msan_test.cc +++ lib/msan/tests/msan_test.cc @@ -175,10 +175,16 @@ } #define EXPECT_NOT_POISONED(x) EXPECT_EQ(true, TestForNotPoisoned((x))) +#define EXPECT_NOT_POISONED2(data, size) \ + EXPECT_EQ(true, TestForNotPoisoned((data), (size))) + +bool TestForNotPoisoned(const void *data, size_t size) { + return __msan_test_shadow(data, size) == -1; +} template bool TestForNotPoisoned(const T& t) { - return __msan_test_shadow((void*)&t, sizeof(t)) == -1; + return TestForNotPoisoned((void *)&t, sizeof(t)); } static U8 poisoned_array[100]; @@ -879,92 +885,194 @@ close(sock); } -TEST(MemorySanitizer, accept) { - int listen_socket = socket(AF_INET, SOCK_STREAM, 0); +class SocketAddr { + public: + virtual ~SocketAddr() = default; + virtual struct sockaddr *ptr() = 0; + virtual size_t size() const = 0; +}; + +class SocketAddr4 : public SocketAddr { + public: + SocketAddr4() { EXPECT_POISONED(sai_); } + explicit SocketAddr4(uint16_t port) { + memset(&sai_, 0, sizeof(sai_)); + sai_.sin_family = AF_INET; + sai_.sin_port = port; + sai_.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } + + sockaddr *ptr() override { return reinterpret_cast(&sai_); } + + size_t size() const override { return sizeof(sai_); } + + private: + sockaddr_in sai_; +}; + +class SocketAddr6 : public SocketAddr { + public: + SocketAddr6() { EXPECT_POISONED(sai_); } + explicit SocketAddr6(uint16_t port) { + memset(&sai_, 0, sizeof(sai_)); + sai_.sin6_family = AF_INET6; + sai_.sin6_port = port; + sai_.sin6_addr = in6addr_loopback; + } + + sockaddr *ptr() override { return reinterpret_cast(&sai_); } + + size_t size() const override { return sizeof(sai_); } + + private: + sockaddr_in6 sai_; +}; + +class MemorySanitizerIpTest : public ::testing::TestWithParam { + public: + void SetUp() override { + ASSERT_TRUE(GetParam() == AF_INET || GetParam() == AF_INET6); + } + + template + std::unique_ptr CreateSockAddr(Args... args) const { + if (GetParam() == AF_INET) + return std::unique_ptr(new SocketAddr4(args...)); + return std::unique_ptr(new SocketAddr6(args...)); + } + + int CreateSocket(int socket_type) const { + return socket(GetParam(), socket_type, 0); + } +}; + +std::vector GetAvailableIpSocketFamilies() { + std::vector result; + + for (int i : std::vector(AF_INET, AF_INET6)) { + int s = socket(i, SOCK_STREAM, 0); + if (s > 0) { + result.push_back(i); + close(s); + } + } + + return result; +} + +INSTANTIATE_TEST_CASE_P(IpTests, MemorySanitizerIpTest, + ::testing::ValuesIn(GetAvailableIpSocketFamilies())); + +TEST_P(MemorySanitizerIpTest, accept) { + int listen_socket = CreateSocket(SOCK_STREAM); ASSERT_LT(0, listen_socket); - struct sockaddr_in sai; - memset(&sai, 0, sizeof(sai)); - sai.sin_family = AF_INET; - sai.sin_port = 0; - sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - int res = bind(listen_socket, (struct sockaddr *)&sai, sizeof(sai)); + auto sai = CreateSockAddr(0); + int res = bind(listen_socket, sai->ptr(), sai->size()); ASSERT_EQ(0, res); res = listen(listen_socket, 1); ASSERT_EQ(0, res); - socklen_t sz = sizeof(sai); - res = getsockname(listen_socket, (struct sockaddr *)&sai, &sz); + socklen_t sz = sai->size(); + res = getsockname(listen_socket, sai->ptr(), &sz); ASSERT_EQ(0, res); - ASSERT_EQ(sizeof(sai), sz); + ASSERT_EQ(sai->size(), sz); - int connect_socket = socket(AF_INET, SOCK_STREAM, 0); + int connect_socket = CreateSocket(SOCK_STREAM); ASSERT_LT(0, connect_socket); res = fcntl(connect_socket, F_SETFL, O_NONBLOCK); ASSERT_EQ(0, res); - res = connect(connect_socket, (struct sockaddr *)&sai, sizeof(sai)); + res = connect(connect_socket, sai->ptr(), sai->size()); // On FreeBSD this connection completes immediately. if (res != 0) { ASSERT_EQ(-1, res); ASSERT_EQ(EINPROGRESS, errno); } - __msan_poison(&sai, sizeof(sai)); - int new_sock = accept(listen_socket, (struct sockaddr *)&sai, &sz); + __msan_poison(sai->ptr(), sai->size()); + int new_sock = accept(listen_socket, sai->ptr(), &sz); ASSERT_LT(0, new_sock); - ASSERT_EQ(sizeof(sai), sz); - EXPECT_NOT_POISONED(sai); + ASSERT_EQ(sai->size(), sz); + EXPECT_NOT_POISONED2(sai->ptr(), sai->size()); - __msan_poison(&sai, sizeof(sai)); - res = getpeername(new_sock, (struct sockaddr *)&sai, &sz); + __msan_poison(sai->ptr(), sai->size()); + res = getpeername(new_sock, sai->ptr(), &sz); ASSERT_EQ(0, res); - ASSERT_EQ(sizeof(sai), sz); - EXPECT_NOT_POISONED(sai); + ASSERT_EQ(sai->size(), sz); + EXPECT_NOT_POISONED2(sai->ptr(), sai->size()); close(new_sock); close(connect_socket); close(listen_socket); } -TEST(MemorySanitizer, getaddrinfo) { - struct addrinfo *ai; - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - int res = getaddrinfo("localhost", NULL, &hints, &ai); +TEST_P(MemorySanitizerIpTest, recvmsg) { + int server_socket = CreateSocket(SOCK_DGRAM); + ASSERT_LT(0, server_socket); + + auto sai = CreateSockAddr(0); + int res = bind(server_socket, sai->ptr(), sai->size()); ASSERT_EQ(0, res); - EXPECT_NOT_POISONED(*ai); - ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen); - EXPECT_NOT_POISONED(*(sockaddr_in*)ai->ai_addr); -} -TEST(MemorySanitizer, getnameinfo) { - struct sockaddr_in sai; - memset(&sai, 0, sizeof(sai)); - sai.sin_family = AF_INET; - sai.sin_port = 80; - sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - char host[500]; - char serv[500]; - int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host, - sizeof(host), serv, sizeof(serv), 0); + socklen_t sz = sai->size(); + res = getsockname(server_socket, sai->ptr(), &sz); ASSERT_EQ(0, res); - EXPECT_NOT_POISONED(host[0]); - EXPECT_POISONED(host[sizeof(host) - 1]); + ASSERT_EQ(sai->size(), sz); - ASSERT_NE(0U, strlen(host)); - EXPECT_NOT_POISONED(serv[0]); - EXPECT_POISONED(serv[sizeof(serv) - 1]); - ASSERT_NE(0U, strlen(serv)); + int client_socket = CreateSocket(SOCK_DGRAM); + ASSERT_LT(0, client_socket); + + auto client_sai = CreateSockAddr(0); + res = bind(client_socket, client_sai->ptr(), client_sai->size()); + ASSERT_EQ(0, res); + + sz = client_sai->size(); + res = getsockname(client_socket, client_sai->ptr(), &sz); + ASSERT_EQ(0, res); + ASSERT_EQ(client_sai->size(), sz); + + const char *s = "message text"; + struct iovec iov; + iov.iov_base = (void *)s; + iov.iov_len = strlen(s) + 1; + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + msg.msg_name = sai->ptr(); + msg.msg_namelen = sai->size(); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + res = sendmsg(client_socket, &msg, 0); + ASSERT_LT(0, res); + + char buf[1000]; + struct iovec recv_iov; + recv_iov.iov_base = (void *)&buf; + recv_iov.iov_len = sizeof(buf); + auto recv_sai = CreateSockAddr(); + struct msghdr recv_msg; + memset(&recv_msg, 0, sizeof(recv_msg)); + recv_msg.msg_name = recv_sai->ptr(); + recv_msg.msg_namelen = recv_sai->size(); + recv_msg.msg_iov = &recv_iov; + recv_msg.msg_iovlen = 1; + res = recvmsg(server_socket, &recv_msg, 0); + ASSERT_LT(0, res); + + ASSERT_EQ(recv_sai->size(), recv_msg.msg_namelen); + EXPECT_NOT_POISONED2(recv_sai->ptr(), recv_sai->size()); + EXPECT_STREQ(s, buf); + + close(server_socket); + close(client_socket); } #define EXPECT_HOSTENT_NOT_POISONED(he) \ do { \ EXPECT_NOT_POISONED(*(he)); \ - ASSERT_NE((void *) 0, (he)->h_name); \ - ASSERT_NE((void *) 0, (he)->h_aliases); \ - ASSERT_NE((void *) 0, (he)->h_addr_list); \ + ASSERT_NE((void *)0, (he)->h_name); \ + ASSERT_NE((void *)0, (he)->h_aliases); \ + ASSERT_NE((void *)0, (he)->h_addr_list); \ EXPECT_NOT_POISONED(strlen((he)->h_name)); \ char **p = (he)->h_aliases; \ while (*p) { \ @@ -993,76 +1101,38 @@ EXPECT_HOSTENT_NOT_POISONED(he); } -#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME +#endif // MSAN_TEST_DISABLE_GETHOSTBYNAME -TEST(MemorySanitizer, recvmsg) { - int server_socket = socket(AF_INET, SOCK_DGRAM, 0); - ASSERT_LT(0, server_socket); +TEST(MemorySanitizer, getaddrinfo) { + struct addrinfo *ai; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + int res = getaddrinfo("localhost", NULL, &hints, &ai); + ASSERT_EQ(0, res); + EXPECT_NOT_POISONED(*ai); + ASSERT_EQ(sizeof(sockaddr_in), ai->ai_addrlen); + EXPECT_NOT_POISONED(*(sockaddr_in *)ai->ai_addr); +} +TEST(MemorySanitizer, getnameinfo) { struct sockaddr_in sai; memset(&sai, 0, sizeof(sai)); sai.sin_family = AF_INET; - sai.sin_port = 0; + sai.sin_port = 80; sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - int res = bind(server_socket, (struct sockaddr *)&sai, sizeof(sai)); - ASSERT_EQ(0, res); - - socklen_t sz = sizeof(sai); - res = getsockname(server_socket, (struct sockaddr *)&sai, &sz); - ASSERT_EQ(0, res); - ASSERT_EQ(sizeof(sai), sz); - - - int client_socket = socket(AF_INET, SOCK_DGRAM, 0); - ASSERT_LT(0, client_socket); - - struct sockaddr_in client_sai; - memset(&client_sai, 0, sizeof(client_sai)); - client_sai.sin_family = AF_INET; - client_sai.sin_port = 0; - client_sai.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - res = bind(client_socket, (struct sockaddr *)&client_sai, sizeof(client_sai)); - ASSERT_EQ(0, res); - - sz = sizeof(client_sai); - res = getsockname(client_socket, (struct sockaddr *)&client_sai, &sz); + char host[500]; + char serv[500]; + int res = getnameinfo((struct sockaddr *)&sai, sizeof(sai), host, + sizeof(host), serv, sizeof(serv), 0); ASSERT_EQ(0, res); - ASSERT_EQ(sizeof(client_sai), sz); - - const char *s = "message text"; - struct iovec iov; - iov.iov_base = (void *)s; - iov.iov_len = strlen(s) + 1; - struct msghdr msg; - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &sai; - msg.msg_namelen = sizeof(sai); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - res = sendmsg(client_socket, &msg, 0); - ASSERT_LT(0, res); - - - char buf[1000]; - struct iovec recv_iov; - recv_iov.iov_base = (void *)&buf; - recv_iov.iov_len = sizeof(buf); - struct sockaddr_in recv_sai; - struct msghdr recv_msg; - memset(&recv_msg, 0, sizeof(recv_msg)); - recv_msg.msg_name = &recv_sai; - recv_msg.msg_namelen = sizeof(recv_sai); - recv_msg.msg_iov = &recv_iov; - recv_msg.msg_iovlen = 1; - res = recvmsg(server_socket, &recv_msg, 0); - ASSERT_LT(0, res); - - ASSERT_EQ(sizeof(recv_sai), recv_msg.msg_namelen); - EXPECT_NOT_POISONED(*(struct sockaddr_in *)recv_msg.msg_name); - EXPECT_STREQ(s, buf); + EXPECT_NOT_POISONED(host[0]); + EXPECT_POISONED(host[sizeof(host) - 1]); - close(server_socket); - close(client_socket); + ASSERT_NE(0U, strlen(host)); + EXPECT_NOT_POISONED(serv[0]); + EXPECT_POISONED(serv[sizeof(serv) - 1]); + ASSERT_NE(0U, strlen(serv)); } TEST(MemorySanitizer, gethostbyname2) { Index: test/msan/Linux/sendmsg.cc =================================================================== --- test/msan/Linux/sendmsg.cc +++ test/msan/Linux/sendmsg.cc @@ -33,17 +33,31 @@ char buf[kBufSize] = {0}; pthread_t client_thread; struct sockaddr_in serveraddr; - - sockfd = socket(AF_INET, SOCK_DGRAM, 0); + struct sockaddr_in6 serveraddr6; memset(&serveraddr, 0, sizeof(serveraddr)); serveraddr.sin_family = AF_INET; serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); serveraddr.sin_port = 0; - - bind(sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr)); + struct sockaddr *addr = (struct sockaddr *)&serveraddr; socklen_t addrlen = sizeof(serveraddr); - getsockname(sockfd, (struct sockaddr *)&serveraddr, &addrlen); + + sockfd = socket(addr->sa_family, SOCK_DGRAM, 0); + if (sockfd <= 0) { + // Try to fall-back to IPv6 + memset(&serveraddr6, 0, sizeof(serveraddr6)); + serveraddr6.sin6_family = AF_INET6; + serveraddr6.sin6_addr = in6addr_any; + serveraddr6.sin6_port = 0; + addr = (struct sockaddr *)&serveraddr6; + addrlen = sizeof(serveraddr6); + + sockfd = socket(addr->sa_family, SOCK_DGRAM, 0); + } + assert(sockfd > 0); + + bind(sockfd, addr, addrlen); + getsockname(sockfd, addr, &addrlen); #if defined(POISON) __msan_poison(buf + 7, 1); @@ -52,7 +66,7 @@ #if defined(SENDMSG) struct iovec iov[2] = {{buf, 5}, {buf + 5, 5}}; struct msghdr msg; - msg.msg_name = &serveraddr; + msg.msg_name = addr; msg.msg_namelen = addrlen; msg.msg_iov = iov; msg.msg_iovlen = 2; @@ -62,14 +76,13 @@ #endif #if defined(SEND) - ret = connect(sockfd, (struct sockaddr *)&serveraddr, addrlen); + ret = connect(sockfd, addr, addrlen); assert(ret == 0); ret = send(sockfd, buf, kBufSize, 0); // SEND: Uninitialized bytes in __interceptor_send at offset 7 inside [{{.*}}, 10) assert(ret > 0); #elif defined(SENDTO) - ret = - sendto(sockfd, buf, kBufSize, 0, (struct sockaddr *)&serveraddr, addrlen); + ret = sendto(sockfd, buf, kBufSize, 0, addr, addrlen); // SENDTO: Uninitialized bytes in __interceptor_sendto at offset 7 inside [{{.*}}, 10) assert(ret > 0); #elif defined(SENDMSG) Index: test/msan/ioctl.cc =================================================================== --- test/msan/ioctl.cc +++ test/msan/ioctl.cc @@ -8,7 +8,7 @@ #include int main(int argc, char **argv) { - int fd = socket(AF_INET, SOCK_DGRAM, 0); + int fd = socket(AF_UNIX, SOCK_DGRAM, 0); unsigned int z; int res = ioctl(fd, FIOGETOWN, &z); Index: test/msan/ioctl_custom.cc =================================================================== --- test/msan/ioctl_custom.cc +++ test/msan/ioctl_custom.cc @@ -14,7 +14,7 @@ #include int main(int argc, char **argv) { - int fd = socket(AF_INET, SOCK_STREAM, 0); + int fd = socket(AF_UNIX, SOCK_STREAM, 0); struct ifreq ifreqs[20]; struct ifconf ifc; Index: test/tsan/fd_socket_connect_norace.cc =================================================================== --- test/tsan/fd_socket_connect_norace.cc +++ test/tsan/fd_socket_connect_norace.cc @@ -1,20 +1,24 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include +#include +#include #include #include #include -#include -#include #include -#include -#include +#include +#include -struct sockaddr_in addr; +struct sockaddr_in addr4; +struct sockaddr_in6 addr6; +struct sockaddr *addr; +socklen_t addrlen; int X; void *ClientThread(void *x) { - int c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + int c = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); X = 42; - if (connect(c, (struct sockaddr*)&addr, sizeof(addr))) { + if (connect(c, addr, addrlen)) { perror("connect"); exit(1); } @@ -23,13 +27,26 @@ } int main() { - int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - addr.sin_family = AF_INET; - inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); - addr.sin_port = INADDR_ANY; - socklen_t len = sizeof(addr); - bind(s, (sockaddr*)&addr, len); - getsockname(s, (sockaddr*)&addr, &len); + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr4.sin_port = INADDR_ANY; + addr = (struct sockaddr *)&addr4; + addrlen = sizeof(addr4); + + int s = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (s <= 0) { + // Try to fall-back to IPv6 + addr6.sin6_family = AF_INET6; + addr6.sin6_addr = in6addr_loopback; + addr6.sin6_port = INADDR_ANY; + addr = (struct sockaddr *)&addr6; + addrlen = sizeof(addr6); + s = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + } + assert(s > 0); + + bind(s, addr, addrlen); + getsockname(s, addr, &addrlen); listen(s, 10); pthread_t t; pthread_create(&t, 0, ClientThread, 0); Index: test/tsan/fd_socket_norace.cc =================================================================== --- test/tsan/fd_socket_norace.cc +++ test/tsan/fd_socket_norace.cc @@ -1,20 +1,24 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include +#include +#include #include #include #include -#include -#include #include -#include -#include +#include +#include -struct sockaddr_in addr; +struct sockaddr_in addr4; +struct sockaddr_in6 addr6; +struct sockaddr *addr; +socklen_t addrlen; int X; void *ClientThread(void *x) { X = 42; - int c = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (connect(c, (struct sockaddr*)&addr, sizeof(addr))) { + int c = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (connect(c, addr, addrlen)) { perror("connect"); exit(1); } @@ -27,13 +31,26 @@ } int main() { - int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - addr.sin_family = AF_INET; - inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr); - addr.sin_port = INADDR_ANY; - socklen_t len = sizeof(addr); - bind(s, (sockaddr*)&addr, len); - getsockname(s, (sockaddr*)&addr, &len); + addr4.sin_family = AF_INET; + addr4.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr4.sin_port = INADDR_ANY; + addr = (struct sockaddr *)&addr4; + addrlen = sizeof(addr4); + + int s = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (s <= 0) { + // Try to fall-back to IPv6 + addr6.sin6_family = AF_INET6; + addr6.sin6_addr = in6addr_loopback; + addr6.sin6_port = INADDR_ANY; + addr = (struct sockaddr *)&addr6; + addrlen = sizeof(addr6); + s = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); + } + assert(s > 0); + + bind(s, addr, addrlen); + getsockname(s, addr, &addrlen); listen(s, 10); pthread_t t; pthread_create(&t, 0, ClientThread, 0);