22//! are entirely implemented inside Miri.
33//! We also use the same infrastructure to implement unnamed pipes.
44
5- use std:: cell:: { OnceCell , RefCell } ;
5+ use std:: cell:: { Cell , OnceCell , RefCell } ;
66use std:: collections:: VecDeque ;
77use std:: io;
88use std:: io:: { Error , ErrorKind , Read } ;
@@ -27,6 +27,10 @@ struct AnonSocket {
2727 /// writing to. This is a weak reference because the other side may be closed before us; all
2828 /// future writes will then trigger EPIPE.
2929 peer_fd : OnceCell < WeakFileDescriptionRef > ,
30+ /// Indicates whether the peer has lost data when the file description is closed.
31+ /// This flag is set to `true` if the peer's `readbuf` is non-empty at the time
32+ /// of closure.
33+ peer_lost_data : Cell < bool > ,
3034 is_nonblock : bool ,
3135}
3236
@@ -91,6 +95,10 @@ impl FileDescription for AnonSocket {
9195 // for read and write.
9296 epoll_ready_events. epollin = true ;
9397 epoll_ready_events. epollout = true ;
98+ // If there is data lost in peer_fd, set EPOLLERR.
99+ if self . peer_lost_data . get ( ) {
100+ epoll_ready_events. epollerr = true ;
101+ }
94102 }
95103 Ok ( epoll_ready_events)
96104 }
@@ -101,6 +109,13 @@ impl FileDescription for AnonSocket {
101109 ecx : & mut MiriInterpCx < ' tcx > ,
102110 ) -> InterpResult < ' tcx , io:: Result < ( ) > > {
103111 if let Some ( peer_fd) = self . peer_fd ( ) . upgrade ( ) {
112+ // If the current readbuf is non-empty when the file description is closed,
113+ // notify the peer that data lost has happened in current file description.
114+ if let Some ( readbuf) = & self . readbuf {
115+ if !readbuf. borrow ( ) . buf . is_empty ( ) {
116+ peer_fd. downcast :: < AnonSocket > ( ) . unwrap ( ) . peer_lost_data . set ( true ) ;
117+ }
118+ }
104119 // Notify peer fd that close has happened, since that can unblock reads and writes.
105120 ecx. check_and_update_readiness ( & peer_fd) ?;
106121 }
@@ -290,11 +305,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
290305 let fd0 = fds. new_ref ( AnonSocket {
291306 readbuf : Some ( RefCell :: new ( Buffer :: new ( ) ) ) ,
292307 peer_fd : OnceCell :: new ( ) ,
308+ peer_lost_data : Cell :: new ( false ) ,
293309 is_nonblock : is_sock_nonblock,
294310 } ) ;
295311 let fd1 = fds. new_ref ( AnonSocket {
296312 readbuf : Some ( RefCell :: new ( Buffer :: new ( ) ) ) ,
297313 peer_fd : OnceCell :: new ( ) ,
314+ peer_lost_data : Cell :: new ( false ) ,
298315 is_nonblock : is_sock_nonblock,
299316 } ) ;
300317
@@ -340,10 +357,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
340357 let fd0 = fds. new_ref ( AnonSocket {
341358 readbuf : Some ( RefCell :: new ( Buffer :: new ( ) ) ) ,
342359 peer_fd : OnceCell :: new ( ) ,
360+ peer_lost_data : Cell :: new ( false ) ,
361+ is_nonblock : false ,
362+ } ) ;
363+ let fd1 = fds. new_ref ( AnonSocket {
364+ readbuf : None ,
365+ peer_fd : OnceCell :: new ( ) ,
366+ peer_lost_data : Cell :: new ( false ) ,
343367 is_nonblock : false ,
344368 } ) ;
345- let fd1 =
346- fds. new_ref ( AnonSocket { readbuf : None , peer_fd : OnceCell :: new ( ) , is_nonblock : false } ) ;
347369
348370 // Make the file descriptions point to each other.
349371 fd0. downcast :: < AnonSocket > ( ) . unwrap ( ) . peer_fd . set ( fd1. downgrade ( ) ) . unwrap ( ) ;
0 commit comments