Skip to content

Commit 57663c0

Browse files
authored
SigSet: Fix incorrect implementation of Eq, PartialEq and Hash (#1946)
`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 8ad064d commit 57663c0

File tree

2 files changed

+71
-1
lines changed

2 files changed

+71
-1
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](https://semver.org/).
55

66
## [Unreleased] - ReleaseDate
77

8+
### Fixed
9+
- Fix `SigSet` incorrect implementation of `Eq`, `PartialEq` and `Hash`
10+
([#1946](https://github.com/nix-rust/nix/pull/1946))
11+
812
### Changed
913

1014
- The following APIs now take an implementation of `AsFd` rather than a

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;
@@ -486,7 +487,7 @@ use std::iter::IntoIterator;
486487
// We are using `transparent` here to be super sure that `SigSet`
487488
// is represented exactly like the `sigset_t` struct from C.
488489
#[repr(transparent)]
489-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
490+
#[derive(Clone, Copy, Debug, Eq)]
490491
pub struct SigSet {
491492
sigset: libc::sigset_t
492493
}
@@ -628,6 +629,27 @@ impl FromIterator<Signal> for SigSet {
628629
}
629630
}
630631

632+
impl PartialEq for SigSet {
633+
fn eq(&self, other: &Self) -> bool {
634+
for signal in Signal::iterator() {
635+
if self.contains(signal) != other.contains(signal) {
636+
return false;
637+
}
638+
}
639+
true
640+
}
641+
}
642+
643+
impl Hash for SigSet {
644+
fn hash<H: Hasher>(&self, state: &mut H) {
645+
for signal in Signal::iterator() {
646+
if self.contains(signal) {
647+
signal.hash(state);
648+
}
649+
}
650+
}
651+
}
652+
631653
/// Iterator for a [`SigSet`].
632654
///
633655
/// Call [`SigSet::iter`] to create an iterator.
@@ -1554,4 +1576,48 @@ mod tests {
15541576
assert!(set.contains(signal));
15551577
}
15561578
}
1579+
1580+
#[test]
1581+
fn test_eq_empty() {
1582+
let set0 = SigSet::empty();
1583+
let set1 = SigSet::empty();
1584+
assert_eq!(set0, set1);
1585+
}
1586+
1587+
#[test]
1588+
fn test_eq_all() {
1589+
let set0 = SigSet::all();
1590+
let set1 = SigSet::all();
1591+
assert_eq!(set0, set1);
1592+
}
1593+
1594+
#[test]
1595+
fn test_hash_empty() {
1596+
use std::collections::hash_map::DefaultHasher;
1597+
1598+
let set0 = SigSet::empty();
1599+
let mut h0 = DefaultHasher::new();
1600+
set0.hash(&mut h0);
1601+
1602+
let set1 = SigSet::empty();
1603+
let mut h1 = DefaultHasher::new();
1604+
set1.hash(&mut h1);
1605+
1606+
assert_eq!(h0.finish(), h1.finish());
1607+
}
1608+
1609+
#[test]
1610+
fn test_hash_all() {
1611+
use std::collections::hash_map::DefaultHasher;
1612+
1613+
let set0 = SigSet::all();
1614+
let mut h0 = DefaultHasher::new();
1615+
set0.hash(&mut h0);
1616+
1617+
let set1 = SigSet::all();
1618+
let mut h1 = DefaultHasher::new();
1619+
set1.hash(&mut h1);
1620+
1621+
assert_eq!(h0.finish(), h1.finish());
1622+
}
15571623
}

0 commit comments

Comments
 (0)