Skip to content

Commit 81c4a78

Browse files
authored
Merge pull request rust-lang#5059 from WhySoBad/network-socket-fix-tests-for-native-hosts
Fix socket tests to run on native host
2 parents 49972bd + ac2e825 commit 81c4a78

2 files changed

Lines changed: 89 additions & 36 deletions

File tree

src/tools/miri/tests/pass-dep/libc/libc-socket-no-blocking-epoll.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,10 +294,17 @@ fn test_send_nonblock() {
294294
if written as usize == fill_buf.len() {
295295
// When we didn't have a short write we should still be able to write more.
296296
// Ensure the socket is still writable.
297-
assert_eq!(
298-
current_epoll_readiness::<8>(client_sockfd, EPOLLOUT | EPOLLET),
299-
EPOLLOUT
300-
);
297+
let readiness = current_epoll_readiness::<8>(client_sockfd, EPOLLOUT | EPOLLET);
298+
if cfg!(miri) {
299+
// With Miri we keep the writable readiness until EWOULDBLOCK is returned.
300+
assert_eq!(readiness, EPOLLOUT);
301+
} else {
302+
// On native Linux hosts, the writable readiness is removed when the buffer
303+
// is "almost" full. We can't emulate this with Miri.
304+
// The buffer must not be "almost" full at the first write.
305+
let is_not_first_write = total_written > fill_buf.len();
306+
assert!(readiness == EPOLLOUT || (is_not_first_write && readiness == 0));
307+
}
301308
}
302309
}
303310
Err(err) if err.kind() == ErrorKind::WouldBlock => break,

src/tools/miri/tests/pass-dep/libc/libc-socket.rs

Lines changed: 78 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ mod utils;
88

99
use std::io::ErrorKind;
1010
use std::time::{Duration, Instant};
11-
use std::{ptr, thread};
11+
use std::{ptr, slice, thread};
1212

1313
use libc_utils::*;
1414

@@ -121,11 +121,26 @@ fn test_set_reuseaddr_invalid_len() {
121121
let sockfd =
122122
unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() };
123123
// Value should be of type `libc::c_int` which has size 4 bytes.
124-
// By providing a u64 of size 8 bytes we trigger an invalid length error.
125-
let err = net::setsockopt(sockfd, libc::SOL_SOCKET, libc::SO_REUSEADDR, 1u64).unwrap_err();
124+
// By providing an u16 of size 2 bytes we trigger an invalid length error.
125+
let err = net::setsockopt(sockfd, libc::SOL_SOCKET, libc::SO_REUSEADDR, 1u16).unwrap_err();
126126
assert_eq!(err.kind(), ErrorKind::InvalidInput);
127127
// Check that it is the right kind of `InvalidInput`.
128128
assert_eq!(err.raw_os_error(), Some(libc::EINVAL));
129+
130+
// By providing an u64 of size 8 bytes the behavior differs between native hosts and Miri.
131+
let result = net::setsockopt(sockfd, libc::SOL_SOCKET, libc::SO_REUSEADDR, 1u64);
132+
match result {
133+
Err(err) => {
134+
// Check that this is the right error.
135+
assert_eq!(err.kind(), ErrorKind::InvalidInput);
136+
assert_eq!(err.raw_os_error(), Some(libc::EINVAL));
137+
}
138+
Ok(_) => {
139+
// Some native hosts just ignore too large inputs and only look at a prefix.
140+
// On Miri we require an exact size.
141+
assert!(!cfg!(miri));
142+
}
143+
}
129144
}
130145

