Skip to content

Commit 9df5abf

Browse files
committed
Optionally implement TryFrom in libc_enum!
This saves code in several separate places that need to do this separately. At the same time, remove a few uses of mem::transmute that were implementing TryFrom or similar functionality. Issue #373
1 parent 68488a4 commit 9df5abf

File tree

5 files changed

+156
-145
lines changed

5 files changed

+156
-145
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,28 @@ This project adheres to [Semantic Versioning](https://semver.org/).
4343
- Many more functions, mostly contructors, are now `const`.
4444
(#[1476](https://github.com/nix-rust/nix/pull/1476))
4545

46+
- `sys::event::KEvent::filter` now returns a `Result` instead of being
47+
infalliable. The only cases where it will now return an error are cases
48+
where it previously would've had undefined behavior.
49+
(#[1484](https://github.com/nix-rust/nix/pull/1484))
50+
4651
### Fixed
4752

4853
- Added more errno definitions for better backwards compatibility with
4954
Nix 0.21.0.
5055
(#[1467](https://github.com/nix-rust/nix/pull/1467))
5156

57+
- Fixed potential undefined behavior in `Signal::try_from` on some platforms.
58+
(#[1484](https://github.com/nix-rust/nix/pull/1484))
59+
5260
### Removed
5361

5462
- Removed a couple of termios constants on redox that were never actually
5563
supported.
5664
(#[1483](https://github.com/nix-rust/nix/pull/1483))
65+
- Removed `nix::sys::signal::NSIG`. It was of dubious utility, and not correct
66+
for all platforms.
67+
(#[1484](https://github.com/nix-rust/nix/pull/1484))
5768

5869
## [0.22.0] - 9 July 2021
5970
### Added

src/macros.rs

Lines changed: 117 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,9 @@ macro_rules! libc_bitflags {
8383
macro_rules! libc_enum {
8484
// Exit rule.
8585
(@make_enum
86+
name: $BitFlags:ident,
8687
{
8788
$v:vis
88-
name: $BitFlags:ident,
8989
attrs: [$($attrs:tt)*],
9090
entries: [$($entries:tt)*],
9191
}
@@ -97,88 +97,171 @@ macro_rules! libc_enum {
9797
}
9898
};
9999

100+
// Exit rule including TryFrom
101+
(@make_enum
102+
name: $BitFlags:ident,
103+
{
104+
$v:vis
105+
attrs: [$($attrs:tt)*],
106+
entries: [$($entries:tt)*],
107+
from_type: $repr:path,
108+
try_froms: [$($try_froms:tt)*]
109+
}
110+
) => {
111+
$($attrs)*
112+
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
113+
$v enum $BitFlags {
114+
$($entries)*
115+
}
116+
#[allow(unused_doc_comment)]
117+
impl ::std::convert::TryFrom<$repr> for $BitFlags {
118+
type Error = $crate::Error;
119+
fn try_from(x: $repr) -> $crate::Result<Self> {
120+
match x {
121+
$($try_froms)*
122+
_ => Err($crate::Error::EINVAL)
123+
}
124+
}
125+
}
126+
};
127+
100128
// Done accumulating.
101129
(@accumulate_entries
130+
name: $BitFlags:ident,
131+
{
132+
$v:vis
133+
attrs: $attrs:tt,
134+
},
135+
$entries:tt,
136+
$try_froms:tt;
137+
) => {
138+
libc_enum! {
139+
@make_enum
140+
name: $BitFlags,
141+
{
142+
$v
143+
attrs: $attrs,
144+
entries: $entries,
145+
}
146+
}
147+
};
148+
149+
// Done accumulating and want TryFrom
150+
(@accumulate_entries
151+
name: $BitFlags:ident,
102152
{
103153
$v:vis
104-
name: $BitFlags:ident,
105154
attrs: $attrs:tt,
155+
from_type: $repr:path,
106156
},
107-
$entries:tt;
157+
$entries:tt,
158+
$try_froms:tt;
108159
) => {
109160
libc_enum! {
110161
@make_enum
162+
name: $BitFlags,
111163
{
112164
$v
113-
name: $BitFlags,
114165
attrs: $attrs,
115166
entries: $entries,
167+
from_type: $repr,
168+
try_froms: $try_froms
116169
}
117170
}
118171
};
119172

120173
// Munch an attr.
121174
(@accumulate_entries
175+
name: $BitFlags:ident,
122176
$prefix:tt,
123-
[$($entries:tt)*];
177+
[$($entries:tt)*],
178+
[$($try_froms:tt)*];
124179
#[$attr:meta] $($tail:tt)*
125180
) => {
126181
libc_enum! {
127182
@accumulate_entries
183+
name: $BitFlags,
128184
$prefix,
129185
[
130186
$($entries)*
131187
#[$attr]
188+
],
189+
[
190+
$($try_froms)*
191+
#[$attr]
132192
];
133193
$($tail)*
134194
}
135195
};
136196

137197
// Munch last ident if not followed by a comma.
138198
(@accumulate_entries
199+
name: $BitFlags:ident,
139200
$prefix:tt,
140-
[$($entries:tt)*];
201+
[$($entries:tt)*],
202+
[$($try_froms:tt)*];
141203
$entry:ident
142204
) => {
143205
libc_enum! {
144206
@accumulate_entries
207+
name: $BitFlags,
145208
$prefix,
146209
[
147210
$($entries)*
148211
$entry = libc::$entry,
212+
],
213+
[
214+
$($try_froms)*
215+
libc::$entry => Ok($BitFlags::$entry),
149216
];
150217
}
151218
};
152219

153220
// Munch an ident; covers terminating comma case.
154221
(@accumulate_entries
222+
name: $BitFlags:ident,
155223
$prefix:tt,
156-
[$($entries:tt)*];
157-
$entry:ident, $($tail:tt)*
224+
[$($entries:tt)*],
225+
[$($try_froms:tt)*];
226+
$entry:ident,
227+
$($tail:tt)*
158228
) => {
159229
libc_enum! {
160230
@accumulate_entries
231+
name: $BitFlags,
161232
$prefix,
162233
[
163234
$($entries)*
164235
$entry = libc::$entry,
236+
],
237+
[
238+
$($try_froms)*
239+
libc::$entry => Ok($BitFlags::$entry),
165240
];
166241
$($tail)*
167242
}
168243
};
169244

170245
// Munch an ident and cast it to the given type; covers terminating comma.
171246
(@accumulate_entries
247+
name: $BitFlags:ident,
172248
$prefix:tt,
173-
[$($entries:tt)*];
174-
$entry:ident as $ty:ty, $($tail:tt)*
249+
[$($entries:tt)*],
250+
[$($try_froms:tt)*];
251+
$entry:ident as $ty:ty,
252+
$($tail:tt)*
175253
) => {
176254
libc_enum! {
177255
@accumulate_entries
256+
name: $BitFlags,
178257
$prefix,
179258
[
180259
$($entries)*
181260
$entry = libc::$entry as $ty,
261+
],
262+
[
263+
$($try_froms)*
264+
libc::$entry as $ty => Ok($BitFlags::$entry),
182265
];
183266
$($tail)*
184267
}
@@ -193,11 +276,34 @@ macro_rules! libc_enum {
193276
) => {
194277
libc_enum! {
195278
@accumulate_entries
279+
name: $BitFlags,
280+
{
281+
$v
282+
attrs: [$(#[$attr])*],
283+
},
284+
[],
285+
[];
286+
$($vals)*
287+
}
288+
};
289+
290+
// Entry rule including TryFrom
291+
(
292+
$(#[$attr:meta])*
293+
$v:vis enum $BitFlags:ident {
294+
$($vals:tt)*
295+
}
296+
impl TryFrom<$repr:path>
297+
) => {
298+
libc_enum! {
299+
@accumulate_entries
300+
name: $BitFlags,
196301
{
197302
$v
198-
name: $BitFlags,
199303
attrs: [$(#[$attr])*],
304+
from_type: $repr,
200305
},
306+
[],
201307
[];
202308
$($vals)*
203309
}

src/sys/event.rs

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use crate::{Errno, Result};
66
use libc::{timespec, time_t, c_int, c_long, intptr_t, uintptr_t};
77
#[cfg(target_os = "netbsd")]
88
use libc::{timespec, time_t, c_long, intptr_t, uintptr_t, size_t};
9+
use std::convert::TryInto;
910
use std::os::unix::io::RawFd;
1011
use std::ptr;
11-
use std::mem;
1212

1313
// Redefine kevent in terms of programmer-friendly enums and bitfields.
1414
#[repr(C)]
@@ -76,6 +76,7 @@ libc_enum! {
7676
EVFILT_VNODE,
7777
EVFILT_WRITE,
7878
}
79+
impl TryFrom<type_of_event_filter>
7980
}
8081

8182
#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
@@ -233,8 +234,8 @@ impl KEvent {
233234
self.kevent.ident
234235
}
235236

236-
pub fn filter(&self) -> EventFilter {
237-
unsafe { mem::transmute(self.kevent.filter as type_of_event_filter) }
237+
pub fn filter(&self) -> Result<EventFilter> {
238+
self.kevent.filter.try_into()
238239
}
239240

240241
pub fn flags(&self) -> EventFlag {
@@ -313,6 +314,8 @@ pub fn ev_set(ev: &mut KEvent,
313314

314315
#[test]
315316
fn test_struct_kevent() {
317+
use std::mem;
318+
316319
let udata : intptr_t = 12345;
317320

318321
let actual = KEvent::new(0xdead_beef,
@@ -322,10 +325,24 @@ fn test_struct_kevent() {
322325
0x1337,
323326
udata);
324327
assert_eq!(0xdead_beef, actual.ident());
325-
assert_eq!(libc::EVFILT_READ, actual.filter() as type_of_event_filter);
328+
let filter = actual.kevent.filter;
329+
assert_eq!(libc::EVFILT_READ, filter);
326330
assert_eq!(libc::EV_ONESHOT | libc::EV_ADD, actual.flags().bits());
327331
assert_eq!(libc::NOTE_CHILD | libc::NOTE_EXIT, actual.fflags().bits());
328332
assert_eq!(0x1337, actual.data() as type_of_data);
329333
assert_eq!(udata as type_of_udata, actual.udata() as type_of_udata);
330334
assert_eq!(mem::size_of::<libc::kevent>(), mem::size_of::<KEvent>());
331335
}
336+
337+
#[test]
338+
fn test_kevent_filter() {
339+
let udata : intptr_t = 12345;
340+
341+
let actual = KEvent::new(0xdead_beef,
342+
EventFilter::EVFILT_READ,
343+
EventFlag::EV_ONESHOT | EventFlag::EV_ADD,
344+
FilterFlag::NOTE_CHILD | FilterFlag::NOTE_EXIT,
345+
0x1337,
346+
udata);
347+
assert_eq!(EventFilter::EVFILT_READ, actual.filter().unwrap());
348+
}

src/sys/signal.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
use crate::{Error, Result};
77
use crate::errno::Errno;
88
use crate::unistd::Pid;
9-
use std::convert::TryFrom;
109
use std::mem;
1110
use std::fmt;
1211
use std::str::FromStr;
@@ -71,6 +70,7 @@ libc_enum!{
7170
target_os = "redox")))]
7271
SIGINFO,
7372
}
73+
impl TryFrom<i32>
7474
}
7575

7676
impl FromStr for Signal {
@@ -335,8 +335,6 @@ const SIGNALS: [Signal; 31] = [
335335
SIGEMT,
336336
SIGINFO];
337337

338-
pub const NSIG: libc::c_int = 32;
339-
340338
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
341339
pub struct SignalIterator {
342340
next: usize,
@@ -362,18 +360,6 @@ impl Signal {
362360
}
363361
}
364362

365-
impl TryFrom<libc::c_int> for Signal {
366-
type Error = Error;
367-
368-
fn try_from(signum: libc::c_int) -> Result<Signal> {
369-
if 0 < signum && signum < NSIG {
370-
Ok(unsafe { mem::transmute(signum) })
371-
} else {
372-
Err(Error::from(Errno::EINVAL))
373-
}
374-
}
375-
}
376-
377363
pub const SIGIOT : Signal = SIGABRT;
378364
pub const SIGPOLL : Signal = SIGIO;
379365
pub const SIGUNUSED : Signal = SIGSYS;
@@ -489,6 +475,8 @@ impl SigSet {
489475
/// signal mask becomes pending, and returns the accepted signal.
490476
#[cfg(not(target_os = "redox"))] // RedoxFS does not yet support sigwait
491477
pub fn wait(&self) -> Result<Signal> {
478+
use std::convert::TryFrom;
479+
492480
let mut signum = mem::MaybeUninit::uninit();
493481
let res = unsafe { libc::sigwait(&self.sigset as *const libc::sigset_t, signum.as_mut_ptr()) };
494482

0 commit comments

Comments
 (0)