1
1
use rayon_core:: ThreadPoolBuilder ;
2
2
3
3
use std:: env;
4
- use std:: process:: Command ;
4
+ use std:: process:: { Command , ExitStatus , Stdio } ;
5
5
6
6
#[ cfg( target_os = "linux" ) ]
7
7
use std:: os:: unix:: process:: ExitStatusExt ;
8
8
9
9
fn 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) ;
11
12
if depth > 0 {
12
13
force_stack_overflow ( depth - 1 ) ;
13
14
}
@@ -34,49 +35,61 @@ fn overflow_code() -> Option<i32> {
34
35
#[ cfg( windows) ]
35
36
fn overflow_code ( ) -> Option < i32 > {
36
37
use std:: os:: windows:: process:: ExitStatusExt ;
37
- use std:: process:: ExitStatus ;
38
38
39
39
ExitStatus :: from_raw ( 0xc00000fd /*STATUS_STACK_OVERFLOW*/ ) . code ( )
40
40
}
41
41
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
+ ) ) ;
50
54
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
+ }
53
61
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
+ }
59
72
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
+ } ) ;
82
95
}
0 commit comments