Skip to content

Commit fc5fe57

Browse files
authored
Add select and poll safe rules (#282)
This also adds `FdRegistry::with_fds` which receives multiple raw file descriptors (i32) and applies function f on the BorrowedFd's derived from the raw file descriptors. The single-fd variant of `with_fds` is the already existing `with_fd`
1 parent f6d80af commit fc5fe57

12 files changed

Lines changed: 832 additions & 8 deletions

File tree

‎libcc2rs/src/fd.rs‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,26 @@ impl FdRegistry {
2727
raw
2828
}
2929

30+
fn lookup(&self, fd: i32) -> BorrowedFd<'_> {
31+
self.fds
32+
.get(fd as usize)
33+
.and_then(|slot| slot.as_ref())
34+
.unwrap_or_else(|| panic!("ub: bad fd {fd}"))
35+
.as_fd()
36+
}
37+
3038
pub fn with_fd<R>(fd: i32, f: impl FnOnce(BorrowedFd<'_>) -> R) -> R {
3139
FD_REGISTRY.with(|r| {
3240
let reg = r.borrow();
33-
let owned = reg
34-
.fds
35-
.get(fd as usize)
36-
.and_then(|slot| slot.as_ref())
37-
.unwrap_or_else(|| panic!("ub: bad fd {fd}"));
38-
f(owned.as_fd())
41+
f(reg.lookup(fd))
42+
})
43+
}
44+
45+
pub fn with_fds<R>(fds: &[i32], f: impl FnOnce(&[BorrowedFd<'_>]) -> R) -> R {
46+
FD_REGISTRY.with(|r| {
47+
let reg = r.borrow();
48+
let borrowed: Vec<BorrowedFd<'_>> = fds.iter().map(|&fd| reg.lookup(fd)).collect();
49+
f(&borrowed)
3950
})
4051
}
4152

‎libcc2rs/src/libc_shims/time.rs‎

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,23 @@ impl Clone for Timeval {
8989
}
9090
}
9191

92-
impl ByteRepr for Timeval {}
92+
impl ByteRepr for Timeval {
93+
fn byte_size() -> usize {
94+
16
95+
}
96+
97+
fn to_bytes(&self, buf: &mut [u8]) {
98+
(*self.tv_sec.borrow()).to_bytes(&mut buf[0..8]);
99+
(*self.tv_usec.borrow()).to_bytes(&mut buf[8..16]);
100+
}
101+
102+
fn from_bytes(buf: &[u8]) -> Self {
103+
Self {
104+
tv_sec: Rc::new(RefCell::new(i64::from_bytes(&buf[0..8]))),
105+
tv_usec: Rc::new(RefCell::new(i64::from_bytes(&buf[8..16]))),
106+
}
107+
}
108+
}
93109

94110
#[derive(Default)]
95111
pub struct Timespec {

‎rules/poll/src.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <poll.h>
55

66
typedef struct pollfd t1;
7+
typedef nfds_t t2;
78

89
int f1(struct pollfd *fds, nfds_t nfds, int timeout) {
910
return poll(fds, nfds, timeout);

‎rules/poll/tgt_refcount.rs‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,52 @@ use libcc2rs::*;
66
fn t1() -> libcc2rs::Pollfd {
77
Default::default()
88
}
9+
10+
fn f1(a0: Ptr<Pollfd>, a1: u64, a2: i32) -> i32 {
11+
let __p = a0.clone();
12+
let __timeout = match nix::poll::PollTimeout::try_from(a2) {
13+
Ok(__t) => __t,
14+
Err(_) => panic!("poll: unsupported timeout {}", a2),
15+
};
16+
let mut __idx = Vec::new();
17+
let mut __wanted = Vec::new();
18+
let mut __events = Vec::new();
19+
for __i in 0..(a1 as usize) {
20+
let (__fd, __ev) = __p
21+
.offset(__i)
22+
.with(|__e| (*__e.fd.borrow(), *__e.events.borrow()));
23+
__p.offset(__i)
24+
.with_mut(|__e| *__e.revents.borrow_mut() = 0);
25+
if __fd >= 0 {
26+
__idx.push(__i);
27+
__wanted.push(__fd);
28+
__events.push(__ev);
29+
}
30+
}
31+
FdRegistry::with_fds(&__wanted, |__b| {
32+
let mut __pfds: Vec<nix::poll::PollFd> = __b
33+
.iter()
34+
.zip(&__events)
35+
.map(|(&__fd, &__ev)| {
36+
nix::poll::PollFd::new(__fd, nix::poll::PollFlags::from_bits_truncate(__ev))
37+
})
38+
.collect();
39+
match nix::poll::poll(&mut __pfds, __timeout) {
40+
Ok(__count) => {
41+
for (__slot, &__i) in __pfds.iter().zip(&__idx) {
42+
let __rev = match __slot.revents() {
43+
Some(__r) => __r.bits(),
44+
None => 0,
45+
};
46+
__p.offset(__i)
47+
.with_mut(|__e| *__e.revents.borrow_mut() = __rev);
48+
}
49+
__count
50+
}
51+
Err(__e) => {
52+
libcc2rs::cpp2rust_errno().write(__e as i32);
53+
-1
54+
}
55+
}
56+
})
57+
}

‎rules/poll/tgt_unsafe.rs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ fn t1() -> ::libc::pollfd {
55
unsafe { std::mem::zeroed() }
66
}
77

8-
unsafe fn f1(a0: *mut ::libc::pollfd, a1: u64, a2: i32) -> i32 {
8+
fn t2() -> ::libc::nfds_t {
9+
0
10+
}
11+
12+
unsafe fn f1(a0: *mut ::libc::pollfd, a1: ::libc::nfds_t, a2: i32) -> i32 {
913
libc::poll(a0, a1 as ::libc::nfds_t, a2)
1014
}

‎rules/select/tgt_refcount.rs‎

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,109 @@ fn f4(a0: i32, a1: Ptr<CFdSet>) -> i32 {
2222
fn f5(a0: Ptr<CFdSet>) {
2323
a0.with_mut(|__s| __s.zero());
2424
}
25+
26+
fn f1(a0: i32, a1: Ptr<CFdSet>, a2: Ptr<CFdSet>, a3: Ptr<CFdSet>, a4: Ptr<Timeval>) -> i32 {
27+
let __rp = a1.clone();
28+
let __wp = a2.clone();
29+
let __ep = a3.clone();
30+
let __tp = a4.clone();
31+
let __r_fds: Vec<i32> = match __rp.is_null() {
32+
true => Vec::new(),
33+
false => __rp.with(|__s| (0..a0).filter(|&__fd| __s.isset(__fd)).collect()),
34+
};
35+
let __w_fds: Vec<i32> = match __wp.is_null() {
36+
true => Vec::new(),
37+
false => __wp.with(|__s| (0..a0).filter(|&__fd| __s.isset(__fd)).collect()),
38+
};
39+
let __e_fds: Vec<i32> = match __ep.is_null() {
40+
true => Vec::new(),
41+
false => __ep.with(|__s| (0..a0).filter(|&__fd| __s.isset(__fd)).collect()),
42+
};
43+
let mut __wanted = Vec::new();
44+
__wanted.extend(&__r_fds);
45+
__wanted.extend(&__w_fds);
46+
__wanted.extend(&__e_fds);
47+
FdRegistry::with_fds(&__wanted, |__b| {
48+
let __rn = __r_fds.len();
49+
let __wn = __w_fds.len();
50+
let mut __rs = nix::sys::select::FdSet::new();
51+
let mut __ws = nix::sys::select::FdSet::new();
52+
let mut __es = nix::sys::select::FdSet::new();
53+
for __bfd in &__b[..__rn] {
54+
__rs.insert(*__bfd);
55+
}
56+
for __bfd in &__b[__rn..__rn + __wn] {
57+
__ws.insert(*__bfd);
58+
}
59+
for __bfd in &__b[__rn + __wn..] {
60+
__es.insert(*__bfd);
61+
}
62+
let mut __tv = match __tp.is_null() {
63+
true => None,
64+
false => Some(__tp.with(|__t| {
65+
nix::sys::time::TimeVal::new(*__t.tv_sec.borrow() as _, *__t.tv_usec.borrow() as _)
66+
})),
67+
};
68+
match nix::sys::select::select(
69+
a0,
70+
match __rp.is_null() {
71+
true => None,
72+
false => Some(&mut __rs),
73+
},
74+
match __wp.is_null() {
75+
true => None,
76+
false => Some(&mut __ws),
77+
},
78+
match __ep.is_null() {
79+
true => None,
80+
false => Some(&mut __es),
81+
},
82+
__tv.as_mut(),
83+
) {
84+
Ok(__n) => {
85+
if !__rp.is_null() {
86+
__rp.with_mut(|__s| {
87+
__s.zero();
88+
for (__fd, __bfd) in __r_fds.iter().zip(&__b[..__rn]) {
89+
if __rs.contains(*__bfd) {
90+
__s.set(*__fd);
91+
}
92+
}
93+
});
94+
}
95+
if !__wp.is_null() {
96+
__wp.with_mut(|__s| {
97+
__s.zero();
98+
for (__fd, __bfd) in __w_fds.iter().zip(&__b[__rn..__rn + __wn]) {
99+
if __ws.contains(*__bfd) {
100+
__s.set(*__fd);
101+
}
102+
}
103+
});
104+
}
105+
if !__ep.is_null() {
106+
__ep.with_mut(|__s| {
107+
__s.zero();
108+
for (__fd, __bfd) in __e_fds.iter().zip(&__b[__rn + __wn..]) {
109+
if __es.contains(*__bfd) {
110+
__s.set(*__fd);
111+
}
112+
}
113+
});
114+
}
115+
match (__tp.is_null(), __tv.as_ref()) {
116+
(false, Some(__t)) => __tp.with_mut(|__dst| {
117+
*__dst.tv_sec.borrow_mut() = __t.tv_sec() as i64;
118+
*__dst.tv_usec.borrow_mut() = __t.tv_usec() as i64;
119+
}),
120+
_ => {}
121+
}
122+
__n
123+
}
124+
Err(__e) => {
125+
libcc2rs::cpp2rust_errno().write(__e as i32);
126+
-1
127+
}
128+
}
129+
})
130+
}

‎tests/unit/out/refcount/poll.rs‎

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
pub fn main() {
10+
std::process::exit(main_0());
11+
}
12+
fn main_0() -> i32 {
13+
let fds: Value<Box<[i32]>> = Rc::new(RefCell::new(
14+
(0..2).map(|_| <i32>::default()).collect::<Box<[i32]>>(),
15+
));
16+
assert!(
17+
(((match nix::unistd::pipe() {
18+
Ok((__r, __w)) => {
19+
let __fds = (fds.as_pointer() as Ptr<i32>).clone();
20+
__fds.write(FdRegistry::register(__r));
21+
__fds.offset(1).write(FdRegistry::register(__w));
22+
0
23+
}
24+
Err(__e) => {
25+
libcc2rs::cpp2rust_errno().write(__e as i32);
26+
-1
27+
}
28+
} == 0) as i32)
29+
!= 0)
30+
);
31+
assert!(
32+
(((match FdRegistry::with_fd((*fds.borrow())[(1) as usize], |__fd| {
33+
Ptr::from_string_literal(b"x")
34+
.to_any()
35+
.reinterpret_cast::<u8>()
36+
.with_slice(1_usize, |__buf| nix::unistd::write(__fd, __buf))
37+
}) {
38+
Ok(__n) => __n as isize,
39+
Err(__e) => {
40+
libcc2rs::cpp2rust_errno().write(__e as i32);
41+
-1
42+
}
43+
} == 1_isize) as i32)
44+
!= 0)
45+
);
46+
let pfd: Value<Box<[libcc2rs::Pollfd]>> = Rc::new(RefCell::new(
47+
(0..2)
48+
.map(|_| Default::default())
49+
.collect::<Box<[libcc2rs::Pollfd]>>(),
50+
));
51+
(*(*pfd.borrow())[(0) as usize].fd.borrow_mut()) = (*fds.borrow())[(0) as usize];
52+
(*(*pfd.borrow())[(0) as usize].events.borrow_mut()) = 1_i16;
53+
(*(*pfd.borrow())[(0) as usize].revents.borrow_mut()) = 0_i16;
54+
(*(*pfd.borrow())[(1) as usize].fd.borrow_mut()) = -1_i32;
55+
(*(*pfd.borrow())[(1) as usize].events.borrow_mut()) = 1_i16;
56+
(*(*pfd.borrow())[(1) as usize].revents.borrow_mut()) = 42_i16;
57+
assert!(
58+
((({
59+
let __p = (pfd.as_pointer() as Ptr<libcc2rs::Pollfd>).clone();
60+
let __timeout = match nix::poll::PollTimeout::try_from(0) {
61+
Ok(__t) => __t,
62+
Err(_) => panic!("poll: unsupported timeout {}", 0),
63+
};
64+
let mut __idx = Vec::new();
65+
let mut __wanted = Vec::new();
66+
let mut __events = Vec::new();
67+
for __i in 0..((2 as ::libc::nfds_t) as usize) {
68+
let (__fd, __ev) = __p
69+
.offset(__i)
70+
.with(|__e| (*__e.fd.borrow(), *__e.events.borrow()));
71+
__p.offset(__i)
72+
.with_mut(|__e| *__e.revents.borrow_mut() = 0);
73+
if __fd >= 0 {
74+
__idx.push(__i);
75+
__wanted.push(__fd);
76+
__events.push(__ev);
77+
}
78+
}
79+
FdRegistry::with_fds(&__wanted, |__b| {
80+
let mut __pfds: Vec<nix::poll::PollFd> = __b
81+
.iter()
82+
.zip(&__events)
83+
.map(|(&__fd, &__ev)| {
84+
nix::poll::PollFd::new(__fd, nix::poll::PollFlags::from_bits_truncate(__ev))
85+
})
86+
.collect();
87+
match nix::poll::poll(&mut __pfds, __timeout) {
88+
Ok(__count) => {
89+
for (__slot, &__i) in __pfds.iter().zip(&__idx) {
90+
let __rev = match __slot.revents() {
91+
Some(__r) => __r.bits(),
92+
None => 0,
93+
};
94+
__p.offset(__i)
95+
.with_mut(|__e| *__e.revents.borrow_mut() = __rev);
96+
}
97+
__count
98+
}
99+
Err(__e) => {
100+
libcc2rs::cpp2rust_errno().write(__e as i32);
101+
-1
102+
}
103+
}
104+
})
105+
} == 1) as i32)
106+
!= 0)
107+
);
108+
assert!(
109+
((((((*(*pfd.borrow())[(0) as usize].revents.borrow()) as i32) & 1) != 0) as i32) != 0)
110+
);
111+
assert!((((((*(*pfd.borrow())[(1) as usize].revents.borrow()) as i32) == 0) as i32) != 0));
112+
let ch: Value<u8> = <Value<u8>>::default();
113+
assert!(
114+
(((match FdRegistry::with_fd((*fds.borrow())[(0) as usize], |__fd| {
115+
((ch.as_pointer()) as Ptr<u8>)
116+
.to_any()
117+
.reinterpret_cast::<u8>()
118+
.with_slice_mut(1_usize, |__buf| nix::unistd::read(__fd, __buf))
119+
}) {
120+
Ok(__n) => __n as isize,
121+
Err(__e) => {
122+
libcc2rs::cpp2rust_errno().write(__e as i32);
123+
-1
124+
}
125+
} == 1_isize) as i32)
126+
!= 0)
127+
);
128+
assert!((((FdRegistry::close((*fds.borrow())[(0) as usize]) == 0) as i32) != 0));
129+
assert!((((FdRegistry::close((*fds.borrow())[(1) as usize]) == 0) as i32) != 0));
130+
return 0;
131+
}

0 commit comments

Comments
 (0)