Skip to content

Commit 49101c1

Browse files
committed
Auto merge of #3960 - tiif:smallchange, r=RalfJung
Pipe minor changes: diagnostics, flag support and comments This PR: - Add the exact syscall names to the blocking not supported diagnostic - Added support for ``pipe2`` ``O_NONBLOCK`` - Fix minor comment error in ``tests/pass-dep/libc/libc-epoll-blocking.rs`` Fixes #3912
2 parents bdc100f + 573ba32 commit 49101c1

File tree

7 files changed

+68
-25
lines changed

7 files changed

+68
-25
lines changed

ci/ci.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,10 @@ case $HOST_TARGET in
150150
# Partially supported targets (tier 2)
151151
BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
152152
UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
153-
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs
154-
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs
155-
TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls
156-
TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls
153+
TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
154+
TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
155+
TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe
156+
TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe
157157
TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap pthread --skip threadname
158158
TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm
159159
TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std

src/shims/unix/foreign_items.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
292292
this.write_scalar(result, dest)?;
293293
}
294294
"pipe2" => {
295+
// Currently this function does not exist on all Unixes, e.g. on macOS.
296+
if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos") {
297+
throw_unsup_format!(
298+
"`pipe2` is not supported on {}",
299+
this.tcx.sess.target.os
300+
);
301+
}
295302
let [pipefd, flags] =
296303
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
297304
let result = this.pipe2(pipefd, Some(flags))?;

src/shims/unix/unnamed_socket.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ impl FileDescription for AnonSocket {
163163
} else {
164164
// Blocking socketpair with writer and empty buffer.
165165
// FIXME: blocking is currently not supported
166-
throw_unsup_format!("socketpair read: blocking isn't supported yet");
166+
throw_unsup_format!("socketpair/pipe/pipe2 read: blocking isn't supported yet");
167167
}
168168
}
169169
}
@@ -230,7 +230,7 @@ impl FileDescription for AnonSocket {
230230
return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest);
231231
} else {
232232
// Blocking socketpair with a full buffer.
233-
throw_unsup_format!("socketpair write: blocking isn't supported yet");
233+
throw_unsup_format!("socketpair/pipe/pipe2 write: blocking isn't supported yet");
234234
}
235235
}
236236
// Remember this clock so `read` can synchronize with us.
@@ -267,21 +267,24 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
267267
let this = self.eval_context_mut();
268268

269269
let domain = this.read_scalar(domain)?.to_i32()?;
270-
let mut type_ = this.read_scalar(type_)?.to_i32()?;
270+
let mut flags = this.read_scalar(type_)?.to_i32()?;
271271
let protocol = this.read_scalar(protocol)?.to_i32()?;
272272
let sv = this.deref_pointer(sv)?;
273273

274274
let mut is_sock_nonblock = false;
275275

