@@ -20,6 +20,16 @@ use crate::*;
20
20
/// be configured in the real system.
21
21
const MAX_SOCKETPAIR_BUFFER_CAPACITY : usize = 212992 ;
22
22
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
+
23
33
/// One end of a pair of connected unnamed sockets.
24
34
#[ derive( Debug ) ]
25
35
struct AnonSocket {
@@ -40,7 +50,10 @@ struct AnonSocket {
40
50
/// A list of thread ids blocked because the buffer was full.
41
51
/// Once another thread reads some bytes, these threads will be unblocked.
42
52
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 ,
44
57
}
45
58
46
59
#[ derive( Debug ) ]
@@ -63,7 +76,10 @@ impl AnonSocket {
63
76
64
77
impl FileDescription for AnonSocket {
65
78
fn name ( & self ) -> & ' static str {
66
- "socketpair"
79
+ match self . fd_type {
80
+ AnonSocketType :: Socketpair => "socketpair" ,
81
+ AnonSocketType :: PipeRead | AnonSocketType :: PipeWrite => "pipe" ,
82
+ }
67
83
}
68
84
69
85
fn close < ' tcx > (
@@ -110,6 +126,66 @@ impl FileDescription for AnonSocket {
110
126
fn as_unix < ' tcx > ( & self , _ecx : & MiriInterpCx < ' tcx > ) -> & dyn UnixFileDescription {
111
127
self
112
128
}
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
+ }
113
189
}
114
190
115
191
/// Write to AnonSocket based on the space available and return the written byte size.
@@ -141,7 +217,7 @@ fn anonsocket_write<'tcx>(
141
217
// Let's see if we can write.
142
218
let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY . strict_sub ( writebuf. borrow ( ) . buf . len ( ) ) ;
143
219
if available_space == 0 {
144
- if self_ref. is_nonblock {
220
+ if self_ref. is_nonblock . get ( ) {
145
221
// Non-blocking socketpair with a full buffer.
146
222
return finish. call ( ecx, Err ( ErrorKind :: WouldBlock . into ( ) ) ) ;
147
223
} else {
@@ -223,7 +299,7 @@ fn anonsocket_read<'tcx>(
223
299
// Socketpair with no peer and empty buffer.
224
300
// 0 bytes successfully read indicates end-of-file.
225
301
return finish. call ( ecx, Ok ( 0 ) ) ;
226
- } else if self_ref. is_nonblock {
302
+ } else if self_ref. is_nonblock . get ( ) {
227
303
// Non-blocking socketpair with writer and empty buffer.
228
304
// https://linux.die.net/man/2/read
229
305
// EAGAIN or EWOULDBLOCK can be returned for socket,
@@ -407,15 +483,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
407
483
peer_lost_data : Cell :: new ( false ) ,
408
484
blocked_read_tid : RefCell :: new ( Vec :: new ( ) ) ,
409
485
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 ,
411
488
} ) ;
412
489
let fd1 = fds. new_ref ( AnonSocket {
413
490
readbuf : Some ( RefCell :: new ( Buffer :: new ( ) ) ) ,
414
491
peer_fd : OnceCell :: new ( ) ,
415
492
peer_lost_data : Cell :: new ( false ) ,
416
493
blocked_read_tid : RefCell :: new ( Vec :: new ( ) ) ,
417
494
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 ,
419
497
} ) ;
420
498
421
499
// Make the file descriptions point to each other.
@@ -475,15 +553,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
475
553
peer_lost_data : Cell :: new ( false ) ,
476
554
blocked_read_tid : RefCell :: new ( Vec :: new ( ) ) ,
477
555
blocked_write_tid : RefCell :: new ( Vec :: new ( ) ) ,
478
- is_nonblock,
556
+ is_nonblock : Cell :: new ( is_nonblock) ,
557
+ fd_type : AnonSocketType :: PipeRead ,
479
558
} ) ;
480
559
let fd1 = fds. new_ref ( AnonSocket {
481
560
readbuf : None ,
482
561
peer_fd : OnceCell :: new ( ) ,
483
562
peer_lost_data : Cell :: new ( false ) ,
484
563
blocked_read_tid : RefCell :: new ( Vec :: new ( ) ) ,
485
564
blocked_write_tid : RefCell :: new ( Vec :: new ( ) ) ,
486
- is_nonblock,
565
+ is_nonblock : Cell :: new ( is_nonblock) ,
566
+ fd_type : AnonSocketType :: PipeWrite ,
487
567
} ) ;
488
568
489
569
// Make the file descriptions point to each other.
0 commit comments