Skip to content

Commit 387efba

Browse files
committed
SigSet: Fix incorrect implementation of Eq, PartialEq and Hash
`signal::SigSet` derives `Eq`, `PartialEq` and `Hash`, but on linux, sigfillset(3) only initializes the first 64 bits, leaving the rest uninitialized. So two `signal::SigSets` can be different even though both have the same set of signals. Signed-off-by: German Maglione <[email protected]>
1 parent 99ea907 commit 387efba

File tree

2 files changed

+70
-1
lines changed

2 files changed

+70
-1
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ This project adheres to [Semantic Versioning](https://semver.org/).
2323
([#1921](https://github.com/nix-rust/nix/pull/1921))
2424

2525
### Fixed
26+
- Fix `SigSet` incorrect implementation of `Eq`, `PartialEq` and `Hash`
27+
([#1946](https://github.com/nix-rust/nix/pull/1946))
28+
2629
### Removed
2730

2831
- Removed deprecated IoVec API.

src/sys/signal.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::errno::Errno;
77
use crate::{Error, Result};
88
use cfg_if::cfg_if;
99
use std::fmt;
10+
use std::hash::{Hash, Hasher};
1011
use std::mem;
1112
#[cfg(any(target_os = "dragonfly", target_os = "freebsd"))]
1213
use std::os::unix::io::RawFd;
@@ -468,7 +469,7 @@ use std::iter::IntoIterator;
468469
// We are using `transparent` here to be super sure that `SigSet`
469470
// is represented exactly like the `sigset_t` struct from C.
470471
#[repr(transparent)]
471-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
472+
#[derive(Clone, Copy, Debug, Eq)]
472473
pub struct SigSet {
473474
sigset: libc::sigset_t
474475
}
@@ -610,6 +611,27 @@ impl FromIterator<Signal> for SigSet {
610611
}
611612
}
612613

614+
impl PartialEq for SigSet {
615+
fn eq(&self, other: &Self) -> bool {
616+
for signal in Signal::iterator() {
617+
if self.contains(signal) != other.contains(signal) {
618+
return false;
619+
}
620+
}
621+
true
622+
}
623+
}
624+
625+
impl Hash for SigSet {
626+
fn hash<H: Hasher>(&self, state: &mut H) {
627+
for signal in Signal::iterator() {
628+
if self.contains(signal) {
629+
signal.hash(state);
630+
}
631+
}
632+
}
633+
}
634+
613635
/// Iterator for a [`SigSet`].
614636
///
615637
/// Call [`SigSet::iter`] to create an iterator.
@@ -1344,4 +1366,48 @@ mod tests {
13441366
assert!(set.contains(signal));
13451367
}
13461368
}
1369+
1370+
#[test]
1371+
fn test_eq_empty() {
1372+
let set0 = SigSet::empty();
1373+
let set1 = SigSet::empty();
1374+
assert_eq!(set0, set1);
1375+
}
1376+
1377+
#[test]
1378+
fn test_eq_all() {
1379+
let set0 = SigSet::all();
1380+
let set1 = SigSet::all();
1381+
assert_eq!(set0, set1);
1382+
}
1383+
1384+
#[test]
1385+
fn test_hash_empty() {
1386+
use std::collections::hash_map::DefaultHasher;
1387+
1388+
let set0 = SigSet::empty();
1389+
let mut h0 = DefaultHasher::new();
1390+
set0.hash(&mut h0);
1391+
1392+
let set1 = SigSet::empty();
1393+
let mut h1 = DefaultHasher::new();
1394+
set1.hash(&mut h1);
1395+
1396+
assert_eq!(h0.finish(), h1.finish());
1397+
}
1398+
1399+
#[test]
1400+
fn test_hash_all() {
1401+
use std::collections::hash_map::DefaultHasher;
1402+
1403+
let set0 = SigSet::all();
1404+
let mut h0 = DefaultHasher::new();
1405+
set0.hash(&mut h0);
1406+
1407+
let set1 = SigSet::all();
1408+
let mut h1 = DefaultHasher::new();
1409+
set1.hash(&mut h1);
1410+
1411+
assert_eq!(h0.finish(), h1.finish());
1412+
}
13471413
}

0 commit comments

Comments
 (0)