@@ -1202,6 +1202,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12021202 }
12031203 }
12041204
1205+ /// NOTE: According to the man page of `possix_fallocate`, it returns the error code instead
1206+ /// of setting `errno`.
12051207 fn posix_fallocate (
12061208 & mut self ,
12071209 fd_num : i32 ,
@@ -1210,54 +1212,56 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
12101212 ) -> InterpResult < ' tcx , Scalar > {
12111213 let this = self . eval_context_mut ( ) ;
12121214
1213- // According to the man page of `possix_fallocate`, it returns the error code instead
1214- // of setting `errno`.
1215- let ebadf = Scalar :: from_i32 ( this. eval_libc_i32 ( "EBADF" ) ) ;
1216- let einval = Scalar :: from_i32 ( this. eval_libc_i32 ( "EINVAL" ) ) ;
1217- let enodev = Scalar :: from_i32 ( this. eval_libc_i32 ( "ENODEV" ) ) ;
1218-
12191215 // Reject if isolation is enabled.
12201216 if let IsolatedOp :: Reject ( reject_with) = this. machine . isolated_op {
12211217 this. reject_in_isolation ( "`posix_fallocate`" , reject_with) ?;
1222- // Set error code as "EBADF" (bad fd)
1223- return interp_ok ( ebadf ) ;
1218+ // Return error code "EBADF" (bad fd).
1219+ return interp_ok ( this . eval_libc ( "EBADF" ) ) ;
12241220 }
12251221
12261222 let Some ( fd) = this. machine . fds . get ( fd_num) else {
1227- return interp_ok ( ebadf ) ;
1223+ return interp_ok ( this . eval_libc ( "EBADF" ) ) ;
12281224 } ;
12291225
12301226 let file = match fd. downcast :: < FileHandle > ( ) {
12311227 Some ( file_handle) => file_handle,
12321228 // Man page specifies to return ENODEV if `fd` is not a regular file.
1233- None => return interp_ok ( enodev ) ,
1229+ None => return interp_ok ( this . eval_libc ( "ENODEV" ) ) ,
12341230 } ;
12351231
12361232 // EINVAL is returned when: "offset was less than 0, or len was less than or equal to 0".
12371233 if offset < 0 || len <= 0 {
1238- return interp_ok ( einval ) ;
1234+ return interp_ok ( this . eval_libc ( "EINVAL" ) ) ;
12391235 }
12401236
1241- if file. writable {
1242- let current_size = match file. file . metadata ( ) {
1243- Ok ( metadata) => metadata. len ( ) ,
1244- Err ( err) => return this. io_error_to_errnum ( err) ,
1245- } ;
1246- let new_size = match offset. checked_add ( len) {
1247- Some ( size) => size. try_into ( ) . unwrap ( ) , // We just checked negative `offset` and `len`.
1248- None => return interp_ok ( einval) ,
1237+ if !file. writable {
1238+ // The file is not writable.
1239+ return interp_ok ( this. eval_libc ( "EBADF" ) ) ;
1240+ }
1241+
1242+ let current_size = match file. file . metadata ( ) {
1243+ Ok ( metadata) => metadata. len ( ) ,
1244+ Err ( err) => return this. io_error_to_errnum ( err) ,
1245+ } ;
1246+ let new_size = match offset. checked_add ( len) {
1247+ // u64::from(i128) can fail if:
1248+ // - the value is negative, but we checed this above with `offset < 0 || len <= 0`
1249+ // - the value is too big/small to fit in u64, this should not happen since the callers
1250+ // check if the value is a `i32` or `i64`.
1251+ // So this unwrap is safe to do.
1252+ Some ( size) => u64:: try_from ( size) . unwrap ( ) ,
1253+ None => return interp_ok ( this. eval_libc ( "EFBIG" ) ) , // Size to big
1254+ } ;
1255+ // `posix_fallocate` only specifies increasing the file size.
1256+ if current_size < new_size {
1257+ let result = match file. file . set_len ( new_size) {
1258+ Ok ( ( ) ) => Scalar :: from_i32 ( 0 ) ,
1259+ Err ( e) => this. io_error_to_errnum ( e) ?,
12491260 } ;
1250- // `posix_fallocate` only specifies increasing the file size.
1251- if current_size < new_size {
1252- let result = file. file . set_len ( new_size) ;
1253- let result = this. try_unwrap_io_result ( result. map ( |_| 0i32 ) ) ?;
1254- interp_ok ( Scalar :: from_i32 ( result) )
1255- } else {
1256- interp_ok ( Scalar :: from_i32 ( 0 ) )
1257- }
1261+
1262+ interp_ok ( result)
12581263 } else {
1259- // The file is not writable.
1260- interp_ok ( ebadf)
1264+ interp_ok ( Scalar :: from_i32 ( 0 ) )
12611265 }
12621266 }
12631267
0 commit comments