276-
// Parse and remove the type flags that we support.
277-
// SOCK_NONBLOCK only exists on Linux.
276+
// Interpret the flag. Every flag we recognize is "subtracted" from `flags`, so
277+
// if there is anything left at the end, that's an unsupported flag.
278278
if this.tcx.sess.target.os == "linux" {
279-
if type_ & this.eval_libc_i32("SOCK_NONBLOCK") == this.eval_libc_i32("SOCK_NONBLOCK") {
279+
// SOCK_NONBLOCK only exists on Linux.
280+
let sock_nonblock = this.eval_libc_i32("SOCK_NONBLOCK");
281+
let sock_cloexec = this.eval_libc_i32("SOCK_CLOEXEC");
282+
if flags & sock_nonblock == sock_nonblock {
280283
is_sock_nonblock = true;
281-
type_ &= !(this.eval_libc_i32("SOCK_NONBLOCK"));
284+
flags &= !sock_nonblock;
282285
}
283-
if type_ & this.eval_libc_i32("SOCK_CLOEXEC") == this.eval_libc_i32("SOCK_CLOEXEC") {
284-
type_ &= !(this.eval_libc_i32("SOCK_CLOEXEC"));
286+
if flags & sock_cloexec == sock_cloexec {
287+
flags &= !sock_cloexec;
285288
}
286289
}
287290

@@ -294,11 +297,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
294297
and AF_LOCAL are allowed",
295298
domain
296299
);
297-
} else if type_ != this.eval_libc_i32("SOCK_STREAM") {
300+
} else if flags != this.eval_libc_i32("SOCK_STREAM") {
298301
throw_unsup_format!(
299302
"socketpair: type {:#x} is unsupported, only SOCK_STREAM, \
300303
SOCK_CLOEXEC and SOCK_NONBLOCK are allowed",
301-
type_
304+
flags
302305
);
303306
} else if protocol != 0 {
304307
throw_unsup_format!(
@@ -347,14 +350,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
347350
let this = self.eval_context_mut();
348351

349352
let pipefd = this.deref_pointer_as(pipefd, this.machine.layouts.i32)?;
350-
let flags = match flags {
353+
let mut flags = match flags {
351354
Some(flags) => this.read_scalar(flags)?.to_i32()?,
352355
None => 0,
353356
};
354357

355-
// As usual we ignore CLOEXEC.
356358
let cloexec = this.eval_libc_i32("O_CLOEXEC");
357-
if flags != 0 && flags != cloexec {
359+
let o_nonblock = this.eval_libc_i32("O_NONBLOCK");
360+
361+
// Interpret the flag. Every flag we recognize is "subtracted" from `flags`, so
362+
// if there is anything left at the end, that's an unsupported flag.
363+
let mut is_nonblock = false;
364+
if flags & o_nonblock == o_nonblock {
365+
is_nonblock = true;
366+
flags &= !o_nonblock;
367+
}
368+
// As usual we ignore CLOEXEC.
369+
if flags & cloexec == cloexec {
370+
flags &= !cloexec;
371+
}
372+
if flags != 0 {
358373
throw_unsup_format!("unsupported flags in `pipe2`");
359374
}
360375

@@ -365,13 +380,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
365380
readbuf: Some(RefCell::new(Buffer::new())),
366381
peer_fd: OnceCell::new(),
367382
peer_lost_data: Cell::new(false),
368-
is_nonblock: false,
383+
is_nonblock,
369384
});
370385
let fd1 = fds.new_ref(AnonSocket {
371386
readbuf: None,
372387
peer_fd: OnceCell::new(),
373388
peer_lost_data: Cell::new(false),
374-
is_nonblock: false,
389+
is_nonblock,
375390
});
376391

377392
// Make the file descriptions point to each other.

tests/fail-dep/libc/socketpair_read_blocking.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: unsupported operation: socketpair read: blocking isn't supported yet
1+
error: unsupported operation: socketpair/pipe/pipe2 read: blocking isn't supported yet
22
--> tests/fail-dep/libc/socketpair_read_blocking.rs:LL:CC
33
|
44
LL | let _res = unsafe { libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair read: blocking isn't supported yet
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair/pipe/pipe2 read: blocking isn't supported yet
66
|
77
= help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
88
= note: BACKTRACE:

tests/fail-dep/libc/socketpair_write_blocking.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: unsupported operation: socketpair write: blocking isn't supported yet
1+
error: unsupported operation: socketpair/pipe/pipe2 write: blocking isn't supported yet
22
--> tests/fail-dep/libc/socketpair_write_blocking.rs:LL:CC
33
|
44
LL | let _ = unsafe { libc::write(fds[0], data as *const libc::c_void, 3) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair write: blocking isn't supported yet
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ socketpair/pipe/pipe2 write: blocking isn't supported yet
66
|
77
= help: this is likely not a bug in the program; it indicates that the program performed an operation that Miri does not support
88
= note: BACKTRACE:

tests/pass-dep/libc/libc-epoll-blocking.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ fn test_epoll_race() {
161161
// Write to the eventfd instance.
162162
let sized_8_data: [u8; 8] = 1_u64.to_ne_bytes();
163163
let res = unsafe { libc::write(fd, sized_8_data.as_ptr() as *const libc::c_void, 8) };
164-
// read returns number of bytes that have been read, which is always 8.
164+
// write returns number of bytes written, which is always 8.
165165
assert_eq!(res, 8);
166166
});
167167
thread::yield_now();

tests/pass-dep/libc/libc-pipe.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ fn main() {
77
test_pipe_threaded();
88
test_race();
99
test_pipe_array();
10+
#[cfg(any(
11+
target_os = "linux",
12+
target_os = "illumos",
13+
target_os = "freebsd",
14+
target_os = "solaris"
15+
))]
16+
// `pipe2` only exists in some specific os.
17+
test_pipe2();
1018
}
1119

1220
fn test_pipe() {
@@ -110,3 +118,16 @@ fn test_pipe_array() {
110118
let mut fds: [i32; 2] = [0; 2];
111119
assert_eq!(unsafe { pipe(&mut fds) }, 0);
112120
}
121+
122+
/// Test if pipe2 (including the O_NONBLOCK flag) is supported.
123+
#[cfg(any(
124+
target_os = "linux",
125+
target_os = "illumos",
126+
target_os = "freebsd",
127+
target_os = "solaris"
128+
))]
129+
fn test_pipe2() {
130+
let mut fds = [-1, -1];
131+
let res = unsafe { libc::pipe2(fds.as_mut_ptr(), libc::O_NONBLOCK) };
132+
assert_eq!(res, 0);
133+
}

0 commit comments

Comments
 (0)