Skip to content

Commit e04514e

Browse files
authored
Merge pull request #194 from hanna-kruppe/save-restore-errno
Save and restore errno
2 parents 017e9b5 + 2f3c6e4 commit e04514e

File tree

5 files changed

+41
-0
lines changed

5 files changed

+41
-0
lines changed

.github/workflows/test.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ jobs:
119119
cd signal-hook-registry
120120
sed -i -e '/signal-hook =/d' Cargo.toml
121121
sed -i -e 's/libc = "^0.2"/libc = "=0.2.156"/' Cargo.toml
122+
sed -i -e 's/errno = ">=0.2, <0.4"/errno = "0.2"/' Cargo.toml
122123
cargo check
123124
124125
ancient:
@@ -144,6 +145,7 @@ jobs:
144145
run: |
145146
rm Cargo.lock
146147
sed -i -e 's/libc = "^0.2"/libc = "=0.2.156"/' Cargo.toml
148+
sed -i -e 's/errno = ">=0.2, <0.4"/errno = "0.2"/' signal-hook-registry/Cargo.toml
147149
cargo update
148150
cargo check --no-default-features
149151

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ci-check.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ rm -f Cargo.lock
1212
if [ "$RUST_VERSION" = 1.36.0 ] || [ "$RUST_VERSION" = 1.40.0 ] ; then
1313
sed -i -e 's/libc = "^0.2"/libc = "=0.2.156"/' Cargo.toml
1414
sed -i -e 's/cc = { version = "^1"/cc = { version = "=1.0.79"/' Cargo.toml
15+
sed -i -e 's/errno = ">=0.2, <0.4"/errno = "0.2"/' signal-hook-registry/Cargo.toml
1516
fi
1617

1718
cargo build --all --exclude signal-hook-async-std --exclude signal-hook-tokio

signal-hook-registry/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ maintenance = { status = "actively-developed" }
2020

2121
[dependencies]
2222
libc = "^0.2"
23+
errno = ">=0.2, <0.4"
2324

2425
[dev-dependencies]
2526
signal-hook = { version = "~0.3", path = ".." }

signal-hook-registry/src/lib.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
//! [signal-hook]: https://docs.rs/signal-hook
6363
//! [async-signal-safe]: http://www.man7.org/linux/man-pages/man7/signal-safety.7.html
6464
65+
extern crate errno;
6566
extern crate libc;
6667

6768
mod half_lock;
@@ -77,6 +78,7 @@ use std::sync::atomic::{AtomicPtr, Ordering};
7778
use std::sync::ONCE_INIT;
7879
use std::sync::{Arc, Once};
7980

81+
use errno::Errno;
8082
#[cfg(not(windows))]
8183
use libc::{c_int, c_void, sigaction, siginfo_t};
8284
#[cfg(windows)]
@@ -337,6 +339,8 @@ impl GlobalData {
337339

338340
#[cfg(windows)]
339341
extern "C" fn handler(sig: c_int) {
342+
let _errno = ErrnoGuard::new();
343+
340344
if sig != SIGFPE {
341345
// Windows CRT `signal` resets handler every time, unless for SIGFPE.
342346
// Reregister the handler to retain maximal compatibility.
@@ -384,6 +388,8 @@ extern "C" fn handler(sig: c_int) {
384388
// cfg_attr is needed because the `allow(clippy::lint)` syntax was added in Rust 1.31
385389
#[cfg_attr(clippy, allow(clippy::incompatible_msrv))]
386390
extern "C" fn handler(sig: c_int, info: *mut siginfo_t, data: *mut c_void) {
391+
let _errno = ErrnoGuard::new();
392+
387393
let globals = GlobalData::get();
388394
let fallback = globals.race_fallback.read();
389395
let sigdata = globals.data.read();
@@ -421,6 +427,20 @@ extern "C" fn handler(sig: c_int, info: *mut siginfo_t, data: *mut c_void) {
421427
}
422428
}
423429

430+
struct ErrnoGuard(Errno);
431+
432+
impl ErrnoGuard {
433+
fn new() -> Self {
434+
ErrnoGuard(errno::errno())
435+
}
436+
}
437+
438+
impl Drop for ErrnoGuard {
439+
fn drop(&mut self) {
440+
errno::set_errno(self.0);
441+
}
442+
}
443+
424444
/// List of forbidden signals.
425445
///
426446
/// Some signals are impossible to replace according to POSIX and some are so special that this
@@ -831,4 +851,20 @@ mod tests {
831851
// The next time unregistering does nothing and tells us so.
832852
assert!(!unregister(signal));
833853
}
854+
855+
/// Check that errno is not clobbered by the signal handler.
856+
#[test]
857+
fn save_restore_errno() {
858+
const MAGIC_ERRNO: i32 = 123456;
859+
let action = move || {
860+
errno::set_errno(Errno(MAGIC_ERRNO));
861+
};
862+
unsafe {
863+
register(SIGUSR1, action).unwrap();
864+
libc::raise(SIGUSR1);
865+
}
866+
// NB: raise() might clobber errno on some platforms, so this test isn't waterproof. But it
867+
// fails at least sometimes on some platforms if the errno save/restore is removed.
868+
assert!(errno::errno().0 != MAGIC_ERRNO);
869+
}
834870
}

0 commit comments

Comments
 (0)