@@ -3,7 +3,7 @@ use std::convert::TryFrom;
3
3
use std:: fs:: { remove_file, File , OpenOptions } ;
4
4
use std:: io:: { Read , Write } ;
5
5
6
- use rustc:: ty:: layout:: Size ;
6
+ use rustc:: ty:: layout:: { Size , Align } ;
7
7
8
8
use crate :: stacked_borrows:: Tag ;
9
9
use crate :: * ;
@@ -166,18 +166,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
166
166
167
167
this. check_no_isolation ( "read" ) ?;
168
168
169
- let ptr_size = this. pointer_size ( ) . bits ( ) ;
170
-
171
- // We cap the number of read bytes to the largest value that we are able to fit in both the
172
- // host's and target's `isize`.
169
+ let fd = this. read_scalar ( fd_op) ?. to_i32 ( ) ?;
170
+ let buf = this. read_scalar ( buf_op) ?. not_undef ( ) ?;
173
171
let count = this
174
172
. read_scalar ( count_op) ?
175
- . to_machine_usize ( & * this. tcx ) ?
176
- . min ( ( 1 << ( ptr_size - 1 ) ) - 1 ) // max value of target `isize`
177
- . min ( isize:: max_value ( ) as u64 ) ;
173
+ . to_machine_usize ( & * this. tcx ) ?;
178
174
179
- let fd = this. read_scalar ( fd_op) ?. to_i32 ( ) ?;
180
- let buf = this. read_scalar ( buf_op) ?. not_undef ( ) ?;
175
+ // Check that the *entire* buffer is actually valid memory.
176
+ this. memory . check_ptr_access ( buf, Size :: from_bytes ( count) , Align :: from_bytes ( 1 ) . unwrap ( ) ) ?;
177
+
178
+ // We cap the number of read bytes to the largest value that we are able to fit in both the
179
+ // host's and target's `isize`. This saves us from having to handle overflows later.
180
+ let count = count
181
+ . min ( this. isize_max ( ) as u64 )
182
+ . min ( isize:: max_value ( ) as u64 ) ;
181
183
182
184
if let Some ( handle) = this. machine . file_handler . handles . get_mut ( & fd) {
183
185
// This can never fail because `count` was capped to be smaller than
@@ -219,18 +221,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
219
221
220
222
this. check_no_isolation ( "write" ) ?;
221
223
222
- let ptr_size = this. pointer_size ( ) . bits ( ) ;
223
-
224
- // We cap the number of read bytes to the largest value that we are able to fit in both the
225
- // host's and target's `isize`.
224
+ let fd = this. read_scalar ( fd_op) ?. to_i32 ( ) ?;
225
+ let buf = this. read_scalar ( buf_op) ?. not_undef ( ) ?;
226
226
let count = this
227
227
. read_scalar ( count_op) ?
228
- . to_machine_usize ( & * this. tcx ) ?
229
- . min ( ( 1 << ( ptr_size - 1 ) ) - 1 ) // max value of target `isize`
230
- . min ( isize:: max_value ( ) as u64 ) ;
228
+ . to_machine_usize ( & * this. tcx ) ?;
231
229
232
- let fd = this. read_scalar ( fd_op) ?. to_i32 ( ) ?;
233
- let buf = this. read_scalar ( buf_op) ?. not_undef ( ) ?;
230
+ // Check that the *entire* buffer is actually valid memory.
231
+ this. memory . check_ptr_access ( buf, Size :: from_bytes ( count) , Align :: from_bytes ( 1 ) . unwrap ( ) ) ?;
232
+
233
+ // We cap the number of written bytes to the largest value that we are able to fit in both the
234
+ // host's and target's `isize`. This saves us from having to handle overflows later.
235
+ let count = count
236
+ . min ( this. isize_max ( ) as u64 )
237
+ . min ( isize:: max_value ( ) as u64 ) ;
234
238
235
239
if let Some ( handle) = this. machine . file_handler . handles . get_mut ( & fd) {
236
240
let bytes = this. memory . read_bytes ( buf, Size :: from_bytes ( count) ) ?;
0 commit comments