From f2f0d255df8d8345a481b949b63a35bcc5db7f2f Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Sat, 17 Feb 2024 14:47:44 +0000 Subject: [PATCH] CFI: Skip non-passed arguments Rust will occasionally rely on fn((), X) -> Y being compatible with fn(X) -> Y, since () is a non-passed argument. Relax CFI by choosing not to encode non-passed arguments. --- .../src/typeid/typeid_itanium_cxx_abi.rs | 22 +++++--- ...-type-metadata-id-itanium-cxx-abi-paths.rs | 50 ++++++++++--------- ...data-id-itanium-cxx-abi-primitive-types.rs | 6 +-- ...-itanium-cxx-abi-repr-transparent-types.rs | 2 +- .../sanitizer/cfi/normalize-integers.rs | 6 +-- tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs | 18 +++++++ 6 files changed, 65 insertions(+), 39 deletions(-) create mode 100644 tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index 51e2c96120ca..76a5d942c66b 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_span::def_id::DefId; use rustc_span::sym; -use rustc_target::abi::call::{Conv, FnAbi}; +use rustc_target::abi::call::{Conv, FnAbi, PassMode}; use rustc_target::abi::Integer; use rustc_target::spec::abi::Abi; use std::fmt::Write as _; @@ -1040,19 +1040,27 @@ pub fn typeid_for_fnabi<'tcx>( typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); // Encode the parameter types + + // We erase ZSTs as we go if the argument is skipped. This is an implementation detail of how + // MIR is currently treated by rustc, and subject to change in the future. Specifically, MIR + // interpretation today will allow skipped arguments to simply not be passed at a call-site. if !fn_abi.c_variadic { - if !fn_abi.args.is_empty() { - for arg in fn_abi.args.iter() { - let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options); - typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); - } - } else { + let mut pushed_arg = false; + for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) { + pushed_arg = true; + let ty = transform_ty(tcx, arg.layout.ty, transform_ty_options); + typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); + } + if !pushed_arg { // Empty parameter lists, whether declared as () or conventionally as (void), are // encoded with a void parameter specifier "v". typeid.push('v'); } } else { for n in 0..fn_abi.fixed_count as usize { + if fn_abi.args[n].mode == PassMode::Ignore { + continue; + } let ty = transform_ty(tcx, fn_abi.args[n].layout.ty, transform_ty_options); typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options)); } diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs index c5d8e0f22a2a..ca781a99296b 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-paths.rs @@ -47,40 +47,42 @@ pub fn foo() where let _: Type4 = ::bar; } -pub fn foo1(_: Type1) { } +// Force arguments to be passed by using a reference. Otherwise, they may end up PassMode::Ignore + +pub fn foo1(_: &Type1) { } // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo2(_: Type1, _: Type1) { } +pub fn foo2(_: &Type1, _: &Type1) { } // CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo3(_: Type1, _: Type1, _: Type1) { } +pub fn foo3(_: &Type1, _: &Type1, _: &Type1) { } // CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo4(_: Type2) { } +pub fn foo4(_: &Type2) { } // CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo5(_: Type2, _: Type2) { } +pub fn foo5(_: &Type2, _: &Type2) { } // CHECK: define{{.*}}4foo5{{.*}}!type ![[TYPE5:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo6(_: Type2, _: Type2, _: Type2) { } +pub fn foo6(_: &Type2, _: &Type2, _: &Type2) { } // CHECK: define{{.*}}4foo6{{.*}}!type ![[TYPE6:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo7(_: Type3) { } +pub fn foo7(_: &Type3) { } // CHECK: define{{.*}}4foo7{{.*}}!type ![[TYPE7:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo8(_: Type3, _: Type3) { } +pub fn foo8(_: &Type3, _: &Type3) { } // CHECK: define{{.*}}4foo8{{.*}}!type ![[TYPE8:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo9(_: Type3, _: Type3, _: Type3) { } +pub fn foo9(_: &Type3, _: &Type3, _: &Type3) { } // CHECK: define{{.*}}4foo9{{.*}}!type ![[TYPE9:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo10(_: Type4) { } +pub fn foo10(_: &Type4) { } // CHECK: define{{.*}}5foo10{{.*}}!type ![[TYPE10:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo11(_: Type4, _: Type4) { } +pub fn foo11(_: &Type4, _: &Type4) { } // CHECK: define{{.*}}5foo11{{.*}}!type ![[TYPE11:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -pub fn foo12(_: Type4, _: Type4, _: Type4) { } +pub fn foo12(_: &Type4, _: &Type4, _: &Type4) { } // CHECK: define{{.*}}5foo12{{.*}}!type ![[TYPE12:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} -// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barS_E"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barS_S_E"} -// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooE"} -// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooS_E"} -// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooS_S_E"} -// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooE"} -// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooS_E"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooS_S_E"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barE"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barS_E"} -// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barS_S_E"} +// CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barEE"} +// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_E"} +// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNFNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo10{{[{}][{}]}}extern{{[}][}]}}3barES0_S0_E"} +// CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooEE"} +// CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_E"} +// CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNCNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo11{{[{}][{}]}}closure{{[}][}]}}3FooES0_S0_E"} +// CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooEE"} +// CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_E"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NtNkNvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo12{{[{}][{}]}}constant{{[}][}]}}3FooES0_S0_E"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barEE"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_E"} +// CHECK: ![[TYPE12]] = !{i64 0, !"_ZTSFvu3refIu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_{{[[:print:]]+}}3foo8{{[{}][{}]}}impl{{[}][}]}}3barES0_S0_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs index 3a1a09150eae..38f507856bde 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-primitive-types.rs @@ -12,9 +12,9 @@ use core::ffi::*; pub fn foo1(_: ()) { } // CHECK: define{{.*}}4foo1{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo2(_: (), _: c_void) { } -// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo2{{.*}}!type ![[TYPE1:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo3(_: (), _: c_void, _: c_void) { } -// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE3:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} +// CHECK: define{{.*}}4foo3{{.*}}!type ![[TYPE2:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo4(_: *mut ()) { } // CHECK: define{{.*}}4foo4{{.*}}!type ![[TYPE4:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} pub fn foo5(_: *mut (), _: *mut c_void) { } @@ -131,8 +131,6 @@ pub fn foo60(_: &str, _: &str, _: &str) { } // CHECK: define{{.*}}5foo60{{.*}}!type ![[TYPE60:[0-9]+]] !type !{{[0-9]+}} !type !{{[0-9]+}} !type !{{[0-9]+}} // CHECK: ![[TYPE1]] = !{i64 0, !"_ZTSFvvE"} -// CHECK: ![[TYPE2]] = !{i64 0, !"_ZTSFvvvE"} -// CHECK: ![[TYPE3]] = !{i64 0, !"_ZTSFvvvvE"} // CHECK: ![[TYPE4]] = !{i64 0, !"_ZTSFvPvE"} // CHECK: ![[TYPE5]] = !{i64 0, !"_ZTSFvPvS_E"} // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFvPvS_S_E"} diff --git a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs index 0deda029c4b0..6f47f5e33557 100644 --- a/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs +++ b/tests/codegen/sanitizer/cfi/emit-type-metadata-id-itanium-cxx-abi-repr-transparent-types.rs @@ -28,7 +28,7 @@ pub struct Type2<'a> { member3: &'a Type2<'a>, } -pub struct Bar; +pub struct Bar(i32); // repr(transparent) user-defined generic type #[repr(transparent)] diff --git a/tests/codegen/sanitizer/cfi/normalize-integers.rs b/tests/codegen/sanitizer/cfi/normalize-integers.rs index 210814eb9ae1..801ed312be5b 100644 --- a/tests/codegen/sanitizer/cfi/normalize-integers.rs +++ b/tests/codegen/sanitizer/cfi/normalize-integers.rs @@ -41,6 +41,6 @@ pub fn foo11(_: (), _: usize, _: usize, _: usize) { } // CHECK: ![[TYPE6]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}E.normalized"} // CHECK: ![[TYPE7]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_E.normalized"} // CHECK: ![[TYPE8]] = !{i64 0, !"_ZTSFv{{u3i16|u3i32|u3i64|u4i128}}S_S_E.normalized"} -// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"} -// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"} -// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFvv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"} +// CHECK: ![[TYPE9]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}E.normalized"} +// CHECK: ![[TYPE10]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_E.normalized"} +// CHECK: ![[TYPE11]] = !{i64 0, !"_ZTSFv{{u3u16|u3u32|u3u64|u4u128}}S_S_E.normalized"} diff --git a/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs new file mode 100644 index 000000000000..a46a3afd7343 --- /dev/null +++ b/tests/ui/sanitizer/cfi-closure-fn-ptr-cast.rs @@ -0,0 +1,18 @@ +// Tests that converting a closure to a function pointer works +// The notable thing being tested here is that when the closure does not capture anything, +// the call method from its Fn trait takes a ZST representing its environment. The compiler then +// uses the assumption that the ZST is non-passed to reify this into a function pointer. +// +// This checks that the reified function pointer will have the expected alias set at its call-site. + +//@ needs-sanitizer-cfi +// FIXME(#122848) Remove only-linux once OSX CFI binaries work +//@ only-linux +//@ compile-flags: --crate-type=bin -Cprefer-dynamic=off -Clto -Zsanitizer=cfi +//@ compile-flags: -C target-feature=-crt-static -C codegen-units=1 -C opt-level=0 +//@ run-pass + +pub fn main() { + let f: &fn() = &((|| ()) as _); + f(); +}