Skip to content

Commit 69512c7

Browse files
committed
Follow up fix for eventfd shim
1 parent b5ae8bd commit 69512c7

File tree

4 files changed

+30
-23
lines changed

4 files changed

+30
-23
lines changed

Diff for: src/tools/miri/src/shims/unix/linux/eventfd.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Linux `eventfd` implementation.
22
use std::io;
33
use std::io::{Error, ErrorKind};
4+
use std::mem;
45

56
use rustc_target::abi::Endian;
67

@@ -9,8 +10,8 @@ use crate::{concurrency::VClock, *};
910

1011
use self::shims::unix::fd::FileDescriptor;
1112

12-
/// Minimum size of u8 array to hold u64 value.
13-
const U64_MIN_ARRAY_SIZE: usize = 8;
13+
// We'll only do reads and writes in chunks of size u64.
14+
const U64_ARRAY_SIZE: usize = mem::size_of::<u64>();
1415

1516
/// Maximum value that the eventfd counter can hold.
1617
const MAX_COUNTER: u64 = u64::MAX - 1;
@@ -51,7 +52,7 @@ impl FileDescription for Event {
5152
ecx: &mut MiriInterpCx<'tcx>,
5253
) -> InterpResult<'tcx, io::Result<usize>> {
5354
// Check the size of slice, and return error only if the size of the slice < 8.
54-
let Some(bytes) = bytes.first_chunk_mut::<U64_MIN_ARRAY_SIZE>() else {
55+
let Some(bytes) = bytes.first_chunk_mut::<U64_ARRAY_SIZE>() else {
5556
return Ok(Err(Error::from(ErrorKind::InvalidInput)));
5657
};
5758
// Block when counter == 0.
@@ -63,15 +64,15 @@ impl FileDescription for Event {
6364
throw_unsup_format!("eventfd: blocking is unsupported");
6465
}
6566
} else {
66-
// Prevent false alarm in data race detection when doing synchronisation via eventfd.
67+
// Synchronize with all prior `write` calls to this FD.
6768
ecx.acquire_clock(&self.clock);
6869
// Return the counter in the host endianness using the buffer provided by caller.
6970
*bytes = match ecx.tcx.sess.target.endian {
7071
Endian::Little => self.counter.to_le_bytes(),
7172
Endian::Big => self.counter.to_be_bytes(),
7273
};
7374
self.counter = 0;
74-
return Ok(Ok(U64_MIN_ARRAY_SIZE));
75+
return Ok(Ok(U64_ARRAY_SIZE));
7576
}
7677
}
7778

@@ -94,7 +95,7 @@ impl FileDescription for Event {
9495
ecx: &mut MiriInterpCx<'tcx>,
9596
) -> InterpResult<'tcx, io::Result<usize>> {
9697
// Check the size of slice, and return error only if the size of the slice < 8.
97-
let Some(bytes) = bytes.first_chunk::<U64_MIN_ARRAY_SIZE>() else {
98+
let Some(bytes) = bytes.first_chunk::<U64_ARRAY_SIZE>() else {
9899
return Ok(Err(Error::from(ErrorKind::InvalidInput)));
99100
};
100101
// Convert from bytes to int according to host endianness.
@@ -110,8 +111,10 @@ impl FileDescription for Event {
110111
// Else, block.
111112
match self.counter.checked_add(num) {
112113
Some(new_count @ 0..=MAX_COUNTER) => {
113-
// Prevent false alarm in data race detection when doing synchronisation via eventfd.
114-
self.clock.join(&ecx.release_clock().unwrap());
114+
// Future `read` calls will synchronize with this write, so update the FD clock.
115+
if let Some(clock) = &ecx.release_clock() {
116+
self.clock.join(clock);
117+
}
115118
self.counter = new_count;
116119
}
117120
None | Some(u64::MAX) => {
@@ -123,7 +126,7 @@ impl FileDescription for Event {
123126
}
124127
}
125128
};
126-
Ok(Ok(U64_MIN_ARRAY_SIZE))
129+
Ok(Ok(U64_ARRAY_SIZE))
127130
}
128131
}
129132

@@ -163,19 +166,18 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
163166
}
164167

