diff options
Diffstat (limited to 'tests/assembly/stack-protector')
4 files changed, 0 insertions, 1351 deletions
diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs deleted file mode 100644 index 3287e018b40..00000000000 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-32bit.rs +++ /dev/null @@ -1,359 +0,0 @@ -//@ revisions: all strong basic none missing -//@ assembly-output: emit-asm -//@ only-windows -//@ only-msvc -//@ ignore-64bit 64-bit table based SEH has slightly different behaviors than classic SEH -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled - -#![crate_type = "lib"] -#![allow(internal_features)] -#![feature(unsized_fn_params)] - -// CHECK-LABEL: emptyfn: -#[no_mangle] -pub fn emptyfn() { - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_char -#[no_mangle] -pub fn array_char(f: fn(*const char)) { - let a = ['c'; 1]; - let b = ['d'; 3]; - let c = ['e'; 15]; - - f(&a as *const _); - f(&b as *const _); - f(&c as *const _); - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_1 -#[no_mangle] -pub fn array_u8_1(f: fn(*const u8)) { - let a = [0u8; 1]; - f(&a as *const _); - - // The 'strong' heuristic adds stack protection to functions with local - // array variables regardless of their size. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_small: -#[no_mangle] -pub fn array_u8_small(f: fn(*const u8)) { - let a = [0u8; 2]; - let b = [0u8; 7]; - f(&a as *const _); - f(&b as *const _); - - // Small arrays do not lead to stack protection by the 'basic' heuristic. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_large: -#[no_mangle] -pub fn array_u8_large(f: fn(*const u8)) { - let a = [0u8; 9]; - f(&a as *const _); - - // Since `a` is a byte array with size greater than 8, the basic heuristic - // will also protect this function. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -#[derive(Copy, Clone)] -pub struct ByteSizedNewtype(u8); - -// CHECK-LABEL: array_bytesizednewtype_9: -#[no_mangle] -pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { - let a = [ByteSizedNewtype(0); 9]; - f(&a as *const _); - - // Since `a` is a byte array in the LLVM output, the basic heuristic will - // also protect this function. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_var_addr_used_indirectly -#[no_mangle] -pub fn local_var_addr_used_indirectly(f: fn(bool)) { - let a = 5; - let a_addr = &a as *const _ as usize; - f(a_addr & 0x10 == 0); - - // This function takes the address of a local variable taken. Although this - // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: - // ``` - // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // void f(void (*g)(bool)) { - // int32_t x; - // g((reinterpret_cast<uintptr_t>(&x) & 0x10U) == 0); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_string_addr_taken -#[no_mangle] -pub fn local_string_addr_taken(f: fn(&String)) { - let x = String::new(); - f(&x); - - // Taking the address of the local variable `x` leads to stack smash - // protection with the `strong` heuristic, but not with the `basic` - // heuristic. It does not matter that the reference is not mut. - // - // An interesting note is that a similar function in C++ *would* be - // protected by the `basic` heuristic, because `std::string` has a char - // array internally as a small object optimization: - // ``` - // cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk - // #include <string> - // void f(void (*g)(const std::string&)) { - // std::string x; - // g(x); - // } - // EOF - // ``` - // - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -pub trait SelfByRef { - fn f(&self) -> i32; -} - -impl SelfByRef for i32 { - fn f(&self) -> i32 { - return self + 1; - } -} - -// CHECK-LABEL: local_var_addr_taken_used_locally_only -#[no_mangle] -pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { - let x = factory(); - let g = x.f(); - sink(g); - - // Even though the local variable conceptually has its address taken, as - // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with - // the `strong` heuristic. - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -pub struct Gigastruct { - does: u64, - not: u64, - have: u64, - array: u64, - members: u64, -} - -// CHECK-LABEL: local_large_var_moved -#[no_mangle] -pub fn local_large_var_moved(f: fn(Gigastruct)) { - let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; - f(x); - - // Even though the local variable conceptually doesn't have its address - // taken, it's so large that the "move" is implemented with a reference to a - // stack-local variable in the ABI. Consequently, this function *is* - // protected. This is also the case for rvalue-references in C++, - // regardless of struct size: - // ``` - // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // #include <utility> - // void f(void (*g)(uint64_t&&)) { - // uint64_t x; - // g(std::move(x)); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_large_var_cloned -#[no_mangle] -pub fn local_large_var_cloned(f: fn(Gigastruct)) { - f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); - - // A new instance of `Gigastruct` is passed to `f()`, without any apparent - // connection to this stack frame. Still, since instances of `Gigastruct` - // are sufficiently large, it is allocated in the caller stack frame and - // passed as a pointer. As such, this function is *also* protected, just - // like `local_large_var_moved`. This is also the case for pass-by-value - // of sufficiently large structs in C++: - // ``` - // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // #include <utility> - // struct Gigastruct { uint64_t a, b, c, d, e; }; - // void f(void (*g)(Gigastruct)) { - // g(Gigastruct{}); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -extern "C" { - // A call to an external `alloca` function is *not* recognized as an - // `alloca(3)` operation. This function is a compiler built-in, as the - // man page explains. Clang translates it to an LLVM `alloca` - // instruction with a count argument, which is also what the LLVM stack - // protector heuristics looks for. The man page for `alloca(3)` details - // a way to avoid using the compiler built-in: pass a -std=c11 - // argument, *and* don't include <alloca.h>. Though this leads to an - // external alloca() function being called, it doesn't lead to stack - // protection being included. It even fails with a linker error - // "undefined reference to `alloca'". Example: - // ``` - // cat<<EOF | clang -fstack-protector-strong -x c -std=c11 - -o /dev/null - // #include <stdlib.h> - // void * alloca(size_t); - // void f(void (*g)(void*)) { - // void * p = alloca(10); - // g(p); - // } - // int main() { return 0; } - // EOF - // ``` - // The following tests demonstrate that calls to an external `alloca` - // function in Rust also doesn't trigger stack protection. - - fn alloca(size: usize) -> *mut (); -} - -// CHECK-LABEL: alloca_small_compile_time_constant_arg -#[no_mangle] -pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(8) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: alloca_large_compile_time_constant_arg -#[no_mangle] -pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(9) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: alloca_dynamic_arg -#[no_mangle] -pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { - f(unsafe { alloca(n) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// The question then is: in what ways can Rust code generate array-`alloca` -// LLVM instructions? This appears to only be generated by -// rustc_codegen_ssa::traits::Builder::array_alloca() through -// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT -// this is support for the "unsized locals" unstable feature: -// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. - -// CHECK-LABEL: unsized_fn_param -#[no_mangle] -pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { - let n = if l { 1 } else { 2 }; - f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from - - // Even though slices are conceptually passed by-value both into this - // function and into `f()`, this is implemented with pass-by-reference - // using a suitably constructed fat-pointer (as if the functions - // accepted &[u8]). This function therefore doesn't need dynamic array - // alloca, and is therefore not protected by the `strong` or `basic` - // heuristics. - - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie - - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs deleted file mode 100644 index 9a3dabc74dd..00000000000 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect-windows-64bit.rs +++ /dev/null @@ -1,366 +0,0 @@ -//@ revisions: all strong basic none missing -//@ assembly-output: emit-asm -//@ only-windows -//@ only-msvc -//@ ignore-32bit 64-bit table based SEH has slightly different behaviors than classic SEH -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled - -#![crate_type = "lib"] -#![feature(unsized_fn_params)] - -// CHECK-LABEL: emptyfn: -#[no_mangle] -pub fn emptyfn() { - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_char -#[no_mangle] -pub fn array_char(f: fn(*const char)) { - let a = ['c'; 1]; - let b = ['d'; 3]; - let c = ['e'; 15]; - - f(&a as *const _); - f(&b as *const _); - f(&c as *const _); - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_1 -#[no_mangle] -pub fn array_u8_1(f: fn(*const u8)) { - let a = [0u8; 1]; - f(&a as *const _); - - // The 'strong' heuristic adds stack protection to functions with local - // array variables regardless of their size. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_small: -#[no_mangle] -pub fn array_u8_small(f: fn(*const u8)) { - let a = [0u8; 2]; - let b = [0u8; 7]; - f(&a as *const _); - f(&b as *const _); - - // Small arrays do not lead to stack protection by the 'basic' heuristic. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: array_u8_large: -#[no_mangle] -pub fn array_u8_large(f: fn(*const u8)) { - let a = [0u8; 9]; - f(&a as *const _); - - // Since `a` is a byte array with size greater than 8, the basic heuristic - // will also protect this function. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -#[derive(Copy, Clone)] -pub struct ByteSizedNewtype(u8); - -// CHECK-LABEL: array_bytesizednewtype_9: -#[no_mangle] -pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { - let a = [ByteSizedNewtype(0); 9]; - f(&a as *const _); - - // Since `a` is a byte array in the LLVM output, the basic heuristic will - // also protect this function. - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_var_addr_used_indirectly -#[no_mangle] -pub fn local_var_addr_used_indirectly(f: fn(bool)) { - let a = 5; - let a_addr = &a as *const _ as usize; - f(a_addr & 0x10 == 0); - - // This function takes the address of a local variable taken. Although this - // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: - // ``` - // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // void f(void (*g)(bool)) { - // int32_t x; - // g((reinterpret_cast<uintptr_t>(&x) & 0x10U) == 0); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_string_addr_taken -#[no_mangle] -pub fn local_string_addr_taken(f: fn(&String)) { - // CHECK-DAG: .seh_endprologue - let x = String::new(); - f(&x); - - // Taking the address of the local variable `x` leads to stack smash - // protection with the `strong` heuristic, but not with the `basic` - // heuristic. It does not matter that the reference is not mut. - // - // An interesting note is that a similar function in C++ *would* be - // protected by the `basic` heuristic, because `std::string` has a char - // array internally as a small object optimization: - // ``` - // cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk - // #include <string> - // void f(void (*g)(const std::string&)) { - // std::string x; - // g(x); - // } - // EOF - // ``` - // - - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie - - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie - - // CHECK-DAG: .seh_endproc -} - -pub trait SelfByRef { - fn f(&self) -> i32; -} - -impl SelfByRef for i32 { - fn f(&self) -> i32 { - return self + 1; - } -} - -// CHECK-LABEL: local_var_addr_taken_used_locally_only -#[no_mangle] -pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { - let x = factory(); - let g = x.f(); - sink(g); - - // Even though the local variable conceptually has its address taken, as - // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with - // the `strong` heuristic. - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -pub struct Gigastruct { - does: u64, - not: u64, - have: u64, - array: u64, - members: u64, -} - -// CHECK-LABEL: local_large_var_moved -#[no_mangle] -pub fn local_large_var_moved(f: fn(Gigastruct)) { - let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; - f(x); - - // Even though the local variable conceptually doesn't have its address - // taken, it's so large that the "move" is implemented with a reference to a - // stack-local variable in the ABI. Consequently, this function *is* - // protected. This is also the case for rvalue-references in C++, - // regardless of struct size: - // ``` - // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // #include <utility> - // void f(void (*g)(uint64_t&&)) { - // uint64_t x; - // g(std::move(x)); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: local_large_var_cloned -#[no_mangle] -pub fn local_large_var_cloned(f: fn(Gigastruct)) { - f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); - - // A new instance of `Gigastruct` is passed to `f()`, without any apparent - // connection to this stack frame. Still, since instances of `Gigastruct` - // are sufficiently large, it is allocated in the caller stack frame and - // passed as a pointer. As such, this function is *also* protected, just - // like `local_large_var_moved`. This is also the case for pass-by-value - // of sufficiently large structs in C++: - // ``` - // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // #include <utility> - // struct Gigastruct { uint64_t a, b, c, d, e; }; - // void f(void (*g)(Gigastruct)) { - // g(Gigastruct{}); - // } - // EOF - // ``` - - // all: __security_check_cookie - // strong: __security_check_cookie - // basic: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -extern "C" { - // A call to an external `alloca` function is *not* recognized as an - // `alloca(3)` operation. This function is a compiler built-in, as the - // man page explains. Clang translates it to an LLVM `alloca` - // instruction with a count argument, which is also what the LLVM stack - // protector heuristics looks for. The man page for `alloca(3)` details - // a way to avoid using the compiler built-in: pass a -std=c11 - // argument, *and* don't include <alloca.h>. Though this leads to an - // external alloca() function being called, it doesn't lead to stack - // protection being included. It even fails with a linker error - // "undefined reference to `alloca'". Example: - // ``` - // cat<<EOF | clang -fstack-protector-strong -x c -std=c11 - -o /dev/null - // #include <stdlib.h> - // void * alloca(size_t); - // void f(void (*g)(void*)) { - // void * p = alloca(10); - // g(p); - // } - // int main() { return 0; } - // EOF - // ``` - // The following tests demonstrate that calls to an external `alloca` - // function in Rust also doesn't trigger stack protection. - - fn alloca(size: usize) -> *mut (); -} - -// CHECK-LABEL: alloca_small_compile_time_constant_arg -#[no_mangle] -pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(8) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: alloca_large_compile_time_constant_arg -#[no_mangle] -pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(9) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// CHECK-LABEL: alloca_dynamic_arg -#[no_mangle] -pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { - f(unsafe { alloca(n) }); - - // all: __security_check_cookie - // strong-NOT: __security_check_cookie - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} - -// The question then is: in what ways can Rust code generate array-`alloca` -// LLVM instructions? This appears to only be generated by -// rustc_codegen_ssa::traits::Builder::array_alloca() through -// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT -// this is support for the "unsized locals" unstable feature: -// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. - -// CHECK-LABEL: unsized_fn_param -#[no_mangle] -pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { - let n = if l { 1 } else { 2 }; - f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from - - // Even though slices are conceptually passed by-value both into this - // function and into `f()`, this is implemented with pass-by-reference - // using a suitably constructed fat-pointer (as if the functions - // accepted &[u8]). This function therefore doesn't need dynamic array - // alloca, and is therefore not protected by the `strong` or `basic` - // heuristics. - - // We should have a __security_check_cookie call in `all` and `strong` modes but - // LLVM does not support generating stack protectors in functions with funclet - // based EH personalities. - // https://github.com/llvm/llvm-project/blob/37fd3c96b917096d8a550038f6e61cdf0fc4174f/llvm/lib/CodeGen/StackProtector.cpp#L103C1-L109C4 - // all-NOT: __security_check_cookie - // strong-NOT: __security_check_cookie - - // basic-NOT: __security_check_cookie - // none-NOT: __security_check_cookie - // missing-NOT: __security_check_cookie -} diff --git a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs b/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs deleted file mode 100644 index ae281cb95da..00000000000 --- a/tests/assembly/stack-protector/stack-protector-heuristics-effect.rs +++ /dev/null @@ -1,345 +0,0 @@ -//@ revisions: all strong basic none missing -//@ assembly-output: emit-asm -//@ ignore-apple slightly different policy on stack protection of arrays -//@ ignore-msvc stack check code uses different function names -//@ ignore-nvptx64 stack protector is not supported -//@ ignore-wasm32-bare -//@ [all] compile-flags: -Z stack-protector=all -//@ [strong] compile-flags: -Z stack-protector=strong -//@ [basic] compile-flags: -Z stack-protector=basic -//@ [none] compile-flags: -Z stack-protector=none -//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled - -// NOTE: the heuristics for stack smash protection inappropriately rely on types in LLVM IR, -// despite those types having no semantic meaning. This means that the `basic` and `strong` -// settings do not behave in a coherent way. This is a known issue in LLVM. -// See comments on https://github.com/rust-lang/rust/issues/114903. - -#![crate_type = "lib"] -#![allow(internal_features)] -#![feature(unsized_fn_params)] - -// CHECK-LABEL: emptyfn{{:|\[}} -#[no_mangle] -pub fn emptyfn() { - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: array_char{{:|\[}} -#[no_mangle] -pub fn array_char(f: fn(*const char)) { - let a = ['c'; 1]; - let b = ['d'; 3]; - let c = ['e'; 15]; - - f(&a as *const _); - f(&b as *const _); - f(&c as *const _); - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: array_u8_1{{:|\[}} -#[no_mangle] -pub fn array_u8_1(f: fn(*const u8)) { - let a = [0u8; 1]; - f(&a as *const _); - - // The 'strong' heuristic adds stack protection to functions with local - // array variables regardless of their size. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: array_u8_small{{:|\[}} -#[no_mangle] -pub fn array_u8_small(f: fn(*const u8)) { - let a = [0u8; 2]; - let b = [0u8; 7]; - f(&a as *const _); - f(&b as *const _); - - // Small arrays do not lead to stack protection by the 'basic' heuristic. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: array_u8_large{{:|\[}} -#[no_mangle] -pub fn array_u8_large(f: fn(*const u8)) { - let a = [0u8; 9]; - f(&a as *const _); - - // Since `a` is a byte array with size greater than 8, the basic heuristic - // will also protect this function. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -#[derive(Copy, Clone)] -pub struct ByteSizedNewtype(u8); - -// CHECK-LABEL: array_bytesizednewtype_9{{:|\[}} -#[no_mangle] -pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { - let a = [ByteSizedNewtype(0); 9]; - f(&a as *const _); - - // Since `a` is a byte array in the LLVM output, the basic heuristic will - // also protect this function. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: local_var_addr_used_indirectly{{:|\[}} -#[no_mangle] -pub fn local_var_addr_used_indirectly(f: fn(bool)) { - let a = 5; - let a_addr = &a as *const _ as usize; - f(a_addr & 0x10 == 0); - - // This function takes the address of a local variable taken. Although this - // address is never used as a way to refer to stack memory, the `strong` - // heuristic adds stack smash protection. This is also the case in C++: - // ``` - // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // void f(void (*g)(bool)) { - // int32_t x; - // g((reinterpret_cast<uintptr_t>(&x) & 0x10U) == 0); - // } - // EOF - // ``` - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: local_string_addr_taken{{:|\[}} -#[no_mangle] -pub fn local_string_addr_taken(f: fn(&String)) { - let x = String::new(); - f(&x); - - // Taking the address of the local variable `x` leads to stack smash - // protection. It does not matter that the reference is not mut. - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -pub trait SelfByRef { - fn f(&self) -> i32; -} - -impl SelfByRef for i32 { - fn f(&self) -> i32 { - return self + 1; - } -} - -// CHECK-LABEL: local_var_addr_taken_used_locally_only{{:|\[}} -#[no_mangle] -pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { - let x = factory(); - let g = x.f(); - sink(g); - - // Even though the local variable conceptually has its address taken, as - // it's passed by reference to the trait function, the use of the reference - // is easily inlined. There is therefore no stack smash protection even with - // the `strong` heuristic. - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -pub struct Gigastruct { - does: u64, - not: u64, - have: u64, - array: u64, - members: u64, -} - -// CHECK-LABEL: local_large_var_moved{{:|\[}} -#[no_mangle] -pub fn local_large_var_moved(f: fn(Gigastruct)) { - let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; - f(x); - - // Even though the local variable conceptually doesn't have its address - // taken, it's so large that the "move" is implemented with a reference to a - // stack-local variable in the ABI. Consequently, this function *is* - // protected. This is also the case for rvalue-references in C++, - // regardless of struct size: - // ``` - // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // #include <utility> - // void f(void (*g)(uint64_t&&)) { - // uint64_t x; - // g(std::move(x)); - // } - // EOF - // ``` - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: local_large_var_cloned{{:|\[}} -#[no_mangle] -pub fn local_large_var_cloned(f: fn(Gigastruct)) { - f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); - - // A new instance of `Gigastruct` is passed to `f()`, without any apparent - // connection to this stack frame. Still, since instances of `Gigastruct` - // are sufficiently large, it is allocated in the caller stack frame and - // passed as a pointer. As such, this function is *also* protected, just - // like `local_large_var_moved`. This is also the case for pass-by-value - // of sufficiently large structs in C++: - // ``` - // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk - // #include <cstdint> - // #include <utility> - // struct Gigastruct { uint64_t a, b, c, d, e; }; - // void f(void (*g)(Gigastruct)) { - // g(Gigastruct{}); - // } - // EOF - // ``` - - // all: __stack_chk_fail - // strong: __stack_chk_fail - // basic: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -extern "C" { - // A call to an external `alloca` function is *not* recognized as an - // `alloca(3)` operation. This function is a compiler built-in, as the - // man page explains. Clang translates it to an LLVM `alloca` - // instruction with a count argument, which is also what the LLVM stack - // protector heuristics looks for. The man page for `alloca(3)` details - // a way to avoid using the compiler built-in: pass a -std=c11 - // argument, *and* don't include <alloca.h>. Though this leads to an - // external alloca() function being called, it doesn't lead to stack - // protection being included. It even fails with a linker error - // "undefined reference to `alloca'". Example: - // ``` - // cat<<EOF | clang -fstack-protector-strong -x c -std=c11 - -o /dev/null - // #include <stdlib.h> - // void * alloca(size_t); - // void f(void (*g)(void*)) { - // void * p = alloca(10); - // g(p); - // } - // int main() { return 0; } - // EOF - // ``` - // The following tests demonstrate that calls to an external `alloca` - // function in Rust also doesn't trigger stack protection. - - fn alloca(size: usize) -> *mut (); -} - -// CHECK-LABEL: alloca_small_compile_time_constant_arg{{:|\[}} -#[no_mangle] -pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(8) }); - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: alloca_large_compile_time_constant_arg{{:|\[}} -#[no_mangle] -pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { - f(unsafe { alloca(9) }); - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// CHECK-LABEL: alloca_dynamic_arg{{:|\[}} -#[no_mangle] -pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { - f(unsafe { alloca(n) }); - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} - -// The question then is: in what ways can Rust code generate array-`alloca` -// LLVM instructions? This appears to only be generated by -// rustc_codegen_ssa::traits::Builder::array_alloca() through -// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT -// this is support for the "unsized locals" unstable feature: -// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. - -// CHECK-LABEL: unsized_fn_param{{:|\[}} -#[no_mangle] -pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { - let n = if l { 1 } else { 2 }; - f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from - - // Even though slices are conceptually passed by-value both into this - // function and into `f()`, this is implemented with pass-by-reference - // using a suitably constructed fat-pointer (as if the functions - // accepted &[u8]). This function therefore doesn't need dynamic array - // alloca, and is therefore not protected by the `strong` or `basic` - // heuristics. - - // all: __stack_chk_fail - // strong-NOT: __stack_chk_fail - // basic-NOT: __stack_chk_fail - // none-NOT: __stack_chk_fail - // missing-NOT: __stack_chk_fail -} diff --git a/tests/assembly/stack-protector/stack-protector-target-support.rs b/tests/assembly/stack-protector/stack-protector-target-support.rs deleted file mode 100644 index a937256a60f..00000000000 --- a/tests/assembly/stack-protector/stack-protector-target-support.rs +++ /dev/null @@ -1,281 +0,0 @@ -// Test that stack smash protection code is emitted for all tier1 and tier2 -// targets, with the exception of nvptx64-nvidia-cuda -// -//@ add-core-stubs -//@ revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 -//@ revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r36 r37 r38 r39 r40 r41 r42 r43 r44 -//@ revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65 -//@ revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 r85 -//@ assembly-output: emit-asm -//@ [r1] compile-flags: --target aarch64-unknown-linux-gnu -//@ [r1] needs-llvm-components: aarch64 -//@ [r2] compile-flags: --target i686-pc-windows-gnu -//@ [r2] needs-llvm-components: x86 -//@ [r3] compile-flags: --target i686-pc-windows-msvc -//@ [r3] needs-llvm-components: x86 -//@ [r4] compile-flags: --target i686-unknown-linux-gnu -//@ [r4] needs-llvm-components: x86 -//@ [r5] compile-flags: --target x86_64-apple-darwin -//@ [r5] needs-llvm-components: x86 -//@ [r6] compile-flags: --target x86_64-pc-windows-gnu -//@ [r6] needs-llvm-components: x86 -//@ [r7] compile-flags: --target x86_64-pc-windows-msvc -//@ [r7] needs-llvm-components: x86 -//@ [r8] compile-flags: --target x86_64-unknown-linux-gnu -//@ [r8] needs-llvm-components: x86 -//@ [r9] compile-flags: --target aarch64-apple-darwin -//@ [r9] needs-llvm-components: aarch64 -//@ [r10] compile-flags: --target aarch64-apple-ios -//@ [r10] needs-llvm-components: aarch64 -//@ [r11] compile-flags: --target aarch64-unknown-fuchsia -//@ [r11] needs-llvm-components: aarch64 -//@ [r12] compile-flags: --target aarch64-linux-android -//@ [r12] needs-llvm-components: aarch64 -//@ [r13] compile-flags: --target aarch64-pc-windows-msvc -//@ [r13] needs-llvm-components: aarch64 -//@ [r14] compile-flags: --target aarch64-unknown-linux-musl -//@ [r14] needs-llvm-components: aarch64 -//@ [r15] compile-flags: --target aarch64-unknown-none -//@ [r15] needs-llvm-components: aarch64 -//@ [r16] compile-flags: --target aarch64-unknown-none-softfloat -//@ [r16] needs-llvm-components: aarch64 -//@ [r17] compile-flags: --target arm-linux-androideabi -//@ [r17] needs-llvm-components: arm -//@ [r18] compile-flags: --target arm-unknown-linux-gnueabi -//@ [r18] needs-llvm-components: arm -//@ [r19] compile-flags: --target arm-unknown-linux-gnueabihf -//@ [r19] needs-llvm-components: arm -//@ [r20] compile-flags: --target arm-unknown-linux-musleabi -//@ [r20] needs-llvm-components: arm -//@ [r21] compile-flags: --target arm-unknown-linux-musleabihf -//@ [r21] needs-llvm-components: arm -//@ [r22] compile-flags: --target armebv7r-none-eabi -//@ [r22] needs-llvm-components: arm -//@ [r23] compile-flags: --target armebv7r-none-eabihf -//@ [r23] needs-llvm-components: arm -//@ [r24] compile-flags: --target armv5te-unknown-linux-gnueabi -//@ [r24] needs-llvm-components: arm -//@ [r25] compile-flags: --target armv5te-unknown-linux-musleabi -//@ [r25] needs-llvm-components: arm -//@ [r26] compile-flags: --target armv7-linux-androideabi -//@ [r26] needs-llvm-components: arm -//@ [r27] compile-flags: --target armv7a-none-eabi -//@ [r27] needs-llvm-components: arm -//@ [r28] compile-flags: --target armv7r-none-eabi -//@ [r28] needs-llvm-components: arm -//@ [r29] compile-flags: --target armv7r-none-eabihf -//@ [r29] needs-llvm-components: arm -//@ [r30] compile-flags: --target armv7-unknown-linux-gnueabi -//@ [r30] needs-llvm-components: arm -//@ [r31] compile-flags: --target armv7-unknown-linux-gnueabihf -//@ [r31] needs-llvm-components: arm -//@ [r32] compile-flags: --target armv7-unknown-linux-musleabi -//@ [r32] needs-llvm-components: arm -//@ [r33] compile-flags: --target armv7-unknown-linux-musleabihf -//@ [r33] needs-llvm-components: arm -//@ [r36] compile-flags: --target i586-unknown-linux-gnu -//@ [r36] needs-llvm-components: x86 -//@ [r37] compile-flags: --target i586-unknown-linux-musl -//@ [r37] needs-llvm-components: x86 -//@ [r38] compile-flags: --target i686-linux-android -//@ [r38] needs-llvm-components: x86 -//@ [r39] compile-flags: --target i686-unknown-freebsd -//@ [r39] needs-llvm-components: x86 -//@ [r40] compile-flags: --target i686-unknown-linux-musl -//@ [r40] needs-llvm-components: x86 -//@ [r41] compile-flags: --target mips-unknown-linux-gnu -//@ [r41] needs-llvm-components: mips -//@ [r42] compile-flags: --target mips-unknown-linux-musl -//@ [r42] needs-llvm-components: mips -//@ [r43] compile-flags: --target mips64-unknown-linux-gnuabi64 -//@ [r43] needs-llvm-components: mips -//@ [r44] compile-flags: --target mips64-unknown-linux-muslabi64 -//@ [r44] needs-llvm-components: mips -//@ [r45] compile-flags: --target mips64el-unknown-linux-gnuabi64 -//@ [r45] needs-llvm-components: mips -//@ [r46] compile-flags: --target mips64el-unknown-linux-muslabi64 -//@ [r46] needs-llvm-components: mips -//@ [r47] compile-flags: --target mipsel-unknown-linux-gnu -//@ [r47] needs-llvm-components: mips -//@ [r48] compile-flags: --target mipsel-unknown-linux-musl -//@ [r48] needs-llvm-components: mips -//@ [r49] compile-flags: --target nvptx64-nvidia-cuda -//@ [r49] needs-llvm-components: nvptx -//@ [r50] compile-flags: --target powerpc-unknown-linux-gnu -//@ [r50] needs-llvm-components: powerpc -//@ [r51] compile-flags: --target powerpc64-unknown-linux-gnu -//@ [r51] needs-llvm-components: powerpc -//@ [r52] compile-flags: --target powerpc64le-unknown-linux-gnu -//@ [r52] needs-llvm-components: powerpc -//@ [r53] compile-flags: --target riscv32i-unknown-none-elf -//@ [r53] needs-llvm-components: riscv -//@ [r54] compile-flags: --target riscv32imac-unknown-none-elf -//@ [r54] needs-llvm-components: riscv -//@ [r55] compile-flags:--target riscv32imc-unknown-none-elf -//@ [r55] needs-llvm-components: riscv -//@ [r56] compile-flags:--target riscv64gc-unknown-linux-gnu -//@ [r56] needs-llvm-components: riscv -//@ [r57] compile-flags:--target riscv64gc-unknown-none-elf -//@ [r57] needs-llvm-components: riscv -//@ [r58] compile-flags:--target riscv64imac-unknown-none-elf -//@ [r58] needs-llvm-components: riscv -//@ [r59] compile-flags:--target s390x-unknown-linux-gnu -//@ [r59] needs-llvm-components: systemz -//@ [r60] compile-flags:--target sparc64-unknown-linux-gnu -//@ [r60] needs-llvm-components: sparc -//@ [r61] compile-flags:--target sparcv9-sun-solaris -//@ [r61] needs-llvm-components: sparc -//@ [r62] compile-flags:--target thumbv6m-none-eabi -//@ [r62] needs-llvm-components: arm -//@ [r63] compile-flags:--target thumbv7em-none-eabi -//@ [r63] needs-llvm-components: arm -//@ [r64] compile-flags:--target thumbv7em-none-eabihf -//@ [r64] needs-llvm-components: arm -//@ [r65] compile-flags:--target thumbv7m-none-eabi -//@ [r65] needs-llvm-components: arm -//@ [r66] compile-flags:--target thumbv7neon-linux-androideabi -//@ [r66] needs-llvm-components: arm -//@ [r67] compile-flags:--target thumbv7neon-unknown-linux-gnueabihf -//@ [r67] needs-llvm-components: arm -//@ [r68] compile-flags:--target thumbv8m.base-none-eabi -//@ [r68] needs-llvm-components: arm -//@ [r69] compile-flags:--target thumbv8m.main-none-eabi -//@ [r69] needs-llvm-components: arm -//@ [r70] compile-flags:--target thumbv8m.main-none-eabihf -//@ [r70] needs-llvm-components: arm -//@ [r71] compile-flags:--target wasm32-unknown-emscripten -//@ [r71] needs-llvm-components: webassembly -//@ [r72] compile-flags:--target wasm32-unknown-unknown -//@ [r72] needs-llvm-components: webassembly -//@ [r73] compile-flags:--target wasm32-wasip1 -//@ [r73] needs-llvm-components: webassembly -//@ [r74] compile-flags:--target wasm32-wasip1-threads -//@ [r74] needs-llvm-components: webassembly -//@ [r75] compile-flags:--target x86_64-apple-ios -//@ [r75] needs-llvm-components: x86 -//@ [r76] compile-flags:--target x86_64-fortanix-unknown-sgx -//@ [r76] needs-llvm-components: x86 -//@ [r77] compile-flags:--target x86_64-unknown-fuchsia -//@ [r77] needs-llvm-components: x86 -//@ [r78] compile-flags:--target x86_64-linux-android -//@ [r78] needs-llvm-components: x86 -//@ [r79] compile-flags:--target x86_64-pc-solaris -//@ [r79] needs-llvm-components: x86 -//@ [r80] compile-flags:--target x86_64-unknown-freebsd -//@ [r80] needs-llvm-components: x86 -//@ [r81] compile-flags:--target x86_64-unknown-illumos -//@ [r81] needs-llvm-components: x86 -//@ [r82] compile-flags:--target x86_64-unknown-linux-gnux32 -//@ [r82] needs-llvm-components: x86 -//@ [r83] compile-flags:--target x86_64-unknown-linux-musl -//@ [r83] needs-llvm-components: x86 -//@ [r84] compile-flags:--target x86_64-unknown-netbsd -//@ [r84] needs-llvm-components: x86 -//@ [r85] compile-flags: --target x86_64-unknown-redox -//@ [r85] needs-llvm-components: x86 -//@ compile-flags: -Z stack-protector=all -//@ compile-flags: -C opt-level=2 - -#![crate_type = "lib"] -#![feature(no_core, lang_items)] -#![crate_type = "lib"] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[no_mangle] -pub fn foo() { - // CHECK: foo{{:|()}} - - // MSVC does the stack checking within a stack-check function: - // r3: calll @__security_check_cookie - // r7: callq __security_check_cookie - // r13: bl __security_check_cookie - - // cuda doesn't support stack-smash protection - // r49-NOT: __security_check_cookie - // r49-NOT: __stack_chk_fail - - // Other targets do stack checking within the function, and call a failure function on error - // r1: __stack_chk_fail - // r2: __stack_chk_fail - // r4: __stack_chk_fail - // r5: __stack_chk_fail - // r6: __stack_chk_fail - // r8: __stack_chk_fail - // r9: __stack_chk_fail - // r10: __stack_chk_fail - // r11: __stack_chk_fail - // r12: __stack_chk_fail - // r14: __stack_chk_fail - // r15: __stack_chk_fail - // r16: __stack_chk_fail - // r17: __stack_chk_fail - // r18: __stack_chk_fail - // r19: __stack_chk_fail - // r20: __stack_chk_fail - // r21: __stack_chk_fail - // r22: __stack_chk_fail - // r23: __stack_chk_fail - // r24: __stack_chk_fail - // r25: __stack_chk_fail - // r26: __stack_chk_fail - // r27: __stack_chk_fail - // r28: __stack_chk_fail - // r29: __stack_chk_fail - // r30: __stack_chk_fail - // r31: __stack_chk_fail - // r32: __stack_chk_fail - // r33: __stack_chk_fail - // r34: __stack_chk_fail - // r36: __stack_chk_fail - // r37: __stack_chk_fail - // r38: __stack_chk_fail - // r39: __stack_chk_fail - // r40: __stack_chk_fail - // r41: __stack_chk_fail - // r42: __stack_chk_fail - // r43: __stack_chk_fail - // r44: __stack_chk_fail - // r45: __stack_chk_fail - // r46: __stack_chk_fail - // r47: __stack_chk_fail - // r48: __stack_chk_fail - // r50: __stack_chk_fail - // r51: __stack_chk_fail - // r52: __stack_chk_fail - // r53: __stack_chk_fail - // r54: __stack_chk_fail - // r55: __stack_chk_fail - // r56: __stack_chk_fail - // r57: __stack_chk_fail - // r58: __stack_chk_fail - // r59: __stack_chk_fail - // r60: __stack_chk_fail - // r61: __stack_chk_fail - // r62: __stack_chk_fail - // r63: __stack_chk_fail - // r64: __stack_chk_fail - // r65: __stack_chk_fail - // r66: __stack_chk_fail - // r67: __stack_chk_fail - // r68: __stack_chk_fail - // r69: __stack_chk_fail - // r70: __stack_chk_fail - // r71: __stack_chk_fail - // r72: __stack_chk_fail - // r73: __stack_chk_fail - // r74: __stack_chk_fail - // r75: __stack_chk_fail - // r76: __stack_chk_fail - // r77: __stack_chk_fail - // r78: __stack_chk_fail - // r79: __stack_chk_fail - // r80: __stack_chk_fail - // r81: __stack_chk_fail - // r82: __stack_chk_fail - // r83: __stack_chk_fail - // r84: __stack_chk_fail - // r85: __stack_chk_fail -} |
