1
1
use std:: convert:: TryFrom ;
2
+ use std:: io:: { self , Read , Write } ;
2
3
3
4
use log:: trace;
4
5
@@ -67,7 +68,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
67
68
let buf = this. read_scalar ( buf) ?. not_undef ( ) ?;
68
69
let count = this. read_scalar ( count) ?. to_machine_usize ( this) ?;
69
70
let result = if fd == 0 {
70
- throw_unsup_format ! ( "reading from stdin is not implemented" )
71
+
72
+ this. check_no_isolation ( "read" ) ?;
73
+
74
+ // We cap the number of read bytes to the largest
75
+ // value that we are able to fit in both the
76
+ // host's and target's `isize`. This saves us from
77
+ // having to handle overflows later.
78
+ let count = count. min ( this. machine_isize_max ( ) as u64 ) . min ( isize:: MAX as u64 ) ;
79
+
80
+ // We want to read at most `count` bytes. We are
81
+ // sure that `count` is not negative because it
82
+ // was a target's `usize`. Also we are sure that
83
+ // its smaller than `usize::MAX` because it is a
84
+ // host's `isize`.
85
+ let mut buffer = vec ! [ 0 ; count as usize ] ;
86
+ let res = io:: stdin ( )
87
+ . read ( & mut buffer)
88
+ // `Stdin::read` never returns a value larger
89
+ // than `count`, so this cannot fail.
90
+ . map ( |c| i64:: try_from ( c) . unwrap ( ) ) ;
91
+
92
+ match res {
93
+ Ok ( bytes) => {
94
+ this. memory . write_bytes ( buf, buffer) ?;
95
+ i64:: try_from ( bytes) . unwrap ( )
96
+ } ,
97
+ Err ( e) => {
98
+ this. set_last_error_from_io_error ( e) ?;
99
+ -1
100
+ } ,
101
+ }
71
102
} else if fd == 1 || fd == 2 {
72
103
throw_unsup_format ! ( "cannot read from stdout/stderr" )
73
104
} else {
@@ -85,7 +116,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
85
116
throw_unsup_format ! ( "cannot write to stdin" )
86
117
} else if fd == 1 || fd == 2 {
87
118
// stdout/stderr
88
- use std:: io:: { self , Write } ;
89
119
90
120
let buf_cont = this. memory . read_bytes ( buf, Size :: from_bytes ( count) ) ?;
91
121
// We need to flush to make sure this actually appears on the screen
@@ -103,6 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
103
133
} ;
104
134
match res {
105
135
Ok ( n) => i64:: try_from ( n) . unwrap ( ) ,
136
+ // FIXME: set errno to appropriate value
106
137
Err ( _) => -1 ,
107
138
}
108
139
} else {
0 commit comments