@@ -20,6 +20,16 @@ use crate::*;
2020/// be configured in the real system.
2121const MAX_SOCKETPAIR_BUFFER_CAPACITY : usize = 212992 ;
2222
23+ #[ derive( Debug , PartialEq ) ]
24+ enum AnonSocketType {
25+ // Either end of the socketpair fd.
26+ Socketpair ,
27+ // Read end of the pipe.
28+ PipeRead ,
29+ // Write end of the pipe.
30+ PipeWrite ,
31+ }
32+
2333/// One end of a pair of connected unnamed sockets.
2434#[ derive( Debug ) ]
2535struct AnonSocket {
@@ -40,7 +50,10 @@ struct AnonSocket {
4050 /// A list of thread ids blocked because the buffer was full.
4151 /// Once another thread reads some bytes, these threads will be unblocked.
4252 blocked_write_tid : RefCell < Vec < ThreadId > > ,
43- is_nonblock : bool ,
53+ /// Whether this fd is non-blocking or not.
54+ is_nonblock : Cell < bool > ,
55+ // Differentiate between different AnonSocket fd types.
56+ fd_type : AnonSocketType ,
4457}
4558
4659#[ derive( Debug ) ]
@@ -63,7 +76,10 @@ impl AnonSocket {
6376
6477impl FileDescription for AnonSocket {
6578 fn name ( & self ) -> & ' static str {
66- "socketpair"
79+ match self . fd_type {
80+ AnonSocketType :: Socketpair => "socketpair" ,
81+ AnonSocketType :: PipeRead | AnonSocketType :: PipeWrite => "pipe" ,
82+ }
6783 }
6884
6985 fn close < ' tcx > (
@@ -110,6 +126,66 @@ impl FileDescription for AnonSocket {
110126 fn as_unix < ' tcx > ( & self , _ecx : & MiriInterpCx < ' tcx > ) -> & dyn UnixFileDescription {
111127 self
112128 }
129+
130+ fn get_flags < ' tcx > ( & self , ecx : & mut MiriInterpCx < ' tcx > ) -> InterpResult < ' tcx , Scalar > {
131+ let mut flags = 0 ;
132+
133+ // Get flag for file access mode.
134+ // The flag for both socketpair and pipe will remain the same even when the peer
135+ // fd is closed, so we need to look at the original type of this socket, not at whether
136+ // the peer socket still exists.
137+ match self . fd_type {
138+ AnonSocketType :: Socketpair => {
139+ flags |= ecx. eval_libc_i32 ( "O_RDWR" ) ;
140+ }
141+ AnonSocketType :: PipeRead => {
142+ flags |= ecx. eval_libc_i32 ( "O_RDONLY" ) ;
143+ }
144+ AnonSocketType :: PipeWrite => {
145+ flags |= ecx. eval_libc_i32 ( "O_WRONLY" ) ;
146+ }
147+ }
148+
149+ // Get flag for blocking status.
150+ if self . is_nonblock . get ( ) {
151+ flags |= ecx. eval_libc_i32 ( "O_NONBLOCK" ) ;
152+ }
153+
154+ interp_ok ( Scalar :: from_i32 ( flags) )
155+ }
156+
157+ fn set_flags < ' tcx > (
158+ & self ,
159+ mut flag : i32 ,
160+ ecx : & mut MiriInterpCx < ' tcx > ,
161+ ) -> InterpResult < ' tcx , Scalar > {
162+ // FIXME: File creation flags should be ignored.
163+
164+ let o_nonblock = ecx. eval_libc_i32 ( "O_NONBLOCK" ) ;
165+ let o_rdonly = ecx. eval_libc_i32 ( "O_RDONLY" ) ;
166+ let o_wronly = ecx. eval_libc_i32 ( "O_WRONLY" ) ;
167+ let o_rdwr = ecx. eval_libc_i32 ( "O_RDWR" ) ;
168+
169+ // O_NONBLOCK flag can be set / unset by user.
170+ if flag & o_nonblock == o_nonblock {
171+ self . is_nonblock . set ( true ) ;
172+ flag &= !o_nonblock;
173+ } else {
174+ self . is_nonblock . set ( false ) ;
175+ }
176+
177+ // Ignore all file access mode flags.
178+ flag &= !( o_rdonly | o_wronly | o_rdwr) ;
179+
180+ // Throw error if there is any unsupported flag.
181+ if flag != 0 {
182+ throw_unsup_format ! (
183+ "fcntl: only O_NONBLOCK is supported for F_SETFL on socketpairs and pipes"
184+ )
185+ }
186+
187+ interp_ok ( Scalar :: from_i32 ( 0 ) )
188+ }
113189}
114190
115191/// Write to AnonSocket based on the space available and return the written byte size.
@@ -141,7 +217,7 @@ fn anonsocket_write<'tcx>(
141217 // Let's see if we can write.
142218 let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY . strict_sub ( writebuf. borrow ( ) . buf . len ( ) ) ;
143219 if available_space == 0 {
144- if self_ref. is_nonblock {
220+ if self_ref. is_nonblock . get ( ) {
145221 // Non-blocking socketpair with a full buffer.
146222 return finish. call ( ecx, Err ( ErrorKind :: WouldBlock . into ( ) ) ) ;
147223 } else {
@@ -223,7 +299,7 @@ fn anonsocket_read<'tcx>(
223299 // Socketpair with no peer and empty buffer.
224300 // 0 bytes successfully read indicates end-of-file.
225301 return finish. call ( ecx, Ok ( 0 ) ) ;
226- } else if self_ref. is_nonblock {
302+ } else if self_ref. is_nonblock . get ( ) {
227303 // Non-blocking socketpair with writer and empty buffer.
228304 // https://linux.die.net/man/2/read
229305 // EAGAIN or EWOULDBLOCK can be returned for socket,
@@ -407,15 +483,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
407483 peer_lost_data : Cell :: new ( false ) ,
408484 blocked_read_tid : RefCell :: new ( Vec :: new ( ) ) ,
409485 blocked_write_tid : RefCell :: new ( Vec :: new ( ) ) ,
410- is_nonblock : is_sock_nonblock,
486+ is_nonblock : Cell :: new ( is_sock_nonblock) ,
487+ fd_type : AnonSocketType :: Socketpair ,
411488 } ) ;
412489 let fd1 = fds. new_ref ( AnonSocket {
413490 readbuf : Some ( RefCell :: new ( Buffer :: new ( ) ) ) ,
414491 peer_fd : OnceCell :: new ( ) ,
415492 peer_lost_data : Cell :: new ( false ) ,
416493 blocked_read_tid : RefCell :: new ( Vec :: new ( ) ) ,
417494 blocked_write_tid : RefCell :: new ( Vec :: new ( ) ) ,
418- is_nonblock : is_sock_nonblock,
495+ is_nonblock : Cell :: new ( is_sock_nonblock) ,
496+ fd_type : AnonSocketType :: Socketpair ,
419497 } ) ;
420498
421499 // Make the file descriptions point to each other.
@@ -475,15 +553,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
475553 peer_lost_data : Cell :: new ( false ) ,
476554 blocked_read_tid : RefCell :: new ( Vec :: new ( ) ) ,
477555 blocked_write_tid : RefCell :: new ( Vec :: new ( ) ) ,
478- is_nonblock,
556+ is_nonblock : Cell :: new ( is_nonblock) ,
557+ fd_type : AnonSocketType :: PipeRead ,
479558 } ) ;
480559 let fd1 = fds. new_ref ( AnonSocket {
481560 readbuf : None ,
482561 peer_fd : OnceCell :: new ( ) ,
483562 peer_lost_data : Cell :: new ( false ) ,
484563 blocked_read_tid : RefCell :: new ( Vec :: new ( ) ) ,
485564 blocked_write_tid : RefCell :: new ( Vec :: new ( ) ) ,
486- is_nonblock,
565+ is_nonblock : Cell :: new ( is_nonblock) ,
566+ fd_type : AnonSocketType :: PipeWrite ,
487567 } ) ;
488568
489569 // Make the file descriptions point to each other.
0 commit comments