@@ -50,6 +50,9 @@ trait FileDescriptor: std::fmt::Debug {
50
50
) -> InterpResult < ' tcx , io:: Result < i32 > > ;
51
51
52
52
fn dup ( & mut self ) -> io:: Result < Box < dyn FileDescriptor > > ;
53
+
54
+ #[ cfg( unix) ]
55
+ fn as_unix_host_fd ( & self ) -> Option < i32 > ;
53
56
}
54
57
55
58
impl FileDescriptor for FileHandle {
@@ -114,6 +117,12 @@ impl FileDescriptor for FileHandle {
114
117
let duplicated = self . file . try_clone ( ) ?;
115
118
Ok ( Box :: new ( FileHandle { file : duplicated, writable : self . writable } ) )
116
119
}
120
+
121
+ #[ cfg( unix) ]
122
+ fn as_unix_host_fd ( & self ) -> Option < i32 > {
123
+ use std:: os:: unix:: io:: AsRawFd ;
124
+ Some ( self . file . as_raw_fd ( ) )
125
+ }
117
126
}
118
127
119
128
impl FileDescriptor for io:: Stdin {
@@ -159,6 +168,11 @@ impl FileDescriptor for io::Stdin {
159
168
fn dup ( & mut self ) -> io:: Result < Box < dyn FileDescriptor > > {
160
169
Ok ( Box :: new ( io:: stdin ( ) ) )
161
170
}
171
+
172
+ #[ cfg( unix) ]
173
+ fn as_unix_host_fd ( & self ) -> Option < i32 > {
174
+ Some ( libc:: STDIN_FILENO )
175
+ }
162
176
}
163
177
164
178
impl FileDescriptor for io:: Stdout {
@@ -209,6 +223,11 @@ impl FileDescriptor for io::Stdout {
209
223
fn dup ( & mut self ) -> io:: Result < Box < dyn FileDescriptor > > {
210
224
Ok ( Box :: new ( io:: stdout ( ) ) )
211
225
}
226
+
227
+ #[ cfg( unix) ]
228
+ fn as_unix_host_fd ( & self ) -> Option < i32 > {
229
+ Some ( libc:: STDOUT_FILENO )
230
+ }
212
231
}
213
232
214
233
impl FileDescriptor for io:: Stderr {
@@ -252,6 +271,11 @@ impl FileDescriptor for io::Stderr {
252
271
fn dup ( & mut self ) -> io:: Result < Box < dyn FileDescriptor > > {
253
272
Ok ( Box :: new ( io:: stderr ( ) ) )
254
273
}
274
+
275
+ #[ cfg( unix) ]
276
+ fn as_unix_host_fd ( & self ) -> Option < i32 > {
277
+ Some ( libc:: STDERR_FILENO )
278
+ }
255
279
}
256
280
257
281
#[ derive( Debug ) ]
@@ -297,6 +321,11 @@ impl FileDescriptor for DummyOutput {
297
321
fn dup < ' tcx > ( & mut self ) -> io:: Result < Box < dyn FileDescriptor > > {
298
322
Ok ( Box :: new ( DummyOutput ) )
299
323
}
324
+
325
+ #[ cfg( unix) ]
326
+ fn as_unix_host_fd ( & self ) -> Option < i32 > {
327
+ None
328
+ }
300
329
}
301
330
302
331
#[ derive( Debug ) ]
@@ -1660,6 +1689,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1660
1689
}
1661
1690
}
1662
1691
}
1692
+
1693
+ #[ cfg_attr( not( unix) , allow( unused) ) ]
1694
+ fn isatty ( & mut self , miri_fd : & OpTy < ' tcx , Tag > ) -> InterpResult < ' tcx , i32 > {
1695
+ let this = self . eval_context_mut ( ) ;
1696
+ #[ cfg( unix) ]
1697
+ {
1698
+ let miri_fd = this. read_scalar ( miri_fd) ?. to_i32 ( ) ?;
1699
+ if let Some ( host_fd) =
1700
+ this. machine . file_handler . handles . get ( & miri_fd) . and_then ( |fd| fd. as_unix_host_fd ( ) )
1701
+ {
1702
+ // "returns 1 if fd is an open file descriptor referring to a terminal;
1703
+ // otherwise 0 is returned, and errno is set to indicate the error"
1704
+ // SAFETY: isatty has no preconditions
1705
+ let is_tty = unsafe { libc:: isatty ( host_fd) } ;
1706
+ if is_tty == 0 {
1707
+ let errno = std:: io:: Error :: last_os_error ( )
1708
+ . raw_os_error ( )
1709
+ . map ( Scalar :: from_i32)
1710
+ . unwrap ( ) ;
1711
+ this. set_last_error ( errno) ?;
1712
+ }
1713
+ return Ok ( is_tty) ;
1714
+ }
1715
+ }
1716
+ // We are attemping to use a Unix interface on a non-Unix platform, or we are on a Unix
1717
+ // platform and the passed file descriptor is not open.
1718
+ // FIXME: It should be possible to emulate this at least on Windows by using
1719
+ // GetConsoleMode.
1720
+ let enotty = this. eval_libc ( "ENOTTY" ) ?;
1721
+ this. set_last_error ( enotty) ?;
1722
+ Ok ( 0 )
1723
+ }
1663
1724
}
1664
1725
1665
1726
/// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when
0 commit comments