165168
let mut is_nonblock = false;
166-
// Unload the flag that we support.
169+
// Unset the flag that we support.
167170
// After unloading, flags != 0 means other flags are used.
168171
if flags & efd_cloexec == efd_cloexec {
172+
// cloexec is ignored because Miri does not support exec.
169173
flags &= !efd_cloexec;
170174
}
171175
if flags & efd_nonblock == efd_nonblock {
172176
flags &= !efd_nonblock;
173177
is_nonblock = true;
174178
}
175179
if flags != 0 {
176-
let einval = this.eval_libc("EINVAL");
177-
this.set_last_error(einval)?;
178-
return Ok(Scalar::from_i32(-1));
180+
throw_unsup_format!("eventfd: encountered unknown unsupported flags {:#x}", flags);
179181
}
180182

181183
let fd = this.machine.fds.insert_fd(FileDescriptor::new(Event {

Diff for: src/tools/miri/tests/fail-dep/libc/libc_eventfd_read_block.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//@ignore-target-windows: No eventfd on Windows
2-
//@ignore-target-apple: No eventfd in macos
1+
//@only-target-linux
32
fn main() {
43
// eventfd read will block when EFD_NONBLOCK flag is clear and counter = 0.
54
// This will pass when blocking is implemented.

Diff for: src/tools/miri/tests/fail-dep/libc/libc_eventfd_write_block.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//@ignore-target-windows: No eventfd on Windows
2-
//@ignore-target-apple: No eventfd in macos
1+
//@only-target-linux
32
fn main() {
43
// eventfd write will block when EFD_NONBLOCK flag is clear
54
// and the addition caused counter to exceed u64::MAX - 1.

Diff for: src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
//@ignore-target-windows: No eventfd in windows
2-
//@ignore-target-apple: No eventfd in macos
1+
//@only-target-linux
32
// test_race depends on a deterministic schedule.
43
//@compile-flags: -Zmiri-preemption-rate=0
54

@@ -42,9 +41,11 @@ fn test_read_write() {
4241
// value -1.
4342
let mut buf: [u8; 8] = [0; 8];
4443
let res = read_bytes(fd, &mut buf);
44+
let e = std::io::Error::last_os_error();
45+
assert_eq!(e.raw_os_error(), Some(libc::EAGAIN));
4546
assert_eq!(res, -1);
4647

47-
// Write with supplied buffer that > 8 bytes should be allowed.
48+
// Write with supplied buffer bigger than 8 bytes should be allowed.
4849
let sized_9_data: [u8; 9];
4950
if cfg!(target_endian = "big") {
5051
// Adjust the data based on the endianness of host system.
@@ -55,26 +56,32 @@ fn test_read_write() {
5556
let res = write_bytes(fd, sized_9_data);
5657
assert_eq!(res, 8);
5758

58-
// Read with supplied buffer that < 8 bytes should fail with return
59+
// Read with supplied buffer smaller than 8 bytes should fail with return
5960
// value -1.
6061
let mut buf: [u8; 7] = [1; 7];
6162
let res = read_bytes(fd, &mut buf);
63+
let e = std::io::Error::last_os_error();
64+
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
6265
assert_eq!(res, -1);
6366

64-
// Write with supplied buffer that < 8 bytes should fail with return
67+
// Write with supplied buffer smaller than 8 bytes should fail with return
6568
// value -1.
6669
let size_7_data: [u8; 7] = [1; 7];
6770
let res = write_bytes(fd, size_7_data);
71+
let e = std::io::Error::last_os_error();
72+
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
6873
assert_eq!(res, -1);
6974

70-
// Read with supplied buffer > 8 bytes should be allowed.
75+
// Read with supplied buffer bigger than 8 bytes should be allowed.
7176
let mut buf: [u8; 9] = [1; 9];
7277
let res = read_bytes(fd, &mut buf);
7378
assert_eq!(res, 8);
7479

7580
// Write u64::MAX should fail.
7681
let u64_max_bytes: [u8; 8] = [255; 8];
7782
let res = write_bytes(fd, u64_max_bytes);
83+
let e = std::io::Error::last_os_error();
84+
assert_eq!(e.raw_os_error(), Some(libc::EINVAL));
7885
assert_eq!(res, -1);
7986
}
8087

0 commit comments

Comments
 (0)