Rollup merge of #147115 - cezarbbb:stable_ssp, r=SparrowLii
More robust stack protector testing I've added some tests related to the stack protector. These tests were originally in the LLVM stack protector test project. These tests were written for the "Stabilize stack-protector" proposal, and therefore removed the "stack-protector=basic" test option, as this stack protector was considered ineffective in Rust. For the proposal, see: rust-lang/rust#146369 For the discussion, see zulip: https://rust-lang.zulipchat.com/#narrow/channel/233931-t-compiler.2Fmajor-changes/topic/Proposal.20for.20Adapt.20Stack.20Protector.20for.20Ru.E2.80.A6.20compiler-team.23841 I have opened an issue to discuss the 'abi_mismatch' issue I encountered while writing tests for the coexistence of 'stack-protector' and 'safe-stack': https://github.com/rust-lang/rust/issues/149340 r? `@wesleywiser` (feel free to reassign) cc `@nikic,` `@rcvalle,` `@davidtwco,` `@arielb1,` `@Darksonn,` `@Noratrieb,` `@SparrowLii`
This commit is contained in:
commit
0a712d2b14
3 changed files with 1456 additions and 0 deletions
|
|
@ -0,0 +1,481 @@
|
|||
//@ revisions: all strong 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
|
||||
//@ [all] compile-flags: -Z stack-protector=all
|
||||
//@ [strong] compile-flags: -Z stack-protector=strong
|
||||
//@ [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)]
|
||||
|
||||
extern "C" {
|
||||
fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8;
|
||||
fn printf(fmt: *const u8, ...) -> i32;
|
||||
fn funcall(p: *mut i32);
|
||||
fn funcall2(p: *mut *mut i32);
|
||||
fn funfloat(p: *mut f64);
|
||||
fn funfloat2(p: *mut *mut f64);
|
||||
fn testi_aux() -> f64;
|
||||
fn getp() -> *mut i32;
|
||||
fn dummy(_: ...) -> i32;
|
||||
|
||||
static STR: [u8; 1];
|
||||
}
|
||||
|
||||
extern "C-unwind" {
|
||||
fn except(p: *mut i32);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Pair {
|
||||
a: i32,
|
||||
b: i32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Nest {
|
||||
first: Pair,
|
||||
second: Pair,
|
||||
}
|
||||
|
||||
// test1: array of [16 x i8]
|
||||
// CHECK-LABEL: test1{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test1(a: *const u8) {
|
||||
let mut buf: [u8; 16] = [0; 16];
|
||||
|
||||
unsafe {
|
||||
strcpy(buf.as_mut_ptr(), a);
|
||||
printf(STR.as_ptr(), buf.as_ptr());
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test2: array [4 x i8]
|
||||
// CHECK-LABEL: test2{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test2(a: *const u8) {
|
||||
let mut buf: [u8; 4] = [0; 4];
|
||||
|
||||
unsafe {
|
||||
strcpy(buf.as_mut_ptr(), a);
|
||||
printf(STR.as_ptr(), buf.as_ptr());
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test3: no arrays / no nested arrays
|
||||
// CHECK-LABEL: test3{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test3(a: *const u8) {
|
||||
unsafe {
|
||||
printf(STR.as_ptr(), a);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong-NOT: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test4: Address-of local taken (j = &a)
|
||||
// CHECK-LABEL: test4{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test4() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
let mut j: *mut i32 = std::ptr::null_mut();
|
||||
|
||||
let tmp = std::ptr::read_volatile(&a);
|
||||
let tmp2 = tmp.wrapping_add(1);
|
||||
std::ptr::write_volatile(&mut a, tmp2);
|
||||
|
||||
std::ptr::write_volatile(&mut j, &mut a);
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test5: PtrToInt Cast
|
||||
// CHECK-LABEL: test5{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test5(a: i32) {
|
||||
let ptr_val: usize = &a as *const i32 as usize;
|
||||
|
||||
unsafe {
|
||||
printf(STR.as_ptr(), ptr_val);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test6: Passing addr-of to function call
|
||||
// CHECK-LABEL: test6{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test6(mut b: i32) {
|
||||
unsafe {
|
||||
funcall(&mut b as *mut i32);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test7: Addr-of in select instruction
|
||||
// CHECK-LABEL: test7{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test7() {
|
||||
let x: f64;
|
||||
|
||||
unsafe {
|
||||
let call = testi_aux();
|
||||
x = call;
|
||||
|
||||
let y: *const f64 = if call > 0.0 { &x as *const f64 } else { std::ptr::null() };
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test8: Addr-of in phi instruction
|
||||
// CHECK-LABEL: test8{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test8() {
|
||||
let mut _x: f64;
|
||||
|
||||
unsafe {
|
||||
let call = testi_aux();
|
||||
_x = call;
|
||||
|
||||
let y: *const f64;
|
||||
|
||||
if call > 3.14 {
|
||||
let call1 = testi_aux();
|
||||
_x = call1;
|
||||
y = std::ptr::null();
|
||||
} else {
|
||||
if call > 1.0 {
|
||||
y = &_x;
|
||||
} else {
|
||||
y = std::ptr::null();
|
||||
}
|
||||
}
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test9: Addr-of struct element(GEP followed by store)
|
||||
// CHECK-LABEL: test9{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test9() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
let b: *mut i32;
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
b = y;
|
||||
|
||||
printf(STR.as_ptr(), b);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test10: Addr-of struct element, GEP followed by ptrtoint
|
||||
// CHECK-LABEL: test10{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test10() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
let addr: i64 = y as i64;
|
||||
|
||||
printf(STR.as_ptr(), addr);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test11: Addr-of struct element, GEP followed by callinst
|
||||
// CHECK-LABEL: test11{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test11() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test12: Addr-of a local, optimized into a GEP (e.g., &a - 12)
|
||||
// CHECK-LABEL: test12{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test12() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
unsafe {
|
||||
let add_ptr = (&mut a as *mut i32).offset(-12);
|
||||
|
||||
printf(STR.as_ptr(), add_ptr);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test13: Addr-of a local cast to a ptr of a different type
|
||||
// (e.g., int a; ... ; ptr b = &a;)
|
||||
// CHECK-LABEL: test13{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test13() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
unsafe {
|
||||
let mut b: *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut b, &mut a); // avoid ptr b from optimization
|
||||
let tmp = std::ptr::read_volatile(&b);
|
||||
|
||||
printf(STR.as_ptr(), tmp);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test14: Addr-of a local cast to a ptr of a different type (optimized)
|
||||
// (e.g., int a; ... ; ptr b = &a;)
|
||||
// CHECK-LABEL: test14{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test14() {
|
||||
let a: i32 = 0;
|
||||
unsafe {
|
||||
funfloat((&a as *const i32).cast::<f64>() as *mut f64);
|
||||
}
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test15: Addr-of a variable passed into an invoke instruction
|
||||
// CHECK-LABEL: test15{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test15() -> i32 {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
except(&mut a as *mut i32);
|
||||
|
||||
0
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test16: Addr-of a struct element passed into an invoke instruction
|
||||
// (GEP followed by an invoke)
|
||||
// CHECK-LABEL: test16{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test16() -> i32 {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
except(&mut c.a as *mut i32);
|
||||
|
||||
0
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test17: Addr-of a pointer
|
||||
// CHECK-LABEL: test17{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test17() {
|
||||
let mut a: *mut i32 = getp();
|
||||
|
||||
let mut _b: *mut *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut _b, &mut a);
|
||||
|
||||
let tmp = std::ptr::read_volatile(&_b);
|
||||
|
||||
funcall2(tmp);
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test18: Addr-of a casted pointer
|
||||
// CHECK-LABEL: test18{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test18() {
|
||||
let mut a: *mut i32 = getp();
|
||||
|
||||
let mut _b: *mut *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut _b, &mut a);
|
||||
|
||||
let tmp = std::ptr::read_volatile(&_b);
|
||||
|
||||
funfloat2(tmp as *mut *mut f64);
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test19: array of [4 x i32]
|
||||
// CHECK-LABEL: test19{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test19() -> i32 {
|
||||
let a: [i32; 4] = [0; 4];
|
||||
|
||||
let _whole = std::ptr::read_volatile(&a as *const _); // avoid array a from optimization
|
||||
|
||||
std::ptr::read_volatile(&a[0])
|
||||
|
||||
// all: __stack_chk_fail
|
||||
// strong: __stack_chk_fail
|
||||
// none-NOT: __stack_chk_fail
|
||||
// missing-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test20: Nested structure, no arrays, no address-of expressions
|
||||
// Verify that the resulting gep-of-gep does not incorrectly trigger
|
||||
// a stack protector
|
||||
// CHECK-LABEL: test20{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test20() {
|
||||
let c = Nest { first: Pair { a: 10, b: 11 }, second: Pair { a: 20, b: 21 } };
|
||||
|
||||
let whole: Nest = std::ptr::read_volatile(&c);
|
||||
|
||||
let v: i32 = whole.second.a;
|
||||
|
||||
printf(STR.as_ptr(), v);
|
||||
|
||||
// strong-NOT: __stack_chk_fail
|
||||
}
|
||||
|
||||
// test21: Address-of a structure taken in a function with a loop where
|
||||
// the alloca is an incoming value to a PHI node and a use of that PHI
|
||||
// node is also an incoming value
|
||||
// Verify that the address-of analysis does not get stuck in infinite
|
||||
// recursion when chasing the alloca through the PHI nodes
|
||||
// CHECK-LABEL: test21{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test21() -> i32 {
|
||||
let mut tmp: *mut u8 = std::ptr::null_mut();
|
||||
let tmp_ptr: *mut *mut u8 = &mut tmp;
|
||||
|
||||
let tmp1 = dummy(tmp_ptr);
|
||||
|
||||
let cur = std::ptr::read_volatile(tmp_ptr);
|
||||
|
||||
let v = (cur as usize as i64) as i32;
|
||||
|
||||
if v > 0 {
|
||||
let mut phi_ptr: *mut u8 = cur;
|
||||
let mut phi_idx: i64 = 1;
|
||||
let mut phi_acc: i32 = tmp1;
|
||||
|
||||
loop {
|
||||
let b = std::ptr::read_volatile(phi_ptr as *const u8);
|
||||
let cond = b == 1u8;
|
||||
let plus = phi_acc.wrapping_add(8);
|
||||
let next_acc = if cond { plus } else { phi_acc };
|
||||
|
||||
if (phi_idx as i32) == v {
|
||||
dummy(next_acc);
|
||||
break;
|
||||
}
|
||||
|
||||
let slot = tmp_ptr.add(phi_idx as usize);
|
||||
let next = std::ptr::read_volatile(slot);
|
||||
phi_ptr = next;
|
||||
phi_idx += 1;
|
||||
phi_acc = next_acc;
|
||||
}
|
||||
} else {
|
||||
dummy(tmp1);
|
||||
}
|
||||
|
||||
0
|
||||
|
||||
// strong: __stack_chk_fail
|
||||
}
|
||||
|
||||
// CHECK-LABEL: IgnoreIntrinsicTest{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn IgnoreIntrinsicTest() -> i32 {
|
||||
let mut x: i32 = 0;
|
||||
|
||||
std::ptr::write_volatile(&mut x, 1);
|
||||
|
||||
let y = std::ptr::read_volatile(&x);
|
||||
|
||||
let result = y.wrapping_mul(42);
|
||||
|
||||
result
|
||||
|
||||
// strong-NOT: __stack_chk_fail
|
||||
}
|
||||
|
|
@ -0,0 +1,484 @@
|
|||
//@ revisions: all strong 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
|
||||
//@ [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)]
|
||||
|
||||
extern "C" {
|
||||
fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8;
|
||||
fn printf(fmt: *const u8, ...) -> i32;
|
||||
fn funcall(p: *mut i32);
|
||||
fn funcall2(p: *mut *mut i32);
|
||||
fn funfloat(p: *mut f64);
|
||||
fn funfloat2(p: *mut *mut f64);
|
||||
fn testi_aux() -> f64;
|
||||
fn getp() -> *mut i32;
|
||||
fn dummy(_: ...) -> i32;
|
||||
|
||||
static STR: [u8; 1];
|
||||
}
|
||||
|
||||
extern "C-unwind" {
|
||||
fn except(p: *mut i32);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Pair {
|
||||
a: i32,
|
||||
b: i32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Nest {
|
||||
first: Pair,
|
||||
second: Pair,
|
||||
}
|
||||
|
||||
// test1: array of [16 x i8]
|
||||
// CHECK-LABEL: test1{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test1(a: *const u8) {
|
||||
let mut buf: [u8; 16] = [0; 16];
|
||||
|
||||
unsafe {
|
||||
strcpy(buf.as_mut_ptr(), a);
|
||||
printf(STR.as_ptr(), buf.as_ptr());
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test2: array [4 x i8]
|
||||
// CHECK-LABEL: test2{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test2(a: *const u8) {
|
||||
let mut buf: [u8; 4] = [0; 4];
|
||||
|
||||
unsafe {
|
||||
strcpy(buf.as_mut_ptr(), a);
|
||||
printf(STR.as_ptr(), buf.as_ptr());
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test3: no arrays / no nested arrays
|
||||
// CHECK-LABEL: test3{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test3(a: *const u8) {
|
||||
unsafe {
|
||||
printf(STR.as_ptr(), a);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test4: Address-of local taken (j = &a)
|
||||
// CHECK-LABEL: test4{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test4() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
let mut j: *mut i32 = std::ptr::null_mut();
|
||||
|
||||
let tmp = std::ptr::read_volatile(&a);
|
||||
let tmp2 = tmp.wrapping_add(1);
|
||||
std::ptr::write_volatile(&mut a, tmp2);
|
||||
|
||||
std::ptr::write_volatile(&mut j, &mut a);
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test5: PtrToInt Cast
|
||||
// CHECK-LABEL: test5{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test5(a: i32) {
|
||||
let ptr_val: usize = &a as *const i32 as usize;
|
||||
|
||||
unsafe {
|
||||
printf(STR.as_ptr(), ptr_val);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test6: Passing addr-of to function call
|
||||
// CHECK-LABEL: test6{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test6(mut b: i32) {
|
||||
unsafe {
|
||||
funcall(&mut b as *mut i32);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test7: Addr-of in select instruction
|
||||
// CHECK-LABEL: test7{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test7() {
|
||||
let x: f64;
|
||||
|
||||
unsafe {
|
||||
let call = testi_aux();
|
||||
x = call;
|
||||
|
||||
let y: *const f64 = if call > 0.0 { &x as *const f64 } else { std::ptr::null() };
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test8: Addr-of in phi instruction
|
||||
// CHECK-LABEL: test8{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test8() {
|
||||
let mut _x: f64;
|
||||
|
||||
unsafe {
|
||||
let call = testi_aux();
|
||||
_x = call;
|
||||
|
||||
let y: *const f64;
|
||||
|
||||
if call > 3.14 {
|
||||
let call1 = testi_aux();
|
||||
_x = call1;
|
||||
y = std::ptr::null();
|
||||
} else {
|
||||
if call > 1.0 {
|
||||
y = &_x;
|
||||
} else {
|
||||
y = std::ptr::null();
|
||||
}
|
||||
}
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test9: Addr-of struct element(GEP followed by store)
|
||||
// CHECK-LABEL: test9{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test9() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
let b: *mut i32;
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
b = y;
|
||||
|
||||
printf(STR.as_ptr(), b);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test10: Addr-of struct element, GEP followed by ptrtoint
|
||||
// CHECK-LABEL: test10{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test10() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
let addr: i64 = y as i64;
|
||||
|
||||
printf(STR.as_ptr(), addr);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test11: Addr-of struct element, GEP followed by callinst
|
||||
// CHECK-LABEL: test11{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test11() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test12: Addr-of a local, optimized into a GEP (e.g., &a - 12)
|
||||
// CHECK-LABEL: test12{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test12() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
unsafe {
|
||||
let add_ptr = (&mut a as *mut i32).offset(-12);
|
||||
|
||||
printf(STR.as_ptr(), add_ptr);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test13: Addr-of a local cast to a ptr of a different type
|
||||
// (e.g., int a; ... ; ptr b = &a;)
|
||||
// CHECK-LABEL: test13{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test13() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
unsafe {
|
||||
let mut b: *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut b, &mut a); // avoid ptr b from optimization
|
||||
let tmp = std::ptr::read_volatile(&b);
|
||||
|
||||
printf(STR.as_ptr(), tmp);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test14: Addr-of a local cast to a ptr of a different type (optimized)
|
||||
// (e.g., int a; ... ; ptr b = &a;)
|
||||
// CHECK-LABEL: test14{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test14() {
|
||||
let a: i32 = 0;
|
||||
unsafe {
|
||||
funfloat((&a as *const i32).cast::<f64>() as *mut f64);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test15: Addr-of a variable passed into an invoke instruction
|
||||
// CHECK-LABEL: test15{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test15() -> i32 {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
except(&mut a as *mut i32);
|
||||
|
||||
0
|
||||
|
||||
// stack protector does not generated by LLVM because of Windows SEH.
|
||||
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test16: Addr-of a struct element passed into an invoke instruction
|
||||
// (GEP followed by an invoke)
|
||||
// CHECK-LABEL: test16{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test16() -> i32 {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
except(&mut c.a as *mut i32);
|
||||
|
||||
0
|
||||
|
||||
// stack protector does not generated by LLVM because of Windows SEH.
|
||||
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test17: Addr-of a pointer
|
||||
// CHECK-LABEL: test17{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test17() {
|
||||
let mut a: *mut i32 = getp();
|
||||
|
||||
let mut _b: *mut *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut _b, &mut a);
|
||||
|
||||
let tmp = std::ptr::read_volatile(&_b);
|
||||
|
||||
funcall2(tmp);
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test18: Addr-of a casted pointer
|
||||
// CHECK-LABEL: test18{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test18() {
|
||||
let mut a: *mut i32 = getp();
|
||||
|
||||
let mut _b: *mut *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut _b, &mut a);
|
||||
|
||||
let tmp = std::ptr::read_volatile(&_b);
|
||||
|
||||
funfloat2(tmp as *mut *mut f64);
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test19: array of [4 x i32]
|
||||
// CHECK-LABEL: test19{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test19() -> i32 {
|
||||
let a: [i32; 4] = [0; 4];
|
||||
|
||||
let _whole = std::ptr::read_volatile(&a as *const _); // avoid array a from optimization
|
||||
|
||||
std::ptr::read_volatile(&a[0])
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test20: Nested structure, no arrays, no address-of expressions
|
||||
// Verify that the resulting gep-of-gep does not incorrectly trigger
|
||||
// a stack protector
|
||||
// CHECK-LABEL: test20{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test20() {
|
||||
let c = Nest { first: Pair { a: 10, b: 11 }, second: Pair { a: 20, b: 21 } };
|
||||
|
||||
let whole: Nest = std::ptr::read_volatile(&c);
|
||||
|
||||
let v: i32 = whole.second.a;
|
||||
|
||||
printf(STR.as_ptr(), v);
|
||||
|
||||
// strong-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test21: Address-of a structure taken in a function with a loop where
|
||||
// the alloca is an incoming value to a PHI node and a use of that PHI
|
||||
// node is also an incoming value
|
||||
// Verify that the address-of analysis does not get stuck in infinite
|
||||
// recursion when chasing the alloca through the PHI nodes
|
||||
// CHECK-LABEL: test21{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test21() -> i32 {
|
||||
let mut tmp: *mut u8 = std::ptr::null_mut();
|
||||
let tmp_ptr: *mut *mut u8 = &mut tmp;
|
||||
|
||||
let tmp1 = dummy(tmp_ptr);
|
||||
|
||||
let cur = std::ptr::read_volatile(tmp_ptr);
|
||||
|
||||
let v = (cur as usize as i64) as i32;
|
||||
|
||||
if v > 0 {
|
||||
let mut phi_ptr: *mut u8 = cur;
|
||||
let mut phi_idx: i64 = 1;
|
||||
let mut phi_acc: i32 = tmp1;
|
||||
|
||||
loop {
|
||||
let b = std::ptr::read_volatile(phi_ptr as *const u8);
|
||||
let cond = b == 1u8;
|
||||
let plus = phi_acc.wrapping_add(8);
|
||||
let next_acc = if cond { plus } else { phi_acc };
|
||||
|
||||
if (phi_idx as i32) == v {
|
||||
dummy(next_acc);
|
||||
break;
|
||||
}
|
||||
|
||||
let slot = tmp_ptr.add(phi_idx as usize);
|
||||
let next = std::ptr::read_volatile(slot);
|
||||
phi_ptr = next;
|
||||
phi_idx += 1;
|
||||
phi_acc = next_acc;
|
||||
}
|
||||
} else {
|
||||
dummy(tmp1);
|
||||
}
|
||||
|
||||
0
|
||||
|
||||
// strong: __security_check_cookie
|
||||
}
|
||||
|
||||
// CHECK-LABEL: IgnoreIntrinsicTest{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn IgnoreIntrinsicTest() -> i32 {
|
||||
let mut x: i32 = 0;
|
||||
|
||||
std::ptr::write_volatile(&mut x, 1);
|
||||
|
||||
let y = std::ptr::read_volatile(&x);
|
||||
|
||||
let result = y.wrapping_mul(42);
|
||||
|
||||
result
|
||||
|
||||
// strong-NOT: __security_check_cookie
|
||||
}
|
||||
|
|
@ -0,0 +1,491 @@
|
|||
//@ revisions: all strong 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
|
||||
//@ [none] compile-flags: -Z stack-protector=none
|
||||
//@ compile-flags: -C opt-level=2 -Z merge-functions=disabled
|
||||
|
||||
#![crate_type = "lib"]
|
||||
#![feature(unsized_fn_params)]
|
||||
|
||||
extern "C" {
|
||||
fn strcpy(dest: *mut u8, src: *const u8) -> *mut u8;
|
||||
fn printf(fmt: *const u8, ...) -> i32;
|
||||
fn funcall(p: *mut i32);
|
||||
fn funcall2(p: *mut *mut i32);
|
||||
fn funfloat(p: *mut f64);
|
||||
fn funfloat2(p: *mut *mut f64);
|
||||
fn testi_aux() -> f64;
|
||||
fn getp() -> *mut i32;
|
||||
fn dummy(_: ...) -> i32;
|
||||
|
||||
static STR: [u8; 1];
|
||||
}
|
||||
|
||||
extern "C-unwind" {
|
||||
fn except(p: *mut i32);
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Pair {
|
||||
a: i32,
|
||||
b: i32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct Nest {
|
||||
first: Pair,
|
||||
second: Pair,
|
||||
}
|
||||
|
||||
// test1: array of [16 x i8]
|
||||
// CHECK-LABEL: test1{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test1(a: *const u8) {
|
||||
let mut buf: [u8; 16] = [0; 16];
|
||||
|
||||
unsafe {
|
||||
strcpy(buf.as_mut_ptr(), a);
|
||||
printf(STR.as_ptr(), buf.as_ptr());
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test2: array [4 x i8]
|
||||
// CHECK-LABEL: test2{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test2(a: *const u8) {
|
||||
let mut buf: [u8; 4] = [0; 4];
|
||||
|
||||
unsafe {
|
||||
strcpy(buf.as_mut_ptr(), a);
|
||||
printf(STR.as_ptr(), buf.as_ptr());
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test3: no arrays / no nested arrays
|
||||
// CHECK-LABEL: test3{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test3(a: *const u8) {
|
||||
unsafe {
|
||||
printf(STR.as_ptr(), a);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test4: Address-of local taken (j = &a)
|
||||
// CHECK-LABEL: test4{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test4() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
let mut j: *mut i32 = std::ptr::null_mut();
|
||||
|
||||
let tmp = std::ptr::read_volatile(&a);
|
||||
let tmp2 = tmp.wrapping_add(1);
|
||||
std::ptr::write_volatile(&mut a, tmp2);
|
||||
|
||||
std::ptr::write_volatile(&mut j, &mut a);
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test5: PtrToInt Cast
|
||||
// CHECK-LABEL: test5{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test5(a: i32) {
|
||||
let ptr_val: usize = &a as *const i32 as usize;
|
||||
|
||||
unsafe {
|
||||
printf(STR.as_ptr(), ptr_val);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test6: Passing addr-of to function call
|
||||
// CHECK-LABEL: test6{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test6(mut b: i32) {
|
||||
unsafe {
|
||||
funcall(&mut b as *mut i32);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test7: Addr-of in select instruction
|
||||
// CHECK-LABEL: test7{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test7() {
|
||||
let x: f64;
|
||||
|
||||
unsafe {
|
||||
let call = testi_aux();
|
||||
x = call;
|
||||
|
||||
let y: *const f64 = if call > 0.0 { &x as *const f64 } else { std::ptr::null() };
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test8: Addr-of in phi instruction
|
||||
// CHECK-LABEL: test8{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test8() {
|
||||
let mut _x: f64;
|
||||
|
||||
unsafe {
|
||||
let call = testi_aux();
|
||||
_x = call;
|
||||
|
||||
let y: *const f64;
|
||||
|
||||
if call > 3.14 {
|
||||
let call1 = testi_aux();
|
||||
_x = call1;
|
||||
y = std::ptr::null();
|
||||
} else {
|
||||
if call > 1.0 {
|
||||
y = &_x;
|
||||
} else {
|
||||
y = std::ptr::null();
|
||||
}
|
||||
}
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test9: Addr-of struct element(GEP followed by store)
|
||||
// CHECK-LABEL: test9{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test9() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
let b: *mut i32;
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
b = y;
|
||||
|
||||
printf(STR.as_ptr(), b);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test10: Addr-of struct element, GEP followed by ptrtoint
|
||||
// CHECK-LABEL: test10{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test10() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
let addr: i64 = y as i64;
|
||||
|
||||
printf(STR.as_ptr(), addr);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test11: Addr-of struct element, GEP followed by callinst
|
||||
// CHECK-LABEL: test11{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test11() {
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
unsafe {
|
||||
let y: *mut i32 = &mut c.b;
|
||||
|
||||
printf(STR.as_ptr(), y);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test12: Addr-of a local, optimized into a GEP (e.g., &a - 12)
|
||||
// CHECK-LABEL: test12{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test12() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
unsafe {
|
||||
let add_ptr = (&mut a as *mut i32).offset(-12);
|
||||
|
||||
printf(STR.as_ptr(), add_ptr);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test13: Addr-of a local cast to a ptr of a different type
|
||||
// (e.g., int a; ... ; ptr b = &a;)
|
||||
// CHECK-LABEL: test13{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test13() {
|
||||
let mut a: i32 = 0;
|
||||
|
||||
unsafe {
|
||||
let mut b: *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut b, &mut a); // avoid ptr b from optimization
|
||||
let tmp = std::ptr::read_volatile(&b);
|
||||
|
||||
printf(STR.as_ptr(), tmp);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test14: Addr-of a local cast to a ptr of a different type (optimized)
|
||||
// (e.g., int a; ... ; ptr b = &a;)
|
||||
// CHECK-LABEL: test14{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub fn test14() {
|
||||
let a: i32 = 0;
|
||||
unsafe {
|
||||
funfloat((&a as *const i32).cast::<f64>() as *mut f64);
|
||||
}
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test15: Addr-of a variable passed into an invoke instruction
|
||||
// CHECK-LABEL: test15{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test15() -> i32 {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
|
||||
let mut a: i32 = 0;
|
||||
|
||||
except(&mut a as *mut i32);
|
||||
|
||||
0
|
||||
|
||||
// stack protector does not generated by LLVM because of Windows SEH.
|
||||
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// test16: Addr-of a struct element passed into an invoke instruction
|
||||
// (GEP followed by an invoke)
|
||||
// CHECK-LABEL: test16{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test16() -> i32 {
|
||||
// CHECK-DAG: .seh_endprologue
|
||||
|
||||
let mut c = Pair { a: 0, b: 0 };
|
||||
|
||||
except(&mut c.a as *mut i32);
|
||||
|
||||
0
|
||||
|
||||
// stack protector does not generated by LLVM because of Windows SEH.
|
||||
|
||||
// all-NOT: __security_check_cookie
|
||||
// strong-NOT: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
|
||||
// CHECK-DAG: .seh_endproc
|
||||
}
|
||||
|
||||
// test17: Addr-of a pointer
|
||||
// CHECK-LABEL: test17{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test17() {
|
||||
let mut a: *mut i32 = getp();
|
||||
|
||||
let mut _b: *mut *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut _b, &mut a);
|
||||
|
||||
let tmp = std::ptr::read_volatile(&_b);
|
||||
|
||||
funcall2(tmp);
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test18: Addr-of a casted pointer
|
||||
// CHECK-LABEL: test18{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test18() {
|
||||
let mut a: *mut i32 = getp();
|
||||
|
||||
let mut _b: *mut *mut i32 = std::ptr::null_mut();
|
||||
|
||||
std::ptr::write_volatile(&mut _b, &mut a);
|
||||
|
||||
let tmp = std::ptr::read_volatile(&_b);
|
||||
|
||||
funfloat2(tmp as *mut *mut f64);
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test19: array of [4 x i32]
|
||||
// CHECK-LABEL: test19{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test19() -> i32 {
|
||||
let a: [i32; 4] = [0; 4];
|
||||
|
||||
let _whole = std::ptr::read_volatile(&a as *const _); // avoid array a from optimization
|
||||
|
||||
std::ptr::read_volatile(&a[0])
|
||||
|
||||
// all: __security_check_cookie
|
||||
// strong: __security_check_cookie
|
||||
// none-NOT: __security_check_cookie
|
||||
// missing-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test20: Nested structure, no arrays, no address-of expressions
|
||||
// Verify that the resulting gep-of-gep does not incorrectly trigger
|
||||
// a stack protector
|
||||
// CHECK-LABEL: test20{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test20() {
|
||||
let c = Nest { first: Pair { a: 10, b: 11 }, second: Pair { a: 20, b: 21 } };
|
||||
|
||||
let whole: Nest = std::ptr::read_volatile(&c);
|
||||
|
||||
let v: i32 = whole.second.a;
|
||||
|
||||
printf(STR.as_ptr(), v);
|
||||
|
||||
// strong-NOT: __security_check_cookie
|
||||
}
|
||||
|
||||
// test21: Address-of a structure taken in a function with a loop where
|
||||
// the alloca is an incoming value to a PHI node and a use of that PHI
|
||||
// node is also an incoming value
|
||||
// Verify that the address-of analysis does not get stuck in infinite
|
||||
// recursion when chasing the alloca through the PHI nodes
|
||||
// CHECK-LABEL: test21{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn test21() -> i32 {
|
||||
let mut tmp: *mut u8 = std::ptr::null_mut();
|
||||
let tmp_ptr: *mut *mut u8 = &mut tmp;
|
||||
|
||||
let tmp1 = dummy(tmp_ptr);
|
||||
|
||||
let cur = std::ptr::read_volatile(tmp_ptr);
|
||||
|
||||
let v = (cur as usize as i64) as i32;
|
||||
|
||||
if v > 0 {
|
||||
let mut phi_ptr: *mut u8 = cur;
|
||||
let mut phi_idx: i64 = 1;
|
||||
let mut phi_acc: i32 = tmp1;
|
||||
|
||||
loop {
|
||||
let b = std::ptr::read_volatile(phi_ptr as *const u8);
|
||||
let cond = b == 1u8;
|
||||
let plus = phi_acc.wrapping_add(8);
|
||||
let next_acc = if cond { plus } else { phi_acc };
|
||||
|
||||
if (phi_idx as i32) == v {
|
||||
dummy(next_acc);
|
||||
break;
|
||||
}
|
||||
|
||||
let slot = tmp_ptr.add(phi_idx as usize);
|
||||
let next = std::ptr::read_volatile(slot);
|
||||
phi_ptr = next;
|
||||
phi_idx += 1;
|
||||
phi_acc = next_acc;
|
||||
}
|
||||
} else {
|
||||
dummy(tmp1);
|
||||
}
|
||||
|
||||
0
|
||||
|
||||
// strong: __security_check_cookie
|
||||
}
|
||||
|
||||
// CHECK-LABEL: IgnoreIntrinsicTest{{:|\[}}
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn IgnoreIntrinsicTest() -> i32 {
|
||||
let mut x: i32 = 0;
|
||||
|
||||
std::ptr::write_volatile(&mut x, 1);
|
||||
|
||||
let y = std::ptr::read_volatile(&x);
|
||||
|
||||
let result = y.wrapping_mul(42);
|
||||
|
||||
result
|
||||
|
||||
// strong-NOT: __security_check_cookie
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue