Skip to content

Commit fb00155

Browse files
committed
Remove untestable branches of statx and add helper function to deal with syscall arguments
1 parent 08ad653 commit fb00155

File tree

2 files changed

+42
-34
lines changed

2 files changed

+42
-34
lines changed

src/helpers.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use std::{mem, iter};
22
use std::ffi::OsStr;
3+
use std::convert::{ TryFrom, TryInto };
4+
use std::num::TryFromIntError;
35

46
use syntax::source_map::DUMMY_SP;
57
use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX};
@@ -480,6 +482,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
480482
self.eval_context_mut().memory.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?;
481483
Ok(true)
482484
}
485+
486+
// Converts an operand with a machine `isize` into the desired integer type using `TryInto`.
487+
// This function is useful when reading syscall related operands which are delivered as pointer
488+
// sized operands.
489+
fn try_from_ptr_sized_operand<T: TryFrom<i64, Error=TryFromIntError>>(
490+
&mut self,
491+
operand: OpTy<'tcx, Tag>,
492+
) -> InterpResult<'tcx, T> {
493+
let this = self.eval_context_mut();
494+
495+
this.read_scalar(operand)?
496+
.to_machine_isize(&*this.tcx)?
497+
.try_into()
498+
.map_err(|e| err_unsup_format!(
499+
"Failed to convert pointer sized operand to integer: {}",
500+
e
501+
).into())
502+
}
503+
483504
}
484505

485506
#[cfg(target_os = "unix")]
@@ -550,3 +571,4 @@ pub fn immty_from_uint_checked<'tcx>(
550571
}
551572
Ok(ImmTy::from_uint(int, layout))
552573
}
574+

src/shims/fs.rs

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::collections::HashMap;
2-
use std::convert::TryFrom;
2+
use std::convert::{TryInto, TryFrom};
33
use std::fs::{remove_file, File, OpenOptions};
44
use std::io::{Read, Write};
55
use std::path::PathBuf;
@@ -304,19 +304,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
304304
};
305305

306306
let pathname: PathBuf = this.read_os_str_from_c_str(pathname_scalar)?.into();
307-
let flags = this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)? as i32;
307+
// This argument should be a `c_int` but the syscall API just returns a pointer sized
308+
// integer.
309+
let flags: i32 = this.try_from_ptr_sized_operand(flags_op)?;
308310

309-
let at_empty_path = this.eval_libc_i32("AT_EMPTY_PATH")?;
310311
let at_fdcwd = this.eval_libc_i32("AT_FDCWD")?;
311-
312312
// Now we need to resolve the path of the target file. This was done following the manual
313313
// entry for `statx`
314314

315315
// If `pathname` is absolute we can ignore `dirfd`.
316316
let path = if pathname.is_absolute() {
317317
pathname
318318
} else {
319-
let dirfd = this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)? as i32;
319+
// This argument should be a `c_int` but the syscall API just returns a pointer sized
320+
// integer.
321+
let dirfd: i32 = this.try_from_ptr_sized_operand(dirfd_op)?;
320322
// If `dirfd` is `AT_FDCWD`, `pathname` is relative to the current directory.
321323
if dirfd == at_fdcwd {
322324
match std::env::current_dir() {
@@ -327,32 +329,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
327329
}
328330
}
329331
} else {
330-
if let Some(path) = &this
331-
.machine
332-
.file_handler
333-
.handles
334-
.get(&dirfd)
335-
.map(|h| &h.path)
336-
{
337-
// If `dirfd` points to a directory, `pathname` is relative to that directory
338-
if path.is_dir() {
339-
path.join(pathname)
340-
} else {
341-
// If `pathname` is empty and the `AT_EMPTY_PATH` flag is set, we use the path of `dirfd`.
342-
if pathname.as_os_str().is_empty() && (flags & at_empty_path != 0) {
343-
(*path).clone()
344-
} else {
345-
// It is not specified what should happen here.
346-
throw_unsup_format!(
347-
"the file descriptor `{}` and path `{:?}` combination is invalid.",
348-
dirfd,
349-
path
350-
);
351-
}
352-
}
353-
} else {
354-
return this.handle_not_found();
355-
}
332+
// This behavior is specified but cannot be tested from `libstd`. If you found this
333+
// error please open an issue reporting it.
334+
throw_unsup_format!(
335+
"Using statx with a fildes different from `AT_FDCWD` is not supported"
336+
)
356337
}
357338
};
358339

@@ -385,15 +366,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
385366
// The `mode` field specifies the type of the file and the permissions over the file for
386367
// the owner, its group and other users. Given that we can only provide the file type
387368
// without using platform specific methods, we only set the bits corresponding to the file
388-
// type.
369+
// type. This argument should be an `__u16` but the syscall API just returns a pointer sized
370+
// integer.
389371
let mode = if file_type.is_file() {
390372
this.eval_libc("S_IFREG")?
391373
} else if file_type.is_dir() {
392374
this.eval_libc("S_IFDIR")?
393375
} else {
394376
this.eval_libc("S_IFLNK")?
395-
}
396-
.to_u32()? as u16;
377+
}.to_u32()?;
378+
379+
let mode: u16 = mode.try_into().map_err(|e|
380+
err_unsup_format!("Failed to convert 32-bit operand to u16: {}",
381+
e
382+
))?;
397383

398384
let size = metadata.len();
399385

0 commit comments

Comments
 (0)