11use rayon_core:: ThreadPoolBuilder ;
22
33use std:: env;
4- use std:: process:: Command ;
4+ use std:: process:: { Command , ExitStatus , Stdio } ;
55
66#[ cfg( target_os = "linux" ) ]
77use std:: os:: unix:: process:: ExitStatusExt ;
88
99fn force_stack_overflow ( depth : u32 ) {
10- let _buffer = [ 0u8 ; 1024 * 1024 ] ;
10+ let mut buffer = [ 0u8 ; 1024 * 1024 ] ;
11+ std:: hint:: black_box ( & mut buffer) ;
1112 if depth > 0 {
1213 force_stack_overflow ( depth - 1 ) ;
1314 }
@@ -34,49 +35,61 @@ fn overflow_code() -> Option<i32> {
3435#[ cfg( windows) ]
3536fn overflow_code ( ) -> Option < i32 > {
3637 use std:: os:: windows:: process:: ExitStatusExt ;
37- use std:: process:: ExitStatus ;
3838
3939 ExitStatus :: from_raw ( 0xc00000fd /*STATUS_STACK_OVERFLOW*/ ) . code ( )
4040}
4141
42- fn main ( ) {
43- if env:: args ( ) . len ( ) == 1 {
44- // first check that the recursivecall actually causes a stack overflow, and does not get optimized away
45- {
46- let status = Command :: new ( env:: current_exe ( ) . unwrap ( ) )
47- . arg ( "8" )
48- . status ( )
49- . unwrap ( ) ;
42+ #[ test]
43+ fn stack_overflow_crash ( ) {
44+ // First check that the recursive call actually causes a stack overflow,
45+ // and does not get optimized away.
46+ let status = run_ignored ( "run_with_small_stack" ) ;
47+ #[ cfg( any( unix, windows) ) ]
48+ assert_eq ! ( status. code( ) , overflow_code( ) ) ;
49+ #[ cfg( target_os = "linux" ) ]
50+ assert ! ( matches!(
51+ status. signal( ) ,
52+ Some ( libc:: SIGABRT | libc:: SIGSEGV )
53+ ) ) ;
5054
51- #[ cfg( any( unix, windows) ) ]
52- assert_eq ! ( status. code( ) , overflow_code( ) ) ;
55+ // Now run with a larger stack and verify correct operation.
56+ let status = run_ignored ( "run_with_large_stack" ) ;
57+ assert_eq ! ( status. code( ) , Some ( 0 ) ) ;
58+ #[ cfg( target_os = "linux" ) ]
59+ assert_eq ! ( status. signal( ) , None ) ;
60+ }
5361
54- #[ cfg( target_os = "linux" ) ]
55- assert ! (
56- status. signal( ) == Some ( 11 /*SIGABRT*/ ) || status. signal( ) == Some ( 6 /*SIGSEGV*/ )
57- ) ;
58- }
62+ fn run_ignored ( test : & str ) -> ExitStatus {
63+ Command :: new ( env:: current_exe ( ) . unwrap ( ) )
64+ . arg ( "--ignored" )
65+ . arg ( "--exact" )
66+ . arg ( test)
67+ . stdout ( Stdio :: null ( ) )
68+ . stderr ( Stdio :: null ( ) )
69+ . status ( )
70+ . unwrap ( )
71+ }
5972
60- // now run with a larger stack and verify correct operation
61- {
62- let status = Command :: new ( env :: current_exe ( ) . unwrap ( ) )
63- . arg ( "48" )
64- . status ( )
65- . unwrap ( ) ;
66- assert_eq ! ( status . code ( ) , Some ( 0 ) ) ;
67- # [ cfg ( target_os = "linux" ) ]
68- assert_eq ! ( status . signal ( ) , None ) ;
69- }
70- } else {
71- let stack_size_in_mb : usize = env :: args ( ) . nth ( 1 ) . unwrap ( ) . parse ( ) . unwrap ( ) ;
72- let pool = ThreadPoolBuilder :: new ( )
73- . stack_size ( stack_size_in_mb * 1024 * 1024 )
74- . build ( )
75- . unwrap ( ) ;
76- pool . install ( || {
77- # [ cfg ( unix ) ]
78- disable_core ( ) ;
79- force_stack_overflow ( 32 ) ;
80- } ) ;
81- }
73+ # [ test ]
74+ # [ ignore ]
75+ fn run_with_small_stack ( ) {
76+ run_with_stack ( 8 ) ;
77+ }
78+
79+ # [ test ]
80+ # [ ignore ]
81+ fn run_with_large_stack ( ) {
82+ run_with_stack ( 48 ) ;
83+ }
84+
85+ fn run_with_stack ( stack_size_in_mb : usize ) {
86+ let pool = ThreadPoolBuilder :: new ( )
87+ . stack_size ( stack_size_in_mb * 1024 * 1024 )
88+ . build ( )
89+ . unwrap ( ) ;
90+ pool . install ( || {
91+ # [ cfg ( unix ) ]
92+ disable_core ( ) ;
93+ force_stack_overflow ( 32 ) ;
94+ } ) ;
8295}
0 commit comments