@@ -1197,6 +1197,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
11971197 }
11981198 }
11991199
1200+ /// NOTE: According to the man page of `possix_fallocate`, it returns the error code instead
1201+ /// of setting `errno`.
12001202 fn posix_fallocate (
12011203 & mut self ,
12021204 fd_num : i32 ,
@@ -1205,54 +1207,56 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12051207 ) -> InterpResult < ' tcx , Scalar > {
12061208 let this = self . eval_context_mut ( ) ;
12071209
1208- // According to the man page of `possix_fallocate`, it returns the error code instead
1209- // of setting `errno`.
1210- let ebadf = Scalar :: from_i32 ( this. eval_libc_i32 ( "EBADF" ) ) ;
1211- let einval = Scalar :: from_i32 ( this. eval_libc_i32 ( "EINVAL" ) ) ;
1212- let enodev = Scalar :: from_i32 ( this. eval_libc_i32 ( "ENODEV" ) ) ;
1213-
12141210 // Reject if isolation is enabled.
12151211 if let IsolatedOp :: Reject ( reject_with) = this. machine . isolated_op {
12161212 this. reject_in_isolation ( "`posix_fallocate`" , reject_with) ?;
1217- // Set error code as "EBADF" (bad fd)
1218- return interp_ok ( ebadf ) ;
1213+ // Return error code "EBADF" (bad fd).
1214+ return interp_ok ( this . eval_libc ( "EBADF" ) ) ;
12191215 }
12201216
12211217 let Some ( fd) = this. machine . fds . get ( fd_num) else {
1222- return interp_ok ( ebadf ) ;
1218+ return interp_ok ( this . eval_libc ( "EBADF" ) ) ;
12231219 } ;
12241220
12251221 let file = match fd. downcast :: < FileHandle > ( ) {
12261222 Some ( file_handle) => file_handle,
12271223 // Man page specifies to return ENODEV if `fd` is not a regular file.
1228- None => return interp_ok ( enodev ) ,
1224+ None => return interp_ok ( this . eval_libc ( "ENODEV" ) ) ,
12291225 } ;
12301226
12311227 // EINVAL is returned when: "offset was less than 0, or len was less than or equal to 0".
12321228 if offset < 0 || len <= 0 {
1233- return interp_ok ( einval ) ;
1229+ return interp_ok ( this . eval_libc ( "EINVAL" ) ) ;
12341230 }
12351231
1236- if file. writable {
1237- let current_size = match file. file . metadata ( ) {
1238- Ok ( metadata) => metadata. len ( ) ,
1239- Err ( err) => return this. io_error_to_errnum ( err) ,
1240- } ;
1241- let new_size = match offset. checked_add ( len) {
1242- Some ( size) => size. try_into ( ) . unwrap ( ) , // We just checked negative `offset` and `len`.
1243- None => return interp_ok ( einval) ,
1232+ if !file. writable {
1233+ // The file is not writable.
1234+ return interp_ok ( this. eval_libc ( "EBADF" ) ) ;
1235+ }
1236+
1237+ let current_size = match file. file . metadata ( ) {
1238+ Ok ( metadata) => metadata. len ( ) ,
1239+ Err ( err) => return this. io_error_to_errnum ( err) ,
1240+ } ;
1241+ let new_size = match offset. checked_add ( len) {
1242+ // u64::from(i128) can fail if:
1243+ // - the value is negative, but we checed this above with `offset < 0 || len <= 0`
1244+ // - the value is too big/small to fit in u64, this should not happen since the callers
1245+ // check if the value is a `i32` or `i64`.
1246+ // So this unwrap is safe to do.
1247+ Some ( size) => u64:: try_from ( size) . unwrap ( ) ,
1248+ None => return interp_ok ( this. eval_libc ( "EFBIG" ) ) , // Size to big
1249+ } ;
1250+ // `posix_fallocate` only specifies increasing the file size.
1251+ if current_size < new_size {
1252+ let result = match file. file . set_len ( new_size) {
1253+ Ok ( ( ) ) => Scalar :: from_i32 ( 0 ) ,
1254+ Err ( e) => this. io_error_to_errnum ( e) ?,
12441255 } ;
1245- // `posix_fallocate` only specifies increasing the file size.
1246- if current_size < new_size {
1247- let result = file. file . set_len ( new_size) ;
1248- let result = this. try_unwrap_io_result ( result. map ( |_| 0i32 ) ) ?;
1249- interp_ok ( Scalar :: from_i32 ( result) )
1250- } else {
1251- interp_ok ( Scalar :: from_i32 ( 0 ) )
1252- }
1256+
1257+ interp_ok ( result)
12531258 } else {
1254- // The file is not writable.
1255- interp_ok ( ebadf)
1259+ interp_ok ( Scalar :: from_i32 ( 0 ) )
12561260 }
12571261 }
12581262
0 commit comments