put FD validity behind late debug_asserts checking
uses the same machinery as assert_unsafe_precondition
This commit is contained in:
parent
25babe9a79
commit
1ba00d9cb2
@ -177,17 +177,9 @@ fn drop(&mut self) {
|
|||||||
// opened after we closed ours.
|
// opened after we closed ours.
|
||||||
#[cfg(not(target_os = "hermit"))]
|
#[cfg(not(target_os = "hermit"))]
|
||||||
{
|
{
|
||||||
use crate::sys::os::errno;
|
#[cfg(unix)]
|
||||||
// ideally this would use assert_unsafe_precondition!, but that's only in core
|
crate::sys::fs::debug_assert_fd_is_open(self.fd);
|
||||||
if cfg!(debug_assertions) {
|
|
||||||
// close() can bubble up error codes from FUSE which can send semantically
|
|
||||||
// inappropriate error codes including EBADF.
|
|
||||||
// So we check file flags instead which live on the file descriptor and not the underlying file.
|
|
||||||
// The downside is that it costs an extra syscall, so we only do it for debug.
|
|
||||||
if libc::fcntl(self.fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
|
|
||||||
rtabort!("IO Safety violation: owned file descriptor already closed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let _ = libc::close(self.fd);
|
let _ = libc::close(self.fd);
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "hermit")]
|
#[cfg(target_os = "hermit")]
|
||||||
|
@ -868,28 +868,39 @@ fn next(&mut self) -> Option<io::Result<DirEntry>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Aborts the process if a file desceriptor is not open, if debug asserts are enabled
|
||||||
|
///
|
||||||
|
/// Many IO syscalls can't be fully trusted about EBADF error codes because those
|
||||||
|
/// might get bubbled up from a remote FUSE server rather than the file descriptor
|
||||||
|
/// in the current process being invalid.
|
||||||
|
///
|
||||||
|
/// So we check file flags instead which live on the file descriptor and not the underlying file.
|
||||||
|
/// The downside is that it costs an extra syscall, so we only do it for debug.
|
||||||
|
#[inline]
|
||||||
|
pub(crate) fn debug_assert_fd_is_open(fd: RawFd) {
|
||||||
|
use crate::sys::os::errno;
|
||||||
|
|
||||||
|
// this is similar to assert_unsafe_precondition!() but it doesn't require const
|
||||||
|
if core::ub_checks::check_library_ub() {
|
||||||
|
if unsafe { libc::fcntl(fd, libc::F_GETFD) } == -1 && errno() == libc::EBADF {
|
||||||
|
rtabort!("IO Safety violation: owned file descriptor already closed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Drop for Dir {
|
impl Drop for Dir {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// ideally this would use assert_unsafe_precondition!, but that's only in core
|
// dirfd isn't supported everywhere
|
||||||
#[cfg(all(
|
#[cfg(not(any(
|
||||||
debug_assertions,
|
miri,
|
||||||
not(any(
|
target_os = "redox",
|
||||||
target_os = "redox",
|
target_os = "nto",
|
||||||
target_os = "nto",
|
target_os = "vita",
|
||||||
target_os = "vita",
|
target_os = "hurd",
|
||||||
target_os = "hurd",
|
)))]
|
||||||
))
|
|
||||||
))]
|
|
||||||
{
|
{
|
||||||
use crate::sys::os::errno;
|
|
||||||
// close() can bubble up error codes from FUSE which can send semantically
|
|
||||||
// inappropriate error codes including EBADF.
|
|
||||||
// So we check file flags instead which live on the file descriptor and not the underlying file.
|
|
||||||
// The downside is that it costs an extra syscall, so we only do it for debug.
|
|
||||||
let fd = unsafe { libc::dirfd(self.0) };
|
let fd = unsafe { libc::dirfd(self.0) };
|
||||||
if unsafe { libc::fcntl(fd, libc::F_GETFD) } == -1 && errno() == libc::EBADF {
|
debug_assert_fd_is_open(fd);
|
||||||
rtabort!("IO Safety violation: DIR*'s owned file descriptor already closed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
let r = unsafe { libc::closedir(self.0) };
|
let r = unsafe { libc::closedir(self.0) };
|
||||||
assert!(
|
assert!(
|
||||||
|
Loading…
Reference in New Issue
Block a user