1use rayon_core::ThreadPoolBuilder;
2
3use std::env;
4use std::process::{Command, ExitStatus, Stdio};
5
6#[cfg(target_os = "linux")]
7use std::os::unix::process::ExitStatusExt;
8
9fn force_stack_overflow(depth: u32) {
10 let mut buffer = [0u8; 1024 * 1024];
11 std::hint::black_box(&mut buffer);
12 if depth > 0 {
13 force_stack_overflow(depth - 1);
14 }
15}
16
17#[cfg(unix)]
18fn disable_core() {
19 unsafe {
20 libc::setrlimit(
21 libc::RLIMIT_CORE,
22 &libc::rlimit {
23 rlim_cur: 0,
24 rlim_max: 0,
25 },
26 );
27 }
28}
29
30#[cfg(unix)]
31fn overflow_code() -> Option<i32> {
32 None
33}
34
35#[cfg(windows)]
36fn overflow_code() -> Option<i32> {
37 use std::os::windows::process::ExitStatusExt;
38
39 ExitStatus::from_raw(0xc00000fd /*STATUS_STACK_OVERFLOW*/).code()
40}
41
42#[test]
43#[cfg_attr(not(any(unix, windows)), ignore)]
44fn stack_overflow_crash() {
45 // First check that the recursive call actually causes a stack overflow,
46 // and does not get optimized away.
47 let status = run_ignored("run_with_small_stack");
48 assert!(!status.success());
49 #[cfg(any(unix, windows))]
50 assert_eq!(status.code(), overflow_code());
51 #[cfg(target_os = "linux")]
52 assert!(matches!(
53 status.signal(),
54 Some(libc::SIGABRT | libc::SIGSEGV)
55 ));
56
57 // Now run with a larger stack and verify correct operation.
58 let status = run_ignored("run_with_large_stack");
59 assert_eq!(status.code(), Some(0));
60 #[cfg(target_os = "linux")]
61 assert_eq!(status.signal(), None);
62}
63
64fn run_ignored(test: &str) -> ExitStatus {
65 Command::new(env::current_exe().unwrap())
66 .arg("--ignored")
67 .arg("--exact")
68 .arg(test)
69 .stdout(Stdio::null())
70 .stderr(Stdio::null())
71 .status()
72 .unwrap()
73}
74
75#[test]
76#[ignore]
77fn run_with_small_stack() {
78 run_with_stack(8);
79}
80
81#[test]
82#[ignore]
83fn run_with_large_stack() {
84 run_with_stack(48);
85}
86
87fn run_with_stack(stack_size_in_mb: usize) {
88 let pool = ThreadPoolBuilder::new()
89 .stack_size(stack_size_in_mb * 1024 * 1024)
90 .build()
91 .unwrap();
92 pool.install(|| {
93 #[cfg(unix)]
94 disable_core();
95 force_stack_overflow(32);
96 });
97}
98