131146
#[cfg(any(
@@ -174,18 +189,35 @@ fn test_bind_ipv4_invalid_addr_len() {
174189
let sockfd =
175190
unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() };
176191
let addr = net::sock_addr_ipv4(net::IPV4_LOCALHOST, 0);
192+
// A too small size is invalid.
177193
let err = unsafe {
178194
errno_result(libc::bind(
179195
sockfd,
180196
(&addr as *const libc::sockaddr_in).cast::<libc::sockaddr>(),
181-
// Add 1 to the address to make the size invalid.
182-
(size_of::<libc::sockaddr_in>() + 1) as libc::socklen_t,
197+
(size_of::<libc::sockaddr_in>() - 1) as libc::socklen_t,
183198
))
184199
.unwrap_err()
185200
};
186201
assert_eq!(err.kind(), ErrorKind::InvalidInput);
187202
// Check that it is the right kind of `InvalidInput`.
188203
assert_eq!(err.raw_os_error(), Some(libc::EINVAL));
204+
205+
if cfg!(miri) {
206+
// A too big size is also invalid. Some native hosts (e.g. Linux)
207+
// allow too big sizes, so we skip this test on native hosts:
208+
// <https://github.com/rust-lang/miri/pull/5059#discussion_r3305439221>
209+
let err = unsafe {
210+
errno_result(libc::bind(
211+
sockfd,
212+
(&addr as *const libc::sockaddr_in).cast::<libc::sockaddr>(),
213+
(size_of::<libc::sockaddr_in>() + 1) as libc::socklen_t,
214+
))
215+
.unwrap_err()
216+
};
217+
assert_eq!(err.kind(), ErrorKind::InvalidInput);
218+
// Check that it is the right kind of `InvalidInput`.
219+
assert_eq!(err.raw_os_error(), Some(libc::EINVAL));
220+
}
189221
}
190222

