Skip to content

Commit b26eca9

Browse files
authored
Fix procfs's open_and_check_file to work in the presence of threads. (#1059)
* Fix `procfs`'s `open_and_check_file` to work in the presence of threads. Have `open_and_check_file` create a new file descriptor before scanning for directory entries, so that it doesn't share a directory position with other threads. Fixes #1050. * Fix build errors on powerpc64-ibm-aix.
1 parent 07a80aa commit b26eca9

File tree

4 files changed

+34
-4
lines changed

4 files changed

+34
-4
lines changed

src/backend/libc/conv.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use crate::io;
1313
#[cfg(not(windows))]
1414
#[inline]
1515
pub(super) fn c_str(c: &CStr) -> *const c::c_char {
16-
c.as_ptr()
16+
c.as_ptr().cast()
1717
}
1818

1919
#[cfg(not(any(windows, target_os = "espidf", target_os = "vita", target_os = "wasi")))]

src/backend/libc/net/read_sockaddr.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ pub(crate) unsafe fn read_sockaddr(
185185
return Err(io::Errno::INVAL);
186186
}
187187
debug_assert_eq!(
188-
CStr::from_ptr(decode.sun_path.as_ptr()).to_bytes().len(),
188+
CStr::from_ptr(decode.sun_path.as_ptr().cast())
189+
.to_bytes()
190+
.len(),
189191
provided_len
190192
);
191193
&decode.sun_path[..provided_len]

src/procfs.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,8 @@ fn is_mountpoint(file: BorrowedFd<'_>) -> bool {
228228
fn proc_opendirat<P: crate::path::Arg, Fd: AsFd>(dirfd: Fd, path: P) -> io::Result<OwnedFd> {
229229
// We don't add `PATH` here because that disables `DIRECTORY`. And we don't
230230
// add `NOATIME` for the same reason as the comment in `open_and_check_file`.
231-
let oflags = OFlags::NOFOLLOW | OFlags::DIRECTORY | OFlags::CLOEXEC | OFlags::NOCTTY;
231+
let oflags =
232+
OFlags::RDONLY | OFlags::NOFOLLOW | OFlags::DIRECTORY | OFlags::CLOEXEC | OFlags::NOCTTY;
232233
openat(dirfd, path, oflags, Mode::empty()).map_err(|_err| io::Errno::NOTSUP)
233234
}
234235

@@ -488,8 +489,18 @@ fn open_and_check_file(
488489
let mut found_file = false;
489490
let mut found_dot = false;
490491

492+
// Open a new fd, so that if we're called on multiple threads, they don't
493+
// share a seek position.
494+
let oflags =
495+
OFlags::RDONLY | OFlags::CLOEXEC | OFlags::NOFOLLOW | OFlags::NOCTTY | OFlags::DIRECTORY;
496+
let dir = openat(dir, cstr!("."), oflags, Mode::empty()).map_err(|_err| io::Errno::NOTSUP)?;
497+
let check_dir_stat = fstat(&dir)?;
498+
if check_dir_stat.st_dev != dir_stat.st_dev || check_dir_stat.st_ino != dir_stat.st_ino {
499+
return Err(io::Errno::NOTSUP);
500+
}
501+
491502
// Position the directory iteration at the start.
492-
seek(dir, SeekFrom::Start(0))?;
503+
seek(&dir, SeekFrom::Start(0))?;
493504

494505
let mut buf = [MaybeUninit::uninit(); 2048];
495506
let mut iter = RawDir::new(dir, &mut buf);

tests/procfs/basic.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,20 @@ fn test_status_twice() {
1414
let fd = rustix::procfs::proc_self_status().unwrap();
1515
drop(fd);
1616
}
17+
18+
#[test]
19+
fn parallel_self_proc_status() {
20+
const THREADS: usize = 3;
21+
22+
fn self_proc_status() {
23+
rustix::procfs::proc_self_status().expect("error getting proc/self/status pid");
24+
}
25+
26+
let mut handles = Vec::with_capacity(THREADS);
27+
for _ in 0..THREADS {
28+
handles.push(std::thread::spawn(self_proc_status));
29+
}
30+
for handle in handles.drain(..) {
31+
handle.join().expect("thread crashed");
32+
}
33+
}

0 commit comments

Comments
 (0)