|
| 1 | +//@only-target: linux |
| 2 | +// ensure single way to order the thread tests |
| 3 | +//@compile-flags: -Zmiri-preemption-rate=0 |
| 4 | + |
| 5 | +use std::convert::TryInto; |
| 6 | +use std::thread; |
| 7 | +use std::thread::spawn; |
| 8 | + |
| 9 | +#[track_caller] |
| 10 | +fncheck_epoll_wait<constN:usize>(epfd:i32,expected_notifications:&[(u32,u64)]){ |
| 11 | +let epoll_event = libc::epoll_event{events:0,u64:0}; |
| 12 | +letmut array:[libc::epoll_event;N] = [epoll_event;N]; |
| 13 | +let maxsize = N; |
| 14 | +let array_ptr = array.as_mut_ptr(); |
| 15 | +let res = unsafe{ libc::epoll_wait(epfd, array_ptr, maxsize.try_into().unwrap(),0)}; |
| 16 | +if res < 0{ |
| 17 | +panic!("epoll_wait failed: {}", std::io::Error::last_os_error()); |
| 18 | +} |
| 19 | +assert_eq!( |
| 20 | + res, |
| 21 | + expected_notifications.len().try_into().unwrap(), |
| 22 | +"got wrong number of notifications" |
| 23 | +); |
| 24 | +let slice = unsafe{ std::slice::from_raw_parts(array_ptr, res.try_into().unwrap())}; |
| 25 | +for(return_event, expected_event)in slice.iter().zip(expected_notifications.iter()){ |
| 26 | +let event = return_event.events; |
| 27 | +let data = return_event.u64; |
| 28 | +assert_eq!(event, expected_event.0,"got wrong events"); |
| 29 | +assert_eq!(data, expected_event.1,"got wrong data"); |
| 30 | +} |
| 31 | +} |
| 32 | + |
| 33 | +fncommon_setup() -> (i32,[i32;2],[i32;2]){ |
| 34 | +// Create an epoll instance. |
| 35 | +let epfd = unsafe{ libc::epoll_create1(0)}; |
| 36 | +assert_ne!(epfd, -1); |
| 37 | + |
| 38 | +// Create two socketpair instances. |
| 39 | +letmut fds_a = [-1, -1]; |
| 40 | +let res = unsafe{ libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM,0, fds_a.as_mut_ptr())}; |
| 41 | +assert_eq!(res,0); |
| 42 | + |
| 43 | +letmut fds_b = [-1, -1]; |
| 44 | +let res = unsafe{ libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM,0, fds_b.as_mut_ptr())}; |
| 45 | +assert_eq!(res,0); |
| 46 | + |
| 47 | +// Register both pipe read ends. |
| 48 | +letmut ev = libc::epoll_event{ |
| 49 | +events:(libc::EPOLLIN | libc::EPOLLET)as_, |
| 50 | +u64: u64::try_from(fds_a[1]).unwrap(), |
| 51 | +}; |
| 52 | +let res = unsafe{ libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds_a[1],&mut ev)}; |
| 53 | +assert_eq!(res,0); |
| 54 | + |
| 55 | +letmut ev = libc::epoll_event{ |
| 56 | +events:(libc::EPOLLIN | libc::EPOLLET)as_, |
| 57 | +u64: u64::try_from(fds_b[1]).unwrap(), |
| 58 | +}; |
| 59 | +let res = unsafe{ libc::epoll_ctl(epfd, libc::EPOLL_CTL_ADD, fds_b[1],&mut ev)}; |
| 60 | +assert_eq!(res,0); |
| 61 | + |
| 62 | +(epfd, fds_a, fds_b) |
| 63 | +} |
| 64 | + |
| 65 | +// Test that the clock sync that happens through an epoll_wait only synchronizes with the clock(s) |
| 66 | +// that were reported. It is possible more events had become ready but the epoll_wait didn't |
| 67 | +// provide room for them all. |
| 68 | +// |
| 69 | +// Well before the fix, this fails to report UB. |
| 70 | +fnmain(){ |
| 71 | +let(epfd, fds_a, fds_b) = common_setup(); |
| 72 | + |
| 73 | +staticmutVAL_ONE:u8 = 40;// This one will be read soundly. |
| 74 | +staticmutVAL_TWO:u8 = 50;// This one will be read unsoundly. |
| 75 | +let thread1 = spawn(move || { |
| 76 | +unsafe{VAL_ONE = 41}; |
| 77 | + |
| 78 | +let data = "abcde".as_bytes().as_ptr(); |
| 79 | +let res = unsafe{ libc::write(fds_a[0], data as*const libc::c_void,5)}; |
| 80 | +assert_eq!(res,5); |
| 81 | + |
| 82 | +unsafe{VAL_TWO = 51}; |
| 83 | + |
| 84 | +let res = unsafe{ libc::write(fds_b[0], data as*const libc::c_void,5)}; |
| 85 | +assert_eq!(res,5); |
| 86 | +}); |
| 87 | + thread::yield_now(); |
| 88 | + |
| 89 | +// With room for one event: check result from epoll_wait. |
| 90 | +let expected_event = u32::try_from(libc::EPOLLIN).unwrap(); |
| 91 | +let expected_value = u64::try_from(fds_a[1]).unwrap(); |
| 92 | +check_epoll_wait::<1>(epfd,&[(expected_event, expected_value)]); |
| 93 | + |
| 94 | +#[allow(static_mut_refs)] |
| 95 | +unsafe{ |
| 96 | +assert_eq!(VAL_ONE,41)// This one is not UB |
| 97 | +}; |
| 98 | +#[allow(static_mut_refs)] |
| 99 | +unsafe{ |
| 100 | +assert_eq!(VAL_TWO,51)// This one should be UB but isn't (yet). |
| 101 | +}; |
| 102 | + |
| 103 | + thread1.join().unwrap(); |
| 104 | +} |
0 commit comments