77//@ [strong] compile-flags: -Z stack-protector=strong
88//@ [basic] compile-flags: -Z stack-protector=basic
99//@ [none] compile-flags: -Z stack-protector=none
10- //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
10+ //@ compile-flags: -C opt-level=2 -Z merge-functions=disabled -Cpanic=abort
1111
1212#![ crate_type = "lib" ]
1313#![ allow( internal_features) ]
1616// CHECK-LABEL: emptyfn:
1717#[ no_mangle]
1818pub fn emptyfn ( ) {
19+ // CHECK-DAG: .cv_fpo_endprologue
1920 // all: __security_check_cookie
2021 // strong-NOT: __security_check_cookie
2122 // basic-NOT: __security_check_cookie
2223 // none-NOT: __security_check_cookie
2324 // missing-NOT: __security_check_cookie
25+ // CHECK-DAG: .cv_fpo_endproc
2426}
2527
2628// CHECK-LABEL: array_char
2729#[ no_mangle]
2830pub fn array_char ( f : fn ( * const char ) ) {
31+ // CHECK-DAG: .cv_fpo_endprologue
2932 let a = [ 'c' ; 1 ] ;
3033 let b = [ 'd' ; 3 ] ;
3134 let c = [ 'e' ; 15 ] ;
@@ -39,11 +42,14 @@ pub fn array_char(f: fn(*const char)) {
3942 // basic: __security_check_cookie
4043 // none-NOT: __security_check_cookie
4144 // missing-NOT: __security_check_cookie
45+
46+ // CHECK-DAG: .cv_fpo_endproc
4247}
4348
4449// CHECK-LABEL: array_u8_1
4550#[ no_mangle]
4651pub fn array_u8_1 ( f : fn ( * const u8 ) ) {
52+ // CHECK-DAG: .cv_fpo_endprologue
4753 let a = [ 0u8 ; 1 ] ;
4854 f ( & a as * const _ ) ;
4955
@@ -55,11 +61,14 @@ pub fn array_u8_1(f: fn(*const u8)) {
5561 // basic-NOT: __security_check_cookie
5662 // none-NOT: __security_check_cookie
5763 // missing-NOT: __security_check_cookie
64+
65+ // CHECK-DAG: .cv_fpo_endproc
5866}
5967
6068// CHECK-LABEL: array_u8_small:
6169#[ no_mangle]
6270pub fn array_u8_small ( f : fn ( * const u8 ) ) {
71+ // CHECK-DAG: .cv_fpo_endprologue
6372 let a = [ 0u8 ; 2 ] ;
6473 let b = [ 0u8 ; 7 ] ;
6574 f ( & a as * const _ ) ;
@@ -72,11 +81,14 @@ pub fn array_u8_small(f: fn(*const u8)) {
7281 // basic-NOT: __security_check_cookie
7382 // none-NOT: __security_check_cookie
7483 // missing-NOT: __security_check_cookie
84+
85+ // CHECK-DAG: .cv_fpo_endproc
7586}
7687
7788// CHECK-LABEL: array_u8_large:
7889#[ no_mangle]
7990pub fn array_u8_large ( f : fn ( * const u8 ) ) {
91+ // CHECK-DAG: .cv_fpo_endprologue
8092 let a = [ 0u8 ; 9 ] ;
8193 f ( & a as * const _ ) ;
8294
@@ -88,6 +100,8 @@ pub fn array_u8_large(f: fn(*const u8)) {
88100 // basic: __security_check_cookie
89101 // none-NOT: __security_check_cookie
90102 // missing-NOT: __security_check_cookie
103+
104+ // CHECK-DAG: .cv_fpo_endproc
91105}
92106
93107#[ derive( Copy , Clone ) ]
@@ -96,6 +110,7 @@ pub struct ByteSizedNewtype(u8);
96110// CHECK-LABEL: array_bytesizednewtype_9:
97111#[ no_mangle]
98112pub fn array_bytesizednewtype_9 ( f : fn ( * const ByteSizedNewtype ) ) {
113+ // CHECK-DAG: .cv_fpo_endprologue
99114 let a = [ ByteSizedNewtype ( 0 ) ; 9 ] ;
100115 f ( & a as * const _ ) ;
101116
@@ -107,11 +122,14 @@ pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) {
107122 // basic: __security_check_cookie
108123 // none-NOT: __security_check_cookie
109124 // missing-NOT: __security_check_cookie
125+
126+ // CHECK-DAG: .cv_fpo_endproc
110127}
111128
112129// CHECK-LABEL: local_var_addr_used_indirectly
113130#[ no_mangle]
114131pub fn local_var_addr_used_indirectly ( f : fn ( bool ) ) {
132+ // CHECK-DAG: .cv_fpo_endprologue
115133 let a = 5 ;
116134 let a_addr = & a as * const _ as usize ;
117135 f ( a_addr & 0x10 == 0 ) ;
@@ -134,37 +152,27 @@ pub fn local_var_addr_used_indirectly(f: fn(bool)) {
134152 // basic-NOT: __security_check_cookie
135153 // none-NOT: __security_check_cookie
136154 // missing-NOT: __security_check_cookie
155+
156+ // CHECK-DAG: .cv_fpo_endproc
137157}
138158
139159// CHECK-LABEL: local_string_addr_taken
140160#[ no_mangle]
141161pub fn local_string_addr_taken ( f : fn ( & String ) ) {
162+ // CHECK-DAG: .cv_fpo_endprologue
142163 let x = String :: new ( ) ;
143164 f ( & x) ;
144165
145166 // Taking the address of the local variable `x` leads to stack smash
146- // protection with the `strong` heuristic, but not with the `basic`
147- // heuristic. It does not matter that the reference is not mut.
148- //
149- // An interesting note is that a similar function in C++ *would* be
150- // protected by the `basic` heuristic, because `std::string` has a char
151- // array internally as a small object optimization:
152- // ```
153- // cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk
154- // #include <string>
155- // void f(void (*g)(const std::string&)) {
156- // std::string x;
157- // g(x);
158- // }
159- // EOF
160- // ```
161- //
167+ // protection. It does not matter that the reference is not mut.
162168
163169 // all: __security_check_cookie
164- // strong-NOT : __security_check_cookie
165- // basic-NOT : __security_check_cookie
170+ // strong: __security_check_cookie
171+ // basic: __security_check_cookie
166172 // none-NOT: __security_check_cookie
167173 // missing-NOT: __security_check_cookie
174+
175+ // CHECK-DAG: .cv_fpo_endproc
168176}
169177
170178pub trait SelfByRef {
@@ -180,6 +188,7 @@ impl SelfByRef for i32 {
180188// CHECK-LABEL: local_var_addr_taken_used_locally_only
181189#[ no_mangle]
182190pub fn local_var_addr_taken_used_locally_only ( factory : fn ( ) -> i32 , sink : fn ( i32 ) ) {
191+ // CHECK-DAG: .cv_fpo_endprologue
183192 let x = factory ( ) ;
184193 let g = x. f ( ) ;
185194 sink ( g) ;
@@ -194,6 +203,8 @@ pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32
194203 // basic-NOT: __security_check_cookie
195204 // none-NOT: __security_check_cookie
196205 // missing-NOT: __security_check_cookie
206+
207+ // CHECK-DAG: .cv_fpo_endproc
197208}
198209
199210pub struct Gigastruct {
@@ -207,6 +218,7 @@ pub struct Gigastruct {
207218// CHECK-LABEL: local_large_var_moved
208219#[ no_mangle]
209220pub fn local_large_var_moved ( f : fn ( Gigastruct ) ) {
221+ // CHECK-DAG: .cv_fpo_endprologue
210222 let x = Gigastruct { does : 0 , not : 1 , have : 2 , array : 3 , members : 4 } ;
211223 f ( x) ;
212224
@@ -231,11 +243,14 @@ pub fn local_large_var_moved(f: fn(Gigastruct)) {
231243 // basic: __security_check_cookie
232244 // none-NOT: __security_check_cookie
233245 // missing-NOT: __security_check_cookie
246+
247+ // CHECK-DAG: .cv_fpo_endproc
234248}
235249
236250// CHECK-LABEL: local_large_var_cloned
237251#[ no_mangle]
238252pub fn local_large_var_cloned ( f : fn ( Gigastruct ) ) {
253+ // CHECK-DAG: .cv_fpo_endprologue
239254 f ( Gigastruct { does : 0 , not : 1 , have : 2 , array : 3 , members : 4 } ) ;
240255
241256 // A new instance of `Gigastruct` is passed to `f()`, without any apparent
@@ -260,6 +275,8 @@ pub fn local_large_var_cloned(f: fn(Gigastruct)) {
260275 // basic: __security_check_cookie
261276 // none-NOT: __security_check_cookie
262277 // missing-NOT: __security_check_cookie
278+
279+ // CHECK-DAG: .cv_fpo_endproc
263280}
264281
265282extern "C" {
@@ -293,49 +310,57 @@ extern "C" {
293310// CHECK-LABEL: alloca_small_compile_time_constant_arg
294311#[ no_mangle]
295312pub fn alloca_small_compile_time_constant_arg ( f : fn ( * mut ( ) ) ) {
313+ // CHECK-DAG: .cv_fpo_endprologue
296314 f ( unsafe { alloca ( 8 ) } ) ;
297315
298316 // all: __security_check_cookie
299317 // strong-NOT: __security_check_cookie
300318 // basic-NOT: __security_check_cookie
301319 // none-NOT: __security_check_cookie
302320 // missing-NOT: __security_check_cookie
321+
322+ // CHECK-DAG: .cv_fpo_endproc
303323}
304324
305325// CHECK-LABEL: alloca_large_compile_time_constant_arg
306326#[ no_mangle]
307327pub fn alloca_large_compile_time_constant_arg ( f : fn ( * mut ( ) ) ) {
328+ // CHECK-DAG: .cv_fpo_endprologue
308329 f ( unsafe { alloca ( 9 ) } ) ;
309330
310331 // all: __security_check_cookie
311332 // strong-NOT: __security_check_cookie
312333 // basic-NOT: __security_check_cookie
313334 // none-NOT: __security_check_cookie
314335 // missing-NOT: __security_check_cookie
336+
337+ // CHECK-DAG: .cv_fpo_endproc
315338}
316339
317340// CHECK-LABEL: alloca_dynamic_arg
318341#[ no_mangle]
319342pub fn alloca_dynamic_arg ( f : fn ( * mut ( ) ) , n : usize ) {
343+ // CHECK-DAG: .cv_fpo_endprologue
320344 f ( unsafe { alloca ( n) } ) ;
321345
322346 // all: __security_check_cookie
323347 // strong-NOT: __security_check_cookie
324348 // basic-NOT: __security_check_cookie
325349 // none-NOT: __security_check_cookie
326350 // missing-NOT: __security_check_cookie
351+
352+ // CHECK-DAG: .cv_fpo_endproc
327353}
328354
329355// The question then is: in what ways can Rust code generate array-`alloca`
330356// LLVM instructions? This appears to only be generated by
331357// rustc_codegen_ssa::traits::Builder::array_alloca() through
332- // rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT
333- // this is support for the "unsized locals" unstable feature:
334- // https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html.
358+ // rustc_codegen_ssa::mir::operand::OperandValue::store_unsized().
335359
336360// CHECK-LABEL: unsized_fn_param
337361#[ no_mangle]
338362pub fn unsized_fn_param ( s : [ u8 ] , l : bool , f : fn ( [ u8 ] ) ) {
363+ // CHECK-DAG: .cv_fpo_endprologue
339364 let n = if l { 1 } else { 2 } ;
340365 f ( * Box :: < [ u8 ] > :: from ( & s[ 0 ..n] ) ) ; // slice-copy with Box::from
341366
@@ -346,14 +371,11 @@ pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) {
346371 // alloca, and is therefore not protected by the `strong` or `basic`
347372 // heuristics.
348373
349- // We should have a __security_check_cookie call in `all` and `strong` modes but
350- // LLVM does not support generating stack protectors in functions with funclet
351- // based EH personalities.
352- // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4
353374 // all-NOT: __security_check_cookie
354375 // strong-NOT: __security_check_cookie
355-
356376 // basic-NOT: __security_check_cookie
357377 // none-NOT: __security_check_cookie
358378 // missing-NOT: __security_check_cookie
379+
380+ // CHECK-DAG: .cv_fpo_endproc
359381}
0 commit comments