rust/tests/ui/sanitizer/cfi-closures.rs
Matthew Maurer 473a70de84 CFI: Support function pointers for trait methods
Adds support for both CFI and KCFI for attaching concrete and abstract
types to functions. KCFI does this through generation of `ReifyShim` on
any function pointer that could go in a vtable, and checking the
`ReifyReason` when emitting the instance. CFI does this by attaching
both the concrete and abstract type to every instance.

TypeID codegen tests are switched to be anchored on the left rather than
the right in order to allow emission of additional type attachments.

Fixes #115953
2024-04-02 19:11:16 +00:00

80 lines
1.6 KiB
Rust

// Check various forms of dynamic closure calls
//@ revisions: cfi kcfi
// FIXME(#122848) Remove only-linux once OSX CFI binaries work
//@ only-linux
//@ [cfi] needs-sanitizer-cfi
//@ [kcfi] needs-sanitizer-kcfi
//@ compile-flags: -C target-feature=-crt-static
//@ [cfi] compile-flags: -C codegen-units=1 -C lto -C prefer-dynamic=off -C opt-level=0
//@ [cfi] compile-flags: -Z sanitizer=cfi
//@ [kcfi] compile-flags: -Z sanitizer=kcfi
//@ [kcfi] compile-flags: -C panic=abort -Z panic-abort-tests -C prefer-dynamic=off
//@ compile-flags: --test
//@ run-pass
#![feature(fn_traits)]
#![feature(unboxed_closures)]
fn foo<'a, T>() -> Box<dyn Fn(&'a T) -> &'a T> {
Box::new(|x| x)
}
#[test]
fn dyn_fn_with_params() {
let x = 3;
let f = foo();
f(&x);
// FIXME remove once drops are working.
std::mem::forget(f);
}
#[test]
fn call_fn_trait() {
let f: &(dyn Fn()) = &(|| {}) as _;
f.call(());
}
#[test]
fn fn_ptr_cast() {
let f: &fn() = &((|| ()) as _);
f();
}
fn use_fnmut<F: FnMut()>(mut f: F) {
f()
}
#[test]
fn fn_to_fnmut() {
let f: &(dyn Fn()) = &(|| {}) as _;
use_fnmut(f);
}
fn hrtb_helper(f: &dyn for<'a> Fn(&'a usize)) {
f(&10)
}
#[test]
fn hrtb_fn() {
hrtb_helper((&|x: &usize| println!("{}", *x)) as _)
}
#[test]
fn fnonce() {
let f: Box<dyn FnOnce()> = Box::new(|| {}) as _;
f();
}
fn use_closure<C>(call: extern "rust-call" fn(&C, ()) -> i32, f: &C) -> i32 {
call(f, ())
}
#[test]
fn closure_addr_taken() {
let x = 3i32;
let f = || x;
let call = Fn::<()>::call;
use_closure(call, &f);
}