• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use rayon_core::ThreadPoolBuilder;
2 
3 use std::env;
4 use std::process::{Command, ExitStatus, Stdio};
5 
6 #[cfg(target_os = "linux")]
7 use std::os::unix::process::ExitStatusExt;
8 
force_stack_overflow(depth: u32)9 fn 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)]
disable_core()18 fn 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)]
overflow_code() -> Option<i32>31 fn overflow_code() -> Option<i32> {
32     None
33 }
34 
35 #[cfg(windows)]
overflow_code() -> Option<i32>36 fn 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)]
stack_overflow_crash()44 fn 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 
run_ignored(test: &str) -> ExitStatus64 fn 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]
run_with_small_stack()77 fn run_with_small_stack() {
78     run_with_stack(8);
79 }
80 
81 #[test]
82 #[ignore]
run_with_large_stack()83 fn run_with_large_stack() {
84     run_with_stack(48);
85 }
86 
run_with_stack(stack_size_in_mb: usize)87 fn 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