191223
fn test_bind_ipv6() {
@@ -719,48 +751,62 @@ fn test_shutdown_writable_after_read_close() {
719751
fn test_getsockopt_truncate() {
720752
let (sockfd, _) = net::make_listener_ipv4().unwrap();
721753

722-
// The actual TTL with a correctly sized buffer.
723-
let ttl = net::getsockopt::<libc::c_uint>(sockfd, libc::IPPROTO_IP, libc::IP_TTL).unwrap();
754+
// Set the read timeout for the socket.
755+
// We use a multiple of 4ms for the `usec` since Linux seems to do rounding.
756+
let new_timeout = libc::timeval { tv_sec: 123, tv_usec: 40_000 };
757+
net::setsockopt(sockfd, libc::SOL_SOCKET, libc::SO_RCVTIMEO, new_timeout).unwrap();
758+
759+
let mut option_value = std::mem::MaybeUninit::<[u8; 5]>::zeroed();
760+
// The actual `timeval` length is more than 5 bytes.
761+
let mut short_option_len = 5 as libc::socklen_t;
762+
assert!(short_option_len < size_of::<libc::timeval>() as libc::socklen_t);
724763

725-
let mut option_value = std::mem::MaybeUninit::<u32>::zeroed();
726-
// The actual length is 4 bytes.
727-
let mut short_option_len = 2 as libc::socklen_t;
764+
let timeout =
765+
net::getsockopt::<libc::timeval>(sockfd, libc::SOL_SOCKET, libc::SO_RCVTIMEO).unwrap();
766+
// Ensure that we get the same value back as we just set.
767+
assert_eq!(timeout.tv_sec, new_timeout.tv_sec);
768+
assert_eq!(timeout.tv_usec, new_timeout.tv_usec);
728769

729770
errno_result(unsafe {
730771
libc::getsockopt(
731772
sockfd,
732-
libc::IPPROTO_IP,
733-
libc::IP_TTL,
773+
libc::SOL_SOCKET,
774+
libc::SO_RCVTIMEO,
734775
option_value.as_mut_ptr().cast(),
735776
&mut short_option_len,
736777
)
737778
})
738779
.unwrap();
739780
// Ensure that the size wasn't changed.
740-
assert_eq!(short_option_len, 2);
741-
let short_ttl = unsafe { option_value.assume_init() };
781+
assert_eq!(short_option_len, 5);
782+
let truncated_timeout = unsafe { option_value.assume_init() };
742783

743-
// Assert that the value was silently truncated.
744-
assert_eq!(short_ttl.to_ne_bytes()[0..2], ttl.to_ne_bytes()[0..2]);
784+
unsafe {
785+
let timeout_ptr = (&new_timeout) as *const libc::timeval as *const u8;
786+
// Assert that the value was silently truncated.
787+
assert_eq!(&truncated_timeout, slice::from_raw_parts(timeout_ptr, 5));
788+
}
745789

746-
let mut option_value = std::mem::MaybeUninit::<u32>::zeroed();
747-
// The actual length is 4 bytes.
748-
let mut long_option_len = 6 as libc::socklen_t;
790+
let mut option_value = std::mem::MaybeUninit::<libc::timeval>::zeroed();
791+
// The actual length is smaller than this.
792+
let mut long_option_len = (size_of::<libc::timeval>() + 2) as libc::socklen_t;
749793

750794
errno_result(unsafe {
751795
libc::getsockopt(
752796
sockfd,
753-
libc::IPPROTO_IP,
754-
libc::IP_TTL,
797+
libc::SOL_SOCKET,
798+
libc::SO_RCVTIMEO,
755799
option_value.as_mut_ptr().cast(),
756800
&mut long_option_len,
757801
)
758802
})
759803
.unwrap();
760804
// Ensure that the size was shortened to the actual length.
761-
assert_eq!(long_option_len, 4);
762-
let long_ttl = unsafe { option_value.assume_init() };
763-
assert_eq!(long_ttl, ttl);
805+
assert_eq!(long_option_len, size_of::<libc::timeval>() as libc::socklen_t);
806+
// The returned timeout should be the same value as we just set.
807+
let untruncated_timeout = unsafe { option_value.assume_init() };
808+
assert_eq!(untruncated_timeout.tv_sec, new_timeout.tv_sec);
809+
assert_eq!(untruncated_timeout.tv_usec, new_timeout.tv_usec);
764810
}
765811

766812
/// Test setting and getting the SO_SNDTIMEO socket option.
@@ -781,8 +827,8 @@ fn test_sockopt_sndtimeo() {
781827
assert_eq!(timeout.tv_sec, 0);
782828
assert_eq!(timeout.tv_usec, 0);
783829

784-
// A 50 millisecond timeout.
785-
let short_timeout = libc::timeval { tv_sec: 0, tv_usec: 50_000 };
830+
// A 40 millisecond timeout.
831+
let short_timeout = libc::timeval { tv_sec: 0, tv_usec: 40_000 };
786832
net::setsockopt(client_sockfd, libc::SOL_SOCKET, libc::SO_SNDTIMEO, short_timeout).unwrap();
787833

788834
let timeout =
@@ -804,9 +850,9 @@ fn test_sockopt_sndtimeo() {
804850
// it's because of the write timeout exceeding because the write buffer
805851
// is full.
806852
Err(err) if err.kind() == ErrorKind::WouldBlock => {
807-
// The last write should return an EAGAIN/EWOULDBLOCK after ~50ms instead
853+
// The last write should return an EAGAIN/EWOULDBLOCK after ~40ms instead
808854
// of blocking indefinitely.
809-
assert!(Instant::now().duration_since(before) >= Duration::from_millis(50));
855+
assert!(Instant::now().duration_since(before) >= Duration::from_millis(40));
810856
break;
811857
}
812858
Err(err) => panic!("unexpected error whilst filling up buffer: {err}"),
@@ -832,8 +878,8 @@ fn test_sockopt_rcvtimeo() {
832878
assert_eq!(timeout.tv_sec, 0);
833879
assert_eq!(timeout.tv_usec, 0);
834880

835-
// A 50 millisecond timeout.
836-
let short_timeout = libc::timeval { tv_sec: 0, tv_usec: 50_000 };
881+
// A 40 millisecond timeout.
882+
let short_timeout = libc::timeval { tv_sec: 0, tv_usec: 40_000 };
837883
net::setsockopt(client_sockfd, libc::SOL_SOCKET, libc::SO_RCVTIMEO, short_timeout).unwrap();
838884

839885
let timeout =
@@ -851,6 +897,6 @@ fn test_sockopt_rcvtimeo() {
851897
.unwrap_err()
852898
};
853899
assert_eq!(err.kind(), ErrorKind::WouldBlock);
854-
// Ensure that we blocked for at least 50 milliseconds.
855-
assert!(Instant::now().duration_since(before) >= Duration::from_millis(50))
900+
// Ensure that we blocked for at least 40 milliseconds.
901+
assert!(Instant::now().duration_since(before) >= Duration::from_millis(40))
856902
}

0 commit comments

Comments
 (0)