Skip to content

Commit

Permalink
Merge #1009
Browse files Browse the repository at this point in the history
1009: Improve rayon-core/tests/stack_overflow_crash.rs r=cuviper a=cuviper

- Rewrite it within the regular test harness, so it doesn't crash in
  arg-parsing on broad `cargo test -- filter` commands.
- Use `std::hint::black_box` so the test even works in `--release`.


Co-authored-by: Josh Stone <cuviper@gmail.com>
  • Loading branch information
bors[bot] and cuviper authored Jan 17, 2023
2 parents 1cacc82 + e4ba8d1 commit 0cc5912
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 41 deletions.
1 change: 0 additions & 1 deletion rayon-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ libc = "0.2"
[[test]]
name = "stack_overflow_crash"
path = "tests/stack_overflow_crash.rs"
harness = false

# NB: having one [[test]] manually defined means we need to declare them all

Expand Down
93 changes: 53 additions & 40 deletions rayon-core/tests/stack_overflow_crash.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use rayon_core::ThreadPoolBuilder;

use std::env;
use std::process::Command;
use std::process::{Command, ExitStatus, Stdio};

#[cfg(target_os = "linux")]
use std::os::unix::process::ExitStatusExt;

fn force_stack_overflow(depth: u32) {
let _buffer = [0u8; 1024 * 1024];
let mut buffer = [0u8; 1024 * 1024];
std::hint::black_box(&mut buffer);
if depth > 0 {
force_stack_overflow(depth - 1);
}
Expand All @@ -34,49 +35,61 @@ fn overflow_code() -> Option<i32> {
#[cfg(windows)]
fn overflow_code() -> Option<i32> {
use std::os::windows::process::ExitStatusExt;
use std::process::ExitStatus;

ExitStatus::from_raw(0xc00000fd /*STATUS_STACK_OVERFLOW*/).code()
}

fn main() {
if env::args().len() == 1 {
// first check that the recursivecall actually causes a stack overflow, and does not get optimized away
{
let status = Command::new(env::current_exe().unwrap())
.arg("8")
.status()
.unwrap();
#[test]
fn stack_overflow_crash() {
// First check that the recursive call actually causes a stack overflow,
// and does not get optimized away.
let status = run_ignored("run_with_small_stack");
#[cfg(any(unix, windows))]
assert_eq!(status.code(), overflow_code());
#[cfg(target_os = "linux")]
assert!(matches!(
status.signal(),
Some(libc::SIGABRT | libc::SIGSEGV)
));

#[cfg(any(unix, windows))]
assert_eq!(status.code(), overflow_code());
// Now run with a larger stack and verify correct operation.
let status = run_ignored("run_with_large_stack");
assert_eq!(status.code(), Some(0));
#[cfg(target_os = "linux")]
assert_eq!(status.signal(), None);
}

#[cfg(target_os = "linux")]
assert!(
status.signal() == Some(11 /*SIGABRT*/) || status.signal() == Some(6 /*SIGSEGV*/)
);
}
fn run_ignored(test: &str) -> ExitStatus {
Command::new(env::current_exe().unwrap())
.arg("--ignored")
.arg("--exact")
.arg(test)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.unwrap()
}

// now run with a larger stack and verify correct operation
{
let status = Command::new(env::current_exe().unwrap())
.arg("48")
.status()
.unwrap();
assert_eq!(status.code(), Some(0));
#[cfg(target_os = "linux")]
assert_eq!(status.signal(), None);
}
} else {
let stack_size_in_mb: usize = env::args().nth(1).unwrap().parse().unwrap();
let pool = ThreadPoolBuilder::new()
.stack_size(stack_size_in_mb * 1024 * 1024)
.build()
.unwrap();
pool.install(|| {
#[cfg(unix)]
disable_core();
force_stack_overflow(32);
});
}
#[test]
#[ignore]
fn run_with_small_stack() {
run_with_stack(8);
}

#[test]
#[ignore]
fn run_with_large_stack() {
run_with_stack(48);
}

fn run_with_stack(stack_size_in_mb: usize) {
let pool = ThreadPoolBuilder::new()
.stack_size(stack_size_in_mb * 1024 * 1024)
.build()
.unwrap();
pool.install(|| {
#[cfg(unix)]
disable_core();
force_stack_overflow(32);
});
}

0 comments on commit 0cc5912

Please sign in to comment.